forked from baron/baron-sso
테넌트 비소속 개발자 권한 신청/부여 가능
This commit is contained in:
@@ -278,7 +278,7 @@ describe("ClientsPage", () => {
|
||||
expect(navigateMock).toHaveBeenCalledWith("/developer-requests");
|
||||
});
|
||||
|
||||
it("shows a tenant-required notice when tenant context is missing", async () => {
|
||||
it("allows a user without tenant context to request developer access", async () => {
|
||||
authState = {
|
||||
user: {
|
||||
access_token: "access-token",
|
||||
@@ -297,11 +297,56 @@ describe("ClientsPage", () => {
|
||||
email: "requester@example.com",
|
||||
phone: "010-1234-5678",
|
||||
});
|
||||
fetchDeveloperRequestStatusMock.mockResolvedValue({ status: "none" });
|
||||
|
||||
const container = await renderPage();
|
||||
expect(container.textContent).toContain(
|
||||
"개발자 권한을 신청하려면 먼저 테넌트에 소속되어 있어야 합니다.",
|
||||
expect(container.textContent).toContain("개발자 등록 신청하기");
|
||||
|
||||
const requestButton = Array.from(container.querySelectorAll("button")).find(
|
||||
(button) => button.textContent === "개발자 등록 신청하기",
|
||||
);
|
||||
expect(fetchDeveloperRequestStatusMock).not.toHaveBeenCalled();
|
||||
expect(requestButton).toBeTruthy();
|
||||
|
||||
await act(async () => {
|
||||
requestButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
|
||||
expect(navigateMock).toHaveBeenCalledWith("/developer-requests");
|
||||
expect(fetchDeveloperRequestStatusMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows the create app button for a super admin without tenant context", async () => {
|
||||
authState = {
|
||||
user: {
|
||||
access_token: "access-token",
|
||||
profile: {
|
||||
role: "super_admin",
|
||||
companyCode: "HANMAC",
|
||||
name: "Dev Admin",
|
||||
email: "dev@example.com",
|
||||
phone: "010-0000-0000",
|
||||
},
|
||||
},
|
||||
};
|
||||
fetchMeMock.mockResolvedValue({
|
||||
role: "super_admin",
|
||||
name: "Dev Admin",
|
||||
email: "dev@example.com",
|
||||
phone: "010-0000-0000",
|
||||
});
|
||||
|
||||
const container = await renderPage();
|
||||
expect(container.textContent).toContain("연동 앱 추가");
|
||||
|
||||
const createButton = Array.from(container.querySelectorAll("button")).find(
|
||||
(button) => button.textContent === "연동 앱 추가",
|
||||
);
|
||||
expect(createButton).toBeTruthy();
|
||||
|
||||
await act(async () => {
|
||||
createButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||
});
|
||||
|
||||
expect(navigateMock).toHaveBeenCalledWith("/clients/new");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -67,7 +67,6 @@ function ClientsPage() {
|
||||
const role = resolveProfileRole(userProfile);
|
||||
const tenantId = userProfile?.tenant_id as string | undefined;
|
||||
const companyCode = userProfile?.companyCode as string | undefined;
|
||||
const isTenantContextMissing = !tenantId?.trim();
|
||||
|
||||
const {
|
||||
data,
|
||||
@@ -94,8 +93,7 @@ function ClientsPage() {
|
||||
} = useQuery({
|
||||
queryKey: ["developer-request", tenantId],
|
||||
queryFn: () => fetchDeveloperRequestStatus(tenantId),
|
||||
enabled:
|
||||
hasAccessToken && profileRole === "user" && !isTenantContextMissing,
|
||||
enabled: hasAccessToken && profileRole === "user",
|
||||
});
|
||||
const { data: tenants } = useQuery({
|
||||
queryKey: ["myTenants"],
|
||||
@@ -110,9 +108,7 @@ function ClientsPage() {
|
||||
const canCreateClient = createAccessState === "can_create";
|
||||
const isDeveloperRequestPending = createAccessState === "pending";
|
||||
const canRequestDeveloperAccess =
|
||||
createAccessState === "request_required" &&
|
||||
!isLoadingRequest &&
|
||||
!isTenantContextMissing;
|
||||
createAccessState === "request_required" && !isLoadingRequest;
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [typeFilter, setTypeFilter] = useState("all");
|
||||
@@ -233,20 +229,7 @@ function ClientsPage() {
|
||||
"OIDC 클라이언트, 인증 방식, 리다이렉트 URI, 비밀키 재발행을 감사 로그와 함께 관리합니다.",
|
||||
)}
|
||||
actions={
|
||||
isTenantContextMissing ? (
|
||||
<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_requires_tenant",
|
||||
"개발자 권한을 신청하려면 먼저 테넌트에 소속되어 있어야 합니다.",
|
||||
)}
|
||||
</p>
|
||||
<Button type="button" variant="outline" size="sm" disabled>
|
||||
<Plus className="h-4 w-4" />
|
||||
{t("ui.dev.welcome.btn_request", "개발자 권한 신청")}
|
||||
</Button>
|
||||
</div>
|
||||
) : canCreateClient ? (
|
||||
canCreateClient ? (
|
||||
<Button
|
||||
size="sm"
|
||||
className="mt-1 shadow-lg shadow-primary/30"
|
||||
@@ -470,11 +453,6 @@ function ClientsPage() {
|
||||
"msg.dev.clients.empty_filtered",
|
||||
"조건에 맞는 연동 앱이 없습니다.",
|
||||
)
|
||||
: isTenantContextMissing
|
||||
? t(
|
||||
"msg.dev.clients.empty_tenant_missing",
|
||||
"개발자 권한을 신청하려면 먼저 테넌트에 소속되어 있어야 합니다.",
|
||||
)
|
||||
: canCreateClient
|
||||
? t(
|
||||
"msg.dev.clients.empty_can_create",
|
||||
@@ -497,11 +475,6 @@ function ClientsPage() {
|
||||
"msg.dev.clients.empty_filtered_detail",
|
||||
"검색어나 필터 조건을 변경해 보세요.",
|
||||
)
|
||||
: isTenantContextMissing
|
||||
? t(
|
||||
"msg.dev.clients.empty_tenant_missing_detail",
|
||||
"현재 계정은 테넌트와 연결되어 있지 않아 개발자 권한을 신청할 수 없습니다.",
|
||||
)
|
||||
: canCreateClient
|
||||
? t(
|
||||
"msg.dev.clients.empty_can_create_detail",
|
||||
@@ -526,18 +499,6 @@ function ClientsPage() {
|
||||
{t("ui.dev.clients.new", "연동 앱 추가")}
|
||||
</button>
|
||||
)}
|
||||
{!isFilteredOut && isTenantContextMissing && (
|
||||
<button
|
||||
type="button"
|
||||
className="font-bold text-muted-foreground"
|
||||
disabled
|
||||
>
|
||||
{t(
|
||||
"ui.dev.welcome.btn_request",
|
||||
"개발자 등록 신청하기",
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
{!isFilteredOut && canRequestDeveloperAccess && (
|
||||
<button
|
||||
type="button"
|
||||
@@ -711,7 +672,6 @@ function RequestAccessModal({
|
||||
const [name, setName] = useState(initialName);
|
||||
const [organization, setOrganization] = useState(initialOrg);
|
||||
const [reason, setReason] = useState("");
|
||||
const isTenantContextMissing = !tenantId.trim();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
@@ -728,15 +688,6 @@ function RequestAccessModal({
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (isTenantContextMissing) {
|
||||
alert(
|
||||
t(
|
||||
"msg.dev.clients.create_requires_tenant",
|
||||
"개발자 권한을 신청하려면 먼저 테넌트에 소속되어 있어야 합니다.",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
mutation.mutate({
|
||||
name,
|
||||
organization,
|
||||
|
||||
Reference in New Issue
Block a user