1
0
forked from baron/baron-sso

페이지 헤더 스타일 통일

This commit is contained in:
2026-05-19 17:28:54 +09:00
parent 528ceea754
commit c2dbc8fc88
14 changed files with 150 additions and 164 deletions

View File

@@ -35,7 +35,7 @@ export function PageHeader({
className={cx( className={cx(
"flex flex-wrap items-start justify-between gap-4", "flex flex-wrap items-start justify-between gap-4",
sticky && 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, className,
)} )}
{...props} {...props}

View File

@@ -1,6 +1,6 @@
import { useInfiniteQuery } from "@tanstack/react-query"; import { useInfiniteQuery } from "@tanstack/react-query";
import type { AxiosError } from "axios"; 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 * as React from "react";
import { parseAuditDetails } from "../../../../common/core/audit"; import { parseAuditDetails } from "../../../../common/core/audit";
import { AuditLogTable } from "../../../../common/core/components/audit"; import { AuditLogTable } from "../../../../common/core/components/audit";
@@ -12,6 +12,7 @@ import { Button } from "../../components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardDescription,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "../../components/ui/card"; } from "../../components/ui/card";
@@ -120,6 +121,7 @@ function AuditLogsPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<PageHeader <PageHeader
icon={<NotebookTabs size={20} />}
title={t("ui.common.audit.title", "Audit Logs")} title={t("ui.common.audit.title", "Audit Logs")}
description={t( description={t(
"msg.dev.audit.subtitle", "msg.dev.audit.subtitle",
@@ -157,6 +159,12 @@ function AuditLogsPage() {
<CardTitle> <CardTitle>
{t("ui.common.audit.registry.title", "Audit registry")} {t("ui.common.audit.registry.title", "Audit registry")}
</CardTitle> </CardTitle>
<CardDescription>
{t(
"msg.dev.audit.registry_description",
"최근 감사 로그를 검색 조건에 맞춰 필터링하고, 작업 이력을 빠르게 확인합니다.",
)}
</CardDescription>
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="space-y-4 pt-0"> <CardContent className="space-y-4 pt-0">

View File

@@ -1,15 +1,16 @@
import { useMutation, useQuery } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
import { import {
ArrowLeft,
ChevronLeft, ChevronLeft,
ChevronRight, ChevronRight,
Download, Download,
Filter, Filter,
Search, Search,
ShieldHalf,
} from "lucide-react"; } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { Link, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import { PageHeader } from "../../../../common/core/components/page";
import { import {
commonStickyTableHeaderClass, commonStickyTableHeaderClass,
commonTableShellClass, commonTableShellClass,
@@ -194,21 +195,13 @@ function ClientConsentsPage() {
)} )}
</span> </span>
</nav> </nav>
<div className="flex items-center gap-2"> <PageHeader
<Button variant="ghost" size="icon" asChild> icon={<ShieldHalf size={20} />}
<Link to={`/clients/${clientId}`}> title={t(
<ArrowLeft className="h-4 w-4" /> "ui.dev.clients.consents.title",
</Link> "User Consent Grants",
</Button> )}
<div> />
<p className="text-3xl font-black leading-tight">
{t(
"ui.dev.clients.consents.title",
"User Consent Grants",
)}
</p>
</div>
</div>
</div> </div>
</div> </div>
<ClientDetailTabs activeTab="consents" clientId={clientId} /> <ClientDetailTabs activeTab="consents" clientId={clientId} />
@@ -242,24 +235,14 @@ function ClientConsentsPage() {
)} )}
</span> </span>
</nav> </nav>
<div className="flex items-center gap-2"> <PageHeader
<Button variant="ghost" size="icon" asChild> icon={<ShieldHalf size={20} />}
<Link to={`/clients/${clientId}`}> title={t("ui.dev.clients.consents.title", "User Consent Grants")}
<ArrowLeft className="h-4 w-4" /> description={t(
</Link> "msg.dev.clients.consents.subtitle",
</Button> "OIDC Relying Party 사용자 권한을 검토·관리합니다.",
<div> )}
<p className="text-3xl font-black leading-tight"> />
{t("ui.dev.clients.consents.title", "User Consent Grants")}
</p>
<p className="text-muted-foreground">
{t(
"msg.dev.clients.consents.subtitle",
"OIDC Relying Party 사용자 권한을 검토·관리합니다.",
)}
</p>
</div>
</div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Badge <Badge
@@ -623,7 +606,7 @@ function ClientConsentsPage() {
"Active Grants", "Active Grants",
)} )}
</p> </p>
<CardTitle className="text-2xl font-black"> <CardTitle className="text-xl font-semibold">
{rows.filter((r) => r.status === "active").length} {rows.filter((r) => r.status === "active").length}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
@@ -636,7 +619,7 @@ function ClientConsentsPage() {
"Total Scopes Issued", "Total Scopes Issued",
)} )}
</p> </p>
<CardTitle className="text-2xl font-black"> <CardTitle className="text-xl font-semibold">
{rows.reduce((acc, row) => acc + row.grantedScopes.length, 0)} {rows.reduce((acc, row) => acc + row.grantedScopes.length, 0)}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
@@ -649,7 +632,7 @@ function ClientConsentsPage() {
"Avg. Scopes per User", "Avg. Scopes per User",
)} )}
</p> </p>
<CardTitle className="text-2xl font-black"> <CardTitle className="text-xl font-semibold">
{rows.length > 0 {rows.length > 0
? ( ? (
rows.reduce( rows.reduce(

View File

@@ -1,16 +1,17 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
import { import {
ArrowLeft,
Eye, Eye,
EyeOff, EyeOff,
Link2, Link2,
RefreshCw, RefreshCw,
Save, Save,
Shield, Shield,
ShieldHalf,
} from "lucide-react"; } from "lucide-react";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { Link, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import { PageHeader } from "../../../../common/core/components/page";
import { Badge } from "../../components/ui/badge"; import { Badge } from "../../components/ui/badge";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
import { import {
@@ -246,36 +247,26 @@ function ClientDetailsPage() {
{t("ui.dev.clients.details.tab.connection", "Federation")} {t("ui.dev.clients.details.tab.connection", "Federation")}
</span> </span>
</nav> </nav>
<div className="flex flex-wrap items-start justify-between gap-3"> <PageHeader
<div className="flex items-center gap-2"> icon={<ShieldHalf size={20} />}
<Button variant="ghost" size="icon" asChild> title={client?.name || client?.id || clientId}
<Link to="/clients"> description={t(
<ArrowLeft className="h-4 w-4" /> "msg.dev.clients.details.subtitle",
</Link> "Manage OIDC credentials and endpoints.",
</Button> )}
<div> actions={
<h1 className="text-4xl font-black leading-tight tracking-tight"> <Badge
{client?.name || client?.id || clientId} variant={client?.status === "active" ? "info" : "muted"}
</h1> className="px-3 py-1 text-xs uppercase"
<p className="text-muted-foreground"> >
{t( {client?.status === "active"
"msg.dev.clients.details.subtitle", ? t("ui.common.status.active", "Active")
"Manage OIDC credentials and endpoints.", : client?.status === "inactive"
)} ? t("ui.common.status.inactive", "Inactive")
</p> : t("msg.common.loading", "Loading...")}
</div> </Badge>
</div> }
<Badge />
variant={client?.status === "active" ? "info" : "muted"}
className="px-3 py-1 text-xs uppercase"
>
{client?.status === "active"
? t("ui.common.status.active", "Active")
: client?.status === "inactive"
? t("ui.common.status.inactive", "Inactive")
: t("msg.common.loading", "Loading...")}
</Badge>
</div>
<ClientDetailTabs activeTab="connection" clientId={clientId} /> <ClientDetailTabs activeTab="connection" clientId={clientId} />
</div> </div>

View File

@@ -1,7 +1,6 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
import { import {
ArrowLeft,
Check, Check,
ExternalLink, ExternalLink,
Info, Info,
@@ -9,6 +8,7 @@ import {
Save, Save,
Search, Search,
Shield, Shield,
ShieldHalf,
Sparkles, Sparkles,
Trash2, Trash2,
Upload, Upload,
@@ -17,6 +17,7 @@ import {
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useAuth } from "react-oidc-context"; import { useAuth } from "react-oidc-context";
import { Link, useNavigate, useParams } from "react-router-dom"; import { Link, useNavigate, useParams } from "react-router-dom";
import { PageHeader } from "../../../../common/core/components/page";
import { Badge } from "../../components/ui/badge"; import { Badge } from "../../components/ui/badge";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
import { import {
@@ -1195,26 +1196,18 @@ function ClientGeneralPage() {
</> </>
)} )}
</nav> </nav>
<div className="flex items-center gap-2"> <PageHeader
<Button variant="ghost" size="icon" asChild> icon={<ShieldHalf size={20} />}
<Link to={isCreate ? "/clients" : `/clients/${clientId}`}> title={
<ArrowLeft className="h-4 w-4" /> isCreate
</Link> ? t("ui.dev.clients.general.title_create", "Create Client")
</Button> : t("ui.dev.clients.general.title_edit", "Client Settings")
<div> }
<h1 className="text-3xl font-black leading-tight"> description={t(
{isCreate "ui.dev.clients.general.subtitle",
? t("ui.dev.clients.general.title_create", "Create Client") "앱 정보, 권한 스코프, 보안 설정을 관리합니다.",
: t("ui.dev.clients.general.title_edit", "Client Settings")} )}
</h1> />
<p className="text-muted-foreground">
{t(
"ui.dev.clients.general.subtitle",
"앱 정보, 권한 스코프, 보안 설정을 관리합니다.",
)}
</p>
</div>
</div>
</div> </div>
{!isCreate && ( {!isCreate && (
<Badge <Badge

View File

@@ -1,9 +1,10 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
import { ArrowLeft, Info, Link2, Plus, Trash2, X } from "lucide-react"; import { Info, Link2, Plus, ShieldHalf, Trash2, X } from "lucide-react";
import { useDeferredValue, useMemo, useState } from "react"; import { useDeferredValue, useMemo, useState } from "react";
import { useAuth } from "react-oidc-context"; import { useAuth } from "react-oidc-context";
import { Link, useParams } from "react-router-dom"; import { Link, useParams } from "react-router-dom";
import { PageHeader } from "../../../../common/core/components/page";
import { Badge } from "../../components/ui/badge"; import { Badge } from "../../components/ui/badge";
import { Button } from "../../components/ui/button"; import { Button } from "../../components/ui/button";
import { import {
@@ -352,27 +353,14 @@ function ClientRelationsPage() {
{t("ui.dev.clients.details.tab.relationships", "Relationships")} {t("ui.dev.clients.details.tab.relationships", "Relationships")}
</span> </span>
</nav> </nav>
<div className="flex items-center gap-2"> <PageHeader
<Button variant="ghost" size="icon" asChild> icon={<ShieldHalf size={20} />}
<Link to={`/clients/${clientId}`}> title={t("ui.dev.clients.relationships.title", "Client Relationships")}
<ArrowLeft className="h-4 w-4" /> description={t(
</Link> "msg.dev.clients.relationships.subtitle",
</Button> "RP direct operator relation을 조회하고 User 단위로 추가·삭제합니다.",
<div> )}
<p className="text-3xl font-black leading-tight"> />
{t(
"ui.dev.clients.relationships.title",
"Client Relationships",
)}
</p>
<p className="text-muted-foreground">
{t(
"msg.dev.clients.relationships.subtitle",
"RP direct operator relation을 조회하고 User 단위로 추가·삭제합니다.",
)}
</p>
</div>
</div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Badge <Badge

View File

@@ -1,6 +1,6 @@
import { useMutation, useQuery } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import type { AxiosError } from "axios"; import type { AxiosError } from "axios";
import { BookOpenText, Filter, Plus, Search, X } from "lucide-react"; import { BookOpenText, Filter, Plus, Search, ShieldHalf, X } from "lucide-react";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { useAuth } from "react-oidc-context"; import { useAuth } from "react-oidc-context";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
@@ -262,6 +262,7 @@ function ClientsPage() {
return ( return (
<div className="space-y-8"> <div className="space-y-8">
<PageHeader <PageHeader
icon={<ShieldHalf size={20} />}
title={t("ui.dev.clients.registry.subtitle", "연동 앱")} title={t("ui.dev.clients.registry.subtitle", "연동 앱")}
description={t( description={t(
"msg.dev.clients.registry.description", "msg.dev.clients.registry.description",

View File

@@ -1,7 +1,8 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; 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 { useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { PageHeader } from "../../../../../common/core/components/page";
import { Button } from "../../../components/ui/button"; import { Button } from "../../../components/ui/button";
import { import {
Card, Card,
@@ -195,24 +196,20 @@ export function ClientFederationPage() {
return ( return (
<div className="space-y-6 p-1"> <div className="space-y-6 p-1">
<header className="flex flex-wrap items-center justify-between gap-4"> <PageHeader
<div> icon={<ShieldHalf size={20} />}
<h1 className="text-2xl font-bold flex items-center gap-2"> title={t("ui.dev.clients.federation.title", "Identity Federation")}
<Globe className="h-6 w-6 text-primary" /> description={t(
{t("ui.dev.clients.federation.title", "Identity Federation")} "msg.dev.clients.federation.subtitle",
</h1> "Manage external identity providers for this application.",
<p className="text-muted-foreground"> )}
{t( actions={
"msg.dev.clients.federation.subtitle", <Button onClick={() => setCreateModalOpen(true)} className="gap-2">
"Manage external identity providers for this application.", <Plus className="h-4 w-4" />
)} {t("ui.dev.clients.federation.add_btn", "Add Provider")}
</p> </Button>
</div> }
<Button onClick={() => setCreateModalOpen(true)} className="gap-2"> />
<Plus className="h-4 w-4" />
{t("ui.dev.clients.federation.add_btn", "Add Provider")}
</Button>
</header>
<Card className="glass-panel"> <Card className="glass-panel">
<CardContent className="p-0"> <CardContent className="p-0">

View File

@@ -1,5 +1,6 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { import {
ClipboardCheck,
CheckCircle2, CheckCircle2,
Clock, Clock,
Plus, Plus,
@@ -20,6 +21,7 @@ import { Button } from "../../components/ui/button";
import { import {
Card, Card,
CardContent, CardContent,
CardDescription,
CardHeader, CardHeader,
CardTitle, CardTitle,
} from "../../components/ui/card"; } from "../../components/ui/card";
@@ -152,6 +154,8 @@ export default function DeveloperRequestPage() {
const hasActiveRequest = requests?.some( const hasActiveRequest = requests?.some(
(r) => r.status === "pending" || r.status === "approved", (r) => r.status === "pending" || r.status === "approved",
); );
const approvedRequestCount =
requests?.filter((request) => request.status === "approved").length ?? 0;
const isActionPending = const isActionPending =
approveMutation.isPending || approveMutation.isPending ||
rejectMutation.isPending || rejectMutation.isPending ||
@@ -160,6 +164,7 @@ export default function DeveloperRequestPage() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<PageHeader <PageHeader
icon={<ClipboardCheck size={20} />}
title={t("ui.dev.nav.developer_request", "개발자 권한 신청")} title={t("ui.dev.nav.developer_request", "개발자 권한 신청")}
description={ description={
isSuperAdmin isSuperAdmin
@@ -187,6 +192,13 @@ export default function DeveloperRequestPage() {
<CardTitle className="text-xl"> <CardTitle className="text-xl">
{t("ui.dev.request.list.title", "신청 내역")} {t("ui.dev.request.list.title", "신청 내역")}
</CardTitle> </CardTitle>
<CardDescription>
{t(
"msg.dev.request.list.approved_count",
"총 {{count}}명의 사용자가 승인되었습니다.",
{ count: approvedRequestCount },
)}
</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className={commonTableShellClass}> <div className={commonTableShellClass}>

View File

@@ -3,8 +3,8 @@ import type { AxiosError } from "axios";
import { import {
Activity, Activity,
AlertTriangle, AlertTriangle,
BarChart3,
CheckCircle2, CheckCircle2,
LayoutDashboard,
Layers3, Layers3,
ShieldCheck, ShieldCheck,
} from "lucide-react"; } from "lucide-react";
@@ -662,17 +662,22 @@ function GlobalOverviewPage() {
return ( return (
<div className="space-y-4 animate-in fade-in duration-500"> <div className="space-y-4 animate-in fade-in duration-500">
<div className="flex flex-wrap items-end justify-between gap-4"> <div className="flex flex-wrap items-start justify-between gap-4">
<div className="space-y-1"> <div className="flex min-w-0 items-start gap-3">
<h2 className="text-2xl font-semibold tracking-tight"> <div className="mt-1 flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-primary/15 bg-primary/10 text-primary">
{t("ui.common.overview.title", "운영 현황")} <LayoutDashboard size={20} />
</h2> </div>
<p className="text-sm text-muted-foreground"> <div className="space-y-1">
{t( <h2 className="text-3xl font-semibold">
"msg.dev.dashboard.description", {t("ui.common.overview.title", "운영 현황")}
"연동 앱 구성과 인증 운영 지표를 한 곳에서 확인합니다.", </h2>
)} <p className="text-sm text-muted-foreground">
</p> {t(
"msg.dev.dashboard.description",
"연동 앱 구성과 인증 운영 지표를 한 곳에서 확인합니다.",
)}
</p>
</div>
</div> </div>
</div> </div>
@@ -704,22 +709,19 @@ function GlobalOverviewPage() {
<section className="space-y-3"> <section className="space-y-3">
<div className="flex flex-wrap items-center justify-between gap-3"> <div className="flex flex-wrap items-center justify-between gap-3">
<div className="flex items-center gap-2"> <div className="space-y-1">
<BarChart3 size={18} className="text-primary" /> <h3 className="text-base font-semibold">
<div className="space-y-1"> {t(
<h3 className="text-base font-semibold"> "ui.dev.dashboard.chart.title",
{t( "애플리케이션별 로그인요청/기타 요청 현황",
"ui.dev.dashboard.chart.title", )}
"애플리케이션별 로그인요청/기타 요청 현황", </h3>
)} <p className="text-sm text-muted-foreground">
</h3> {t(
<p className="text-sm text-muted-foreground"> "msg.dev.dashboard.chart.filter_description",
{t( "전체 또는 선택한 애플리케이션만 기준으로 그래프를 확인합니다.",
"msg.dev.dashboard.chart.filter_description", )}
"전체 또는 선택한 애플리케이션만 기준으로 그래프를 확인합니다.", </p>
)}
</p>
</div>
</div> </div>
<div className="flex h-8 items-center gap-1" aria-label="집계 단위"> <div className="flex h-8 items-center gap-1" aria-label="집계 단위">
{[ {[

View File

@@ -64,9 +64,14 @@ function ProfilePage() {
return ( return (
<div className="space-y-6 max-w-4xl mx-auto"> <div className="space-y-6 max-w-4xl mx-auto">
<div> <div>
<h1 className="text-3xl font-black tracking-tight"> <div className="flex items-center gap-3">
{t("ui.dev.profile.title", "내 정보")} <div className="mt-1 flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-primary/15 bg-primary/10 text-primary">
</h1> <User className="h-5 w-5" />
</div>
<h1 className="text-3xl font-semibold tracking-tight">
{t("ui.dev.profile.title", "내 정보")}
</h1>
</div>
<p className="text-muted-foreground mt-2"> <p className="text-muted-foreground mt-2">
{t( {t(
"ui.dev.profile.subtitle", "ui.dev.profile.subtitle",

View File

@@ -313,6 +313,7 @@ forbidden = "You do not have permission to view audit logs. Please request acces
load_error = "Error loading audit logs: {{error}}" load_error = "Error loading audit logs: {{error}}"
loaded_count = "Loaded {{count}} rows" loaded_count = "Loaded {{count}} rows"
loading = "Loading audit logs..." 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." subtitle = "View developer activity history within the current app scope and review target-specific changes."
[msg.dev.request] [msg.dev.request]
@@ -320,6 +321,7 @@ admin_desc = "Manage developer access requests submitted by users."
approved = "Approved." approved = "Approved."
cancelled = "Approval has been cancelled." cancelled = "Approval has been cancelled."
empty = "No requests found." empty = "No requests found."
list.approved_count = "{{count}} users have been approved."
need_cancel_notes = "Please enter a reason for cancelling approval." need_cancel_notes = "Please enter a reason for cancelling approval."
need_notes = "Please enter a rejection reason." need_notes = "Please enter a rejection reason."
rejected = "Rejected." rejected = "Rejected."

View File

@@ -313,6 +313,7 @@ forbidden = "감사 로그를 조회할 권한이 없습니다. 관리자에게
load_error = "감사 로그 조회 실패: {{error}}" load_error = "감사 로그 조회 실패: {{error}}"
loaded_count = "로드된 로그 {{count}}건" loaded_count = "로드된 로그 {{count}}건"
loading = "감사 로그를 불러오는 중..." loading = "감사 로그를 불러오는 중..."
registry_description = "최근 감사 로그를 검색 조건에 맞춰 필터링하고, 작업 이력을 빠르게 확인합니다."
subtitle = "현재 앱 범위에서 개발자 작업 이력을 조회하고 대상별 변경 내역을 확인합니다." subtitle = "현재 앱 범위에서 개발자 작업 이력을 조회하고 대상별 변경 내역을 확인합니다."
[msg.dev.request] [msg.dev.request]
@@ -320,6 +321,7 @@ admin_desc = "사용자들의 개발자 권한 신청 내역을 관리합니다.
approved = "승인되었습니다." approved = "승인되었습니다."
cancelled = "승인이 취소되었습니다." cancelled = "승인이 취소되었습니다."
empty = "신청 내역이 없습니다." empty = "신청 내역이 없습니다."
list.approved_count = "총 {{count}}명의 사용자가 승인되었습니다."
need_cancel_notes = "승인 취소 사유를 입력해주세요." need_cancel_notes = "승인 취소 사유를 입력해주세요."
need_notes = "반려 사유를 입력해주세요." need_notes = "반려 사유를 입력해주세요."
rejected = "반려되었습니다." rejected = "반려되었습니다."

View File

@@ -327,6 +327,7 @@ forbidden = ""
load_error = "" load_error = ""
loaded_count = "" loaded_count = ""
loading = "" loading = ""
registry_description = ""
subtitle = "" subtitle = ""
[msg.dev.request] [msg.dev.request]
@@ -334,6 +335,7 @@ admin_desc = ""
approved = "" approved = ""
cancelled = "" cancelled = ""
empty = "" empty = ""
list.approved_count = ""
need_cancel_notes = "" need_cancel_notes = ""
need_notes = "" need_notes = ""
rejected = "" rejected = ""