From 40d64acf15e6f01c334ad44259a6082a2e26b923 Mon Sep 17 00:00:00 2001 From: kyy Date: Wed, 13 May 2026 16:50:25 +0900 Subject: [PATCH] =?UTF-8?q?devfront=20=EC=97=B0=EB=8F=99=20=EC=95=B1=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EA=B0=84?= =?UTF-8?q?=EA=B2=A9=20=EB=B0=8F=20=EB=AC=B8=EA=B5=AC=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devfront/src/features/clients/ClientsPage.tsx | 436 +++++++++--------- devfront/src/locales/en.toml | 2 +- devfront/src/locales/ko.toml | 2 +- 3 files changed, 219 insertions(+), 221 deletions(-) diff --git a/devfront/src/features/clients/ClientsPage.tsx b/devfront/src/features/clients/ClientsPage.tsx index 73b03603..2d840605 100644 --- a/devfront/src/features/clients/ClientsPage.tsx +++ b/devfront/src/features/clients/ClientsPage.tsx @@ -15,6 +15,10 @@ import { sortableTableHeadBaseClassName, sortableTableHeaderClassName, } from "../../../../common/core/components/sort"; +import { + commonTableShellClass, + commonTableViewportClass, +} from "../../../../common/ui/table"; import { type SortConfig, type SortResolverMap, @@ -427,233 +431,227 @@ function ClientsPage() { - -
+ +
{t("ui.dev.clients.list.title", "클라이언트 목록")} - {canCreateClient && ( -
- -
- )} -
-
- - - - - - - - - - - {t("ui.dev.clients.table.actions", "액션")} - - - - - {!hasFilterResult && ( - - -
-

- {isFilteredOut - ? t( - "msg.dev.clients.empty_filtered", - "조건에 맞는 연동 앱이 없습니다.", - ) - : canCreateClient - ? t( - "msg.dev.clients.empty_can_create", - "아직 등록된 연동 앱이 없습니다.", - ) - : isDeveloperRequestPending - ? t( - "msg.dev.clients.empty_pending", - "개발자 권한 신청을 검토 중입니다.", - ) - : t( - "msg.dev.clients.empty", - "조회 가능한 RP가 없습니다.", - )} -

-
-

- {isFilteredOut - ? t( - "msg.dev.clients.empty_filtered_detail", - "검색어나 필터 조건을 변경해 보세요.", - ) - : canCreateClient - ? t( - "msg.dev.clients.empty_can_create_detail", - "연동 앱 추가 버튼으로 새 RP를 생성하면 이 목록에 표시됩니다.", - ) - : isDeveloperRequestPending - ? t( - "msg.dev.clients.empty_pending_detail", - "super admin이 승인하면 연동 앱을 추가할 수 있습니다.", - ) - : t( - "msg.dev.clients.empty_detail", - "RP 관계가 부여되면 이 목록에 해당 RP가 표시됩니다.", - )} -

- {!isFilteredOut && canCreateClient && ( - - )} - {!isFilteredOut && canRequestDeveloperAccess && ( - - )} -
-
-
-
- )} - {filteredClients.map((client) => ( - - - - -
-

- {client.name || - t("ui.dev.clients.untitled", "Untitled")} -

-

- {t("ui.dev.clients.tenant_scoped", "Tenant-scoped")} -

-
- -
- -
- - {client.id} - -
-
- -
- - {client.metadata?.headless_login_enabled - ? t( - "ui.dev.clients.type.private_headless", - "Server side App (Headless Login)", - ) - : client.type === "private" - ? t( - "ui.dev.clients.type.private", - "Server side App", - ) - : t("ui.dev.clients.type.pkce", "PKCE")} - -
-
- - - {client.status === "active" - ? t("ui.common.status.active", "Active") - : t("ui.common.status.inactive", "Inactive")} - - - - {client.createdAt - ? new Date(client.createdAt).toLocaleDateString() - : "-"} - - -
- -
-
-
- ))} -
-
-
- + {t( "msg.dev.clients.showing", - "Showing {{shown}} of {{total}} clients", - { shown: filteredClients.length, total: totalClients }, + "총 {{shown}}개의 애플리케이션이 등록되어 있습니다.", + { shown: totalClients }, )} - -
- -
+ {canCreateClient && ( +
+
+ )} + + +
+
+ + + + + + + + + + {t("ui.dev.clients.table.actions", "액션")} + + + + + {!hasFilterResult && ( + + +
+

+ {isFilteredOut + ? t( + "msg.dev.clients.empty_filtered", + "조건에 맞는 연동 앱이 없습니다.", + ) + : canCreateClient + ? t( + "msg.dev.clients.empty_can_create", + "아직 등록된 연동 앱이 없습니다.", + ) + : isDeveloperRequestPending + ? t( + "msg.dev.clients.empty_pending", + "개발자 권한 신청을 검토 중입니다.", + ) + : t( + "msg.dev.clients.empty", + "조회 가능한 RP가 없습니다.", + )} +

+
+

+ {isFilteredOut + ? t( + "msg.dev.clients.empty_filtered_detail", + "검색어나 필터 조건을 변경해 보세요.", + ) + : canCreateClient + ? t( + "msg.dev.clients.empty_can_create_detail", + "연동 앱 추가 버튼으로 새 RP를 생성하면 이 목록에 표시됩니다.", + ) + : isDeveloperRequestPending + ? t( + "msg.dev.clients.empty_pending_detail", + "super admin이 승인하면 연동 앱을 추가할 수 있습니다.", + ) + : t( + "msg.dev.clients.empty_detail", + "RP 관계가 부여되면 이 목록에 해당 RP가 표시됩니다.", + )} +

+ {!isFilteredOut && canCreateClient && ( + + )} + {!isFilteredOut && canRequestDeveloperAccess && ( + + )} +
+
+
+
+ )} + {filteredClients.map((client) => ( + + + + +
+

+ {client.name || + t("ui.dev.clients.untitled", "Untitled")} +

+

+ {t("ui.dev.clients.tenant_scoped", "Tenant-scoped")} +

+
+ +
+ +
+ + {client.id} + +
+
+ +
+ + {client.metadata?.headless_login_enabled + ? t( + "ui.dev.clients.type.private_headless", + "Server side App (Headless Login)", + ) + : client.type === "private" + ? t( + "ui.dev.clients.type.private", + "Server side App", + ) + : t("ui.dev.clients.type.pkce", "PKCE")} + +
+
+ + + {client.status === "active" + ? t("ui.common.status.active", "Active") + : t("ui.common.status.inactive", "Inactive")} + + + + {client.createdAt + ? new Date(client.createdAt).toLocaleDateString() + : "-"} + + +
+ +
+
+
+ ))} +
+
+
diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml index 1ca157cd..008f3bd5 100644 --- a/devfront/src/locales/en.toml +++ b/devfront/src/locales/en.toml @@ -331,7 +331,7 @@ desc = "Please enter the reason for your request. It will be approved after admi [msg.dev.clients] load_error = "Error loading clients: {{error}}" loading = "Loading apps..." -showing = "Showing {{shown}} of {{total}} apps" +showing = "A total of {{shown}} applications are registered." deleted = "App deleted." delete_error = "Failed to delete: {{error}}" delete_confirm = "Are you sure you want to delete this app? This action cannot be undone." diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml index 3bb51e4e..1d5ca5d3 100644 --- a/devfront/src/locales/ko.toml +++ b/devfront/src/locales/ko.toml @@ -342,7 +342,7 @@ empty_pending = "개발자 권한 신청을 검토 중입니다." empty_pending_detail = "super admin이 승인하면 연동 앱을 추가할 수 있습니다." load_error = "앱 정보를 불러오지 못했습니다: {{error}}" loading = "앱 정보를 불러오는 중..." -showing = "전체 {{total}}개 중 {{shown}}개를 표시하는 중입니다." +showing = "총 {{shown}}개의 애플리케이션이 등록되어 있습니다." [msg.dev.clients.consents] empty = "조회된 동의 내역이 없습니다."