1
0
forked from baron/baron-sso

린트 적용

This commit is contained in:
2026-02-23 16:18:01 +09:00
parent 04938d7cd9
commit 68becb43bc
36 changed files with 1240 additions and 1057 deletions

View File

@@ -43,9 +43,15 @@ import {
import { t } from "../../../lib/i18n";
import { toast } from "sonner";
type UserGroupNode = GroupSummary & { children: UserGroupNode[]; isExpanded?: boolean };
type UserGroupNode = GroupSummary & {
children: UserGroupNode[];
isExpanded?: boolean;
};
function buildGroupTree(groups: GroupSummary[], parentId: string | null = null): UserGroupNode[] {
function buildGroupTree(
groups: GroupSummary[],
parentId: string | null = null,
): UserGroupNode[] {
const nodes: UserGroupNode[] = [];
const childrenOf = new Map<string, UserGroupNode[]>();
@@ -56,7 +62,10 @@ function buildGroupTree(groups: GroupSummary[], parentId: string | null = null):
// Second pass: Populate children
groups.forEach((group) => {
const node: UserGroupNode = { ...group, children: childrenOf.get(group.id)! };
const node: UserGroupNode = {
...group,
children: childrenOf.get(group.id)!,
};
if (group.parentId === parentId) {
nodes.push(node);
} else {
@@ -73,7 +82,7 @@ function buildGroupTree(groups: GroupSummary[], parentId: string | null = null):
// Sort children for consistent rendering (optional, but good for UI)
nodes.sort((a, b) => a.name.localeCompare(b.name));
nodes.forEach(node => {
nodes.forEach((node) => {
node.children.sort((a, b) => a.name.localeCompare(b.name));
});
@@ -130,11 +139,16 @@ const UserGroupTreeNode: React.FC<UserGroupTreeNodeProps> = ({
<ChevronRight size={16} />
)}
</Button>
) : (level > 0 && (
) : (
level > 0 && (
<span className="inline-block w-6 text-center">
<ChevronRight size={16} className="text-muted-foreground inline-block align-middle" />
<ChevronRight
size={16}
className="text-muted-foreground inline-block align-middle"
/>
</span>
))}
)
)}
<Users size={14} className="text-muted-foreground" />
<span className="font-semibold">{node.name}</span>
<Badge variant="secondary" className="text-[10px] font-mono">
@@ -221,7 +235,12 @@ function TenantGroupsPage() {
parentId: newGroupParentId || undefined,
}),
onSuccess: () => {
toast.success(t("msg.admin.groups.list.create_success", "그룹이 성공적으로 생성되었습니다."));
toast.success(
t(
"msg.admin.groups.list.create_success",
"그룹이 성공적으로 생성되었습니다.",
),
);
groupsQuery.refetch();
setNewGroupName("");
setNewGroupNameDesc("");
@@ -229,21 +248,27 @@ function TenantGroupsPage() {
setNewGroupParentId(null);
},
onError: (error: AxiosError<{ error?: string }>) => {
toast.error(t("msg.admin.groups.list.create_error", "그룹 생성 실패"), { description: error.response?.data?.error || error.message });
}
toast.error(t("msg.admin.groups.list.create_error", "그룹 생성 실패"), {
description: error.response?.data?.error || error.message,
});
},
});
// 그룹 삭제
const deleteMutation = useMutation({
mutationFn: (id: string) => deleteGroup(tenantId, id),
onSuccess: () => {
toast.success(t("msg.admin.groups.list.delete_success", "그룹이 삭제되었습니다."));
toast.success(
t("msg.admin.groups.list.delete_success", "그룹이 삭제되었습니다."),
);
groupsQuery.refetch();
setSelectedGroupId(null);
},
onError: (error: AxiosError<{ error?: string }>) => {
toast.error(t("msg.admin.groups.list.delete_error", "그룹 삭제 실패"), { description: error.response?.data?.error || error.message });
}
toast.error(t("msg.admin.groups.list.delete_error", "그룹 삭제 실패"), {
description: error.response?.data?.error || error.message,
});
},
});
// 멤버 추가
@@ -251,12 +276,16 @@ function TenantGroupsPage() {
mutationFn: ({ groupId, userId }: { groupId: string; userId: string }) =>
addGroupMember(tenantId, groupId, userId),
onSuccess: () => {
toast.success(t("msg.admin.groups.members.add_success", "멤버가 추가되었습니다."));
toast.success(
t("msg.admin.groups.members.add_success", "멤버가 추가되었습니다."),
);
groupsQuery.refetch();
},
onError: (error: AxiosError<{ error?: string }>) => {
toast.error(t("msg.common.error", "오류 발생"), { description: error.response?.data?.error || error.message });
}
toast.error(t("msg.common.error", "오류 발생"), {
description: error.response?.data?.error || error.message,
});
},
});
// 멤버 제거
@@ -264,15 +293,21 @@ function TenantGroupsPage() {
mutationFn: ({ groupId, userId }: { groupId: string; userId: string }) =>
removeGroupMember(tenantId, groupId, userId),
onSuccess: () => {
toast.success(t("msg.admin.groups.members.remove_success", "멤버가 제거되었습니다."));
toast.success(
t("msg.admin.groups.members.remove_success", "멤버가 제거되었습니다."),
);
groupsQuery.refetch();
},
onError: (error: AxiosError<{ error?: string }>) => {
toast.error(t("msg.common.error", "오류 발생"), { description: error.response?.data?.error || error.message });
}
toast.error(t("msg.common.error", "오류 발생"), {
description: error.response?.data?.error || error.message,
});
},
});
const groupTree = groupsQuery.data ? buildGroupTree(groupsQuery.data, tenantId) : [];
const groupTree = groupsQuery.data
? buildGroupTree(groupsQuery.data, tenantId)
: [];
const handleAddSubGroup = (parentId: string) => {
setNewGroupParentId(parentId);
@@ -304,7 +339,10 @@ function TenantGroupsPage() {
{t("ui.admin.groups.create.title", "새 그룹 생성")}
</CardTitle>
<CardDescription>
{t("ui.admin.groups.create.description", "새로운 사용자 그룹을 생성하고 계층 구조를 설정합니다.")}
{t(
"ui.admin.groups.create.description",
"새로운 사용자 그룹을 생성하고 계층 구조를 설정합니다.",
)}
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
@@ -425,8 +463,14 @@ function TenantGroupsPage() {
)}
{!groupsQuery.isLoading && groupTree.length === 0 && (
<TableRow>
<TableCell colSpan={3} className="text-center py-8 text-muted-foreground">
{t("msg.admin.groups.list.empty", "아직 등록된 그룹이 없습니다.")}
<TableCell
colSpan={3}
className="text-center py-8 text-muted-foreground"
>
{t(
"msg.admin.groups.list.empty",
"아직 등록된 그룹이 없습니다.",
)}
</TableCell>
</TableRow>
)}
@@ -438,9 +482,16 @@ function TenantGroupsPage() {
onSelect={setSelectedGroupId}
selectedGroupId={selectedGroupId}
onDelete={(id) => {
if (window.confirm(t("msg.admin.groups.list.delete_confirm", "그룹을 삭제하시겠습니까?"))) {
deleteMutation.mutate(id);
}
if (
window.confirm(
t(
"msg.admin.groups.list.delete_confirm",
"그룹을 삭제하시겠습니까?",
),
)
) {
deleteMutation.mutate(id);
}
}}
onAddSubGroup={handleAddSubGroup}
addMemberMutation={addMemberMutation}
@@ -464,15 +515,22 @@ function TenantGroupsPage() {
})}
</CardTitle>
<CardDescription>
{t("ui.admin.groups.detail.members_subtitle", "그룹에 속한 멤버들을 확인하고 관리합니다.")}
{t(
"ui.admin.groups.detail.members_subtitle",
"그룹에 속한 멤버들을 확인하고 관리합니다.",
)}
</CardDescription>
</CardHeader>
<CardContent>
<div className="flex justify-end mb-4">
<Button size="sm" onClick={() => handleAddMember(currentGroup.id)} disabled={addMemberMutation.isPending}>
<UserPlus size={14} className="mr-1" />
{t("ui.common.add", "멤버 추가")}
</Button>
<Button
size="sm"
onClick={() => handleAddMember(currentGroup.id)}
disabled={addMemberMutation.isPending}
>
<UserPlus size={14} className="mr-1" />
{t("ui.common.add", "멤버 추가")}
</Button>
</div>
<Table>
<TableHeader>