From 3cfece2a33e16231c9eb7fcc43d0649c5426e4dc Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 25 Feb 2026 16:07:41 +0900 Subject: [PATCH] =?UTF-8?q?devfront=20UI=20=EC=9D=BC=EA=B4=80=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A0=95=EB=A0=AC=20=EC=A0=95=EC=B1=85=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devfront/src/components/layout/AppLayout.tsx | 26 +- .../features/clients/ClientGeneralPage.tsx | 155 ++++---- .../clients/routes/ClientFederationPage.tsx | 356 +++++++++--------- devfront/src/locales/en.toml | 1 + devfront/src/locales/ko.toml | 1 + devfront/src/locales/template.toml | 1 + locales/en.toml | 2 +- locales/ko.toml | 2 +- 8 files changed, 287 insertions(+), 257 deletions(-) diff --git a/devfront/src/components/layout/AppLayout.tsx b/devfront/src/components/layout/AppLayout.tsx index 9e798031..a5163929 100644 --- a/devfront/src/components/layout/AppLayout.tsx +++ b/devfront/src/components/layout/AppLayout.tsx @@ -197,7 +197,20 @@ function AppLayout() { ))} -
+
+ +
+
+ +
+

{t("msg.dev.sidebar.notice", "개발자 전용 콘솔입니다.")}

{t( @@ -207,17 +220,6 @@ function AppLayout() {

- -
- -
diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx index ba910abd..349bba58 100644 --- a/devfront/src/features/clients/ClientGeneralPage.tsx +++ b/devfront/src/features/clients/ClientGeneralPage.tsx @@ -1,6 +1,6 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; -import { Plus, Shield, Sparkles, Trash2, Upload } from "lucide-react"; +import { Plus, Save, Shield, Sparkles, Trash2, Upload } from "lucide-react"; import { useEffect, useState } from "react"; import { Link, useNavigate, useParams } from "react-router-dom"; import { Badge } from "../../components/ui/badge"; @@ -16,6 +16,7 @@ import { Input } from "../../components/ui/input"; import { Label } from "../../components/ui/label"; import { Switch } from "../../components/ui/switch"; import { Textarea } from "../../components/ui/textarea"; +import { toast } from "../../components/ui/use-toast"; import { createClient, deleteClient, @@ -128,6 +129,21 @@ function ClientGeneralPage() { setScopes(scopes.filter((s) => s.id !== id)); }; + const handleStatusChange = (nextStatus: ClientStatus) => { + setStatus(nextStatus); + const statusLabel = + nextStatus === "active" + ? t("ui.common.status.active", "Active") + : t("ui.common.status.inactive", "Inactive"); + toast( + t( + "msg.dev.clients.general.status_changed", + "상태가 {{status}}로 변경되었습니다.", + { status: statusLabel }, + ), + ); + }; + const mutation = useMutation({ mutationFn: async () => { const scopeNames = scopes.map((scope) => scope.name).filter(Boolean); @@ -204,7 +220,7 @@ function ClientGeneralPage() { window.confirm( t( "msg.dev.clients.delete_confirm", - "정말로 이 앱을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "정말로 이 앱을 삭제하시습니까? 이 작업은 되돌릴 수 없습니다.", ), ) ) { @@ -309,33 +325,6 @@ function ClientGeneralPage() { )}
- {!isCreate && ( -
- -
- - setStatus(checked ? "active" : "inactive") - } - /> - - {status === "active" - ? t("ui.common.status.active", "활성") - : t("ui.common.status.inactive", "비활성")} - -
-
- )}
@@ -371,40 +360,66 @@ function ClientGeneralPage() { />
-
- -
-
- setLogoUrl(e.target.value)} - placeholder={t( - "ui.dev.clients.general.identity.logo_placeholder", - "https://example.com/logo.png", - )} - /> -

- {t( - "msg.dev.clients.general.identity.logo_help", - "인증 화면에 표시될 PNG/SVG URL입니다.", - )} -

-
-
- {logoUrl ? ( - {t( +
+ +
+
+ setLogoUrl(e.target.value)} + placeholder={t( + "ui.dev.clients.general.identity.logo_placeholder", + "https://example.com/logo.png", )} - className="h-full w-full object-contain" /> - ) : ( - - )} +

+ {t( + "msg.dev.clients.general.identity.logo_help", + "인증 화면에 표시될 PNG/SVG URL입니다.", + )} +

+
+
+ {logoUrl ? ( + {t( + ) : ( + + )} +
+
+
+ +
+ +
+ +
@@ -658,20 +673,30 @@ function ClientGeneralPage() { )}
-
+
diff --git a/devfront/src/features/clients/routes/ClientFederationPage.tsx b/devfront/src/features/clients/routes/ClientFederationPage.tsx index 898f4dc7..7fc7ca69 100644 --- a/devfront/src/features/clients/routes/ClientFederationPage.tsx +++ b/devfront/src/features/clients/routes/ClientFederationPage.tsx @@ -1,11 +1,30 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { Plus, Trash2, Edit, Globe, Save } from "lucide-react"; import { useState } from "react"; import { useParams } from "react-router-dom"; +import { Button } from "../../../components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "../../../components/ui/card"; +import { Input } from "../../../components/ui/input"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "../../../components/ui/table"; import { createIdpConfigForClient, listIdpConfigsForClient, } from "../../../lib/devApi"; import type { IdpConfig, IdpConfigCreateRequest } from "../../../lib/devApi"; +import { t } from "../../../lib/i18n"; // Proper Modal Component with Form const CreateIdpModal = ({ @@ -37,12 +56,10 @@ const CreateIdpModal = ({ onClose(); }, onError: (error) => { - // Basic error handling alert(`Failed to create configuration: ${error.message}`); }, }); - // 이 내용으로 교체해주세요 const handleChange = ( e: React.ChangeEvent, ) => { @@ -61,104 +78,89 @@ const CreateIdpModal = ({ if (!isOpen) return null; return ( -
-
-

Add New IdP Configuration

-
- {/* Display Name */} -
- - -
+
+ + + {t("ui.dev.clients.federation.add_title", "Add Identity Provider")} + + {t("msg.dev.clients.federation.add_subtitle", "Connect an external OIDC provider.")} + + + + +
+ + +
- {/* Issuer URL */} -
- - -
+
+ + +
- {/* Client ID */} -
- - -
+
+
+ + +
+
+ + +
+
- {/* Client Secret */} -
- - -
+
+ + +
- {/* Scopes */} -
- - -
- - {/* Action Buttons */} -
- - -
- -
+
+ + +
+ + +
); }; @@ -168,7 +170,7 @@ export function ClientFederationPage() { const [isCreateModalOpen, setCreateModalOpen] = useState(false); if (!clientId) { - return
Client ID is missing
; + return
Client ID is missing
; } const { data, isLoading, error } = useQuery({ @@ -177,94 +179,92 @@ export function ClientFederationPage() { }); return ( -
-

Identity Federation Settings

-

- Manage external identity providers for this application. -

+
+
+
+

+ + {t("ui.dev.clients.federation.title", "Identity Federation")} +

+

+ {t("msg.dev.clients.federation.subtitle", "Manage external identity providers for this application.")} +

+
+ +
-
- -
+ + + + + + Display Name + Provider Type + Status + Actions + + + + {isLoading ? ( + + + {t("msg.common.loading", "Loading...")} + + + ) : error ? ( + + + {(error as Error).message} + + + ) : data?.length === 0 ? ( + + + {t("msg.dev.clients.federation.empty", "No IdP configurations found.")} + + + ) : ( + data?.map((config: IdpConfig) => ( + + {config.display_name} + {config.provider_type.toUpperCase()} + + + {config.status} + + + +
+ + +
+
+ + )) + )} + +
+
+
setCreateModalOpen(false)} clientId={clientId} /> - - {isLoading &&
Loading configurations...
} - {error && ( -
- Failed to load configurations: {error.message} -
- )} - - {data && ( -
- - - - - - - - - - - {data.length === 0 ? ( - - - - ) : ( - data.map((config: IdpConfig) => ( - - - - - - - )) - )} - -
Display NameProvider TypeStatusActions
- No IdP configurations found. -
- {config.display_name} - - {config.provider_type.toUpperCase()} - - - {config.status} - - - - -
-
- )}
); } diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml index e01dd020..6b0d3b9c 100644 --- a/devfront/src/locales/en.toml +++ b/devfront/src/locales/en.toml @@ -252,6 +252,7 @@ load_error = "Error loading client: {{error}}" loading = "Loading client..." saved = "Saved" save_error = "Failed to save: {{error}}" +status_changed = "Status changed to {{status}}." [msg.dev.clients.general.identity] logo_help = "Logo Help" diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml index ef85680a..dfea9909 100644 --- a/devfront/src/locales/ko.toml +++ b/devfront/src/locales/ko.toml @@ -252,6 +252,7 @@ load_error = "Error loading client: {{error}}" loading = "Loading client..." saved = "설정이 저장되었습니다." save_error = "저장 실패: {{error}}" +status_changed = "상태가 {{status}}로 변경되었습니다." [msg.dev.clients.general.identity] logo_help = "인증 화면에 표시될 PNG/SVG URL입니다." diff --git a/devfront/src/locales/template.toml b/devfront/src/locales/template.toml index 5c2934c5..dc467da6 100644 --- a/devfront/src/locales/template.toml +++ b/devfront/src/locales/template.toml @@ -252,6 +252,7 @@ load_error = "" loading = "" saved = "" save_error = "" +status_changed = "" [msg.dev.clients.general.identity] logo_help = "" diff --git a/locales/en.toml b/locales/en.toml index 48fed153..fb709370 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -1168,7 +1168,7 @@ settings = "Settings" [ui.dev.clients.general] create = "Create Application" display_new = "Add Connected Application" -save = "Settings Save" +save = "Save" title_create = "Create Client" title_edit = "Client Settings" diff --git a/locales/ko.toml b/locales/ko.toml index 07162c9c..f28333d8 100644 --- a/locales/ko.toml +++ b/locales/ko.toml @@ -1168,7 +1168,7 @@ settings = "Settings" [ui.dev.clients.general] create = "앱 생성" display_new = "연동 앱 추가" -save = "설정 저장" +save = "저장" title_create = "Create Client" title_edit = "Client Settings"