diff --git a/common/core/components/page/PageHeader.tsx b/common/core/components/page/PageHeader.tsx index c574079a..a1a10969 100644 --- a/common/core/components/page/PageHeader.tsx +++ b/common/core/components/page/PageHeader.tsx @@ -35,7 +35,7 @@ export function PageHeader({ className={cx( "flex flex-wrap items-start justify-between gap-4", sticky && - "sticky top-[-2.5rem] z-20 -mt-4 bg-background/95 pt-4 pb-2 backdrop-blur", + "sticky top-[-2.5rem] z-20 -mt-4 bg-background/95 pt-4 pb-2 backdrop-blur", className, )} {...props} diff --git a/devfront/src/features/audit/AuditLogsPage.tsx b/devfront/src/features/audit/AuditLogsPage.tsx index c15aaa6f..14fe276f 100644 --- a/devfront/src/features/audit/AuditLogsPage.tsx +++ b/devfront/src/features/audit/AuditLogsPage.tsx @@ -1,6 +1,6 @@ import { useInfiniteQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; -import { Download, RefreshCw, Search } from "lucide-react"; +import { Download, NotebookTabs, RefreshCw, Search } from "lucide-react"; import * as React from "react"; import { parseAuditDetails } from "../../../../common/core/audit"; import { AuditLogTable } from "../../../../common/core/components/audit"; @@ -12,6 +12,7 @@ import { Button } from "../../components/ui/button"; import { Card, CardContent, + CardDescription, CardHeader, CardTitle, } from "../../components/ui/card"; @@ -120,6 +121,7 @@ function AuditLogsPage() { return (
} title={t("ui.common.audit.title", "Audit Logs")} description={t( "msg.dev.audit.subtitle", @@ -157,6 +159,12 @@ function AuditLogsPage() { {t("ui.common.audit.registry.title", "Audit registry")} + + {t( + "msg.dev.audit.registry_description", + "최근 감사 로그를 검색 조건에 맞춰 필터링하고, 작업 이력을 빠르게 확인합니다.", + )} +
diff --git a/devfront/src/features/clients/ClientConsentsPage.tsx b/devfront/src/features/clients/ClientConsentsPage.tsx index 00da9ce7..8d9bb12b 100644 --- a/devfront/src/features/clients/ClientConsentsPage.tsx +++ b/devfront/src/features/clients/ClientConsentsPage.tsx @@ -1,15 +1,16 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { - ArrowLeft, ChevronLeft, ChevronRight, Download, Filter, Search, + ShieldHalf, } from "lucide-react"; import { useState } from "react"; import { Link, useParams } from "react-router-dom"; +import { PageHeader } from "../../../../common/core/components/page"; import { commonStickyTableHeaderClass, commonTableShellClass, @@ -194,21 +195,13 @@ function ClientConsentsPage() { )} -
- -
-

- {t( - "ui.dev.clients.consents.title", - "User Consent Grants", - )} -

-
-
+ } + title={t( + "ui.dev.clients.consents.title", + "User Consent Grants", + )} + /> @@ -242,24 +235,14 @@ function ClientConsentsPage() { )} -
- -
-

- {t("ui.dev.clients.consents.title", "User Consent Grants")} -

-

- {t( - "msg.dev.clients.consents.subtitle", - "OIDC Relying Party 사용자 권한을 검토·관리합니다.", - )} -

-
-
+ } + title={t("ui.dev.clients.consents.title", "User Consent Grants")} + description={t( + "msg.dev.clients.consents.subtitle", + "OIDC Relying Party 사용자 권한을 검토·관리합니다.", + )} + />
- + {rows.filter((r) => r.status === "active").length} @@ -636,7 +619,7 @@ function ClientConsentsPage() { "Total Scopes Issued", )}

- + {rows.reduce((acc, row) => acc + row.grantedScopes.length, 0)} @@ -649,7 +632,7 @@ function ClientConsentsPage() { "Avg. Scopes per User", )}

- + {rows.length > 0 ? ( rows.reduce( diff --git a/devfront/src/features/clients/ClientDetailsPage.tsx b/devfront/src/features/clients/ClientDetailsPage.tsx index 0f2c50b0..e7ada9b3 100644 --- a/devfront/src/features/clients/ClientDetailsPage.tsx +++ b/devfront/src/features/clients/ClientDetailsPage.tsx @@ -1,16 +1,17 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { - ArrowLeft, Eye, EyeOff, Link2, RefreshCw, Save, Shield, + ShieldHalf, } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { Link, useParams } from "react-router-dom"; +import { PageHeader } from "../../../../common/core/components/page"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; import { @@ -246,36 +247,26 @@ function ClientDetailsPage() { {t("ui.dev.clients.details.tab.connection", "Federation")} -
-
- -
-

- {client?.name || client?.id || clientId} -

-

- {t( - "msg.dev.clients.details.subtitle", - "Manage OIDC credentials and endpoints.", - )} -

-
-
- - {client?.status === "active" - ? t("ui.common.status.active", "Active") - : client?.status === "inactive" - ? t("ui.common.status.inactive", "Inactive") - : t("msg.common.loading", "Loading...")} - -
+ } + title={client?.name || client?.id || clientId} + description={t( + "msg.dev.clients.details.subtitle", + "Manage OIDC credentials and endpoints.", + )} + actions={ + + {client?.status === "active" + ? t("ui.common.status.active", "Active") + : client?.status === "inactive" + ? t("ui.common.status.inactive", "Inactive") + : t("msg.common.loading", "Loading...")} + + } + />
diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx index 8e3ace74..dd6e2788 100644 --- a/devfront/src/features/clients/ClientGeneralPage.tsx +++ b/devfront/src/features/clients/ClientGeneralPage.tsx @@ -1,7 +1,6 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { - ArrowLeft, Check, ExternalLink, Info, @@ -9,6 +8,7 @@ import { Save, Search, Shield, + ShieldHalf, Sparkles, Trash2, Upload, @@ -17,6 +17,7 @@ import { import { useEffect, useState } from "react"; import { useAuth } from "react-oidc-context"; import { Link, useNavigate, useParams } from "react-router-dom"; +import { PageHeader } from "../../../../common/core/components/page"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; import { @@ -1195,26 +1196,18 @@ function ClientGeneralPage() { )} -
- -
-

- {isCreate - ? t("ui.dev.clients.general.title_create", "Create Client") - : t("ui.dev.clients.general.title_edit", "Client Settings")} -

-

- {t( - "ui.dev.clients.general.subtitle", - "앱 정보, 권한 스코프, 보안 설정을 관리합니다.", - )} -

-
-
+ } + title={ + isCreate + ? t("ui.dev.clients.general.title_create", "Create Client") + : t("ui.dev.clients.general.title_edit", "Client Settings") + } + description={t( + "ui.dev.clients.general.subtitle", + "앱 정보, 권한 스코프, 보안 설정을 관리합니다.", + )} + /> {!isCreate && ( -
- -
-

- {t( - "ui.dev.clients.relationships.title", - "Client Relationships", - )} -

-

- {t( - "msg.dev.clients.relationships.subtitle", - "RP direct operator relation을 조회하고 User 단위로 추가·삭제합니다.", - )} -

-
-
+ } + title={t("ui.dev.clients.relationships.title", "Client Relationships")} + description={t( + "msg.dev.clients.relationships.subtitle", + "RP direct operator relation을 조회하고 User 단위로 추가·삭제합니다.", + )} + />
} title={t("ui.dev.clients.registry.subtitle", "연동 앱")} description={t( "msg.dev.clients.registry.description", diff --git a/devfront/src/features/clients/routes/ClientFederationPage.tsx b/devfront/src/features/clients/routes/ClientFederationPage.tsx index 6700e7fe..8f8a2999 100644 --- a/devfront/src/features/clients/routes/ClientFederationPage.tsx +++ b/devfront/src/features/clients/routes/ClientFederationPage.tsx @@ -1,7 +1,8 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { Edit, Globe, Plus, Save, Trash2 } from "lucide-react"; +import { Edit, Plus, Save, ShieldHalf, Trash2 } from "lucide-react"; import { useState } from "react"; import { useParams } from "react-router-dom"; +import { PageHeader } from "../../../../../common/core/components/page"; import { Button } from "../../../components/ui/button"; import { Card, @@ -195,24 +196,20 @@ export function ClientFederationPage() { return (
-
-
-

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

-

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

-
- -
+ } + title={t("ui.dev.clients.federation.title", "Identity Federation")} + description={t( + "msg.dev.clients.federation.subtitle", + "Manage external identity providers for this application.", + )} + actions={ + + } + /> diff --git a/devfront/src/features/developer-request/DeveloperRequestPage.tsx b/devfront/src/features/developer-request/DeveloperRequestPage.tsx index 76bdd042..1031b02f 100644 --- a/devfront/src/features/developer-request/DeveloperRequestPage.tsx +++ b/devfront/src/features/developer-request/DeveloperRequestPage.tsx @@ -1,5 +1,6 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { + ClipboardCheck, CheckCircle2, Clock, Plus, @@ -20,6 +21,7 @@ import { Button } from "../../components/ui/button"; import { Card, CardContent, + CardDescription, CardHeader, CardTitle, } from "../../components/ui/card"; @@ -152,6 +154,8 @@ export default function DeveloperRequestPage() { const hasActiveRequest = requests?.some( (r) => r.status === "pending" || r.status === "approved", ); + const approvedRequestCount = + requests?.filter((request) => request.status === "approved").length ?? 0; const isActionPending = approveMutation.isPending || rejectMutation.isPending || @@ -160,6 +164,7 @@ export default function DeveloperRequestPage() { return (
} title={t("ui.dev.nav.developer_request", "개발자 권한 신청")} description={ isSuperAdmin @@ -187,6 +192,13 @@ export default function DeveloperRequestPage() { {t("ui.dev.request.list.title", "신청 내역")} + + {t( + "msg.dev.request.list.approved_count", + "총 {{count}}명의 사용자가 승인되었습니다.", + { count: approvedRequestCount }, + )} +
diff --git a/devfront/src/features/overview/GlobalOverviewPage.tsx b/devfront/src/features/overview/GlobalOverviewPage.tsx index 7db5b53d..4d6302bd 100644 --- a/devfront/src/features/overview/GlobalOverviewPage.tsx +++ b/devfront/src/features/overview/GlobalOverviewPage.tsx @@ -3,8 +3,8 @@ import type { AxiosError } from "axios"; import { Activity, AlertTriangle, - BarChart3, CheckCircle2, + LayoutDashboard, Layers3, ShieldCheck, } from "lucide-react"; @@ -662,17 +662,22 @@ function GlobalOverviewPage() { return (
-
-
-

- {t("ui.common.overview.title", "운영 현황")} -

-

- {t( - "msg.dev.dashboard.description", - "연동 앱 구성과 인증 운영 지표를 한 곳에서 확인합니다.", - )} -

+
+
+
+ +
+
+

+ {t("ui.common.overview.title", "운영 현황")} +

+

+ {t( + "msg.dev.dashboard.description", + "연동 앱 구성과 인증 운영 지표를 한 곳에서 확인합니다.", + )} +

+
@@ -704,22 +709,19 @@ function GlobalOverviewPage() {
-
- -
-

- {t( - "ui.dev.dashboard.chart.title", - "애플리케이션별 로그인요청/기타 요청 현황", - )} -

-

- {t( - "msg.dev.dashboard.chart.filter_description", - "전체 또는 선택한 애플리케이션만 기준으로 그래프를 확인합니다.", - )} -

-
+
+

+ {t( + "ui.dev.dashboard.chart.title", + "애플리케이션별 로그인요청/기타 요청 현황", + )} +

+

+ {t( + "msg.dev.dashboard.chart.filter_description", + "전체 또는 선택한 애플리케이션만 기준으로 그래프를 확인합니다.", + )} +

{[ diff --git a/devfront/src/features/profile/ProfilePage.tsx b/devfront/src/features/profile/ProfilePage.tsx index e19164bc..1aba06df 100644 --- a/devfront/src/features/profile/ProfilePage.tsx +++ b/devfront/src/features/profile/ProfilePage.tsx @@ -64,9 +64,14 @@ function ProfilePage() { return (
-

- {t("ui.dev.profile.title", "내 정보")} -

+
+
+ +
+

+ {t("ui.dev.profile.title", "내 정보")} +

+

{t( "ui.dev.profile.subtitle", diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml index 47c470d7..3deacc90 100644 --- a/devfront/src/locales/en.toml +++ b/devfront/src/locales/en.toml @@ -313,6 +313,7 @@ forbidden = "You do not have permission to view audit logs. Please request acces load_error = "Error loading audit logs: {{error}}" loaded_count = "Loaded {{count}} rows" loading = "Loading audit logs..." +registry_description = "Filter recent audit logs by search criteria and review action history quickly." subtitle = "View developer activity history within the current app scope and review target-specific changes." [msg.dev.request] @@ -320,6 +321,7 @@ admin_desc = "Manage developer access requests submitted by users." approved = "Approved." cancelled = "Approval has been cancelled." empty = "No requests found." +list.approved_count = "{{count}} users have been approved." need_cancel_notes = "Please enter a reason for cancelling approval." need_notes = "Please enter a rejection reason." rejected = "Rejected." diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml index 31638c6d..18a8b646 100644 --- a/devfront/src/locales/ko.toml +++ b/devfront/src/locales/ko.toml @@ -313,6 +313,7 @@ forbidden = "감사 로그를 조회할 권한이 없습니다. 관리자에게 load_error = "감사 로그 조회 실패: {{error}}" loaded_count = "로드된 로그 {{count}}건" loading = "감사 로그를 불러오는 중..." +registry_description = "최근 감사 로그를 검색 조건에 맞춰 필터링하고, 작업 이력을 빠르게 확인합니다." subtitle = "현재 앱 범위에서 개발자 작업 이력을 조회하고 대상별 변경 내역을 확인합니다." [msg.dev.request] @@ -320,6 +321,7 @@ admin_desc = "사용자들의 개발자 권한 신청 내역을 관리합니다. approved = "승인되었습니다." cancelled = "승인이 취소되었습니다." empty = "신청 내역이 없습니다." +list.approved_count = "총 {{count}}명의 사용자가 승인되었습니다." need_cancel_notes = "승인 취소 사유를 입력해주세요." need_notes = "반려 사유를 입력해주세요." rejected = "반려되었습니다." diff --git a/devfront/src/locales/template.toml b/devfront/src/locales/template.toml index 5be16834..9a0145d1 100644 --- a/devfront/src/locales/template.toml +++ b/devfront/src/locales/template.toml @@ -327,6 +327,7 @@ forbidden = "" load_error = "" loaded_count = "" loading = "" +registry_description = "" subtitle = "" [msg.dev.request] @@ -334,6 +335,7 @@ admin_desc = "" approved = "" cancelled = "" empty = "" +list.approved_count = "" need_cancel_notes = "" need_notes = "" rejected = ""