diff --git a/adminfront/src/features/tenants/routes/TenantListPage.tsx b/adminfront/src/features/tenants/routes/TenantListPage.tsx index 06c2fa73..88151c11 100644 --- a/adminfront/src/features/tenants/routes/TenantListPage.tsx +++ b/adminfront/src/features/tenants/routes/TenantListPage.tsx @@ -85,6 +85,8 @@ import { fetchMe, fetchTenants, importTenantsCSV, + type TenantImportDetail, + type TenantImportResult, type TenantSummary, updateTenant, } from "../../../lib/adminApi"; @@ -297,8 +299,10 @@ function TenantListPage() { if (!importResult) return []; if (importResultFilter === "all") return importResult.details; if (importResultFilter === "failed") - return importResult.details.filter((d) => !d.success); - return importResult.details.filter((d) => d.action === importResultFilter); + return importResult.details.filter((d: TenantImportDetail) => !d.success); + return importResult.details.filter( + (d: TenantImportDetail) => d.action === importResultFilter, + ); }, [importResult, importResultFilter]); const [selectedBulkStatus, setSelectedBulkStatus] = React.useState(""); const _tenantTableScrollRef = React.useRef(null); @@ -404,6 +408,17 @@ function TenantListPage() { onSuccess: (result) => { setImportResult(result); setImportResultOpen(true); + setImportMessage( + t( + "msg.admin.tenants.import_result", + "생성 {{created}}, 갱신 {{updated}}, 실패 {{failed}}", + { + created: result.created, + updated: result.updated, + failed: result.failed, + }, + ), + ); setPreviewOpen(false); setPreviewRows([]); setSelectedMatches({}); @@ -1135,7 +1150,7 @@ function TenantListPage() { ) : ( - filteredImportDetails.map((detail) => ( + filteredImportDetails.map((detail: TenantImportDetail) => ( {detail.row} @@ -1173,7 +1188,7 @@ function TenantListPage() { "수정됨:", )} - {detail.modifiedFields.map((field) => ( + {detail.modifiedFields.map((field: string) => ( { importRequested = true; importBody = route.request().postData() ?? ""; 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, }); } @@ -774,9 +789,12 @@ test.describe("Tenants Management", () => { ); await page.getByTestId("tenant-import-confirm-btn").click(); - await expect(page.getByTestId("tenant-import-result")).toContainText( - /갱신 1|Updated 1/i, - ); + const resultDialog = page.getByRole("dialog").filter({ + 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(importBody).toContain('filename="tenants.csv"'); if (browserName !== "webkit") { @@ -799,7 +817,30 @@ test.describe("Tenants Management", () => { if (url.includes("/import")) { importBody = route.request().postData() ?? ""; 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, }); } diff --git a/common/locales/en.toml b/common/locales/en.toml index a9a3a9d3..8b6d9b81 100644 --- a/common/locales/en.toml +++ b/common/locales/en.toml @@ -26,6 +26,7 @@ subtitle = "View administrator activity history." subtitle = "View developer activity history within the current app scope." [ui.common] +no_results = "No results to display." apply = "Apply" actions = "Actions" add = "Add" diff --git a/common/locales/ko.toml b/common/locales/ko.toml index 9efc4959..57ba4cdb 100644 --- a/common/locales/ko.toml +++ b/common/locales/ko.toml @@ -26,6 +26,7 @@ subtitle = "관리자 작업 이력을 조회합니다." subtitle = "현재 앱 범위의 개발자 작업 이력을 조회합니다." [ui.common] +no_results = "표시할 결과가 없습니다." apply = "적용" actions = "액션" add = "추가" diff --git a/common/locales/template.toml b/common/locales/template.toml index c07c1054..9e536ab3 100644 --- a/common/locales/template.toml +++ b/common/locales/template.toml @@ -26,6 +26,7 @@ subtitle = "" subtitle = "" [ui.common] +no_results = "" apply = "Apply" actions = "" add = "" diff --git a/common/ui/badge.ts b/common/ui/badge.ts index 8d2b7db5..36f069d8 100644 --- a/common/ui/badge.ts +++ b/common/ui/badge.ts @@ -12,6 +12,8 @@ export const commonBadgeVariantClasses = { "border-transparent bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300", warning: "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", } as const; diff --git a/locales/en.toml b/locales/en.toml index dde44f75..6c33882b 100644 --- a/locales/en.toml +++ b/locales/en.toml @@ -1179,6 +1179,12 @@ pick = "Select parent scope" description = "" title = "Domain conflict" +[ui.admin.tenants.import_result] +message = "Message" +modified = "Modified:" +status = "Status" +title = "Import Result Report" + [ui.admin.tenants.import_preview] candidates = "Candidates" confirm = "Run import" @@ -1323,6 +1329,12 @@ total = "Total" total_label = "Total" view_profile = "View Profile" +[ui.admin.tenants.import_result] +message = "Message" +modified = "Modified:" +status = "Status" +title = "Import Result Report" + [ui.admin.tenants.import_preview] candidates = "Candidates" confirm = "Confirm Import" diff --git a/locales/ko.toml b/locales/ko.toml index e99be6df..f2655ee2 100644 --- a/locales/ko.toml +++ b/locales/ko.toml @@ -375,6 +375,12 @@ view_org_chart = "전체 조직도 보기" description = "" title = "도메인 충돌" +[ui.admin.tenants.import_result] +message = "상세 내용" +modified = "수정됨:" +status = "상태" +title = "가져오기 결과 리포트" + [ui.admin.tenants.import_preview] candidates = "후보" confirm = "가져오기 실행" @@ -1786,6 +1792,12 @@ total = "전체" total_label = "전체" view_profile = "상세 정보" +[ui.admin.tenants.import_result] +message = "상세 내용" +modified = "수정됨:" +status = "상태" +title = "가져오기 결과 리포트" + [ui.admin.tenants.import_preview] candidates = "후보" confirm = "임포트 확정" diff --git a/locales/template.toml b/locales/template.toml index bd9cf3f9..eac89aca 100644 --- a/locales/template.toml +++ b/locales/template.toml @@ -233,6 +233,12 @@ view_org_chart = "" description = "" title = "" +[ui.admin.tenants.import_result] +message = "" +modified = "" +status = "" +title = "" + [ui.admin.tenants.import_preview] candidates = "" confirm = "" @@ -1747,6 +1753,12 @@ search_placeholder = "" title = "" tree_search_placeholder = "" +[ui.admin.tenants.import_result] +message = "" +modified = "" +status = "" +title = "" + [ui.admin.tenants.import_preview] candidates = "" confirm = ""