mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
feat: upgrade AdminAlert to PermissionGuard (#4074)
https://linear.app/unleash/issue/2-1165/improve-adminalert-usage-to-be-more-generic-accept-non-admin Upgrades our `AdminAlert` to a new `PermissionGuard`. **Question**: We don't **need** to, but **should** we be specific about the `ADMIN` permission every time? Technically `PermissionGuard` could have `permissions` as optional and assume `[]` by default, which will add `ADMIN` anyways. However, I feel like we may gain some readability if we're specific about it. WDYT? Single permission:  Multiple permissions: 
This commit is contained in:
parent
d2a98d0338
commit
95a0c7748f
@ -1,7 +1,4 @@
|
||||
import { useContext } from 'react';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { ApiTokenTable } from 'component/common/ApiTokenTable/ApiTokenTable';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
@ -24,7 +21,6 @@ import {
|
||||
} from '@server/types/permissions';
|
||||
|
||||
export const ApiTokenPage = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { tokens, loading, refetch } = useApiTokens();
|
||||
const { deleteToken } = useApiTokensApi();
|
||||
|
||||
@ -71,51 +67,49 @@ export const ApiTokenPage = () => {
|
||||
});
|
||||
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={hasAccess([
|
||||
<PermissionGuard
|
||||
permissions={[
|
||||
READ_CLIENT_API_TOKEN,
|
||||
READ_FRONTEND_API_TOKEN,
|
||||
ADMIN,
|
||||
])}
|
||||
show={() => (
|
||||
<PageContent
|
||||
header={
|
||||
<PageHeader
|
||||
title={`API access (${rows.length})`}
|
||||
actions={
|
||||
<>
|
||||
<Search
|
||||
initialValue={globalFilter}
|
||||
onChange={setGlobalFilter}
|
||||
/>
|
||||
<PageHeader.Divider />
|
||||
<CreateApiTokenButton
|
||||
permission={[
|
||||
CREATE_FRONTEND_API_TOKEN,
|
||||
CREATE_CLIENT_API_TOKEN,
|
||||
ADMIN,
|
||||
]}
|
||||
path="/admin/api/create-token"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ApiTokenTable
|
||||
loading={loading}
|
||||
headerGroups={headerGroups}
|
||||
setHiddenColumns={setHiddenColumns}
|
||||
prepareRow={prepareRow}
|
||||
getTableBodyProps={getTableBodyProps}
|
||||
getTableProps={getTableProps}
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
globalFilter={globalFilter}
|
||||
]}
|
||||
>
|
||||
<PageContent
|
||||
header={
|
||||
<PageHeader
|
||||
title={`API access (${rows.length})`}
|
||||
actions={
|
||||
<>
|
||||
<Search
|
||||
initialValue={globalFilter}
|
||||
onChange={setGlobalFilter}
|
||||
/>
|
||||
<PageHeader.Divider />
|
||||
<CreateApiTokenButton
|
||||
permission={[
|
||||
CREATE_FRONTEND_API_TOKEN,
|
||||
CREATE_CLIENT_API_TOKEN,
|
||||
ADMIN,
|
||||
]}
|
||||
path="/admin/api/create-token"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</PageContent>
|
||||
)}
|
||||
elseShow={() => <AdminAlert />}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<ApiTokenTable
|
||||
loading={loading}
|
||||
headerGroups={headerGroups}
|
||||
setHiddenColumns={setHiddenColumns}
|
||||
prepareRow={prepareRow}
|
||||
getTableBodyProps={getTableBodyProps}
|
||||
getTableProps={getTableProps}
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
globalFilter={globalFilter}
|
||||
/>
|
||||
</PageContent>
|
||||
</PermissionGuard>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,3 @@
|
||||
import React from 'react';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
@ -8,6 +7,8 @@ import { SamlAuth } from './SamlAuth/SamlAuth';
|
||||
import { PasswordAuth } from './PasswordAuth/PasswordAuth';
|
||||
import { GoogleAuth } from './GoogleAuth/GoogleAuth';
|
||||
import { TabNav } from 'component/common/TabNav/TabNav/TabNav';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { ADMIN } from '@server/types/permissions';
|
||||
|
||||
export const AuthSettings = () => {
|
||||
const { authenticationType } = useUiConfig().uiConfig;
|
||||
@ -36,51 +37,54 @@ export const AuthSettings = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageContent header="Single Sign-On">
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'enterprise'}
|
||||
show={<TabNav tabData={tabs} />}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'open-source'}
|
||||
show={
|
||||
<Alert severity="warning">
|
||||
You are running the open-source version of Unleash.
|
||||
You have to use the Enterprise edition in order
|
||||
configure Single Sign-on.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'demo'}
|
||||
show={
|
||||
<Alert severity="warning">
|
||||
You are running Unleash in demo mode. You have to
|
||||
use the Enterprise edition in order configure Single
|
||||
Sign-on.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'custom'}
|
||||
show={
|
||||
<Alert severity="warning">
|
||||
You have decided to use custom authentication type.
|
||||
You have to use the Enterprise edition in order
|
||||
configure Single Sign-on from the user interface.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'hosted'}
|
||||
show={
|
||||
<Alert severity="info">
|
||||
Your Unleash instance is managed by the Unleash
|
||||
team.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
</PageContent>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<PageContent header="Single Sign-On">
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'enterprise'}
|
||||
show={<TabNav tabData={tabs} />}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'open-source'}
|
||||
show={
|
||||
<Alert severity="warning">
|
||||
You are running the open-source version of
|
||||
Unleash. You have to use the Enterprise edition
|
||||
in order configure Single Sign-on.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'demo'}
|
||||
show={
|
||||
<Alert severity="warning">
|
||||
You are running Unleash in demo mode. You have
|
||||
to use the Enterprise edition in order configure
|
||||
Single Sign-on.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'custom'}
|
||||
show={
|
||||
<Alert severity="warning">
|
||||
You have decided to use custom authentication
|
||||
type. You have to use the Enterprise edition in
|
||||
order configure Single Sign-on from the user
|
||||
interface.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={authenticationType === 'hosted'}
|
||||
show={
|
||||
<Alert severity="info">
|
||||
Your Unleash instance is managed by the Unleash
|
||||
team.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
</PageContent>
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@ -9,8 +9,6 @@ import {
|
||||
} from '@mui/material';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import useAuthSettings from 'hooks/api/getters/useAuthSettings/useAuthSettings';
|
||||
import useAuthSettingsApi from 'hooks/api/actions/useAuthSettingsApi/useAuthSettingsApi';
|
||||
@ -31,7 +29,6 @@ export const GoogleAuth = () => {
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { uiConfig } = useUiConfig();
|
||||
const [data, setData] = useState(initialState);
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { config } = useAuthSettings('google');
|
||||
const { updateSettings, errors, loading } = useAuthSettingsApi('google');
|
||||
|
||||
@ -41,10 +38,6 @@ export const GoogleAuth = () => {
|
||||
}
|
||||
}, [config]);
|
||||
|
||||
if (!hasAccess(ADMIN)) {
|
||||
return <span>You need admin privileges to access this section.</span>;
|
||||
}
|
||||
|
||||
const updateField = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setData({
|
||||
...data,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
@ -12,8 +12,6 @@ import {
|
||||
} from '@mui/material';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { AutoCreateForm } from '../AutoCreateForm/AutoCreateForm';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import useAuthSettingsApi from 'hooks/api/actions/useAuthSettingsApi/useAuthSettingsApi';
|
||||
@ -41,7 +39,6 @@ export const OidcAuth = () => {
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { uiConfig } = useUiConfig();
|
||||
const [data, setData] = useState(initialState);
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { config } = useAuthSettings('oidc');
|
||||
const { updateSettings, errors, loading } = useAuthSettingsApi('oidc');
|
||||
|
||||
@ -51,14 +48,6 @@ export const OidcAuth = () => {
|
||||
}
|
||||
}, [config]);
|
||||
|
||||
if (!hasAccess(ADMIN)) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
You need to be a root admin to access this section.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
const updateField = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(event.target.name, event.target.value);
|
||||
};
|
||||
|
@ -1,9 +1,7 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, FormControlLabel, Grid, Switch } from '@mui/material';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import useAuthSettings from 'hooks/api/getters/useAuthSettings/useAuthSettings';
|
||||
import useAuthSettingsApi, {
|
||||
ISimpleAuthSettings,
|
||||
@ -22,7 +20,6 @@ export const PasswordAuth = () => {
|
||||
useState<boolean>(false);
|
||||
const { updateSettings, errors, loading } =
|
||||
useAuthSettingsApi<ISimpleAuthSettings>('simple');
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const [confirmationOpen, setConfirmationOpen] = useState(false);
|
||||
const { data: adminCount } = useAdminCount();
|
||||
const { tokens } = useApiTokens();
|
||||
@ -31,14 +28,6 @@ export const PasswordAuth = () => {
|
||||
setDisablePasswordAuth(!!config.disabled);
|
||||
}, [config.disabled]);
|
||||
|
||||
if (!hasAccess(ADMIN)) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
You need to be a root admin to access this section.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
const updateDisabled = () => {
|
||||
setDisablePasswordAuth(!disablePasswordAuth);
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
FormControlLabel,
|
||||
@ -8,8 +8,6 @@ import {
|
||||
} from '@mui/material';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { AutoCreateForm } from '../AutoCreateForm/AutoCreateForm';
|
||||
import useToast from 'hooks/useToast';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
@ -36,7 +34,6 @@ export const SamlAuth = () => {
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { uiConfig } = useUiConfig();
|
||||
const [data, setData] = useState(initialState);
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { config } = useAuthSettings('saml');
|
||||
const { updateSettings, errors, loading } = useAuthSettingsApi('saml');
|
||||
|
||||
@ -46,14 +43,6 @@ export const SamlAuth = () => {
|
||||
}
|
||||
}, [config]);
|
||||
|
||||
if (!hasAccess(ADMIN)) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
You need to be a root admin to access this section.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
const updateField = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(event.target.name, event.target.value);
|
||||
};
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { useInstanceStatus } from 'hooks/api/getters/useInstanceStatus/useInstanceStatus';
|
||||
import { Alert } from '@mui/material';
|
||||
import { BillingDashboard } from './BillingDashboard/BillingDashboard';
|
||||
@ -19,7 +18,6 @@ export const Billing = () => {
|
||||
loading,
|
||||
} = useInstanceStatus();
|
||||
const { invoices } = useInvoices();
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
useEffect(() => {
|
||||
const hardRefresh = async () => {
|
||||
@ -35,18 +33,14 @@ export const Billing = () => {
|
||||
<ConditionallyRender
|
||||
condition={isBilling}
|
||||
show={
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={() => (
|
||||
<>
|
||||
<BillingDashboard
|
||||
instanceStatus={instanceStatus!}
|
||||
/>
|
||||
<BillingHistory data={invoices} />
|
||||
</>
|
||||
)}
|
||||
elseShow={() => <AdminAlert />}
|
||||
/>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<>
|
||||
<BillingDashboard
|
||||
instanceStatus={instanceStatus!}
|
||||
/>
|
||||
<BillingHistory data={invoices} />
|
||||
</>
|
||||
</PermissionGuard>
|
||||
}
|
||||
elseShow={
|
||||
<Alert severity="error">
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Navigate } from 'react-router-dom';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import InvoiceAdminPage from 'component/admin/invoice/InvoiceAdminPage';
|
||||
import { InvoiceAdminPage } from 'component/admin/invoice/InvoiceAdminPage';
|
||||
|
||||
const FlaggedBillingRedirect = () => {
|
||||
const { uiConfig, loading } = useUiConfig();
|
||||
|
@ -1,8 +1,5 @@
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import React, { useContext } from 'react';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
import { Box } from '@mui/material';
|
||||
@ -10,19 +7,13 @@ import { CorsHelpAlert } from 'component/admin/cors/CorsHelpAlert';
|
||||
import { CorsForm } from 'component/admin/cors/CorsForm';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
|
||||
export const CorsAdmin = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<CorsPage />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const CorsAdmin = () => (
|
||||
<div>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<CorsPage />
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
|
||||
const CorsPage = () => {
|
||||
const { uiConfig, loading } = useUiConfig();
|
||||
|
@ -1,20 +1,11 @@
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { GroupsList } from './GroupsList/GroupsList';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { useContext } from 'react';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ADMIN } from '@server/types/permissions';
|
||||
|
||||
export const GroupsAdmin = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<GroupsList />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const GroupsAdmin = () => (
|
||||
<div>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<GroupsList />
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,25 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
import InvoiceList from './InvoiceList';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { Alert } from '@mui/material';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
|
||||
const InvoiceAdminPage = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<InvoiceList />}
|
||||
elseShow={
|
||||
<Alert severity="error">
|
||||
You need to be instance admin to access this section.
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InvoiceAdminPage;
|
||||
export const InvoiceAdminPage = () => (
|
||||
<div>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<InvoiceList />
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,8 +1,5 @@
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import React, { useContext } from 'react';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
import { Box, styled } from '@mui/material';
|
||||
@ -10,19 +7,13 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { MaintenanceTooltip } from './MaintenanceTooltip';
|
||||
import { MaintenanceToggle } from './MaintenanceToggle';
|
||||
|
||||
export const MaintenanceAdmin = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<MaintenancePage />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const MaintenanceAdmin = () => (
|
||||
<div>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<MaintenancePage />
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
|
||||
const StyledBox = styled(Box)(({ theme }) => ({
|
||||
display: 'grid',
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { useContext, useState } from 'react';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { useState } from 'react';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { RolesTable } from './RolesTable/RolesTable';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { Tab, Tabs, styled, useMediaQuery } from '@mui/material';
|
||||
import { Route, Routes, useLocation } from 'react-router-dom';
|
||||
@ -45,7 +44,6 @@ const StyledActions = styled('div')({
|
||||
|
||||
export const Roles = () => {
|
||||
const { uiConfig } = useUiConfig();
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const { roles, projectRoles, loading } = useRoles();
|
||||
@ -84,122 +82,109 @@ export const Roles = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(READ_ROLE)}
|
||||
show={
|
||||
<StyledPageContent
|
||||
headerClass="page-header"
|
||||
bodyClass="page-body"
|
||||
isLoading={loading}
|
||||
header={
|
||||
<>
|
||||
<StyledHeader>
|
||||
<StyledTabsContainer>
|
||||
<Tabs
|
||||
value={pathname}
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
>
|
||||
{tabs.map(
|
||||
({ label, path, total }) => (
|
||||
<Tab
|
||||
key={label}
|
||||
value={path}
|
||||
label={
|
||||
<CenteredNavLink
|
||||
to={path}
|
||||
>
|
||||
<span>
|
||||
{label} (
|
||||
{total})
|
||||
</span>
|
||||
</CenteredNavLink>
|
||||
}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Tabs>
|
||||
</StyledTabsContainer>
|
||||
<StyledActions>
|
||||
<ConditionallyRender
|
||||
condition={!isSmallScreen}
|
||||
show={
|
||||
<>
|
||||
<Search
|
||||
initialValue={
|
||||
searchValue
|
||||
}
|
||||
onChange={
|
||||
setSearchValue
|
||||
}
|
||||
/>
|
||||
<PageHeader.Divider />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<ResponsiveButton
|
||||
onClick={() => {
|
||||
setSelectedRole(undefined);
|
||||
setModalOpen(true);
|
||||
}}
|
||||
maxWidth={`${theme.breakpoints.values['sm']}px`}
|
||||
Icon={Add}
|
||||
permission={ADMIN}
|
||||
>
|
||||
New {type} role
|
||||
</ResponsiveButton>
|
||||
</StyledActions>
|
||||
</StyledHeader>
|
||||
<ConditionallyRender
|
||||
condition={isSmallScreen}
|
||||
show={
|
||||
<Search
|
||||
initialValue={searchValue}
|
||||
onChange={setSearchValue}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Routes>
|
||||
<Route
|
||||
path="project-roles"
|
||||
element={
|
||||
<RolesTable
|
||||
type={PROJECT_ROLE_TYPE}
|
||||
searchValue={searchValue}
|
||||
modalOpen={modalOpen}
|
||||
setModalOpen={setModalOpen}
|
||||
selectedRole={selectedRole}
|
||||
setSelectedRole={setSelectedRole}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="*"
|
||||
element={
|
||||
<RolesTable
|
||||
type={
|
||||
uiConfig.flags.customRootRoles
|
||||
? ROOT_ROLE_TYPE
|
||||
: PROJECT_ROLE_TYPE
|
||||
<PermissionGuard permissions={[READ_ROLE, ADMIN]}>
|
||||
<StyledPageContent
|
||||
headerClass="page-header"
|
||||
bodyClass="page-body"
|
||||
isLoading={loading}
|
||||
header={
|
||||
<>
|
||||
<StyledHeader>
|
||||
<StyledTabsContainer>
|
||||
<Tabs
|
||||
value={pathname}
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
>
|
||||
{tabs.map(({ label, path, total }) => (
|
||||
<Tab
|
||||
key={label}
|
||||
value={path}
|
||||
label={
|
||||
<CenteredNavLink to={path}>
|
||||
<span>
|
||||
{label} ({total})
|
||||
</span>
|
||||
</CenteredNavLink>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
</StyledTabsContainer>
|
||||
<StyledActions>
|
||||
<ConditionallyRender
|
||||
condition={!isSmallScreen}
|
||||
show={
|
||||
<>
|
||||
<Search
|
||||
initialValue={searchValue}
|
||||
onChange={setSearchValue}
|
||||
/>
|
||||
<PageHeader.Divider />
|
||||
</>
|
||||
}
|
||||
searchValue={searchValue}
|
||||
modalOpen={modalOpen}
|
||||
setModalOpen={setModalOpen}
|
||||
selectedRole={selectedRole}
|
||||
setSelectedRole={setSelectedRole}
|
||||
/>
|
||||
<ResponsiveButton
|
||||
onClick={() => {
|
||||
setSelectedRole(undefined);
|
||||
setModalOpen(true);
|
||||
}}
|
||||
maxWidth={`${theme.breakpoints.values['sm']}px`}
|
||||
Icon={Add}
|
||||
permission={ADMIN}
|
||||
>
|
||||
New {type} role
|
||||
</ResponsiveButton>
|
||||
</StyledActions>
|
||||
</StyledHeader>
|
||||
<ConditionallyRender
|
||||
condition={isSmallScreen}
|
||||
show={
|
||||
<Search
|
||||
initialValue={searchValue}
|
||||
onChange={setSearchValue}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</StyledPageContent>
|
||||
}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Routes>
|
||||
<Route
|
||||
path="project-roles"
|
||||
element={
|
||||
<RolesTable
|
||||
type={PROJECT_ROLE_TYPE}
|
||||
searchValue={searchValue}
|
||||
modalOpen={modalOpen}
|
||||
setModalOpen={setModalOpen}
|
||||
selectedRole={selectedRole}
|
||||
setSelectedRole={setSelectedRole}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="*"
|
||||
element={
|
||||
<RolesTable
|
||||
type={
|
||||
uiConfig.flags.customRootRoles
|
||||
? ROOT_ROLE_TYPE
|
||||
: PROJECT_ROLE_TYPE
|
||||
}
|
||||
searchValue={searchValue}
|
||||
modalOpen={modalOpen}
|
||||
setModalOpen={setModalOpen}
|
||||
selectedRole={selectedRole}
|
||||
setSelectedRole={setSelectedRole}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</StyledPageContent>
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,20 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { ServiceAccountsTable } from './ServiceAccountsTable/ServiceAccountsTable';
|
||||
|
||||
export const ServiceAccounts = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<ServiceAccountsTable />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const ServiceAccounts = () => (
|
||||
<div>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<ServiceAccountsTable />
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,24 +1,15 @@
|
||||
import { useContext } from 'react';
|
||||
import UsersList from './UsersList/UsersList';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { InviteLinkBar } from './InviteLinkBar/InviteLinkBar';
|
||||
|
||||
export const UsersAdmin = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<InviteLinkBar />
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<UsersList />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const UsersAdmin = () => (
|
||||
<div>
|
||||
<InviteLinkBar />
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<UsersList />
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default UsersAdmin;
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { Alert } from '@mui/material';
|
||||
|
||||
export const AdminAlert = () => {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
You need instance admin to access this section.
|
||||
</Alert>
|
||||
);
|
||||
};
|
@ -0,0 +1,54 @@
|
||||
import { useContext } from 'react';
|
||||
import { Alert, styled } from '@mui/material';
|
||||
import { ADMIN } from '@server/types/permissions';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
|
||||
const StyledList = styled('ul')(({ theme }) => ({
|
||||
paddingInlineStart: theme.spacing(2),
|
||||
}));
|
||||
|
||||
interface IPermissionGuardProps {
|
||||
permissions: string | string[];
|
||||
children: JSX.Element;
|
||||
}
|
||||
|
||||
export const PermissionGuard = ({
|
||||
permissions,
|
||||
children,
|
||||
}: IPermissionGuardProps) => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
const permissionsArray = Array.isArray(permissions)
|
||||
? permissions
|
||||
: [permissions];
|
||||
|
||||
if (!permissionsArray.includes(ADMIN)) {
|
||||
permissionsArray.push(ADMIN);
|
||||
}
|
||||
|
||||
if (hasAccess(permissionsArray)) {
|
||||
return children;
|
||||
}
|
||||
|
||||
if (permissionsArray.length === 1) {
|
||||
return (
|
||||
<Alert severity="error">
|
||||
You need the <strong>{permissionsArray[0]}</strong> permission
|
||||
to access this section.
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert severity="error">
|
||||
You need one of the following permissions to access this section:
|
||||
<StyledList>
|
||||
{permissionsArray.sort().map(permission => (
|
||||
<li key={permission}>
|
||||
<strong>{permission}</strong>
|
||||
</li>
|
||||
))}
|
||||
</StyledList>
|
||||
</Alert>
|
||||
);
|
||||
};
|
@ -1,18 +1,9 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { EventLog } from 'component/events/EventLog/EventLog';
|
||||
|
||||
export const EventPage = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={() => <EventLog title="Event log" />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export const EventPage = () => (
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<EventLog title="Event log" />
|
||||
</PermissionGuard>
|
||||
);
|
||||
|
@ -1,20 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
import AccessContext from 'contexts/AccessContext';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
|
||||
import { LoginHistoryTable } from './LoginHistoryTable/LoginHistoryTable';
|
||||
|
||||
export const LoginHistory = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<LoginHistoryTable />}
|
||||
elseShow={<AdminAlert />}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const LoginHistory = () => (
|
||||
<div>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<LoginHistoryTable />
|
||||
</PermissionGuard>
|
||||
</div>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user