From 077ff0e6a4e97f91538d9f79388e92c29dcaa474 Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 14:49:28 +0900
Subject: [PATCH 1/8] =?UTF-8?q?=EC=84=B8=EC=85=98=20=EB=A7=8C=EB=A3=8C=20?=
=?UTF-8?q?=EB=A1=9C=EC=BC=80=EC=9D=BC=20=EC=A0=81=EC=9A=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
devfront/src/locales/en.toml | 8 ++++++++
devfront/src/locales/ko.toml | 8 ++++++++
devfront/src/locales/template.toml | 8 ++++++++
locales/en.toml | 7 +++++++
locales/ko.toml | 7 +++++++
locales/template.toml | 6 ++++++
6 files changed, 44 insertions(+)
diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml
index 79dbcf4f..49e3d051 100644
--- a/devfront/src/locales/en.toml
+++ b/devfront/src/locales/en.toml
@@ -248,6 +248,7 @@ note = "Note"
load_error = "Error loading client: {{error}}"
loading = "Loading client..."
saved = "Saved"
+save_error = "Failed to save: {{error}}"
[msg.dev.clients.general.identity]
logo_help = "Logo Help"
@@ -315,6 +316,7 @@ approved_device = "Approved Device"
approved_ip = "Approve IP: {{ip}}"
audit_empty = "Audit Empty"
audit_load_error = "Audit Load Error"
+render_error = "Dashboard render error: {{error}}"
auth_method = "Auth Method"
client_id = "Client ID: {{id}}"
client_id_missing = "Client Id Missing"
@@ -1122,6 +1124,12 @@ title = "Stack readiness"
plane = "Dev Plane"
subtitle = "Manage your applications"
+[ui.dev.session]
+active = "Checking expiration..."
+unknown = "Unknown"
+expired = "Session expired"
+expiring = "Expiring soon: {{minutes}}m {{seconds}}s left"
+remaining = "Expires in: {{minutes}}m {{seconds}}s"
[ui.userfront]
app_title = "Baron SW Portal"
diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml
index a8392019..1022c46b 100644
--- a/devfront/src/locales/ko.toml
+++ b/devfront/src/locales/ko.toml
@@ -248,6 +248,7 @@ note = "엔드포인트는 읽기 전용으로 유지하고, 비밀키 재발행
load_error = "Error loading client: {{error}}"
loading = "Loading client..."
saved = "설정이 저장되었습니다."
+save_error = "저장 실패: {{error}}"
[msg.dev.clients.general.identity]
logo_help = "인증 화면에 표시될 PNG/SVG URL입니다."
@@ -315,6 +316,7 @@ approved_device = "승인 기기: {{device}}"
approved_ip = "승인 IP: {{ip}}"
audit_empty = "최근 접속 이력이 없습니다."
audit_load_error = "접속이력을 불러오지 못했습니다."
+render_error = "대시보드 렌더링 오류: {{error}}"
auth_method = "인증수단: {{method}}"
client_id = "Client ID: {{id}}"
client_id_missing = "Client ID 없음"
@@ -1122,6 +1124,12 @@ title = "Stack readiness"
plane = "Dev Plane"
subtitle = "Manage your applications"
+[ui.dev.session]
+active = "만료 시간 확인 중..."
+unknown = "확인 불가"
+expired = "세션 만료"
+expiring = "만료 임박: {{minutes}}분 {{seconds}}초 남음"
+remaining = "만료 예정: {{minutes}}분 {{seconds}}초 남음"
[ui.userfront]
app_title = "Baron SW 포탈"
diff --git a/devfront/src/locales/template.toml b/devfront/src/locales/template.toml
index fb270793..8fdb9d02 100644
--- a/devfront/src/locales/template.toml
+++ b/devfront/src/locales/template.toml
@@ -248,6 +248,7 @@ note = ""
load_error = ""
loading = ""
saved = ""
+save_error = ""
[msg.dev.clients.general.identity]
logo_help = ""
@@ -315,6 +316,7 @@ approved_device = ""
approved_ip = ""
audit_empty = ""
audit_load_error = ""
+render_error = ""
auth_method = ""
client_id = ""
client_id_missing = ""
@@ -1134,6 +1136,12 @@ title = ""
plane = ""
subtitle = ""
+[ui.dev.session]
+active = ""
+unknown = ""
+expired = ""
+expiring = ""
+remaining = ""
[ui.userfront]
app_title = ""
diff --git a/locales/en.toml b/locales/en.toml
index 1781fe1c..98246ac5 100644
--- a/locales/en.toml
+++ b/locales/en.toml
@@ -1266,6 +1266,13 @@ title = "Stack readiness"
plane = "Dev Plane"
subtitle = "Manage your applications"
+[ui.dev.session]
+active = "Checking expiration..."
+unknown = "Unknown"
+expired = "Session expired"
+expiring = "Expiring soon: {{minutes}}m {{seconds}}s left"
+remaining = "Expires in: {{minutes}}m {{seconds}}s"
+
[ui.userfront]
app_title = "Baron SW Portal"
diff --git a/locales/ko.toml b/locales/ko.toml
index 3d5e6d9a..1632965f 100644
--- a/locales/ko.toml
+++ b/locales/ko.toml
@@ -1266,6 +1266,13 @@ title = "Stack readiness"
plane = "Dev Plane"
subtitle = "Manage your applications"
+[ui.dev.session]
+active = "만료 시간 확인 중..."
+unknown = "확인 불가"
+expired = "세션 만료"
+expiring = "만료 임박: {{minutes}}분 {{seconds}}초 남음"
+remaining = "만료 예정: {{minutes}}분 {{seconds}}초 남음"
+
[ui.userfront]
app_title = "Baron SW 포탈"
diff --git a/locales/template.toml b/locales/template.toml
index 4243afdb..c5986bcd 100644
--- a/locales/template.toml
+++ b/locales/template.toml
@@ -1154,6 +1154,12 @@ title = ""
plane = ""
subtitle = ""
+[ui.dev.session]
+active = ""
+unknown = ""
+expired = ""
+expiring = ""
+remaining = ""
[ui.userfront]
app_title = ""
From c9a364a8ba1712221fc8c2f28b8ee7068c5c6401 Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 14:50:07 +0900
Subject: [PATCH 2/8] =?UTF-8?q?=EB=A7=8C=EB=A3=8C=20=EC=8B=9C=EA=B0=84=20?=
=?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=83=81=EB=8B=A8=20=EB=84=A4?=
=?UTF-8?q?=EC=9D=B4=EA=B2=8C=EC=9D=B4=EC=85=98=20=EB=B0=94=20=EC=B6=94?=
=?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
devfront/src/components/layout/AppLayout.tsx | 169 ++++++++++++++++++-
docker/ory/hydra/hydra.yml | 4 +
2 files changed, 171 insertions(+), 2 deletions(-)
diff --git a/devfront/src/components/layout/AppLayout.tsx b/devfront/src/components/layout/AppLayout.tsx
index e0a1d7bb..469a9362 100644
--- a/devfront/src/components/layout/AppLayout.tsx
+++ b/devfront/src/components/layout/AppLayout.tsx
@@ -1,5 +1,11 @@
-import { BadgeCheck, LogOut, Moon, ShieldHalf, Sun } from "lucide-react";
-import { useEffect, useState } from "react";
+import {
+ BadgeCheck,
+ LogOut,
+ Moon,
+ ShieldHalf,
+ Sun,
+} from "lucide-react";
+import { useEffect, useRef, useState } from "react";
import { useAuth } from "react-oidc-context";
import { NavLink, Outlet, useNavigate } from "react-router-dom";
import { t } from "../../lib/i18n";
@@ -18,10 +24,14 @@ const navItems = [
function AppLayout() {
const auth = useAuth();
const navigate = useNavigate();
+ const profileMenuRef = useRef(null);
const [theme, setTheme] = useState<"light" | "dark">(() => {
const stored = window.localStorage.getItem("admin_theme");
return stored === "dark" ? "dark" : "light";
});
+ const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false);
+ const [isRefreshingSession, setIsRefreshingSession] = useState(false);
+ const [nowMs, setNowMs] = useState(() => Date.now());
const handleLogout = () => {
if (window.confirm(t("msg.dev.logout_confirm", "로그아웃 하시겠습니까?"))) {
@@ -41,10 +51,106 @@ function AppLayout() {
window.localStorage.setItem("admin_theme", theme);
}, [theme]);
+ useEffect(() => {
+ const timer = window.setInterval(() => {
+ setNowMs(Date.now());
+ }, 1000);
+ return () => {
+ window.clearInterval(timer);
+ };
+ }, []);
+
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (
+ profileMenuRef.current &&
+ !profileMenuRef.current.contains(event.target as Node)
+ ) {
+ setIsProfileMenuOpen(false);
+ }
+ };
+
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => {
+ document.removeEventListener("mousedown", handleClickOutside);
+ };
+ }, []);
+
const toggleTheme = () => {
setTheme((prev) => (prev === "light" ? "dark" : "light"));
};
+ const profileName =
+ auth.user?.profile?.name?.toString().trim() ||
+ auth.user?.profile?.preferred_username?.toString().trim() ||
+ auth.user?.profile?.nickname?.toString().trim() ||
+ t("ui.dev.profile.unknown_name", "Unknown User");
+ const profileEmail =
+ auth.user?.profile?.email?.toString().trim() ||
+ t("ui.dev.profile.unknown_email", "unknown@example.com");
+ const profileInitial = profileName.charAt(0).toUpperCase();
+ const expiresAtSec = auth.user?.expires_at;
+ const remainingMs =
+ typeof expiresAtSec === "number" ? expiresAtSec * 1000 - nowMs : null;
+ const remainingTotalSec =
+ remainingMs !== null ? Math.max(0, Math.floor(remainingMs / 1000)) : null;
+ const remainingMinutes =
+ remainingTotalSec !== null ? Math.floor(remainingTotalSec / 60) : null;
+ const remainingSeconds =
+ remainingTotalSec !== null ? remainingTotalSec % 60 : null;
+
+ let sessionToneClass =
+ "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300";
+ let sessionText = t("ui.dev.session.active", "세션 만료 시간 확인 중");
+
+ if (remainingMs === null) {
+ sessionToneClass =
+ "border-border bg-card text-muted-foreground";
+ sessionText = t("ui.dev.session.unknown", "세션 만료 시간 확인 불가");
+ } else if (remainingMs <= 0) {
+ sessionToneClass =
+ "border-rose-500/30 bg-rose-500/10 text-rose-700 dark:text-rose-300";
+ sessionText = t("ui.dev.session.expired", "세션 만료됨");
+ } else {
+ if (remainingMinutes !== null && remainingSeconds !== null && remainingMinutes <= 5) {
+ sessionToneClass =
+ "border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300";
+ sessionText = t(
+ "ui.dev.session.expiring",
+ "만료 임박: {{minutes}}분 {{seconds}}초 남음",
+ {
+ minutes: remainingMinutes,
+ seconds: remainingSeconds,
+ },
+ );
+ } else {
+ sessionText = t(
+ "ui.dev.session.remaining",
+ "만료까지 {{minutes}}분 {{seconds}}초",
+ {
+ minutes: remainingMinutes ?? 0,
+ seconds: remainingSeconds ?? 0,
+ },
+ );
+ }
+ }
+
+ const handleRefreshSessionExpiry = async () => {
+ if (isRefreshingSession) {
+ return;
+ }
+ setIsRefreshingSession(true);
+ try {
+ await auth.signinSilent();
+ setNowMs(Date.now());
+ setIsProfileMenuOpen(false);
+ } catch (error) {
+ console.error("Failed to refresh session expiry:", error);
+ } finally {
+ setIsRefreshingSession(false);
+ }
+ };
+
return (
diff --git a/docker/ory/hydra/hydra.yml b/docker/ory/hydra/hydra.yml
index 82f9fb37..7bf79b10 100644
--- a/docker/ory/hydra/hydra.yml
+++ b/docker/ory/hydra/hydra.yml
@@ -92,3 +92,7 @@ oidc:
salt: youReallyNeedToChangeThis
dynamic_client_registration:
enabled: true
+
+ttl:
+ access_token: 15m
+ id_token: 15m
From 75cde56761bc2781c441731cbc41126074506da1 Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 15:24:15 +0900
Subject: [PATCH 3/8] =?UTF-8?q?=EC=97=B0=EB=8F=99=20=EC=95=B1(RP)=20?=
=?UTF-8?q?=EC=9A=A9=EC=96=B4=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20i18n=20?=
=?UTF-8?q?=EC=A0=81=EC=9A=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
devfront/src/features/clients/ClientConsentsPage.tsx | 2 +-
devfront/src/features/clients/ClientDetailsPage.tsx | 2 +-
devfront/src/features/clients/ClientGeneralPage.tsx | 5 ++++-
devfront/src/features/clients/ClientsPage.tsx | 4 ++--
4 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/devfront/src/features/clients/ClientConsentsPage.tsx b/devfront/src/features/clients/ClientConsentsPage.tsx
index 7bacc080..e82277ca 100644
--- a/devfront/src/features/clients/ClientConsentsPage.tsx
+++ b/devfront/src/features/clients/ClientConsentsPage.tsx
@@ -117,7 +117,7 @@ function ClientConsentsPage() {
to={`/clients/${clientId}`}
className="whitespace-nowrap border-b-2 border-transparent text-muted-foreground hover:text-foreground"
>
- {t("ui.dev.clients.details.tab.connection", "Connection")}
+ {t("ui.dev.clients.details.tab.connection", "Federation")}
{t("ui.dev.clients.details.tab.consents", "Consent & Users")}
diff --git a/devfront/src/features/clients/ClientDetailsPage.tsx b/devfront/src/features/clients/ClientDetailsPage.tsx
index 1882c04a..a372fef0 100644
--- a/devfront/src/features/clients/ClientDetailsPage.tsx
+++ b/devfront/src/features/clients/ClientDetailsPage.tsx
@@ -218,7 +218,7 @@ function ClientDetailsPage() {
to={`/clients/${clientId}`}
className="border-b-2 border-primary pb-3 text-sm font-bold text-primary"
>
- {t("ui.dev.clients.details.tab.connection", "Connection")}
+ {t("ui.dev.clients.details.tab.connection", "Federation")}
- {t("ui.dev.clients.general.security.private", "Private")}
+ {t(
+ "ui.dev.clients.general.security.private",
+ "Server side App",
+ )}
{t(
diff --git a/devfront/src/features/clients/ClientsPage.tsx b/devfront/src/features/clients/ClientsPage.tsx
index 7cd7ad2a..cb43ae6b 100644
--- a/devfront/src/features/clients/ClientsPage.tsx
+++ b/devfront/src/features/clients/ClientsPage.tsx
@@ -159,7 +159,7 @@ function ClientsPage() {
{t("ui.dev.clients.registry.title", "RP registry")}
- {t("ui.dev.clients.registry.subtitle", "Relying Parties")}
+ {t("ui.dev.clients.registry.subtitle", "연동 앱")}
{t(
@@ -315,7 +315,7 @@ function ClientsPage() {
variant={client.type === "private" ? "success" : "muted"}
>
{client.type === "private"
- ? t("ui.dev.clients.type.private", "Private")
+ ? t("ui.dev.clients.type.private", "Server side App")
: t("ui.dev.clients.type.pkce", "PKCE")}
From 38e0b6d80e7dc86c0b35d848b2a242eaf746c601 Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 15:24:35 +0900
Subject: [PATCH 4/8] =?UTF-8?q?=EC=9A=A9=EC=96=B4=20=EA=B0=9C=EC=84=A0?=
=?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=A1=9C=EC=BC=80=EC=9D=BC=20?=
=?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
devfront/src/locales/en.toml | 14 +++++++-------
devfront/src/locales/ko.toml | 14 +++++++-------
locales/en.toml | 14 +++++++-------
locales/ko.toml | 14 +++++++-------
4 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml
index 49e3d051..fa5e4b56 100644
--- a/devfront/src/locales/en.toml
+++ b/devfront/src/locales/en.toml
@@ -255,14 +255,14 @@ logo_help = "Logo Help"
subtitle = "Subtitle"
[msg.dev.clients.general.redirect]
-help = "Help"
+help = "Enter the redirect URIs. You can modify them in the Federation tab after creation."
[msg.dev.clients.general.scopes]
empty = "Empty"
subtitle = "Subtitle"
[msg.dev.clients.general.security]
-private_help = "Private App (Server-side): For apps that can safely store a client secret, such as Node.js or Java servers."
+private_help = "Server side App: For apps that can safely store a client secret, such as Node.js or Java servers."
pkce_help = "PKCE App (SPA/Mobile): For apps that cannot safely store a client secret. PKCE is mandatory."
subtitle = "Select application type. Security level determines authentication method."
@@ -981,7 +981,7 @@ user = "User"
[ui.dev.clients.details.breadcrumb]
current = "Current"
-section = "Relying Parties"
+section = "Applications"
[ui.dev.clients.details.credentials]
client_id = "Client ID"
@@ -1008,7 +1008,7 @@ show = "Show"
title = "Title"
[ui.dev.clients.details.tab]
-connection = "Connection"
+connection = "Federation"
consents = "Consent & Users"
settings = "Settings"
@@ -1053,7 +1053,7 @@ name = "Scope Name"
delete = "Delete"
[ui.dev.clients.general.security]
-private = "Private"
+private = "Server Side App"
pkce = "PKCE"
title = "Security Settings"
@@ -1075,7 +1075,7 @@ subtitle = "Tenant admin on-call"
title = "Owner"
[ui.dev.clients.registry]
-subtitle = "Relying Parties"
+subtitle = "Applications"
title = "RP registry"
[ui.dev.clients.table]
@@ -1087,7 +1087,7 @@ status = "Status"
type = "Type"
[ui.dev.clients.type]
-private = "Private"
+private = "Server side App"
pkce = "PKCE"
[ui.dev.dashboard]
diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml
index 1022c46b..6959405d 100644
--- a/devfront/src/locales/ko.toml
+++ b/devfront/src/locales/ko.toml
@@ -255,14 +255,14 @@ logo_help = "인증 화면에 표시될 PNG/SVG URL입니다."
subtitle = "앱 이름과 설명, 로고를 설정합니다."
[msg.dev.clients.general.redirect]
-help = "인증 후 리다이렉트될 URI를 입력하세요. 생성 후 Connection 탭에서 수정 가능합니다."
+help = "인증 후 리다이렉트될 URI를 입력하세요. 생성 후 연동 설정 탭에서 수정 가능합니다."
[msg.dev.clients.general.scopes]
empty = "등록된 스코프가 없습니다."
subtitle = "이 앱이 요청할 수 있는 권한 범위를 정의합니다."
[msg.dev.clients.general.security]
-private_help = "Private 앱 (서버 사이드 앱): Node.js, Java 등 비밀키를 안전하게 보관 가능한 경우 사용합니다."
+private_help = "Server side App (서버 사이드 앱): Node.js, Java 등 비밀키를 안전하게 보관 가능한 경우 사용합니다."
pkce_help = "PKCE 앱 (SPA/모바일): 브라우저나 앱처럼 비밀키를 보관하기 어려운 경우 사용하며, PKCE가 강제됩니다."
subtitle = "앱 유형을 선택하세요. 보안 수준에 따라 인증 방식이 달라집니다."
@@ -981,7 +981,7 @@ user = "User"
[ui.dev.clients.details.breadcrumb]
current = "연동 앱 상세"
-section = "Relying Parties"
+section = "연동 앱"
[ui.dev.clients.details.credentials]
client_id = "Client ID"
@@ -1008,7 +1008,7 @@ show = "비밀키 보기"
title = "보안 메모"
[ui.dev.clients.details.tab]
-connection = "Connection"
+connection = "연동 설정"
consents = "Consent & Users"
settings = "Settings"
@@ -1053,7 +1053,7 @@ name = "Scope Name"
delete = "Delete"
[ui.dev.clients.general.security]
-private = "Private"
+private = "Server side App"
pkce = "PKCE"
title = "보안 설정"
@@ -1075,7 +1075,7 @@ subtitle = "Tenant admin on-call"
title = "Owner"
[ui.dev.clients.registry]
-subtitle = "Relying Parties"
+subtitle = "연동 앱"
title = "RP registry"
[ui.dev.clients.table]
@@ -1087,7 +1087,7 @@ status = "상태"
type = "유형"
[ui.dev.clients.type]
-private = "Private"
+private = "Server side App"
pkce = "PKCE"
[ui.dev.dashboard]
diff --git a/locales/en.toml b/locales/en.toml
index 98246ac5..b5753efc 100644
--- a/locales/en.toml
+++ b/locales/en.toml
@@ -311,14 +311,14 @@ logo_help = "Logo Help"
subtitle = "Subtitle"
[msg.dev.clients.general.redirect]
-help = "Help"
+help = "Enter the redirect URIs. You can modify them in the Federation tab after creation."
[msg.dev.clients.general.scopes]
empty = "Empty"
subtitle = "Subtitle"
[msg.dev.clients.general.security]
-private_help = "Private App (Server-side): For apps that can safely store a client secret, such as Node.js or Java servers."
+private_help = "Server side App: For apps that can safely store a client secret, such as Node.js or Java servers."
pkce_help = "PKCE App (SPA/Mobile): For apps that cannot safely store a client secret. PKCE is mandatory."
subtitle = "Select application type. Security level determines authentication method."
@@ -1123,7 +1123,7 @@ user = "User"
[ui.dev.clients.details.breadcrumb]
current = "Current"
-section = "Relying Parties"
+section = "Applications"
[ui.dev.clients.details.credentials]
client_id = "Client ID"
@@ -1150,7 +1150,7 @@ show = "Show"
title = "Title"
[ui.dev.clients.details.tab]
-connection = "Connection"
+connection = "Federation"
consents = "Consent & Users"
settings = "Settings"
@@ -1195,7 +1195,7 @@ name = "Scope Name"
delete = "Delete"
[ui.dev.clients.general.security]
-private = "Private"
+private = "Server Side App"
pkce = "PKCE"
title = "Security Settings"
@@ -1217,7 +1217,7 @@ subtitle = "Tenant admin on-call"
title = "Owner"
[ui.dev.clients.registry]
-subtitle = "Relying Parties"
+subtitle = "Applications"
title = "RP registry"
[ui.dev.clients.table]
@@ -1229,7 +1229,7 @@ status = "Status"
type = "Type"
[ui.dev.clients.type]
-private = "Private"
+private = "Server side App"
pkce = "PKCE"
[ui.dev.dashboard]
diff --git a/locales/ko.toml b/locales/ko.toml
index 1632965f..847f2569 100644
--- a/locales/ko.toml
+++ b/locales/ko.toml
@@ -311,14 +311,14 @@ logo_help = "인증 화면에 표시될 PNG/SVG URL입니다."
subtitle = "앱 이름과 설명, 로고를 설정합니다."
[msg.dev.clients.general.redirect]
-help = "인증 후 리다이렉트될 URI를 입력하세요. 생성 후 Connection 탭에서 수정 가능합니다."
+help = "인증 후 리다이렉트될 URI를 입력하세요. 생성 후 연동 설정 탭에서 수정 가능합니다."
[msg.dev.clients.general.scopes]
empty = "등록된 스코프가 없습니다."
subtitle = "이 앱이 요청할 수 있는 권한 범위를 정의합니다."
[msg.dev.clients.general.security]
-private_help = "Private 앱 (서버 사이드 앱): Node.js, Java 등 비밀키를 안전하게 보관 가능한 경우 사용합니다."
+private_help = "Server side App (서버 사이드 앱): Node.js, Java 등 비밀키를 안전하게 보관 가능한 경우 사용합니다."
pkce_help = "PKCE 앱 (SPA/모바일): 브라우저나 앱처럼 비밀키를 보관하기 어려운 경우 사용하며, PKCE가 강제됩니다."
subtitle = "앱 유형을 선택하세요. 보안 수준에 따라 인증 방식이 달라집니다."
@@ -1123,7 +1123,7 @@ user = "User"
[ui.dev.clients.details.breadcrumb]
current = "연동 앱 상세"
-section = "Relying Parties"
+section = "연동 앱"
[ui.dev.clients.details.credentials]
client_id = "Client ID"
@@ -1150,7 +1150,7 @@ show = "비밀키 보기"
title = "보안 메모"
[ui.dev.clients.details.tab]
-connection = "Connection"
+connection = "연동 설정"
consents = "Consent & Users"
settings = "Settings"
@@ -1195,7 +1195,7 @@ name = "Scope Name"
delete = "Delete"
[ui.dev.clients.general.security]
-private = "Private"
+private = "Server side App"
pkce = "PKCE"
title = "보안 설정"
@@ -1217,7 +1217,7 @@ subtitle = "Tenant admin on-call"
title = "Owner"
[ui.dev.clients.registry]
-subtitle = "Relying Parties"
+subtitle = "연동 앱"
title = "RP registry"
[ui.dev.clients.table]
@@ -1229,7 +1229,7 @@ status = "상태"
type = "유형"
[ui.dev.clients.type]
-private = "Private"
+private = "Server side App"
pkce = "PKCE"
[ui.dev.dashboard]
From 558d88593a5fdbd89c4ea8df61db684216bd4430 Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 15:57:09 +0900
Subject: [PATCH 5/8] =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B3=80=ED=99=94?=
=?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=A1=9C=EC=BC=80=EC=9D=BC=20?=
=?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
devfront/src/locales/en.toml | 4 ++++
devfront/src/locales/ko.toml | 4 ++++
devfront/src/locales/template.toml | 4 ++++
locales/en.toml | 4 ++++
locales/ko.toml | 4 ++++
locales/template.toml | 3 +++
6 files changed, 23 insertions(+)
diff --git a/devfront/src/locales/en.toml b/devfront/src/locales/en.toml
index fa5e4b56..e01dd020 100644
--- a/devfront/src/locales/en.toml
+++ b/devfront/src/locales/en.toml
@@ -214,6 +214,9 @@ loading = "Loading apps..."
showing = "Showing {{shown}} of {{total}} apps"
status_update_error = "Failed to update client status"
status_updated = "The app has been {{status}}."
+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."
[msg.dev.clients.consents]
empty = "No consents found."
@@ -905,6 +908,7 @@ theme_dark = "Dark"
theme_light = "Light"
theme_toggle = "Theme Toggle"
unknown = "Unknown"
+view = "View"
[ui.common.badge]
admin_only = "Admin only"
diff --git a/devfront/src/locales/ko.toml b/devfront/src/locales/ko.toml
index 6959405d..ef85680a 100644
--- a/devfront/src/locales/ko.toml
+++ b/devfront/src/locales/ko.toml
@@ -214,6 +214,9 @@ loading = "Loading apps..."
showing = "Showing {{shown}} of {{total}} apps"
status_update_error = "Failed to update client status"
status_updated = "앱이 {{status}}되었습니다."
+deleted = "앱이 삭제되었습니다."
+delete_error = "삭제 실패: {{error}}"
+delete_confirm = "정말로 이 앱을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
[msg.dev.clients.consents]
empty = "No consents found."
@@ -905,6 +908,7 @@ theme_dark = "Dark"
theme_light = "Light"
theme_toggle = "테마 전환"
unknown = "Unknown"
+view = "보기"
[ui.common.badge]
admin_only = "Admin only"
diff --git a/devfront/src/locales/template.toml b/devfront/src/locales/template.toml
index 8fdb9d02..5c2934c5 100644
--- a/devfront/src/locales/template.toml
+++ b/devfront/src/locales/template.toml
@@ -214,6 +214,9 @@ loading = ""
showing = ""
status_update_error = ""
status_updated = ""
+deleted = ""
+delete_error = ""
+delete_confirm = ""
[msg.dev.clients.consents]
empty = ""
@@ -917,6 +920,7 @@ theme_dark = ""
theme_light = ""
theme_toggle = ""
unknown = ""
+view = ""
[ui.common.badge]
admin_only = ""
diff --git a/locales/en.toml b/locales/en.toml
index b5753efc..a56f7c8b 100644
--- a/locales/en.toml
+++ b/locales/en.toml
@@ -270,6 +270,9 @@ loading = "Loading apps..."
showing = "Showing {{shown}} of {{total}} apps"
status_update_error = "Failed to update client status"
status_updated = "The app has been {{status}}."
+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."
[msg.dev.clients.consents]
empty = "No consents found."
@@ -1047,6 +1050,7 @@ theme_dark = "Dark"
theme_light = "Light"
theme_toggle = "Theme Toggle"
unknown = "Unknown"
+view = "View"
[ui.common.badge]
admin_only = "Admin only"
diff --git a/locales/ko.toml b/locales/ko.toml
index 847f2569..f7889a55 100644
--- a/locales/ko.toml
+++ b/locales/ko.toml
@@ -270,6 +270,9 @@ loading = "Loading apps..."
showing = "Showing {{shown}} of {{total}} apps"
status_update_error = "Failed to update client status"
status_updated = "앱이 {{status}}되었습니다."
+deleted = "앱이 삭제되었습니다."
+delete_error = "삭제 실패: {{error}}"
+delete_confirm = "정말로 이 앱을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
[msg.dev.clients.consents]
empty = "No consents found."
@@ -1047,6 +1050,7 @@ theme_dark = "Dark"
theme_light = "Light"
theme_toggle = "테마 전환"
unknown = "Unknown"
+view = "보기"
[ui.common.badge]
admin_only = "Admin only"
diff --git a/locales/template.toml b/locales/template.toml
index c5986bcd..db96cadd 100644
--- a/locales/template.toml
+++ b/locales/template.toml
@@ -232,6 +232,9 @@ loading = ""
showing = ""
status_update_error = ""
status_updated = ""
+deleted = ""
+delete_error = ""
+delete_confirm = ""
[msg.dev.clients.consents]
empty = ""
From 45dc68427a0ff6ccb66a6479fdf103acfe23db3f Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 16:00:37 +0900
Subject: [PATCH 6/8] =?UTF-8?q?=EC=97=B0=EB=8F=99=20=EC=95=B1=20=EB=AA=A9?=
=?UTF-8?q?=EB=A1=9D=20=EB=B0=8F=20=ED=8E=B8=EC=A7=91=20=ED=8E=98=EC=9D=B4?=
=?UTF-8?q?=EC=A7=80=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../features/clients/ClientGeneralPage.tsx | 176 ++++++++++++------
devfront/src/features/clients/ClientsPage.tsx | 115 ++----------
2 files changed, 140 insertions(+), 151 deletions(-)
diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx
index 7bb0e8c0..cf00077a 100644
--- a/devfront/src/features/clients/ClientGeneralPage.tsx
+++ b/devfront/src/features/clients/ClientGeneralPage.tsx
@@ -16,7 +16,12 @@ 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 { createClient, fetchClient, updateClient } from "../../lib/devApi";
+import {
+ createClient,
+ deleteClient,
+ fetchClient,
+ updateClient,
+} from "../../lib/devApi";
import type {
ClientStatus,
ClientType,
@@ -174,6 +179,39 @@ function ClientGeneralPage() {
},
});
+ const deleteMutation = useMutation({
+ mutationFn: (id: string) => deleteClient(id),
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ["clients"] });
+ alert(t("msg.dev.clients.deleted", "앱이 삭제되었습니다."));
+ navigate("/clients");
+ },
+ onError: (err) => {
+ const errorMessage =
+ (err as AxiosError<{ error?: string }>).response?.data?.error ??
+ (err as Error)?.message;
+ alert(
+ t("msg.dev.clients.delete_error", "삭제 실패: {{error}}", {
+ error: errorMessage,
+ }),
+ );
+ },
+ });
+
+ const handleDelete = () => {
+ if (
+ clientId &&
+ window.confirm(
+ t(
+ "msg.dev.clients.delete_confirm",
+ "정말로 이 앱을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
+ ),
+ )
+ ) {
+ deleteMutation.mutate(clientId);
+ }
+ };
+
if (!isCreate && isLoading) {
return (
@@ -220,14 +258,16 @@ function ClientGeneralPage() {
: t("ui.dev.clients.general.title_edit", "Client Settings")}
-
- {status === "active"
- ? t("ui.common.status.active", "Active")
- : t("ui.common.status.inactive", "Inactive")}
-
+ {!isCreate && (
+
+ {status === "active"
+ ? t("ui.common.status.active", "Active")
+ : t("ui.common.status.inactive", "Inactive")}
+
+ )}
{!isCreate && (
@@ -254,15 +294,49 @@ function ClientGeneralPage() {
{/* 1. Application Identity */}
-
- {t("ui.dev.clients.general.identity.title", "Application Identity")}
-
-
- {t(
- "msg.dev.clients.general.identity.subtitle",
- "앱 이름과 설명, 로고를 설정합니다.",
+
+
+
+ {t(
+ "ui.dev.clients.general.identity.title",
+ "Application Identity",
+ )}
+
+
+ {t(
+ "msg.dev.clients.general.identity.subtitle",
+ "앱 이름과 설명, 로고를 설정합니다.",
+ )}
+
+
+ {!isCreate && (
+
+
+
+
+ setStatus(checked ? "active" : "inactive")
+ }
+ />
+
+ {status === "active"
+ ? t("ui.common.status.active", "활성")
+ : t("ui.common.status.inactive", "비활성")}
+
+
+
)}
-
+
@@ -568,43 +642,41 @@ function ClientGeneralPage() {
-
-
-
+
+
+ {!isCreate && (
+
+ )}
+
+
+
+
+
- {!isCreate && (
-
-
-
- {t("ui.dev.clients.general.footer.client_id", "Client ID")}
-
- {data?.client?.id}
-
-
-
- {t("ui.dev.clients.general.footer.created_on", "Created On")}
-
-
- {data?.client?.createdAt
- ? new Date(data.client.createdAt).toLocaleString()
- : "-"}
-
-
-
- )}
+
);
}
diff --git a/devfront/src/features/clients/ClientsPage.tsx b/devfront/src/features/clients/ClientsPage.tsx
index cb43ae6b..9d9def58 100644
--- a/devfront/src/features/clients/ClientsPage.tsx
+++ b/devfront/src/features/clients/ClientsPage.tsx
@@ -1,4 +1,4 @@
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import { useQuery } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import {
BookOpenText,
@@ -22,10 +22,8 @@ import {
CardHeader,
CardTitle,
} from "../../components/ui/card";
-import { CopyButton } from "../../components/ui/copy-button";
import { Input } from "../../components/ui/input";
import { Separator } from "../../components/ui/separator";
-import { Switch } from "../../components/ui/switch";
import {
Table,
TableBody,
@@ -34,56 +32,16 @@ import {
TableHeader,
TableRow,
} from "../../components/ui/table";
-import { toast } from "../../components/ui/use-toast";
-import {
- deleteClient,
- fetchClients,
- updateClientStatus,
-} from "../../lib/devApi";
+import { fetchClients } from "../../lib/devApi";
import { t } from "../../lib/i18n";
import { cn } from "../../lib/utils";
function ClientsPage() {
const navigate = useNavigate();
- const queryClient = useQueryClient();
const { data, isLoading, error } = useQuery({
queryKey: ["clients"],
queryFn: fetchClients,
});
- const updateStatusMutation = useMutation({
- mutationFn: (payload: { id: string; status: "active" | "inactive" }) =>
- updateClientStatus(payload.id, payload.status),
- onSuccess: (_, variables) => {
- const statusText =
- variables.status === "active"
- ? t("ui.common.status.active", "활성화")
- : t("ui.common.status.inactive", "비활성화");
- toast(
- t(
- "msg.dev.clients.status_updated",
- "클라이언트가 {{status}}되었습니다.",
- {
- status: statusText,
- },
- ),
- );
- queryClient.invalidateQueries({ queryKey: ["clients"] });
- },
- onError: (error: AxiosError<{ error?: string }>) => {
- const errMsg =
- error.response?.data?.error ??
- error.message ??
- t(
- "msg.dev.clients.status_update_error",
- "Failed to update client status",
- );
- toast(errMsg, "error");
- },
- });
- const deleteMutation = useMutation({
- mutationFn: (clientId: string) => deleteClient(clientId),
- onSuccess: () => queryClient.invalidateQueries({ queryKey: ["clients"] }),
- });
const clients = data?.items || [];
const totalClients = clients.length;
@@ -267,7 +225,10 @@ function ClientsPage() {
{clients.map((client) => (
-
+
{client.type === "private" ? (
@@ -284,30 +245,13 @@ function ClientsPage() {
{t("ui.dev.clients.tenant_scoped", "Tenant-scoped")}
-
+
{client.id}
-
- toast(
- t(
- "msg.dev.clients.copy_client_id",
- "클라이언트 ID가 복사되었습니다.",
- ),
- )
- }
- />
@@ -320,33 +264,14 @@ function ClientsPage() {
-
-
- updateStatusMutation.mutate({
- id: client.id,
- status: checked ? "active" : "inactive",
- })
- }
- />
-
- {client.status === "active"
- ? t("ui.common.status.active", "활성")
- : t("ui.common.status.inactive", "비활성")}
-
-
+
+ {client.status === "active"
+ ? t("ui.common.status.active", "Active")
+ : t("ui.common.status.inactive", "Inactive")}
+
{client.createdAt
@@ -357,17 +282,9 @@ function ClientsPage() {
-
From 75cf8355de03c1f344ac0197c69e70f333e251b1 Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 17:24:30 +0900
Subject: [PATCH 7/8] =?UTF-8?q?i18n=20=ED=82=A4=20=EC=A0=95=EB=A6=AC=20?=
=?UTF-8?q?=EB=B0=8F=20=EC=BA=90=EC=8B=9C/=EC=82=B0=EC=B6=9C=EB=AC=BC=20?=
=?UTF-8?q?=EC=A0=95=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 1 +
adminfront/playwright-report/index.html | 85 -------------------------
locales/en.toml | 9 +++
locales/ko.toml | 9 +++
locales/template.toml | 52 +++------------
tools/i18n-scanner/manual-keys.ts | 1 +
6 files changed, 30 insertions(+), 127 deletions(-)
delete mode 100644 adminfront/playwright-report/index.html
diff --git a/.gitignore b/.gitignore
index 9c6d4a32..ba9819d2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@
*.log
*.out
*.exe
+.npm-cache/
reports
reports/*
diff --git a/adminfront/playwright-report/index.html b/adminfront/playwright-report/index.html
deleted file mode 100644
index a369469d..00000000
--- a/adminfront/playwright-report/index.html
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
-
-
-
-
- Playwright Test Report
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/locales/en.toml b/locales/en.toml
index a56f7c8b..19966500 100644
--- a/locales/en.toml
+++ b/locales/en.toml
@@ -258,6 +258,7 @@ error = "Error"
loading = "Loading..."
no_description = "No Description."
saving = "Saving..."
+requesting = "Requesting..."
unknown_error = "unknown error"
[msg.dev]
@@ -1080,6 +1081,12 @@ scope_badge = "Scoped to /dev"
clients = "Connected Application"
logout = "Logout"
+[ui.dev.profile]
+menu_aria = "Open account menu"
+menu_title = "Account"
+unknown_email = "unknown@example.com"
+unknown_name = "Unknown User"
+
[ui.dev.clients]
copy_client_id = "Copy client id"
new = "Add Connected Application"
@@ -1276,6 +1283,8 @@ unknown = "Unknown"
expired = "Session expired"
expiring = "Expiring soon: {{minutes}}m {{seconds}}s left"
remaining = "Expires in: {{minutes}}m {{seconds}}s"
+refresh = "Refresh session expiry"
+refreshing = "Refreshing session expiry..."
[ui.userfront]
app_title = "Baron SW Portal"
diff --git a/locales/ko.toml b/locales/ko.toml
index f7889a55..977a9b07 100644
--- a/locales/ko.toml
+++ b/locales/ko.toml
@@ -258,6 +258,7 @@ error = "오류가 발생했습니다."
loading = "로딩 중..."
no_description = "설명이 없습니다."
saving = "저장 중..."
+requesting = "요청 중..."
unknown_error = "unknown error"
[msg.dev]
@@ -1080,6 +1081,12 @@ scope_badge = "Scoped to /dev"
clients = "연동 앱"
logout = "로그아웃"
+[ui.dev.profile]
+menu_aria = "계정 메뉴 열기"
+menu_title = "계정"
+unknown_email = "unknown@example.com"
+unknown_name = "Unknown User"
+
[ui.dev.clients]
copy_client_id = "Copy client id"
new = "연동 앱 추가"
@@ -1276,6 +1283,8 @@ unknown = "확인 불가"
expired = "세션 만료"
expiring = "만료 임박: {{minutes}}분 {{seconds}}초 남음"
remaining = "만료 예정: {{minutes}}분 {{seconds}}초 남음"
+refresh = "세션 만료 시간 갱신"
+refreshing = "세션 만료 시간 갱신 중..."
[ui.userfront]
app_title = "Baron SW 포탈"
diff --git a/locales/template.toml b/locales/template.toml
index db96cadd..55567ffb 100644
--- a/locales/template.toml
+++ b/locales/template.toml
@@ -18,24 +18,6 @@ saman = ""
[err.common]
unknown = ""
-[err.backend]
-authorization_pending = ""
-bad_request = ""
-conflict = ""
-expired_token = ""
-forbidden = ""
-internal_error = ""
-invalid_code = ""
-invalid_or_expired_code = ""
-invalid_session = ""
-invalid_session_reference = ""
-not_found = ""
-not_supported = ""
-password_or_email_mismatch = ""
-rate_limited = ""
-service_unavailable = ""
-slow_down = ""
-
[err.userfront]
[err.userfront.auth_proxy]
@@ -220,18 +202,16 @@ count = ""
[msg.common]
loading = ""
saving = ""
+requesting = ""
unknown_error = ""
[msg.dev]
logout_confirm = ""
[msg.dev.clients]
-copy_client_id = ""
load_error = ""
loading = ""
showing = ""
-status_update_error = ""
-status_updated = ""
deleted = ""
delete_error = ""
delete_confirm = ""
@@ -430,7 +410,6 @@ token_missing = ""
verification_failed = ""
[msg.userfront.login.link]
-approved = ""
helper = ""
missing_login_id = ""
missing_phone = ""
@@ -493,8 +472,6 @@ organization = ""
security = ""
[msg.userfront.qr]
-approve_error = ""
-approve_success = ""
camera_error = ""
permission_error = ""
permission_required = ""
@@ -915,6 +892,7 @@ create = ""
delete = ""
details = ""
edit = ""
+view = ""
hyphen = ""
na = ""
never = ""
@@ -925,7 +903,6 @@ previous = ""
qr = ""
read_only = ""
refresh = ""
-requesting = ""
resend = ""
retry = ""
save = ""
@@ -967,8 +944,13 @@ scope_badge = ""
clients = ""
logout = ""
+[ui.dev.profile]
+menu_aria = ""
+menu_title = ""
+unknown_email = ""
+unknown_name = ""
+
[ui.dev.clients]
-copy_client_id = ""
new = ""
search_placeholder = ""
tenant_scoped = ""
@@ -1055,10 +1037,6 @@ title_edit = ""
[ui.dev.clients.general.breadcrumb]
section = ""
-[ui.dev.clients.general.footer]
-client_id = ""
-created_on = ""
-
[ui.dev.clients.general.identity]
description = ""
description_placeholder = ""
@@ -1163,6 +1141,8 @@ unknown = ""
expired = ""
expiring = ""
remaining = ""
+refresh = ""
+refreshing = ""
[ui.userfront]
app_title = ""
@@ -1239,12 +1219,9 @@ login_id = ""
password = ""
[ui.userfront.login.link]
-action_label = ""
code_only = ""
-page_title = ""
resend_with_time = ""
send = ""
-title = ""
[ui.userfront.login.qr]
expired = ""
@@ -1314,9 +1291,7 @@ organization = ""
security = ""
[ui.userfront.qr]
-request_permission = ""
rescan = ""
-result_failure = ""
result_success = ""
title = ""
@@ -1393,8 +1368,6 @@ delete_confirm = ""
delete_error = ""
delete_success = ""
empty = ""
-import_error = ""
-import_success = ""
loading = ""
[msg.admin.groups.members]
@@ -1428,7 +1401,6 @@ no_description = ""
[ui.admin.groups]
add_unit = ""
-import_csv = ""
[ui.admin.groups.create]
description = ""
@@ -1448,10 +1420,6 @@ parent_none = ""
unit_level_label = ""
unit_level_placeholder = ""
-[ui.admin.groups.table]
-created_at = ""
-level = ""
-
[ui.admin.tenants.admins]
add_button = ""
already_admin = ""
diff --git a/tools/i18n-scanner/manual-keys.ts b/tools/i18n-scanner/manual-keys.ts
index ee374a68..f6dff763 100644
--- a/tools/i18n-scanner/manual-keys.ts
+++ b/tools/i18n-scanner/manual-keys.ts
@@ -14,6 +14,7 @@ t("ui.admin.nav.audit_logs");
t("ui.admin.nav.auth_guard");
t("ui.admin.nav.logout");
t("ui.admin.nav.relying_parties");
+t("ui.dev.nav.clients");
// Common & Info
t("err.common.unknown");
From 242c088730f73148960a79d8b01b959666bcf0c6 Mon Sep 17 00:00:00 2001
From: kyy
Date: Tue, 24 Feb 2026 17:28:39 +0900
Subject: [PATCH 8/8] =?UTF-8?q?make=20code-check=20=EC=A0=81=EC=9A=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
devfront/src/components/layout/AppLayout.tsx | 24 +++++++-------
.../features/clients/ClientGeneralPage.tsx | 2 --
userfront/assets/translations/en.toml | 1 +
userfront/assets/translations/ko.toml | 1 +
userfront/assets/translations/template.toml | 10 +-----
userfront/pubspec.lock | 32 +++++++------------
6 files changed, 27 insertions(+), 43 deletions(-)
diff --git a/devfront/src/components/layout/AppLayout.tsx b/devfront/src/components/layout/AppLayout.tsx
index 469a9362..9e798031 100644
--- a/devfront/src/components/layout/AppLayout.tsx
+++ b/devfront/src/components/layout/AppLayout.tsx
@@ -1,10 +1,4 @@
-import {
- BadgeCheck,
- LogOut,
- Moon,
- ShieldHalf,
- Sun,
-} from "lucide-react";
+import { BadgeCheck, LogOut, Moon, ShieldHalf, Sun } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useAuth } from "react-oidc-context";
import { NavLink, Outlet, useNavigate } from "react-router-dom";
@@ -104,22 +98,25 @@ function AppLayout() {
let sessionText = t("ui.dev.session.active", "세션 만료 시간 확인 중");
if (remainingMs === null) {
- sessionToneClass =
- "border-border bg-card text-muted-foreground";
+ sessionToneClass = "border-border bg-card text-muted-foreground";
sessionText = t("ui.dev.session.unknown", "세션 만료 시간 확인 불가");
} else if (remainingMs <= 0) {
sessionToneClass =
"border-rose-500/30 bg-rose-500/10 text-rose-700 dark:text-rose-300";
sessionText = t("ui.dev.session.expired", "세션 만료됨");
} else {
- if (remainingMinutes !== null && remainingSeconds !== null && remainingMinutes <= 5) {
+ if (
+ remainingMinutes !== null &&
+ remainingSeconds !== null &&
+ remainingMinutes <= 5
+ ) {
sessionToneClass =
"border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300";
sessionText = t(
"ui.dev.session.expiring",
"만료 임박: {{minutes}}분 {{seconds}}초 남음",
{
- minutes: remainingMinutes,
+ minutes: remainingMinutes,
seconds: remainingSeconds,
},
);
@@ -300,7 +297,10 @@ function AppLayout() {
disabled={isRefreshingSession}
>
{isRefreshingSession
- ? t("ui.dev.session.refreshing", "세션 만료 시간 갱신 중...")
+ ? t(
+ "ui.dev.session.refreshing",
+ "세션 만료 시간 갱신 중...",
+ )
: t("ui.dev.session.refresh", "세션 만료 시간 갱신")}
diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx
index cf00077a..ba910abd 100644
--- a/devfront/src/features/clients/ClientGeneralPage.tsx
+++ b/devfront/src/features/clients/ClientGeneralPage.tsx
@@ -675,8 +675,6 @@ function ClientGeneralPage() {
-
-
);
}
diff --git a/userfront/assets/translations/en.toml b/userfront/assets/translations/en.toml
index c8e88505..1acbecba 100644
--- a/userfront/assets/translations/en.toml
+++ b/userfront/assets/translations/en.toml
@@ -334,6 +334,7 @@ theme_dark = "Dark"
theme_light = "Light"
theme_toggle = "Theme Toggle"
unknown = "Unknown"
+view = "View"
[ui.common.badge]
admin_only = "Admin only"
diff --git a/userfront/assets/translations/ko.toml b/userfront/assets/translations/ko.toml
index 0ec335ff..6442beeb 100644
--- a/userfront/assets/translations/ko.toml
+++ b/userfront/assets/translations/ko.toml
@@ -334,6 +334,7 @@ theme_dark = "Dark"
theme_light = "Light"
theme_toggle = "테마 전환"
unknown = "Unknown"
+view = "보기"
[ui.common.badge]
admin_only = "Admin only"
diff --git a/userfront/assets/translations/template.toml b/userfront/assets/translations/template.toml
index d1f5404d..3911cf30 100644
--- a/userfront/assets/translations/template.toml
+++ b/userfront/assets/translations/template.toml
@@ -131,7 +131,6 @@ token_missing = ""
verification_failed = ""
[msg.userfront.login.link]
-approved = ""
helper = ""
missing_login_id = ""
missing_phone = ""
@@ -194,8 +193,6 @@ organization = ""
security = ""
[msg.userfront.qr]
-approve_error = ""
-approve_success = ""
camera_error = ""
permission_error = ""
permission_required = ""
@@ -306,6 +303,7 @@ create = ""
delete = ""
details = ""
edit = ""
+view = ""
hyphen = ""
na = ""
never = ""
@@ -316,7 +314,6 @@ previous = ""
qr = ""
read_only = ""
refresh = ""
-requesting = ""
resend = ""
retry = ""
save = ""
@@ -423,12 +420,9 @@ login_id = ""
password = ""
[ui.userfront.login.link]
-action_label = ""
code_only = ""
-page_title = ""
resend_with_time = ""
send = ""
-title = ""
[ui.userfront.login.qr]
expired = ""
@@ -498,9 +492,7 @@ organization = ""
security = ""
[ui.userfront.qr]
-request_permission = ""
rescan = ""
-result_failure = ""
result_success = ""
title = ""
diff --git a/userfront/pubspec.lock b/userfront/pubspec.lock
index fecd33f1..ae003ec3 100644
--- a/userfront/pubspec.lock
+++ b/userfront/pubspec.lock
@@ -45,10 +45,10 @@ packages:
dependency: transitive
description:
name: characters
- sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
+ sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted
- version: "1.4.0"
+ version: "1.4.1"
cli_config:
dependency: transitive
description:
@@ -268,14 +268,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
- js:
- dependency: transitive
- description:
- name: js
- sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
- url: "https://pub.dev"
- source: hosted
- version: "0.7.2"
leak_tracker:
dependency: transitive
description:
@@ -328,18 +320,18 @@ packages:
dependency: transitive
description:
name: matcher
- sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
+ sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
- version: "0.12.17"
+ version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
- sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
+ sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
- version: "0.11.1"
+ version: "0.13.0"
meta:
dependency: transitive
description:
@@ -653,26 +645,26 @@ packages:
dependency: transitive
description:
name: test
- sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
+ sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a"
url: "https://pub.dev"
source: hosted
- version: "1.26.3"
+ version: "1.29.0"
test_api:
dependency: transitive
description:
name: test_api
- sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
+ sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
- version: "0.7.7"
+ version: "0.7.9"
test_core:
dependency: transitive
description:
name: test_core
- sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
+ sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943"
url: "https://pub.dev"
source: hosted
- version: "0.6.12"
+ version: "0.6.15"
toml:
dependency: "direct main"
description: