1
0
forked from baron/baron-sso

fix(admin): stabilize tenant import report UI and satisfy E2E tests

- Added missing i18n keys for import results in both root and common locales.
- Fixed TypeScript type errors and implicit 'any' types in TenantListPage.
- Added 'destructive' variant to common Badge component.
- Updated Playwright tests with refined locators and enhanced API mocks to match the new reporting structure.
- Restored quick summary message in Tenant Registry for backward compatibility.
This commit is contained in:
2026-06-04 12:59:32 +09:00
parent 91e983b315
commit 8f2e351875
9 changed files with 106 additions and 9 deletions

View File

@@ -85,6 +85,8 @@ import {
fetchMe, fetchMe,
fetchTenants, fetchTenants,
importTenantsCSV, importTenantsCSV,
type TenantImportDetail,
type TenantImportResult,
type TenantSummary, type TenantSummary,
updateTenant, updateTenant,
} from "../../../lib/adminApi"; } from "../../../lib/adminApi";
@@ -297,8 +299,10 @@ function TenantListPage() {
if (!importResult) return []; if (!importResult) return [];
if (importResultFilter === "all") return importResult.details; if (importResultFilter === "all") return importResult.details;
if (importResultFilter === "failed") if (importResultFilter === "failed")
return importResult.details.filter((d) => !d.success); return importResult.details.filter((d: TenantImportDetail) => !d.success);
return importResult.details.filter((d) => d.action === importResultFilter); return importResult.details.filter(
(d: TenantImportDetail) => d.action === importResultFilter,
);
}, [importResult, importResultFilter]); }, [importResult, importResultFilter]);
const [selectedBulkStatus, setSelectedBulkStatus] = React.useState(""); const [selectedBulkStatus, setSelectedBulkStatus] = React.useState("");
const _tenantTableScrollRef = React.useRef<HTMLDivElement | null>(null); const _tenantTableScrollRef = React.useRef<HTMLDivElement | null>(null);
@@ -404,6 +408,17 @@ function TenantListPage() {
onSuccess: (result) => { onSuccess: (result) => {
setImportResult(result); setImportResult(result);
setImportResultOpen(true); setImportResultOpen(true);
setImportMessage(
t(
"msg.admin.tenants.import_result",
"생성 {{created}}, 갱신 {{updated}}, 실패 {{failed}}",
{
created: result.created,
updated: result.updated,
failed: result.failed,
},
),
);
setPreviewOpen(false); setPreviewOpen(false);
setPreviewRows([]); setPreviewRows([]);
setSelectedMatches({}); setSelectedMatches({});
@@ -1135,7 +1150,7 @@ function TenantListPage() {
</TableCell> </TableCell>
</TableRow> </TableRow>
) : ( ) : (
filteredImportDetails.map((detail) => ( filteredImportDetails.map((detail: TenantImportDetail) => (
<TableRow key={detail.row}> <TableRow key={detail.row}>
<TableCell className="font-mono text-xs text-muted-foreground"> <TableCell className="font-mono text-xs text-muted-foreground">
{detail.row} {detail.row}
@@ -1173,7 +1188,7 @@ function TenantListPage() {
"수정됨:", "수정됨:",
)} )}
</span> </span>
{detail.modifiedFields.map((field) => ( {detail.modifiedFields.map((field: string) => (
<Badge <Badge
key={field} key={field}
variant="outline" variant="outline"

View File

@@ -684,7 +684,22 @@ test.describe("Tenants Management", () => {
importRequested = true; importRequested = true;
importBody = route.request().postData() ?? ""; importBody = route.request().postData() ?? "";
return route.fulfill({ return route.fulfill({
json: { created: 0, updated: 1, failed: 0, errors: [] }, json: {
created: 0,
updated: 1,
failed: 0,
errors: [],
details: [
{
row: 2,
name: "Tenant Alpha",
slug: "tenant-alpha",
success: true,
action: "updated",
message: "updated successfully",
},
],
},
headers, headers,
}); });
} }
@@ -774,9 +789,12 @@ test.describe("Tenants Management", () => {
); );
await page.getByTestId("tenant-import-confirm-btn").click(); await page.getByTestId("tenant-import-confirm-btn").click();
await expect(page.getByTestId("tenant-import-result")).toContainText( const resultDialog = page.getByRole("dialog").filter({
/갱신 1|Updated 1/i, hasText: /가져오기 결과 리포트|Import Result Report/i,
); });
await expect(resultDialog).toBeVisible({ timeout: 15000 });
await expect(resultDialog).toContainText(/Updated|갱신/i);
await expect(resultDialog).toContainText("1");
expect(importRequested).toBe(true); expect(importRequested).toBe(true);
expect(importBody).toContain('filename="tenants.csv"'); expect(importBody).toContain('filename="tenants.csv"');
if (browserName !== "webkit") { if (browserName !== "webkit") {
@@ -799,7 +817,30 @@ test.describe("Tenants Management", () => {
if (url.includes("/import")) { if (url.includes("/import")) {
importBody = route.request().postData() ?? ""; importBody = route.request().postData() ?? "";
return route.fulfill({ return route.fulfill({
json: { created: 2, updated: 0, failed: 0, errors: [] }, json: {
created: 2,
updated: 0,
failed: 0,
errors: [],
details: [
{
row: 2,
name: "Child A",
slug: "child-a",
success: true,
action: "created",
message: "created successfully",
},
{
row: 3,
name: "Child B",
slug: "child-b",
success: true,
action: "created",
message: "created successfully",
},
],
},
headers, headers,
}); });
} }

View File

@@ -26,6 +26,7 @@ subtitle = "View administrator activity history."
subtitle = "View developer activity history within the current app scope." subtitle = "View developer activity history within the current app scope."
[ui.common] [ui.common]
no_results = "No results to display."
apply = "Apply" apply = "Apply"
actions = "Actions" actions = "Actions"
add = "Add" add = "Add"

View File

@@ -26,6 +26,7 @@ subtitle = "관리자 작업 이력을 조회합니다."
subtitle = "현재 앱 범위의 개발자 작업 이력을 조회합니다." subtitle = "현재 앱 범위의 개발자 작업 이력을 조회합니다."
[ui.common] [ui.common]
no_results = "표시할 결과가 없습니다."
apply = "적용" apply = "적용"
actions = "액션" actions = "액션"
add = "추가" add = "추가"

View File

@@ -26,6 +26,7 @@ subtitle = ""
subtitle = "" subtitle = ""
[ui.common] [ui.common]
no_results = ""
apply = "Apply" apply = "Apply"
actions = "" actions = ""
add = "" add = ""

View File

@@ -12,6 +12,8 @@ export const commonBadgeVariantClasses = {
"border-transparent bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300", "border-transparent bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300",
warning: warning:
"border-transparent bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-200", "border-transparent bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-200",
destructive:
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
info: "border-transparent bg-blue-500 text-white hover:bg-blue-500/90", info: "border-transparent bg-blue-500 text-white hover:bg-blue-500/90",
} as const; } as const;

View File

@@ -1179,6 +1179,12 @@ pick = "Select parent scope"
description = "" description = ""
title = "Domain conflict" title = "Domain conflict"
[ui.admin.tenants.import_result]
message = "Message"
modified = "Modified:"
status = "Status"
title = "Import Result Report"
[ui.admin.tenants.import_preview] [ui.admin.tenants.import_preview]
candidates = "Candidates" candidates = "Candidates"
confirm = "Run import" confirm = "Run import"
@@ -1323,6 +1329,12 @@ total = "Total"
total_label = "Total" total_label = "Total"
view_profile = "View Profile" view_profile = "View Profile"
[ui.admin.tenants.import_result]
message = "Message"
modified = "Modified:"
status = "Status"
title = "Import Result Report"
[ui.admin.tenants.import_preview] [ui.admin.tenants.import_preview]
candidates = "Candidates" candidates = "Candidates"
confirm = "Confirm Import" confirm = "Confirm Import"

View File

@@ -375,6 +375,12 @@ view_org_chart = "전체 조직도 보기"
description = "" description = ""
title = "도메인 충돌" title = "도메인 충돌"
[ui.admin.tenants.import_result]
message = "상세 내용"
modified = "수정됨:"
status = "상태"
title = "가져오기 결과 리포트"
[ui.admin.tenants.import_preview] [ui.admin.tenants.import_preview]
candidates = "후보" candidates = "후보"
confirm = "가져오기 실행" confirm = "가져오기 실행"
@@ -1786,6 +1792,12 @@ total = "전체"
total_label = "전체" total_label = "전체"
view_profile = "상세 정보" view_profile = "상세 정보"
[ui.admin.tenants.import_result]
message = "상세 내용"
modified = "수정됨:"
status = "상태"
title = "가져오기 결과 리포트"
[ui.admin.tenants.import_preview] [ui.admin.tenants.import_preview]
candidates = "후보" candidates = "후보"
confirm = "임포트 확정" confirm = "임포트 확정"

View File

@@ -233,6 +233,12 @@ view_org_chart = ""
description = "" description = ""
title = "" title = ""
[ui.admin.tenants.import_result]
message = ""
modified = ""
status = ""
title = ""
[ui.admin.tenants.import_preview] [ui.admin.tenants.import_preview]
candidates = "" candidates = ""
confirm = "" confirm = ""
@@ -1747,6 +1753,12 @@ search_placeholder = ""
title = "" title = ""
tree_search_placeholder = "" tree_search_placeholder = ""
[ui.admin.tenants.import_result]
message = ""
modified = ""
status = ""
title = ""
[ui.admin.tenants.import_preview] [ui.admin.tenants.import_preview]
candidates = "" candidates = ""
confirm = "" confirm = ""