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 (
-
+
}
+ 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 = ""