From 4ef7ab78e24fda2b0a0e9b39865e19a1bfa8cc08 Mon Sep 17 00:00:00 2001 From: chan Date: Wed, 11 Feb 2026 10:47:44 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=85=8C=EB=84=8C=ED=8A=B8=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=EA=B4=80=EB=A6=AC=20UI=20=EB=B0=8F=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EB=A9=A4=EB=B2=84=EC=8B=AD=20=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20#239?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adminfront/src/app/routes.tsx | 13 ++ .../routes/TenantGroupCreatePage.tsx | 142 +++++++++++++ .../routes/TenantGroupDetailPage.tsx | 77 +++++++ .../routes/TenantGroupProfileTab.tsx | 97 +++++++++ .../routes/TenantGroupTenantsTab.tsx | 200 ++++++++++++++++++ .../tenants/routes/TenantProfilePage.tsx | 27 +++ adminfront/src/lib/adminApi.ts | 61 +++--- backend/cmd/server/main.go | 2 +- backend/internal/handler/tenant_handler.go | 81 ++++--- 9 files changed, 644 insertions(+), 56 deletions(-) create mode 100644 adminfront/src/features/tenant-groups/routes/TenantGroupCreatePage.tsx create mode 100644 adminfront/src/features/tenant-groups/routes/TenantGroupDetailPage.tsx create mode 100644 adminfront/src/features/tenant-groups/routes/TenantGroupProfileTab.tsx create mode 100644 adminfront/src/features/tenant-groups/routes/TenantGroupTenantsTab.tsx diff --git a/adminfront/src/app/routes.tsx b/adminfront/src/app/routes.tsx index 8cd13cf1..96bde96f 100644 --- a/adminfront/src/app/routes.tsx +++ b/adminfront/src/app/routes.tsx @@ -6,7 +6,11 @@ import AuditLogsPage from "../features/audit/AuditLogsPage"; import AuthPage from "../features/auth/AuthPage"; import DashboardPage from "../features/dashboard/DashboardPage"; import GlobalOverviewPage from "../features/overview/GlobalOverviewPage"; +import TenantGroupCreatePage from "../features/tenant-groups/routes/TenantGroupCreatePage"; +import TenantGroupDetailPage from "../features/tenant-groups/routes/TenantGroupDetailPage"; import TenantGroupListPage from "../features/tenant-groups/routes/TenantGroupListPage"; +import TenantGroupProfileTab from "../features/tenant-groups/routes/TenantGroupProfileTab"; +import TenantGroupTenantsTab from "../features/tenant-groups/routes/TenantGroupTenantsTab"; import TenantCreatePage from "../features/tenants/routes/TenantCreatePage"; import TenantDetailPage from "../features/tenants/routes/TenantDetailPage"; import TenantListPage from "../features/tenants/routes/TenantListPage"; @@ -32,6 +36,15 @@ export const router = createBrowserRouter( { path: "tenants", element: }, { path: "tenants/new", element: }, { path: "tenant-groups", element: }, + { path: "tenant-groups/new", element: }, + { + path: "tenant-groups/:id", + element: , + children: [ + { index: true, element: }, + { path: "tenants", element: }, + ], + }, { path: "tenants/:tenantId", element: , diff --git a/adminfront/src/features/tenant-groups/routes/TenantGroupCreatePage.tsx b/adminfront/src/features/tenant-groups/routes/TenantGroupCreatePage.tsx new file mode 100644 index 00000000..ccbd63e5 --- /dev/null +++ b/adminfront/src/features/tenant-groups/routes/TenantGroupCreatePage.tsx @@ -0,0 +1,142 @@ +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { LayoutGrid, Sparkles } from "lucide-react"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { Badge } from "../../../components/ui/badge"; +import { Button } from "../../../components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "../../../components/ui/card"; +import { Input } from "../../../components/ui/input"; +import { Label } from "../../../components/ui/label"; +import { Textarea } from "../../../components/ui/textarea"; +import { createTenantGroup } from "../../../lib/adminApi"; + +function TenantGroupCreatePage() { + const navigate = useNavigate(); + const [name, setName] = useState(""); + const [slug, setSlug] = useState(""); + const [description, setDescription] = useState(""); + + const mutation = useMutation({ + mutationFn: () => + createTenantGroup({ + name, + slug: slug || name.toLowerCase().replace(/ /g, "-"), + description: description || undefined, + }), + onSuccess: () => { + navigate("/tenant-groups"); + }, + }); + + const errorMsg = (mutation.error as AxiosError<{ error?: string }>)?.response + ?.data?.error; + + return ( +
+
+
+ Tenants + / + Groups + / + Create +
+
+
+

테넌트 그룹 추가

+

+ 여러 테넌트를 논리적으로 묶어 관리하기 위한 그룹을 생성합니다. +

+
+ Super Admin only +
+
+ + + + + + Group Profile + + + 그룹 이름과 식별자(Slug)를 입력합니다. + + + +
+ + setName(e.target.value)} + placeholder="예: 바론소프트웨어 통합그룹" + /> +
+
+ + setSlug(e.target.value)} + placeholder="baron-group" + /> +

+ URL이나 API에서 사용될 고유 식별자입니다. 비워두면 이름 기반으로 자동 생성됩니다. +

+
+
+ +