forked from baron/baron-sso
앱 생성 개발자 권한 신청 안내 추가
This commit is contained in:
@@ -60,6 +60,7 @@ import { t } from "../../lib/i18n";
|
||||
import { resolveProfileRole } from "../../lib/role";
|
||||
import { cn } from "../../lib/utils";
|
||||
import { fetchMe } from "../auth/authApi";
|
||||
import { resolveClientCreateAccess } from "./clientCreateAccess";
|
||||
import { ClientLogo } from "./components/ClientLogo";
|
||||
|
||||
type ClientSortKey = "application" | "id" | "type" | "status" | "createdAt";
|
||||
@@ -96,7 +97,8 @@ function ClientsPage() {
|
||||
} = useQuery({
|
||||
queryKey: ["developer-request", tenantId],
|
||||
queryFn: () => fetchDeveloperRequestStatus(tenantId),
|
||||
enabled: hasAccessToken && role === "user",
|
||||
enabled:
|
||||
hasAccessToken && (role === "user" || role === "tenant_member"),
|
||||
});
|
||||
const { data: tenants } = useQuery({
|
||||
queryKey: ["myTenants"],
|
||||
@@ -109,15 +111,14 @@ function ClientsPage() {
|
||||
enabled: hasAccessToken,
|
||||
});
|
||||
|
||||
const canCreateClient =
|
||||
(role !== "user" && role !== "tenant_member") ||
|
||||
requestStatus?.status === "approved";
|
||||
const isDeveloperRequestPending = requestStatus?.status === "pending";
|
||||
const createAccessState = resolveClientCreateAccess({
|
||||
role,
|
||||
requestStatus: requestStatus?.status,
|
||||
});
|
||||
const canCreateClient = createAccessState === "can_create";
|
||||
const isDeveloperRequestPending = createAccessState === "pending";
|
||||
const canRequestDeveloperAccess =
|
||||
role === "user" &&
|
||||
!isLoadingRequest &&
|
||||
!canCreateClient &&
|
||||
!isDeveloperRequestPending;
|
||||
createAccessState === "request_required" && !isLoadingRequest;
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [typeFilter, setTypeFilter] = useState("all");
|
||||
@@ -278,7 +279,54 @@ function ClientsPage() {
|
||||
<Plus className="h-4 w-4" />
|
||||
{t("ui.dev.clients.new", "새 클라이언트")}
|
||||
</Button>
|
||||
) : null
|
||||
) : isDeveloperRequestPending ? (
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<p className="max-w-xs text-right text-sm text-muted-foreground">
|
||||
{t(
|
||||
"msg.dev.clients.create_pending_detail",
|
||||
"개발자 권한 신청을 검토 중입니다. 승인되면 연동 앱을 추가할 수 있습니다.",
|
||||
)}
|
||||
</p>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => navigate("/developer-requests")}
|
||||
>
|
||||
{t("ui.dev.nav.developer_request", "개발자 권한 신청")}
|
||||
</Button>
|
||||
</div>
|
||||
) : canRequestDeveloperAccess ? (
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<p className="max-w-xs whitespace-pre-line text-right text-sm text-muted-foreground">
|
||||
{t(
|
||||
"msg.dev.clients.create_requires_request",
|
||||
"연동 앱을 생성할 권한이 없습니다.\n개발자 권한 신청을 요청한 뒤 승인 받아주세요.",
|
||||
).replaceAll("\\n", "\n")}
|
||||
</p>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => navigate("/developer-requests")}
|
||||
>
|
||||
{t("ui.dev.welcome.btn_request", "개발자 권한 신청")}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-end gap-2 text-right">
|
||||
<p className="max-w-xs text-sm text-muted-foreground">
|
||||
{t(
|
||||
"msg.dev.clients.create_forbidden_detail",
|
||||
"연동 앱을 생성할 권한이 없습니다. 관리자에게 개발자 권한 또는 적절한 RP 권한 부여를 요청해 주세요.",
|
||||
)}
|
||||
</p>
|
||||
<Button type="button" variant="outline" size="sm" disabled>
|
||||
<Plus className="h-4 w-4" />
|
||||
{t("ui.dev.clients.new", "새 클라이언트")}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
55
devfront/src/features/clients/clientCreateAccess.test.ts
Normal file
55
devfront/src/features/clients/clientCreateAccess.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveClientCreateAccess } from "./clientCreateAccess";
|
||||
|
||||
describe("client create access", () => {
|
||||
it("allows privileged roles to create clients without developer request approval", () => {
|
||||
expect(
|
||||
resolveClientCreateAccess({
|
||||
role: "rp_admin",
|
||||
}),
|
||||
).toBe("can_create");
|
||||
});
|
||||
|
||||
it("requires a developer request for basic users without approval", () => {
|
||||
expect(
|
||||
resolveClientCreateAccess({
|
||||
role: "user",
|
||||
requestStatus: "none",
|
||||
}),
|
||||
).toBe("request_required");
|
||||
});
|
||||
|
||||
it("shows pending state while a developer request is under review", () => {
|
||||
expect(
|
||||
resolveClientCreateAccess({
|
||||
role: "tenant_member",
|
||||
requestStatus: "pending",
|
||||
}),
|
||||
).toBe("pending");
|
||||
});
|
||||
|
||||
it("allows client creation after developer request approval", () => {
|
||||
expect(
|
||||
resolveClientCreateAccess({
|
||||
role: "user",
|
||||
requestStatus: "approved",
|
||||
}),
|
||||
).toBe("can_create");
|
||||
});
|
||||
|
||||
it("routes cancelled or rejected requests back to requestable state", () => {
|
||||
expect(
|
||||
resolveClientCreateAccess({
|
||||
role: "user",
|
||||
requestStatus: "cancelled",
|
||||
}),
|
||||
).toBe("request_required");
|
||||
|
||||
expect(
|
||||
resolveClientCreateAccess({
|
||||
role: "user",
|
||||
requestStatus: "rejected",
|
||||
}),
|
||||
).toBe("request_required");
|
||||
});
|
||||
});
|
||||
44
devfront/src/features/clients/clientCreateAccess.ts
Normal file
44
devfront/src/features/clients/clientCreateAccess.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { DeveloperRequestStatus } from "../../lib/devApi";
|
||||
|
||||
export type ClientCreateAccessState =
|
||||
| "can_create"
|
||||
| "pending"
|
||||
| "request_required"
|
||||
| "forbidden";
|
||||
|
||||
type ResolveClientCreateAccessParams = {
|
||||
role: string;
|
||||
requestStatus?: DeveloperRequestStatus;
|
||||
};
|
||||
|
||||
function canSelfRequestDeveloperAccess(role: string) {
|
||||
return role === "user" || role === "tenant_member";
|
||||
}
|
||||
|
||||
export function resolveClientCreateAccess({
|
||||
role,
|
||||
requestStatus,
|
||||
}: ResolveClientCreateAccessParams): ClientCreateAccessState {
|
||||
if (!canSelfRequestDeveloperAccess(role)) {
|
||||
return "can_create";
|
||||
}
|
||||
|
||||
if (requestStatus === "approved") {
|
||||
return "can_create";
|
||||
}
|
||||
|
||||
if (requestStatus === "pending") {
|
||||
return "pending";
|
||||
}
|
||||
|
||||
if (
|
||||
requestStatus === "none" ||
|
||||
requestStatus === "rejected" ||
|
||||
requestStatus === "cancelled" ||
|
||||
typeof requestStatus === "undefined"
|
||||
) {
|
||||
return "request_required";
|
||||
}
|
||||
|
||||
return "forbidden";
|
||||
}
|
||||
@@ -341,6 +341,9 @@ empty = "No RPs are available."
|
||||
empty_detail = "RPs will appear here when a relationship is assigned to your account."
|
||||
empty_can_create = "No linked apps have been registered yet."
|
||||
empty_can_create_detail = "Create a new RP with the Add linked app button, and it will appear here."
|
||||
create_requires_request = "You do not have permission to create applications.\nSubmit a developer access request and wait for approval."
|
||||
create_pending_detail = "Your developer access request is under review. You will be able to add applications after approval."
|
||||
create_forbidden_detail = "You do not have permission to create applications. Ask an administrator to grant developer access or the appropriate RP permissions."
|
||||
empty_filtered = "No linked apps match the current filters."
|
||||
empty_filtered_detail = "Try changing the search text or filters."
|
||||
empty_pending = "Your developer access request is under review."
|
||||
|
||||
@@ -338,6 +338,9 @@ empty = "조회 가능한 RP가 없습니다."
|
||||
empty_detail = "RP 관계가 부여되면 이 목록에 해당 RP가 표시됩니다."
|
||||
empty_can_create = "아직 등록된 연동 앱이 없습니다."
|
||||
empty_can_create_detail = "연동 앱 추가 버튼으로 새 RP를 생성하면 이 목록에 표시됩니다."
|
||||
create_requires_request = "연동 앱을 생성할 권한이 없습니다.\n개발자 권한 신청을 요청한 뒤 승인 받아주세요."
|
||||
create_pending_detail = "개발자 권한 신청을 검토 중입니다. 승인되면 연동 앱을 추가할 수 있습니다."
|
||||
create_forbidden_detail = "연동 앱을 생성할 권한이 없습니다. 관리자에게 개발자 권한 또는 적절한 RP 권한 부여를 요청해 주세요."
|
||||
empty_filtered = "조건에 맞는 연동 앱이 없습니다."
|
||||
empty_filtered_detail = "검색어나 필터 조건을 변경해 보세요."
|
||||
empty_pending = "개발자 권한 신청을 검토 중입니다."
|
||||
|
||||
@@ -379,6 +379,9 @@ empty = ""
|
||||
empty_detail = ""
|
||||
empty_can_create = ""
|
||||
empty_can_create_detail = ""
|
||||
create_requires_request = ""
|
||||
create_pending_detail = ""
|
||||
create_forbidden_detail = ""
|
||||
empty_filtered = ""
|
||||
empty_filtered_detail = ""
|
||||
empty_pending = ""
|
||||
|
||||
Reference in New Issue
Block a user