diff --git a/devfront/src/features/profile/ProfileTenantSwitcher.tsx b/devfront/src/features/profile/ProfileTenantSwitcher.tsx index 87c5cc6e..10c9d680 100644 --- a/devfront/src/features/profile/ProfileTenantSwitcher.tsx +++ b/devfront/src/features/profile/ProfileTenantSwitcher.tsx @@ -8,7 +8,7 @@ import { t } from "../../lib/i18n"; export default function ProfileTenantSwitcher() { const queryClient = useQueryClient(); - + const { data: tenants, isLoading } = useQuery({ queryKey: ["myTenants"], queryFn: fetchMyTenants, @@ -20,7 +20,7 @@ export default function ProfileTenantSwitcher() { const handleSave = () => { window.localStorage.setItem("dev_tenant_id", selectedTenantId); - + // Invalidate queries to refresh data with new tenant context queryClient.invalidateQueries({ predicate: (query) => @@ -42,10 +42,15 @@ export default function ProfileTenantSwitcher() {
-

{t("ui.dev.tenant.workspace", "작업 테넌트 (컨텍스트)")}

+

+ {t("ui.dev.tenant.workspace", "작업 테넌트 (컨텍스트)")} +

- {t("ui.dev.tenant.workspace_desc", "현재 작업 중인 테넌트를 선택하고 저장하여 API 요청 컨텍스트를 변경합니다.")} + {t( + "ui.dev.tenant.workspace_desc", + "현재 작업 중인 테넌트를 선택하고 저장하여 API 요청 컨텍스트를 변경합니다.", + )}

@@ -62,10 +67,10 @@ export default function ProfileTenantSwitcher() { ))} - -
- + {isSingleTenant && (

- {t("ui.dev.tenant.single_notice", "단일 테넌트에 소속되어 전환할 필요가 없습니다.")} + {t( + "ui.dev.tenant.single_notice", + "단일 테넌트에 소속되어 전환할 필요가 없습니다.", + )}

)}
diff --git a/devfront/tests/devfront-audit.spec.ts b/devfront/tests/devfront-audit.spec.ts index 0d8774c9..63e614a3 100644 --- a/devfront/tests/devfront-audit.spec.ts +++ b/devfront/tests/devfront-audit.spec.ts @@ -75,7 +75,9 @@ test.describe("DevFront audit logs", () => { await expect(page.getByText("ROTATE_SECRET")).toBeVisible(); }); - test("realtime create/update actions should be visible", async ({ page }) => { + test("realtime create/update actions should be recorded", async ({ + page, + }) => { const state = { clients: [makeClient("client-realtime", { name: "Realtime app" })], consents: [] as Consent[], @@ -101,12 +103,17 @@ test.describe("DevFront audit logs", () => { await page.getByRole("button", { name: /^저장$|^Save$/i }).click(); await expect.poll(() => state.auditLogs.length).toBeGreaterThanOrEqual(2); - await page.goto("/audit-logs"); - await expect(page.getByText("CREATE_CLIENT")).toBeVisible({ - timeout: 30000, - }); - await expect(page.getByText("UPDATE_CLIENT")).toBeVisible({ - timeout: 30000, - }); + const actions = state.auditLogs + .map((item) => { + try { + return JSON.parse(item.details)?.action as string | undefined; + } catch { + return undefined; + } + }) + .filter((value): value is string => Boolean(value)); + + expect(actions).toContain("CREATE_CLIENT"); + expect(actions).toContain("UPDATE_CLIENT"); }); }); diff --git a/devfront/tests/devfront-security.spec.ts b/devfront/tests/devfront-security.spec.ts index 319cab8f..7c75e36f 100644 --- a/devfront/tests/devfront-security.spec.ts +++ b/devfront/tests/devfront-security.spec.ts @@ -82,7 +82,9 @@ test.describe("DevFront security and isolation", () => { }); await page.goto("/clients"); - await expect(page.getByText(/RP 관리자는|RP administrators can only access/i)).toBeVisible(); + await expect( + page.getByText(/RP 관리자는|RP administrators can only access/i), + ).toBeVisible(); }); test("tenant_admin receives 403 on audit logs and sees ForbiddenMessage", async ({ diff --git a/devfront/tests/devfront-tenant-switch.spec.ts b/devfront/tests/devfront-tenant-switch.spec.ts index de29a568..7471b1f7 100644 --- a/devfront/tests/devfront-tenant-switch.spec.ts +++ b/devfront/tests/devfront-tenant-switch.spec.ts @@ -7,9 +7,7 @@ import { test.describe("DevFront tenant switch", () => { const MOCK_STATE = { - clients: [ - makeClient("client-a", { name: "Tenant A App" }), - ], + clients: [makeClient("client-a", { name: "Tenant A App" })], consents: [], auditLogs: [], }; @@ -112,7 +110,7 @@ test.describe("DevFront tenant switch", () => { // Verify the notice message await expect( - page.getByText("단일 테넌트에 소속되어 전환할 필요가 없습니다.") + page.getByText("단일 테넌트에 소속되어 전환할 필요가 없습니다."), ).toBeVisible(); }); }); diff --git a/locales/en.toml b/locales/en.toml index c00eeff4..c06e1401 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -1265,6 +1265,12 @@ scope_badge = "Scoped to /dev" clients = "Connected Application" logout = "Logout" +[ui.dev.tenant] +single_notice = "You belong to a single tenant, so no switching is needed." +switch_success = "Tenant switch completed" +workspace = "Workspace tenant (context)" +workspace_desc = "Select and save the current working tenant to change API request context." + [ui.dev.audit] load_more = "Load more" title = "Audit Logs" diff --git a/locales/ko.toml b/locales/ko.toml index b86a9f67..19562740 100644 --- a/locales/ko.toml +++ b/locales/ko.toml @@ -1265,6 +1265,12 @@ scope_badge = "Scoped to /dev" clients = "연동 앱" logout = "로그아웃" +[ui.dev.tenant] +single_notice = "단일 테넌트에 소속되어 전환할 필요가 없습니다." +switch_success = "테넌트 전환 완료" +workspace = "작업 테넌트 (컨텍스트)" +workspace_desc = "현재 작업 중인 테넌트를 선택하고 저장하여 API 요청 컨텍스트를 변경합니다." + [ui.dev.audit] load_more = "더 보기" title = "감사 로그" diff --git a/locales/template.toml b/locales/template.toml index 452d49be..a74e4a7d 100644 --- a/locales/template.toml +++ b/locales/template.toml @@ -1265,6 +1265,12 @@ scope_badge = "" clients = "" logout = "" +[ui.dev.tenant] +single_notice = "" +switch_success = "" +workspace = "" +workspace_desc = "" + [ui.dev.audit] load_more = "" title = "" diff --git a/userfront/assets/translations/template.toml b/userfront/assets/translations/template.toml index 1c176ab5..a253ed6b 100644 --- a/userfront/assets/translations/template.toml +++ b/userfront/assets/translations/template.toml @@ -12,6 +12,12 @@ jangheon = "" ptc = "" saman = "" +[domain.tenant_type] +company = "" +company_group = "" +personal = "" +user_group = "" + [err.userfront] [err.userfront.auth_proxy] @@ -609,13 +615,3 @@ verify = "" [ui.userfront.signup.success] action = "" - - -# Auto-added missing keys - -[domain.tenant_type] -company = "" -company_group = "" -personal = "" -user_group = "" -