forked from baron/baron-sso
tenants 레지스트리 가독성/로케일 적용
This commit is contained in:
@@ -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>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user