From a31eceaf1665c5a32004fb130397d8b44d1824e6 Mon Sep 17 00:00:00 2001 From: chan Date: Wed, 13 May 2026 14:50:11 +0900 Subject: [PATCH 1/3] feat(adminfront): implement user role management and cleanup tenant list UI - Add user role management (view, edit, bulk) in UserListPage, UserDetailPage, and UserCreatePage. - Restrict role modification to super_admin only. - Remove redundant action columns from tenant-related lists (TenantListPage, TenantSubTenantsPage, TenantUsersPage, TenantAdminsAndOwnersTab). - Improve navigation by making table rows clickable where actions were removed. --- .../routes/TenantAdminsAndOwnersTab.tsx | 100 ++---------------- .../tenants/routes/TenantListPage.tsx | 23 +--- .../tenants/routes/TenantSubTenantsPage.tsx | 21 ++-- .../tenants/routes/TenantUsersPage.tsx | 50 ++------- .../src/features/users/UserCreatePage.tsx | 33 ++++++ .../src/features/users/UserDetailPage.tsx | 33 +++++- .../src/features/users/UserListPage.tsx | 84 +++++++++++++++ 7 files changed, 170 insertions(+), 174 deletions(-) diff --git a/adminfront/src/features/tenants/routes/TenantAdminsAndOwnersTab.tsx b/adminfront/src/features/tenants/routes/TenantAdminsAndOwnersTab.tsx index d592d6f2..4f031db5 100644 --- a/adminfront/src/features/tenants/routes/TenantAdminsAndOwnersTab.tsx +++ b/adminfront/src/features/tenants/routes/TenantAdminsAndOwnersTab.tsx @@ -371,22 +371,19 @@ export function TenantAdminsAndOwnersTab() { {t("ui.admin.tenants.owners.table_email", "이메일")} - - {t("ui.admin.tenants.owners.table_actions", "액션")} - {ownersQuery.isLoading ? ( - +
) : currentOwners.length === 0 ? (
@@ -404,7 +401,8 @@ export function TenantAdminsAndOwnersTab() { currentOwners.map((owner) => ( navigate(`/users/${owner.id}`)} >
@@ -417,46 +415,6 @@ export function TenantAdminsAndOwnersTab() { {owner.email} - - - - - {owner.id === currentUserId - ? t( - "msg.admin.tenants.owners.remove_self", - "본인의 권한은 회수할 수 없습니다.", - ) - : currentOwners.length <= 1 - ? t( - "msg.admin.tenants.owners.remove_last", - "마지막 소유자는 회수할 수 없습니다.", - ) - : t( - "ui.admin.tenants.owners.remove_title", - "소유자 권한 회수", - )} - - - )) )} @@ -502,22 +460,19 @@ export function TenantAdminsAndOwnersTab() { {t("ui.admin.tenants.admins.table_email", "이메일")} - - {t("ui.admin.tenants.admins.table_actions", "액션")} - {adminsQuery.isLoading ? ( - +
) : currentAdmins.length === 0 ? (
@@ -535,7 +490,8 @@ export function TenantAdminsAndOwnersTab() { currentAdmins.map((admin) => ( navigate(`/users/${admin.id}`)} >
@@ -548,46 +504,6 @@ export function TenantAdminsAndOwnersTab() { {admin.email} - - - - - {admin.id === currentUserId - ? t( - "msg.admin.tenants.admins.remove_self", - "본인의 권한은 회수할 수 없습니다.", - ) - : currentAdmins.length <= 1 - ? t( - "msg.admin.tenants.admins.remove_last", - "마지막 관리자는 회수할 수 없습니다.", - ) - : t( - "ui.admin.tenants.admins.remove_title", - "관리자 권한 회수", - )} - - - )) )} diff --git a/adminfront/src/features/tenants/routes/TenantListPage.tsx b/adminfront/src/features/tenants/routes/TenantListPage.tsx index 25b9381d..69f331fc 100644 --- a/adminfront/src/features/tenants/routes/TenantListPage.tsx +++ b/adminfront/src/features/tenants/routes/TenantListPage.tsx @@ -850,15 +850,12 @@ function TenantListPage() { {getSortIcon("updatedAt")}
- - {t("ui.common.actions", "액션")} -
{query.isLoading && ( - + {t("msg.common.loading", "로딩 중...")} @@ -866,7 +863,7 @@ function TenantListPage() { {!query.isLoading && tenants.length === 0 && ( {t( @@ -954,22 +951,6 @@ function TenantListPage() { ) : "-"} - - - ))} diff --git a/adminfront/src/features/tenants/routes/TenantSubTenantsPage.tsx b/adminfront/src/features/tenants/routes/TenantSubTenantsPage.tsx index dbc965a9..de2a2d7b 100644 --- a/adminfront/src/features/tenants/routes/TenantSubTenantsPage.tsx +++ b/adminfront/src/features/tenants/routes/TenantSubTenantsPage.tsx @@ -72,16 +72,13 @@ function TenantSubTenantsPage() { {t("ui.admin.tenants.sub.table.status", "STATUS")} - - {t("ui.admin.tenants.sub.table.action", "ACTION")} - {subTenants.length === 0 && ( {t( @@ -92,7 +89,11 @@ function TenantSubTenantsPage() { )} {subTenants.map((tenant) => ( - + navigate(`/tenants/${tenant.id}`)} + > {tenant.name} @@ -108,16 +109,6 @@ function TenantSubTenantsPage() { {t(`ui.common.status.${tenant.status}`, tenant.status)} - - - ))} diff --git a/adminfront/src/features/tenants/routes/TenantUsersPage.tsx b/adminfront/src/features/tenants/routes/TenantUsersPage.tsx index 2f91f404..7d7e9946 100644 --- a/adminfront/src/features/tenants/routes/TenantUsersPage.tsx +++ b/adminfront/src/features/tenants/routes/TenantUsersPage.tsx @@ -137,15 +137,12 @@ function TenantUsersPage() { {t("ui.admin.tenants.members.table.status", "STATUS")} - - {t("ui.admin.tenants.members.table.actions", "ACTIONS")} - {usersQuery.isLoading ? ( - +
{t( @@ -171,7 +168,11 @@ function TenantUsersPage() { ) : ( users.map((user) => ( - + navigate(`/users/${user.id}`)} + > {user.name} @@ -198,43 +199,6 @@ function TenantUsersPage() { {t(`ui.common.status.${user.status}`, user.status)} - - - - - - - - - - {t( - "ui.admin.tenants.members.view_profile", - "상세 정보", - )} - - - - handleRemoveMember(user.id, user.name) - } - disabled={removeTenantMutation.isPending} - > - - {t( - "ui.admin.tenants.members.remove", - "조직에서 제외", - )} - - - - )) )} diff --git a/adminfront/src/features/users/UserCreatePage.tsx b/adminfront/src/features/users/UserCreatePage.tsx index 56d4d8e4..a763a280 100644 --- a/adminfront/src/features/users/UserCreatePage.tsx +++ b/adminfront/src/features/users/UserCreatePage.tsx @@ -152,6 +152,7 @@ function UserCreatePage() { grade: "", position: "", jobTitle: "", + role: "user", metadata: {}, }, }); @@ -366,6 +367,7 @@ function UserCreatePage() { password: data.password, name: data.name, phone: data.phone, + role: data.role, metadata, }; @@ -644,6 +646,37 @@ function UserCreatePage() {
+
+ + +

+ {t( + "msg.admin.users.create.form.role_help", + "시스템 접근 권한을 결정합니다.", + )} +

+
+
+
+ +
+ +
+
{ + if (selectedUserIds.length === 0) return; + bulkUpdateMutation.mutate({ userIds: selectedUserIds, role }); + }; + const handleBulkDelete = () => { if (selectedUserIds.length === 0) return; if ( @@ -567,6 +572,15 @@ function UserListPage() { {getSortIcon("status")}
+ requestSort("role")} + > +
+ {t("ui.admin.users.list.table.role", "ROLE")} + {getSortIcon("role")} +
+
requestSort("tenant_dept")} @@ -711,6 +725,48 @@ function UserListPage() {
+ + +
@@ -775,6 +831,34 @@ function UserListPage() { {t("ui.common.status.inactive", "비활성화")}
+ {profile?.role === "super_admin" && ( + <> + +
+ + )}