1
0
forked from baron/baron-sso

tenants 레지스트리 가독성/로케일 적용

This commit is contained in:
2026-06-04 15:15:05 +09:00
parent 47d2f15283
commit f6c7cb3b22
6 changed files with 138 additions and 38 deletions

View File

@@ -69,7 +69,6 @@ import {
SelectTrigger,
SelectValue,
} from "../../../components/ui/select";
import { Switch } from "../../../components/ui/switch";
import {
Table,
TableBody,
@@ -80,7 +79,6 @@ import {
} from "../../../components/ui/table";
import { Tabs, TabsList, TabsTrigger } from "../../../components/ui/tabs";
import { toast } from "../../../components/ui/use-toast";
import type { UserProfileResponse } from "../../../lib/adminApi";
import {
deleteTenantsBulk,
exportTenantsCSV,
@@ -142,6 +140,51 @@ const getTenantIcon = (type?: string) => {
}
};
function getTenantTypeLabel(type?: string) {
if (!type) return "-";
return t(`domain.tenant_type.${type.toLowerCase()}`, type);
}
function getTenantTypeTextClass(type?: string) {
switch (type?.toUpperCase()) {
case "COMPANY_GROUP":
return "text-sky-700";
case "COMPANY":
return "text-violet-700";
case "ORGANIZATION":
return "text-emerald-700";
case "USER_GROUP":
return "text-amber-700";
case "PERSONAL":
return "text-slate-700";
default:
return "text-muted-foreground";
}
}
function buildTenantParentPathMap(tenants: TenantSummary[]) {
const tenantById = new Map(tenants.map((tenant) => [tenant.id, tenant]));
const pathMap = new Map<string, string[]>();
for (const tenant of tenants) {
const names: string[] = [];
const visited = new Set<string>();
let currentParentId = tenant.parentId;
while (currentParentId && !visited.has(currentParentId)) {
visited.add(currentParentId);
const parent = tenantById.get(currentParentId);
if (!parent) break;
names.unshift(parent.name);
currentParentId = parent.parentId;
}
pathMap.set(tenant.id, names);
}
return pathMap;
}
const noImportParentRef = "__none__";
function tenantParentRef(tenantId: string) {
@@ -339,19 +382,6 @@ function TenantListPage() {
},
});
const statusMutation = useMutation({
mutationFn: ({ tenantId, status }: { tenantId: string; status: string }) =>
updateTenant(tenantId, { status }),
onSuccess: () => {
query.refetch();
},
onError: () => {
toast.error(
t("msg.admin.tenants.status_error", "테넌트 상태 변경에 실패했습니다."),
);
},
});
const bulkUpdateStatusMutation = useMutation({
mutationFn: async ({
tenantIds,
@@ -935,8 +965,6 @@ function TenantListPage() {
onSelectAll={handleSelectAll}
search={search}
deletableTenants={deletableTenants}
statusMutation={statusMutation}
profile={profile}
sortConfig={sortConfig}
requestSort={requestSort}
getSortIcon={getSortIcon}
@@ -1513,13 +1541,6 @@ const TenantHierarchyView: React.FC<{
onSelectAll: (checked: boolean) => void;
search: string;
deletableTenants: TenantSummary[];
statusMutation: UseMutationResult<
TenantSummary,
Error,
{ tenantId: string; status: string },
unknown
>;
profile: UserProfileResponse | undefined;
sortConfig: SortConfig<TenantSortKey> | null;
requestSort: (key: TenantSortKey) => void;
getSortIcon: (key: TenantSortKey) => React.ReactNode;
@@ -1536,8 +1557,6 @@ const TenantHierarchyView: React.FC<{
onSelectAll,
search,
deletableTenants,
statusMutation,
profile,
sortConfig,
requestSort,
getSortIcon,
@@ -1558,6 +1577,10 @@ const TenantHierarchyView: React.FC<{
() => buildTenantFullTree(tenants, scopeTenantId || undefined, !!search),
[scopeTenantId, tenants, search],
);
const tenantParentPathMap = React.useMemo(
() => buildTenantParentPathMap(tenants),
[tenants],
);
// Initial expanded state: everything open
const [expandedIds, setExpandedIds] = React.useState<Set<string>>(() => {
@@ -1682,6 +1705,22 @@ const TenantHierarchyView: React.FC<{
const visibleSelectedCount = selectedIds.filter((id) =>
visibleSelectableIds.has(id),
).length;
const normalizedSearch = search.trim();
const emptyMessage = React.useMemo(() => {
if (normalizedSearch) {
return t(
"msg.admin.tenants.empty_search",
"검색 조건에 맞는 테넌트가 없습니다.",
);
}
if (scopeTenantId) {
return t(
"msg.admin.tenants.empty_scope",
"선택한 범위에 표시할 하위 테넌트가 없습니다.",
);
}
return t("msg.admin.tenants.empty", "아직 등록된 테넌트가 없습니다.");
}, [normalizedSearch, scopeTenantId]);
const renderRow = (
node: TenantViewRow,
@@ -1923,10 +1962,7 @@ const TenantHierarchyView: React.FC<{
colSpan={8}
className="py-8 text-center text-muted-foreground"
>
{t(
"msg.admin.tenants.empty",
"아직 등록된 테넌트가 없습니다.",
)}
{emptyMessage}
</TableCell>
</TableRow>
)}

View File

@@ -1071,6 +1071,7 @@ user = "General User (Tenant Member)"
[ui.admin.tenants]
add = "Add Tenant"
csv_template = "Template"
data_mgmt = "Data Management"
delete_selected = "Delete Selected"
export_with_ids = "Include UUIDs"
export_without_ids = "Export without UUIDs"
@@ -1267,6 +1268,15 @@ name = "NAME"
slug = "SLUG"
status = "STATUS"
[ui.admin.tenants.view]
list = "List"
table = "Table"
tree = "Tree"
[ui.admin.tenants.scope]
active = "{{name}} descendants"
pick = "Select parent scope"
[ui.admin.tenants.table]
actions = "ACTIONS"
id = "ID"

View File

@@ -1074,6 +1074,7 @@ user = "일반 사용자 (Tenant Member)"
[ui.admin.tenants]
add = "테넌트 추가"
csv_template = "템플릿"
data_mgmt = "데이터 관리"
delete_selected = "선택 삭제"
export_with_ids = "UUID 포함"
export_without_ids = "UUID 제외 내보내기"
@@ -1270,15 +1271,24 @@ name = "NAME"
slug = "SLUG"
status = "STATUS"
[ui.admin.tenants.view]
list = "평면 목록"
table = "평면"
tree = "트리"
[ui.admin.tenants.scope]
active = "{{name}} 하위"
pick = "상위 범위 선택"
[ui.admin.tenants.table]
actions = "ACTIONS"
id = "ID"
members = "멤버수"
name = "NAME"
slug = "SLUG"
status = "STATUS"
name = "이름"
slug = "슬러그"
status = "상태"
type = "유형"
updated = "UPDATED"
updated = "수정일"
[ui.admin.users]
csv_template = "템플릿 다운로드"

View File

@@ -264,6 +264,15 @@ subtitle = "List of owners with top-level permissions for this tenant."
[msg.admin.tenants.registry]
count = "{{count}} tenants loaded."
scope_results = "{{count}} tenants under {{name}}"
scope_search_results = "{{count}} search results under {{name}}"
search_results = "{{count}} search results"
table_hint = "Compare IDs, status, and size quickly in the sortable flat list."
tree_hint = "Review parent-child relationships and subtree coverage in the hierarchy."
[msg.admin.tenants]
empty_scope = "There are no child tenants to display in the selected scope."
empty_search = "No tenants match the current search."
[msg.admin.tenants.schema]
empty = "No custom fields defined. Click \\\\\\\"Add Field\\\\\\\" to begin."
@@ -1157,6 +1166,7 @@ user = "TENANT MEMBER"
[ui.admin.tenants]
add = "Add Tenant"
csv_template = "Template"
data_mgmt = "Data Management"
delete_selected = "Delete Selected"
export_with_ids = "Include UUIDs"
export_without_ids = "Export without UUIDs"
@@ -1441,9 +1451,14 @@ status = "STATUS"
[ui.admin.tenants.table]
actions = "ACTIONS"
context = "Parent Path"
id = "ID"
id_copy = "Copy ID"
members = "Members"
members_count = "{{count}} members"
members_recursive = "including descendants"
name = "NAME"
root = "Top Level"
slug = "SLUG"
status = "STATUS"
type = "TYPE"

View File

@@ -765,6 +765,15 @@ subtitle = "이 테넌트의 최상위 권한을 가진 소유자(조직장) 목
[msg.admin.tenants.registry]
count = "총 {{count}}개 테넌트"
scope_results = "{{name}} 하위 {{count}}개"
scope_search_results = "{{name}} 하위 검색 결과 {{count}}개"
search_results = "검색 결과 {{count}}개"
table_hint = "정렬 가능한 평면 목록에서 ID, 상태, 규모를 빠르게 비교합니다."
tree_hint = "계층 구조를 따라 부모-자식 관계와 하위 범위를 함께 확인합니다."
[msg.admin.tenants]
empty_scope = "선택한 범위에 표시할 하위 테넌트가 없습니다."
empty_search = "검색 조건에 맞는 테넌트가 없습니다."
[msg.admin.tenants.schema]
empty = "등록된 커스텀 필드가 없습니다. 필드 추가를 눌러 시작하세요."
@@ -1652,6 +1661,7 @@ user = "TENANT MEMBER"
[ui.admin.tenants]
add = "테넌트 추가"
data_mgmt = "데이터 관리"
delete_selected = "선택 삭제"
seed_badge = "초기 설정"
title = "테넌트 목록"
@@ -1904,13 +1914,18 @@ status = "STATUS"
[ui.admin.tenants.table]
actions = "ACTIONS"
context = "상위 경로"
id = "ID"
id_copy = "ID 복사"
members = "멤버수"
name = "NAME"
slug = "SLUG"
status = "STATUS"
members_count = "{{count}}명"
members_recursive = "하위 포함"
name = "이름"
root = "최상위"
slug = "슬러그"
status = "상태"
type = "유형"
updated = "UPDATED"
updated = "수정일"
created = "CREATED"
created = "CREATED"

View File

@@ -622,6 +622,15 @@ subtitle = ""
[msg.admin.tenants.registry]
count = ""
scope_results = ""
scope_search_results = ""
search_results = ""
table_hint = ""
tree_hint = ""
[msg.admin.tenants]
empty_scope = ""
empty_search = ""
[msg.admin.tenants.schema]
empty = ""
@@ -1781,9 +1790,14 @@ status = ""
[ui.admin.tenants.table]
actions = ""
context = ""
id = ""
id_copy = ""
members = ""
members_count = ""
members_recursive = ""
name = ""
root = ""
slug = ""
status = ""
type = ""