From b9232687b529c48d1a88ae9d94ad15ee402b23dd Mon Sep 17 00:00:00 2001 From: kyy Date: Fri, 24 Apr 2026 17:18:47 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8A=A4=EC=BD=94=ED=94=84=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EB=B0=8F=20=ED=85=8C=EB=84=8C=ED=8A=B8=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/clients/ClientGeneralPage.tsx | 53 ++++++++++++------- devfront/src/lib/devApi.ts | 7 +-- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/devfront/src/features/clients/ClientGeneralPage.tsx b/devfront/src/features/clients/ClientGeneralPage.tsx index b20cfb80..a2b384ee 100644 --- a/devfront/src/features/clients/ClientGeneralPage.tsx +++ b/devfront/src/features/clients/ClientGeneralPage.tsx @@ -34,7 +34,7 @@ import { createClient, deleteClient, fetchClient, - fetchTenants, + fetchMyTenants, refreshHeadlessJwksCache, revokeHeadlessJwksCache, updateClient, @@ -44,6 +44,7 @@ import type { ClientStatus, ClientType, ClientUpsertRequest, + MyTenantSummary, TenantSummary, } from "../../lib/devApi"; import { t } from "../../lib/i18n"; @@ -138,8 +139,8 @@ function ClientGeneralPage() { enabled: !isCreate, }); const { data: tenantData } = useQuery({ - queryKey: ["tenants"], - queryFn: () => fetchTenants(1000, 0), + queryKey: ["my-tenants"], + queryFn: fetchMyTenants, }); const [name, setName] = useState(""); @@ -172,18 +173,6 @@ function ClientGeneralPage() { }, { id: "2", - name: "profile", - description: t("msg.dev.clients.scopes.profile", "기본 프로필 정보 접근"), - mandatory: false, - }, - { - id: "3", - name: "email", - description: t("msg.dev.clients.scopes.email", "이메일 주소 접근"), - mandatory: false, - }, - { - id: "4", name: "tenant", description: t( "msg.dev.clients.scopes.tenant", @@ -191,6 +180,18 @@ function ClientGeneralPage() { ), mandatory: false, }, + { + id: "3", + name: "profile", + description: t("msg.dev.clients.scopes.profile", "기본 프로필 정보 접근"), + mandatory: false, + }, + { + id: "4", + name: "email", + description: t("msg.dev.clients.scopes.email", "이메일 주소 접근"), + mandatory: false, + }, ]); useEffect(() => { @@ -355,7 +356,18 @@ function ClientGeneralPage() { normalized.push(buildTenantScope(`tenant-${Date.now()}`)); } - return normalized; + const openidScopes = normalized.filter( + (scope) => scope.name.trim() === "openid", + ); + const tenantScopes = normalized.filter( + (scope) => scope.name.trim() === "tenant", + ); + const remainingScopes = normalized.filter((scope) => { + const name = scope.name.trim(); + return name !== "openid" && name !== "tenant"; + }); + + return [...openidScopes, ...tenantScopes, ...remainingScopes]; } const handleTenantAccessToggle = (enabled: boolean) => { @@ -514,12 +526,13 @@ function ClientGeneralPage() { const hasValidationErrors = validationErrors.length > 0; const normalizedTenantSearch = tenantSearch.trim().toLowerCase(); - const tenantOptions: TenantSummary[] = tenantData?.items ?? []; + const tenantOptions: Array = tenantData ?? []; const filteredTenants = tenantOptions.filter((tenant) => { if (!normalizedTenantSearch) { return true; } - const searchable = `${tenant.name} ${tenant.slug} ${tenant.description} ${tenant.type}`.toLowerCase(); + const searchable = + `${tenant.name} ${tenant.slug} ${tenant.description ?? ""} ${tenant.type ?? ""}`.toLowerCase(); return searchable.includes(normalizedTenantSearch); }); const tenantSuggestions = filteredTenants @@ -527,7 +540,9 @@ function ClientGeneralPage() { .slice(0, 8); const selectedAllowedTenants = allowedTenantIds .map((tenantId) => tenantOptions.find((item) => item.id === tenantId)) - .filter((tenant): tenant is TenantSummary => tenant != null); + .filter( + (tenant): tenant is TenantSummary | MyTenantSummary => tenant != null, + ); const refreshHeadlessJwksCacheMutation = useMutation({ mutationFn: async () => { diff --git a/devfront/src/lib/devApi.ts b/devfront/src/lib/devApi.ts index c31cba26..0a6574f2 100644 --- a/devfront/src/lib/devApi.ts +++ b/devfront/src/lib/devApi.ts @@ -409,11 +409,8 @@ export async function fetchDevAuditLogs( return data; } -export type MyTenantSummary = { - id: string; - name: string; - slug: string; -}; +export type MyTenantSummary = Pick & + Partial; export async function fetchMyTenants() { const { data } = await apiClient.get("/dev/my-tenants");