forked from baron/baron-sso
로컬 code-check 오류 수정
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
|||||||
Save,
|
Save,
|
||||||
Shield,
|
Shield,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Link, useParams } from "react-router-dom";
|
import { Link, useParams } from "react-router-dom";
|
||||||
import { Badge } from "../../components/ui/badge";
|
import { Badge } from "../../components/ui/badge";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
@@ -44,7 +44,7 @@ function ClientDetailsPage() {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const clientId = params.id ?? "";
|
const clientId = params.id ?? "";
|
||||||
|
|
||||||
const { data, isLoading, error } = useQuery({
|
const { data, error } = useQuery({
|
||||||
queryKey: ["client", clientId],
|
queryKey: ["client", clientId],
|
||||||
queryFn: () => fetchClient(clientId),
|
queryFn: () => fetchClient(clientId),
|
||||||
enabled: clientId.length > 0,
|
enabled: clientId.length > 0,
|
||||||
@@ -52,12 +52,18 @@ function ClientDetailsPage() {
|
|||||||
|
|
||||||
const [redirectUris, setRedirectUris] = useState("");
|
const [redirectUris, setRedirectUris] = useState("");
|
||||||
const [showSecret, setShowSecret] = useState(false);
|
const [showSecret, setShowSecret] = useState(false);
|
||||||
|
const redirectUrisHydratedRef = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data?.client?.redirectUris) {
|
if (
|
||||||
|
!redirectUrisHydratedRef.current &&
|
||||||
|
data?.client?.redirectUris &&
|
||||||
|
redirectUris === ""
|
||||||
|
) {
|
||||||
setRedirectUris(data.client.redirectUris.join(", "));
|
setRedirectUris(data.client.redirectUris.join(", "));
|
||||||
|
redirectUrisHydratedRef.current = true;
|
||||||
}
|
}
|
||||||
}, [data]);
|
}, [data, redirectUris]);
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: () => {
|
mutationFn: () => {
|
||||||
@@ -129,15 +135,7 @@ function ClientDetailsPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading) {
|
if (error && !data) {
|
||||||
return (
|
|
||||||
<div className="p-8 text-center">
|
|
||||||
{t("msg.dev.clients.details.loading", "Loading app...")}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error || !data) {
|
|
||||||
const errMsg =
|
const errMsg =
|
||||||
(error as AxiosError<{ error?: string }>).response?.data?.error ??
|
(error as AxiosError<{ error?: string }>).response?.data?.error ??
|
||||||
(error as Error)?.message;
|
(error as Error)?.message;
|
||||||
@@ -152,37 +150,45 @@ function ClientDetailsPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const client = data?.client;
|
||||||
|
const endpointValues = data?.endpoints ?? {
|
||||||
|
discovery: "-",
|
||||||
|
issuer: "-",
|
||||||
|
authorization: "-",
|
||||||
|
token: "-",
|
||||||
|
userinfo: "-",
|
||||||
|
};
|
||||||
const endpoints = [
|
const endpoints = [
|
||||||
{
|
{
|
||||||
labelKey: "ui.dev.clients.details.endpoint.discovery",
|
labelKey: "ui.dev.clients.details.endpoint.discovery",
|
||||||
labelFallback: "Discovery Endpoint",
|
labelFallback: "Discovery Endpoint",
|
||||||
value: data.endpoints.discovery,
|
value: endpointValues.discovery,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelKey: "ui.dev.clients.details.endpoint.issuer",
|
labelKey: "ui.dev.clients.details.endpoint.issuer",
|
||||||
labelFallback: "Issuer URL",
|
labelFallback: "Issuer URL",
|
||||||
value: data.endpoints.issuer,
|
value: endpointValues.issuer,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelKey: "ui.dev.clients.details.endpoint.authorization",
|
labelKey: "ui.dev.clients.details.endpoint.authorization",
|
||||||
labelFallback: "Authorization Endpoint",
|
labelFallback: "Authorization Endpoint",
|
||||||
value: data.endpoints.authorization,
|
value: endpointValues.authorization,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelKey: "ui.dev.clients.details.endpoint.token",
|
labelKey: "ui.dev.clients.details.endpoint.token",
|
||||||
labelFallback: "Token Endpoint",
|
labelFallback: "Token Endpoint",
|
||||||
value: data.endpoints.token,
|
value: endpointValues.token,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
labelKey: "ui.dev.clients.details.endpoint.userinfo",
|
labelKey: "ui.dev.clients.details.endpoint.userinfo",
|
||||||
labelFallback: "UserInfo Endpoint",
|
labelFallback: "UserInfo Endpoint",
|
||||||
value: data.endpoints.userinfo,
|
value: endpointValues.userinfo,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Client Secret from API
|
// Client Secret from API
|
||||||
const secretPlaceholder = "SECRET_NOT_AVAILABLE";
|
const secretPlaceholder = "SECRET_NOT_AVAILABLE";
|
||||||
const clientSecret = data.client.clientSecret || secretPlaceholder;
|
const clientSecret = client?.clientSecret || secretPlaceholder;
|
||||||
const displaySecret =
|
const displaySecret =
|
||||||
clientSecret === secretPlaceholder
|
clientSecret === secretPlaceholder
|
||||||
? t("msg.dev.clients.details.secret_unavailable", "SECRET_NOT_AVAILABLE")
|
? t("msg.dev.clients.details.secret_unavailable", "SECRET_NOT_AVAILABLE")
|
||||||
@@ -200,7 +206,7 @@ function ClientDetailsPage() {
|
|||||||
{t("ui.dev.clients.consents.breadcrumb.clients", "Apps")}
|
{t("ui.dev.clients.consents.breadcrumb.clients", "Apps")}
|
||||||
</Link>
|
</Link>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>{data.client.name || clientId}</span>
|
<span>{client?.name || clientId}</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span className="text-foreground font-semibold">
|
<span className="text-foreground font-semibold">
|
||||||
{t("ui.dev.clients.details.tab.connection", "Federation")}
|
{t("ui.dev.clients.details.tab.connection", "Federation")}
|
||||||
@@ -215,7 +221,7 @@ function ClientDetailsPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-4xl font-black leading-tight tracking-tight">
|
<h1 className="text-4xl font-black leading-tight tracking-tight">
|
||||||
{data.client.name || data.client.id}
|
{client?.name || client?.id || clientId}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
{t(
|
{t(
|
||||||
@@ -226,12 +232,14 @@ function ClientDetailsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Badge
|
<Badge
|
||||||
variant={data.client.status === "active" ? "info" : "muted"}
|
variant={client?.status === "active" ? "info" : "muted"}
|
||||||
className="px-3 py-1 text-xs uppercase"
|
className="px-3 py-1 text-xs uppercase"
|
||||||
>
|
>
|
||||||
{data.client.status === "active"
|
{client?.status === "active"
|
||||||
? t("ui.common.status.active", "Active")
|
? t("ui.common.status.active", "Active")
|
||||||
: t("ui.common.status.inactive", "Inactive")}
|
: client?.status === "inactive"
|
||||||
|
? t("ui.common.status.inactive", "Inactive")
|
||||||
|
: t("msg.common.loading", "Loading...")}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-6 border-b border-border">
|
<div className="flex gap-6 border-b border-border">
|
||||||
@@ -276,10 +284,10 @@ function ClientDetailsPage() {
|
|||||||
</p>
|
</p>
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<p className="font-mono text-lg truncate">
|
<p className="font-mono text-lg truncate">
|
||||||
{data.client.id}
|
{client?.id || clientId}
|
||||||
</p>
|
</p>
|
||||||
<CopyButton
|
<CopyButton
|
||||||
value={data.client.id}
|
value={client?.id || clientId}
|
||||||
onCopy={() =>
|
onCopy={() =>
|
||||||
toast(
|
toast(
|
||||||
t(
|
t(
|
||||||
@@ -461,7 +469,10 @@ function ClientDetailsPage() {
|
|||||||
)}
|
)}
|
||||||
rows={5}
|
rows={5}
|
||||||
value={redirectUris}
|
value={redirectUris}
|
||||||
onChange={(e) => setRedirectUris(e.target.value)}
|
onChange={(e) => {
|
||||||
|
redirectUrisHydratedRef.current = true;
|
||||||
|
setRedirectUris(e.target.value);
|
||||||
|
}}
|
||||||
className="font-mono text-sm"
|
className="font-mono text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -513,6 +513,7 @@ browser = "Browser: {{value}}"
|
|||||||
date = "Date: {{value}}"
|
date = "Date: {{value}}"
|
||||||
device = "Device: {{value}}"
|
device = "Device: {{value}}"
|
||||||
end = "No more items to show."
|
end = "No more items to show."
|
||||||
|
filtered_empty = "No sign-in history matches the active session filter."
|
||||||
ip = "IP address: {{value}}"
|
ip = "IP address: {{value}}"
|
||||||
load_more_error = "Could not load more history."
|
load_more_error = "Could not load more history."
|
||||||
result = "Result: {{value}}"
|
result = "Result: {{value}}"
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ browser = "브라우저: {{value}}"
|
|||||||
date = "접속일자: {{value}}"
|
date = "접속일자: {{value}}"
|
||||||
device = "접속환경: {{value}}"
|
device = "접속환경: {{value}}"
|
||||||
end = "더 이상 항목이 없습니다."
|
end = "더 이상 항목이 없습니다."
|
||||||
|
filtered_empty = "활성 세션으로 필터링된 접속 이력이 없습니다."
|
||||||
ip = "접속 IP: {{value}}"
|
ip = "접속 IP: {{value}}"
|
||||||
load_more_error = "더 불러오지 못했습니다."
|
load_more_error = "더 불러오지 못했습니다."
|
||||||
result = "인증결과: {{value}}"
|
result = "인증결과: {{value}}"
|
||||||
@@ -905,9 +906,11 @@ saved_success = "저장이 완료되었습니다."
|
|||||||
greeting = "안녕하세요, {{name}}님"
|
greeting = "안녕하세요, {{name}}님"
|
||||||
|
|
||||||
[msg.userfront.audit]
|
[msg.userfront.audit]
|
||||||
|
browser = "브라우저: {{value}}"
|
||||||
date = "접속일자: {{value}}"
|
date = "접속일자: {{value}}"
|
||||||
device = "접속환경: {{value}}"
|
device = "접속환경: {{value}}"
|
||||||
end = "더 이상 항목이 없습니다."
|
end = "더 이상 항목이 없습니다."
|
||||||
|
filtered_empty = "활성 세션으로 필터링된 접속 이력이 없습니다."
|
||||||
ip = "접속 IP: {{value}}"
|
ip = "접속 IP: {{value}}"
|
||||||
load_more_error = "더 불러오지 못했습니다."
|
load_more_error = "더 불러오지 못했습니다."
|
||||||
result = "인증결과: {{value}}"
|
result = "인증결과: {{value}}"
|
||||||
|
|||||||
@@ -782,9 +782,11 @@ saved_success = ""
|
|||||||
greeting = ""
|
greeting = ""
|
||||||
|
|
||||||
[msg.userfront.audit]
|
[msg.userfront.audit]
|
||||||
|
browser = ""
|
||||||
date = ""
|
date = ""
|
||||||
device = ""
|
device = ""
|
||||||
end = ""
|
end = ""
|
||||||
|
filtered_empty = ""
|
||||||
ip = ""
|
ip = ""
|
||||||
load_more_error = ""
|
load_more_error = ""
|
||||||
result = ""
|
result = ""
|
||||||
@@ -2330,6 +2332,7 @@ dev_console = ""
|
|||||||
action = ""
|
action = ""
|
||||||
app = ""
|
app = ""
|
||||||
auth_method = ""
|
auth_method = ""
|
||||||
|
browser = ""
|
||||||
date = ""
|
date = ""
|
||||||
device = ""
|
device = ""
|
||||||
ip = ""
|
ip = ""
|
||||||
@@ -2557,4 +2560,4 @@ title = ""
|
|||||||
toggle_label = ""
|
toggle_label = ""
|
||||||
|
|
||||||
[msg.userfront.audit.filter]
|
[msg.userfront.audit.filter]
|
||||||
description = ""
|
description = ""
|
||||||
|
|||||||
@@ -48,13 +48,12 @@ browser = "Browser: {value}"
|
|||||||
date = "Date: {value}"
|
date = "Date: {value}"
|
||||||
device = "Device: {value}"
|
device = "Device: {value}"
|
||||||
end = "No more items to show."
|
end = "No more items to show."
|
||||||
filtered_empty = "There are no active or current sessions to display."
|
filtered_empty = "No sign-in history matches the active session filter."
|
||||||
filter.description = "Turn this on to show only active or current sessions."
|
|
||||||
ip = "IP address: {value}"
|
ip = "IP address: {value}"
|
||||||
load_more_error = "Could not load more history."
|
load_more_error = "Could not load more history."
|
||||||
result = "Result: {value}"
|
result = "Result: {value}"
|
||||||
session_id = "Session ID: {value}"
|
session_id = "Session ID: {value}"
|
||||||
status = "Status: {value}"
|
status = "Status: pending"
|
||||||
|
|
||||||
[msg.userfront.consent]
|
[msg.userfront.consent]
|
||||||
accept_error = "Failed to process consent: {error}"
|
accept_error = "Failed to process consent: {error}"
|
||||||
@@ -286,7 +285,7 @@ uppercase = "At least one uppercase letter"
|
|||||||
|
|
||||||
[msg.userfront.sections]
|
[msg.userfront.sections]
|
||||||
apps_subtitle = "Your linked apps and their latest sign-in status."
|
apps_subtitle = "Your linked apps and their latest sign-in status."
|
||||||
audit_subtitle = "Review current session status and recent sign-in history together."
|
audit_subtitle = "Recent access history for Baron sign-in."
|
||||||
sessions_subtitle = "Your currently signed-in devices and browser sessions."
|
sessions_subtitle = "Your currently signed-in devices and browser sessions."
|
||||||
|
|
||||||
[msg.userfront.settings]
|
[msg.userfront.settings]
|
||||||
@@ -437,10 +436,6 @@ dev_console = "Dev Console"
|
|||||||
|
|
||||||
[ui.userfront.audit]
|
[ui.userfront.audit]
|
||||||
|
|
||||||
[ui.userfront.audit.filter]
|
|
||||||
title = "Session filter"
|
|
||||||
toggle_label = "Active only"
|
|
||||||
|
|
||||||
[ui.userfront.audit.table]
|
[ui.userfront.audit.table]
|
||||||
action = "Action"
|
action = "Action"
|
||||||
app = "App"
|
app = "App"
|
||||||
@@ -669,5 +664,9 @@ verify = "Verification"
|
|||||||
action = "Go to sign-in"
|
action = "Go to sign-in"
|
||||||
|
|
||||||
|
|
||||||
|
[ui.userfront.audit.filter]
|
||||||
|
title = "Manage My Activity"
|
||||||
|
toggle_label = "Show active sessions only"
|
||||||
|
|
||||||
[msg.userfront.audit.filter]
|
[msg.userfront.audit.filter]
|
||||||
description = "Toggle to view only active sessions."
|
description = "Toggle to view only active sessions."
|
||||||
|
|||||||
@@ -45,13 +45,12 @@ browser = "브라우저: {value}"
|
|||||||
date = "접속일자: {value}"
|
date = "접속일자: {value}"
|
||||||
device = "접속환경: {value}"
|
device = "접속환경: {value}"
|
||||||
end = "더 이상 항목이 없습니다."
|
end = "더 이상 항목이 없습니다."
|
||||||
filtered_empty = "활성화 또는 접속중인 세션이 없습니다."
|
filtered_empty = "활성 세션으로 필터링된 접속 이력이 없습니다."
|
||||||
filter.description = "토글을 켜면 활성화 또는 접속중인 세션만 표시됩니다."
|
|
||||||
ip = "접속 IP: {value}"
|
ip = "접속 IP: {value}"
|
||||||
load_more_error = "더 불러오지 못했습니다."
|
load_more_error = "더 불러오지 못했습니다."
|
||||||
result = "인증결과: {value}"
|
result = "인증결과: {value}"
|
||||||
session_id = "Session ID: {value}"
|
session_id = "Session ID: {value}"
|
||||||
status = "현황: {value}"
|
status = "현황: (준비중)"
|
||||||
|
|
||||||
[msg.userfront.dashboard]
|
[msg.userfront.dashboard]
|
||||||
approved_device = "승인 기기: {device}"
|
approved_device = "승인 기기: {device}"
|
||||||
@@ -141,7 +140,7 @@ success = "비밀번호가 성공적으로 변경되었습니다. 다시 로그
|
|||||||
|
|
||||||
[msg.userfront.sections]
|
[msg.userfront.sections]
|
||||||
apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다."
|
apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다."
|
||||||
audit_subtitle = "현재 세션 현황과 최근 접근 기록을 함께 확인할 수 있습니다."
|
audit_subtitle = "Baron 로그인 기준의 최근 접근 기록입니다."
|
||||||
sessions_subtitle = "현재 로그인된 기기와 브라우저 세션입니다."
|
sessions_subtitle = "현재 로그인된 기기와 브라우저 세션입니다."
|
||||||
|
|
||||||
[msg.userfront.settings]
|
[msg.userfront.settings]
|
||||||
@@ -251,9 +250,11 @@ title = "회원가입"
|
|||||||
greeting = "안녕하세요, {name}님"
|
greeting = "안녕하세요, {name}님"
|
||||||
|
|
||||||
[msg.userfront.audit]
|
[msg.userfront.audit]
|
||||||
|
browser = "브라우저: {value}"
|
||||||
date = "접속일자: {value}"
|
date = "접속일자: {value}"
|
||||||
device = "접속환경: {value}"
|
device = "접속환경: {value}"
|
||||||
end = "더 이상 항목이 없습니다."
|
end = "더 이상 항목이 없습니다."
|
||||||
|
filtered_empty = "활성 세션으로 필터링된 접속 이력이 없습니다."
|
||||||
ip = "접속 IP: {value}"
|
ip = "접속 IP: {value}"
|
||||||
load_more_error = "더 불러오지 못했습니다."
|
load_more_error = "더 불러오지 못했습니다."
|
||||||
result = "인증결과: {value}"
|
result = "인증결과: {value}"
|
||||||
@@ -490,7 +491,7 @@ uppercase = "대문자 1개 이상"
|
|||||||
|
|
||||||
[msg.userfront.sections]
|
[msg.userfront.sections]
|
||||||
apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다."
|
apps_subtitle = "현재 연결된 앱과 최근 인증 상태입니다."
|
||||||
audit_subtitle = "현재 세션 현황과 최근 접근 기록을 함께 확인할 수 있습니다."
|
audit_subtitle = "Baron 로그인 기준의 최근 접근 기록입니다."
|
||||||
|
|
||||||
[msg.userfront.settings]
|
[msg.userfront.settings]
|
||||||
disabled = "현재 계정 설정 화면은 준비 중입니다."
|
disabled = "현재 계정 설정 화면은 준비 중입니다."
|
||||||
@@ -640,10 +641,6 @@ dev_console = "Dev Console"
|
|||||||
|
|
||||||
[ui.userfront.audit]
|
[ui.userfront.audit]
|
||||||
|
|
||||||
[ui.userfront.audit.filter]
|
|
||||||
title = "세션 필터"
|
|
||||||
toggle_label = "활성 세션만"
|
|
||||||
|
|
||||||
[ui.userfront.audit.table]
|
[ui.userfront.audit.table]
|
||||||
action = "관리"
|
action = "관리"
|
||||||
app = "애플리케이션"
|
app = "애플리케이션"
|
||||||
@@ -871,5 +868,9 @@ verify = "본인인증"
|
|||||||
action = "로그인하기"
|
action = "로그인하기"
|
||||||
|
|
||||||
|
|
||||||
|
[ui.userfront.audit.filter]
|
||||||
|
title = "내 활동 관리"
|
||||||
|
toggle_label = "활성 세션만 보기"
|
||||||
|
|
||||||
[msg.userfront.audit.filter]
|
[msg.userfront.audit.filter]
|
||||||
description = "활성화된 세션만 보려면 토글을 켜주세요."
|
description = "활성화된 세션만 보려면 토글을 켜주세요."
|
||||||
|
|||||||
@@ -228,7 +228,6 @@ date = ""
|
|||||||
device = ""
|
device = ""
|
||||||
end = ""
|
end = ""
|
||||||
filtered_empty = ""
|
filtered_empty = ""
|
||||||
filter.description = ""
|
|
||||||
ip = ""
|
ip = ""
|
||||||
load_more_error = ""
|
load_more_error = ""
|
||||||
result = ""
|
result = ""
|
||||||
@@ -615,10 +614,6 @@ dev_console = ""
|
|||||||
|
|
||||||
[ui.userfront.audit]
|
[ui.userfront.audit]
|
||||||
|
|
||||||
[ui.userfront.audit.filter]
|
|
||||||
title = ""
|
|
||||||
toggle_label = ""
|
|
||||||
|
|
||||||
[ui.userfront.audit.table]
|
[ui.userfront.audit.table]
|
||||||
action = ""
|
action = ""
|
||||||
app = ""
|
app = ""
|
||||||
@@ -846,5 +841,9 @@ verify = ""
|
|||||||
action = ""
|
action = ""
|
||||||
|
|
||||||
|
|
||||||
|
[ui.userfront.audit.filter]
|
||||||
|
title = ""
|
||||||
|
toggle_label = ""
|
||||||
|
|
||||||
[msg.userfront.audit.filter]
|
[msg.userfront.audit.filter]
|
||||||
description = ""
|
description = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user