1
0
forked from baron/baron-sso

개발자 권한 신청 승인/취소 및 RP 생성 흐름 개선

This commit is contained in:
2026-04-22 14:39:06 +09:00
parent 2216d9c4e4
commit 685923a03e
12 changed files with 382 additions and 44 deletions

View File

@@ -529,12 +529,16 @@ function ClientGeneralPage() {
onError: (err) => {
const axiosError = err as AxiosError<{ error?: string }>;
if (axiosError.response?.status === 403) {
toast(
t(
"msg.dev.clients.general.save_forbidden",
"이 RP 설정을 수정할 권한이 없습니다.\n관리자에게 RP 일반 설정 또는 RP 관리자 관계 부여를 요청해 주세요.",
),
"error",
alert(
isCreate
? t(
"msg.dev.clients.general.create_forbidden",
"이 RP를 생성할 권한이 없습니다.\n관리자에게 개발자 권한 부여를 요청해 주세요.",
)
: t(
"msg.dev.clients.general.save_forbidden",
"이 RP 설정을 수정할 권한이 없습니다.\n관리자에게 RP 일반 설정 또는 RP 관리자 관계 부여를 요청해 주세요.",
),
);
return;
}

View File

@@ -57,8 +57,6 @@ function ClientsPage() {
const role = resolveProfileRole(userProfile);
const tenantId = userProfile?.tenant_id as string | undefined;
const canCreateClient = role !== "user" && role !== "tenant_member";
const {
data,
isLoading: isLoadingClients,
@@ -76,6 +74,7 @@ function ClientsPage() {
});
const {
data: requestStatus,
isLoading: isLoadingRequest,
refetch: refetchRequest,
} = useQuery({
@@ -84,6 +83,16 @@ function ClientsPage() {
enabled: hasAccessToken && role === "user",
});
const canCreateClient =
(role !== "user" && role !== "tenant_member") ||
requestStatus?.status === "approved";
const isDeveloperRequestPending = requestStatus?.status === "pending";
const canRequestDeveloperAccess =
role === "user" &&
!isLoadingRequest &&
!canCreateClient &&
!isDeveloperRequestPending;
const [searchQuery, setSearchQuery] = useState("");
const [typeFilter, setTypeFilter] = useState("all");
const [statusFilter, setStatusFilter] = useState("all");
@@ -106,6 +115,8 @@ function ClientsPage() {
const totalClients = statsData?.total_clients ?? clients.length;
const activeSessions = statsData?.active_sessions ?? 0;
const authFailures = statsData?.auth_failures_24h ?? 0;
const hasFilterResult = filteredClients.length > 0;
const isFilteredOut = clients.length > 0 && !hasFilterResult;
type StatTone = "up" | "down" | "stable";
type StatItem = {
@@ -378,7 +389,7 @@ function ClientsPage() {
</TableRow>
</TableHeader>
<TableBody>
{filteredClients.length === 0 && (
{!hasFilterResult && (
<TableRow>
<TableCell
colSpan={6}
@@ -386,19 +397,58 @@ function ClientsPage() {
>
<div className="space-y-1">
<p className="font-medium text-foreground">
{t(
"msg.dev.clients.empty",
"조회 가능한 RP가 없습니다.",
)}
{isFilteredOut
? t(
"msg.dev.clients.empty_filtered",
"조건에 맞는 연동 앱이 없습니다.",
)
: canCreateClient
? t(
"msg.dev.clients.empty_can_create",
"아직 등록된 연동 앱이 없습니다.",
)
: isDeveloperRequestPending
? t(
"msg.dev.clients.empty_pending",
"개발자 권한 신청을 검토 중입니다.",
)
: t(
"msg.dev.clients.empty",
"조회 가능한 RP가 없습니다.",
)}
</p>
<div className="text-sm space-y-2">
<p className="text-muted-foreground">
{t(
"msg.dev.clients.empty_detail",
"RP 관계가 부여되면 이 목록에 해당 RP가 표시됩니다.",
)}
{isFilteredOut
? t(
"msg.dev.clients.empty_filtered_detail",
"검색어나 필터 조건을 변경해 보세요.",
)
: canCreateClient
? t(
"msg.dev.clients.empty_can_create_detail",
"연동 앱 추가 버튼으로 새 RP를 생성하면 이 목록에 표시됩니다.",
)
: isDeveloperRequestPending
? t(
"msg.dev.clients.empty_pending_detail",
"super admin이 승인하면 연동 앱을 추가할 수 있습니다.",
)
: t(
"msg.dev.clients.empty_detail",
"RP 관계가 부여되면 이 목록에 해당 RP가 표시됩니다.",
)}
</p>
{role === "user" && (
{!isFilteredOut && canCreateClient && (
<button
type="button"
className="text-primary font-bold hover:underline"
onClick={() => navigate("/clients/new")}
>
{t("ui.dev.clients.new", "연동 앱 추가")}
</button>
)}
{!isFilteredOut && canRequestDeveloperAccess && (
<button
type="button"
className="text-primary font-bold hover:underline"