manage license app launch policies
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-07-10 13:14:23 +09:00
parent 93fc7b7b4e
commit ac0c8eb29d
7 changed files with 620 additions and 97 deletions
+31 -9
View File
@@ -13,7 +13,7 @@ import {
deleteAdminSshKey,
loadAdminAppPermissions,
loadAdminRoles,
loadAdmins,
loadAdminsPage,
resetAdminPassword,
updateAdminAppPermissions,
updateAdminRole,
@@ -44,6 +44,10 @@ const fallbackAdminRoles: AdminRoleOption[] = [
export function AdminManagementPage() {
const { toast } = useToast();
const [admins, setAdmins] = useState<AdminAccount[]>([]);
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const [keyword, setKeyword] = useState('');
const [filterValues, setFilterValues] = useState<Record<string, string>>({});
const [adminRoles, setAdminRoles] = useState<AdminRoleOption[]>([]);
const [loading, setLoading] = useState(true);
const [failed, setFailed] = useState(false);
@@ -75,9 +79,13 @@ export function AdminManagementPage() {
const refresh = () => {
setLoading(true);
Promise.all([loadAdmins(), loadAdminRoles().catch(() => fallbackAdminRoles)])
.then(([nextAdmins, nextRoles]) => {
setAdmins(nextAdmins);
Promise.all([
loadAdminsPage({ page, limit: 6, keyword, role: filterValues.role, state: filterValues.state }),
loadAdminRoles().catch(() => fallbackAdminRoles)
])
.then(([result, nextRoles]) => {
setAdmins(result.items);
setTotal(result.total);
setAdminRoles(nextRoles.filter((role) => role.isActive));
setFailed(false);
})
@@ -91,7 +99,7 @@ export function AdminManagementPage() {
useEffect(() => {
refresh();
}, []);
}, [page, keyword, filterValues.role, filterValues.state]);
useEffect(() => {
if (!menuAdmin) return;
@@ -110,7 +118,7 @@ export function AdminManagementPage() {
}, [menuAdmin]);
const rows = useMemo<AdminRow[]>(
() => admins.map((admin, index) => ({ ...admin, no: admins.length - index, state: admin.isActive ? '활성' : '비활성' })),
() => admins.map((admin) => ({ ...admin, no: admin.no ?? 0, state: admin.isActive ? '활성' : '비활성' })),
[admins]
);
const roleOptions = adminRoles.length ? adminRoles : fallbackAdminRoles;
@@ -318,10 +326,10 @@ export function AdminManagementPage() {
const filters = useMemo<Array<DataTableFilter<AdminRow>>>(
() => [
{ key: 'role', label: '권한', options: [...new Set(rows.map((row) => row.role))].map((role) => ({ label: role, value: role })), getValue: (row) => row.role },
{ key: 'state', label: '상태', options: [...new Set(rows.map((row) => row.state))].map((state) => ({ label: state, value: state })), getValue: (row) => row.state }
{ key: 'role', label: '권한', options: roleOptions.map((role) => ({ label: role.name, value: role.code })), getValue: (row) => row.role },
{ key: 'state', label: '상태', options: [{ label: '활성', value: 'active' }, { label: '비활성', value: 'inactive' }], getValue: (row) => row.isActive ? 'active' : 'inactive' }
],
[rows]
[roleOptions]
);
return (
@@ -354,6 +362,20 @@ export function AdminManagementPage() {
minWidth={1040}
loading={loading}
emptyMessage="등록된 관리자가 없습니다."
serverPagination={{
page,
total,
onPageChange: setPage,
onSearchChange: (value) => {
setKeyword(value);
setPage(1);
},
filterValues,
onFilterChange: (key, value) => {
setFilterValues((prev) => ({ ...prev, [key]: value }));
setPage(1);
}
}}
/>
{menuAdmin ? (() => {
const row = rows.find((item) => item.id === menuAdmin.id);