{
- updateUserStatusMutation.mutate({
- email: row.original.email,
- isActive: checked,
- });
- }}
- disabled={updateUserStatusMutation.isPending}
- />
- ),
- }),
columnHelper.accessor('is_active', {
header: t('admin.status'),
- cell: ({ cell }) => (
-
-
- {t(
- parseBooleanish(cell.getValue())
- ? 'admin.active'
- : 'admin.inactive',
- )}
-
- ),
+ cell: ({ cell, row }) => {
+ const isMe = row.original.email === userInfo?.email;
+
+ if (isMe) {
+ return (
+
+
+ {parseBooleanish(cell.getValue())
+ ? t('admin.active')
+ : t('admin.inactive')}
+
+ );
+ }
+
+ return (
+
+ );
+ },
filterFn: createColumnFilterFn(
(row, id, filterValue) => row.getValue(id) === filterValue,
{
@@ -307,48 +347,106 @@ function AdminUserManagement() {
},
),
}),
+
+ columnHelper.accessor('is_superuser', {
+ header: t('admin.userType'),
+ cell: ({ cell, row }) => {
+ const isMe = row.original.email === userInfo?.email;
+
+ if (isMe) {
+ return {t('admin.superuser')};
+ }
+
+ return (
+
+ );
+ },
+ }),
+
columnHelper.display({
id: 'actions',
header: t('admin.actions'),
- cell: ({ row }) => (
-
-
-
-
-
- ),
+ cell: ({ row }) => {
+ const isMe = row.original.email === userInfo?.email;
+
+ return (
+
+
+
+ {!isMe && (
+ <>
+
+
+ >
+ )}
+
+ );
+ },
}),
],
- [t, updateUserRoleMutation, roleList, updateUserStatusMutation, navigate],
+ [
+ t,
+ roleList,
+ updateUserRoleMutation,
+ userInfo?.email,
+ updateUserStatusMutation,
+ setSuperuserMutation,
+ navigate,
+ ],
);
const table = useReactTable({
@@ -505,11 +603,11 @@ function AdminUserManagement() {
- {() => }
+ {() => }
-
-
+
+
diff --git a/web/src/pages/admin/wrappers/authorized.tsx b/web/src/pages/admin/wrappers/authorized.tsx
deleted file mode 100644
index 97ea830b6..000000000
--- a/web/src/pages/admin/wrappers/authorized.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Routes } from '@/routes';
-import authorizationUtil from '@/utils/authorization-util';
-import { Navigate, Outlet } from 'react-router';
-
-export default function AuthorizedAdminWrapper() {
- const isLogin = !!authorizationUtil.getAuthorization();
-
- return isLogin ? : ;
-}
diff --git a/web/src/routes.tsx b/web/src/routes.tsx
index 834a6e026..f0c32db96 100644
--- a/web/src/routes.tsx
+++ b/web/src/routes.tsx
@@ -1,5 +1,5 @@
import { lazy } from 'react';
-import { createBrowserRouter, Navigate } from 'react-router';
+import { createBrowserRouter, Navigate, type RouteObject } from 'react-router';
import FallbackComponent from './components/fallback-component';
import { IS_ENTERPRISE } from './pages/admin/utils';
@@ -389,53 +389,58 @@ const routeConfig = [
},
{
path: Routes.Admin,
- layout: false,
Component: lazy(() => import('@/pages/admin/layouts/root-layout')),
+ errorElement: ,
children: [
{
- path: '',
+ path: Routes.Admin,
Component: lazy(() => import('@/pages/admin/login')),
},
- {
- path: `${Routes.AdminUserManagement}/:id`,
- Component: lazy(() => import('@/pages/admin/user-detail')),
- },
{
path: Routes.Admin,
Component: lazy(
- () => import('@/pages/admin/layouts/navigation-layout'),
+ () => import('@/pages/admin/layouts/authorized-layout'),
),
- wrappers: ['@/pages/admin/wrappers/authorized'],
children: [
{
- path: Routes.AdminServices,
- Component: lazy(() => import('@/pages/admin/service-status')),
+ path: `${Routes.AdminUserManagement}/:id`,
+ Component: lazy(() => import('@/pages/admin/user-detail')),
},
{
- path: Routes.AdminUserManagement,
- Component: lazy(() => import('@/pages/admin/users')),
+ Component: lazy(
+ () => import('@/pages/admin/layouts/navigation-layout'),
+ ),
+ children: [
+ {
+ path: Routes.AdminServices,
+ Component: lazy(() => import('@/pages/admin/service-status')),
+ },
+ {
+ path: Routes.AdminUserManagement,
+ Component: lazy(() => import('@/pages/admin/users')),
+ },
+ ...(IS_ENTERPRISE
+ ? [
+ {
+ path: Routes.AdminWhitelist,
+ Component: lazy(() => import('@/pages/admin/whitelist')),
+ },
+ {
+ path: Routes.AdminRoles,
+ Component: lazy(() => import('@/pages/admin/roles')),
+ },
+ {
+ path: Routes.AdminMonitoring,
+ Component: lazy(() => import('@/pages/admin/monitoring')),
+ },
+ ]
+ : []),
+ ],
},
- ...(IS_ENTERPRISE
- ? [
- {
- path: Routes.AdminWhitelist,
- Component: lazy(() => import('@/pages/admin/whitelist')),
- },
- {
- path: Routes.AdminRoles,
- Component: lazy(() => import('@/pages/admin/roles')),
- },
- {
- path: Routes.AdminMonitoring,
- Component: lazy(() => import('@/pages/admin/monitoring')),
- },
- ]
- : []),
],
},
],
- errorElement: ,
- },
+ } satisfies RouteObject,
];
const routers = createBrowserRouter(routeConfig, {
diff --git a/web/src/services/admin-service.ts b/web/src/services/admin-service.ts
index 6aec2b89c..3b19eddcd 100644
--- a/web/src/services/admin-service.ts
+++ b/web/src/services/admin-service.ts
@@ -157,6 +157,13 @@ export const createUser = (email: string, password: string) =>
username: email,
password,
});
+
+export const grantSuperuser = (email: string) =>
+ request.put>(api.adminSetSuperuser(email));
+
+export const revokeSuperuser = (email: string) =>
+ request.delete>(api.adminSetSuperuser(email));
+
export const getUserDetails = (email: string) =>
request.get>(
adminGetUserDetails(email),
diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts
index 9091539b3..0fe695497 100644
--- a/web/src/utils/api.ts
+++ b/web/src/utils/api.ts
@@ -263,6 +263,8 @@ export default {
adminLogout: `${ExternalApi}${api_host}/admin/logout`,
adminListUsers: `${ExternalApi}${api_host}/admin/users`,
adminCreateUser: `${ExternalApi}${api_host}/admin/users`,
+ adminSetSuperuser: (username: string) =>
+ `${ExternalApi}${api_host}/admin/users/${username}/admin`,
adminGetUserDetails: (username: string) =>
`${ExternalApi}${api_host}/admin/users/${username}`,
adminUpdateUserStatus: (username: string) =>
diff --git a/web/src/utils/authorization-util.ts b/web/src/utils/authorization-util.ts
index 227f33b54..e25e4915f 100644
--- a/web/src/utils/authorization-util.ts
+++ b/web/src/utils/authorization-util.ts
@@ -13,7 +13,8 @@ const storage = {
return localStorage.getItem(UserInfo);
},
getUserInfoObject: () => {
- return JSON.parse(localStorage.getItem('userInfo') || '');
+ const userInfoStr = localStorage.getItem(UserInfo);
+ return userInfoStr ? JSON.parse(userInfoStr) : null;
},
setAuthorization: (value: string) => {
localStorage.setItem(Authorization, value);