mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-03 01:18:43 +02:00
feat: use READ_API_TOKEN permission (#906)
* refactor: extract AdminAlert component * refactor: split ApiTokenPage from ApiTokenList * refactor: display AdminMenu based on path instead of permissions * feat: use the new READ_API_TOKEN permission
This commit is contained in:
parent
49a63173f8
commit
f6e42f99f9
@ -1,16 +1,19 @@
|
|||||||
import { ApiTokenList } from '../apiToken/ApiTokenList/ApiTokenList';
|
|
||||||
import AdminMenu from '../menu/AdminMenu';
|
import AdminMenu from '../menu/AdminMenu';
|
||||||
import ConditionallyRender from 'component/common/ConditionallyRender';
|
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||||
import AccessContext from 'contexts/AccessContext';
|
import { ApiTokenPage } from 'component/admin/apiToken/ApiTokenPage/ApiTokenPage';
|
||||||
import { useContext } from 'react';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
const ApiPage = () => {
|
const ApiPage = () => {
|
||||||
const { isAdmin } = useContext(AccessContext);
|
const { pathname } = useLocation();
|
||||||
|
const showAdminMenu = pathname.includes('/admin/');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ConditionallyRender condition={isAdmin} show={<AdminMenu />} />
|
<ConditionallyRender
|
||||||
<ApiTokenList />
|
condition={showAdminMenu}
|
||||||
|
show={<AdminMenu />}
|
||||||
|
/>
|
||||||
|
<ApiTokenPage />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -13,10 +13,6 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
apiError: {
|
|
||||||
maxWidth: '400px',
|
|
||||||
marginBottom: '1rem',
|
|
||||||
},
|
|
||||||
center: {
|
center: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
@ -25,9 +21,6 @@ export const useStyles = makeStyles(theme => ({
|
|||||||
display: 'flex-inline',
|
display: 'flex-inline',
|
||||||
flexWrap: 'nowrap',
|
flexWrap: 'nowrap',
|
||||||
},
|
},
|
||||||
infoBoxContainer: {
|
|
||||||
marginBottom: 40,
|
|
||||||
},
|
|
||||||
hideSM: {
|
hideSM: {
|
||||||
[theme.breakpoints.down('sm')]: {
|
[theme.breakpoints.down('sm')]: {
|
||||||
display: 'none',
|
display: 'none',
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import { Fragment, useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@ -17,19 +15,12 @@ import useApiTokens from 'hooks/api/getters/useApiTokens/useApiTokens';
|
|||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import useApiTokensApi from 'hooks/api/actions/useApiTokensApi/useApiTokensApi';
|
import useApiTokensApi from 'hooks/api/actions/useApiTokensApi/useApiTokensApi';
|
||||||
import ApiError from 'component/common/ApiError/ApiError';
|
import ApiError from 'component/common/ApiError/ApiError';
|
||||||
import PageContent from 'component/common/PageContent';
|
|
||||||
import HeaderTitle from 'component/common/HeaderTitle';
|
|
||||||
import ConditionallyRender from 'component/common/ConditionallyRender';
|
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||||
import {
|
import { DELETE_API_TOKEN } from 'component/providers/AccessProvider/permissions';
|
||||||
CREATE_API_TOKEN,
|
|
||||||
DELETE_API_TOKEN,
|
|
||||||
} from 'component/providers/AccessProvider/permissions';
|
|
||||||
import { useStyles } from './ApiTokenList.styles';
|
import { useStyles } from './ApiTokenList.styles';
|
||||||
import Secret from './secret';
|
import Secret from './secret';
|
||||||
import { Delete, FileCopy } from '@material-ui/icons';
|
import { Delete, FileCopy } from '@material-ui/icons';
|
||||||
import Dialogue from 'component/common/Dialogue';
|
import Dialogue from 'component/common/Dialogue';
|
||||||
import { CREATE_API_TOKEN_BUTTON } from 'utils/testIds';
|
|
||||||
import { Alert } from '@material-ui/lab';
|
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import { useLocationSettings } from 'hooks/useLocationSettings';
|
import { useLocationSettings } from 'hooks/useLocationSettings';
|
||||||
import { formatDateYMD } from 'utils/formatDate';
|
import { formatDateYMD } from 'utils/formatDate';
|
||||||
@ -56,16 +47,9 @@ export const ApiTokenList = () => {
|
|||||||
const { tokens, loading, refetch, error } = useApiTokens();
|
const { tokens, loading, refetch, error } = useApiTokens();
|
||||||
const { deleteToken } = useApiTokensApi();
|
const { deleteToken } = useApiTokensApi();
|
||||||
const ref = useLoading(loading);
|
const ref = useLoading(loading);
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
const renderError = () => {
|
const renderError = () => {
|
||||||
return (
|
return <ApiError onClick={refetch} text="Error fetching api tokens" />;
|
||||||
<ApiError
|
|
||||||
onClick={refetch}
|
|
||||||
// className={styles.apiError}
|
|
||||||
text="Error fetching api tokens"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyToken = (value: string) => {
|
const copyToken = (value: string) => {
|
||||||
@ -236,53 +220,6 @@ export const ApiTokenList = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
<PageContent
|
|
||||||
headerContent={
|
|
||||||
<HeaderTitle
|
|
||||||
title="API Access"
|
|
||||||
actions={
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={hasAccess(CREATE_API_TOKEN)}
|
|
||||||
show={
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={() =>
|
|
||||||
history.push(
|
|
||||||
'/admin/api/create-token'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
data-testid={CREATE_API_TOKEN_BUTTON}
|
|
||||||
>
|
|
||||||
New API token
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Alert severity="info" className={styles.infoBoxContainer}>
|
|
||||||
<p>
|
|
||||||
Read the{' '}
|
|
||||||
<a
|
|
||||||
href="https://docs.getunleash.io/docs"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
Getting started guide
|
|
||||||
</a>{' '}
|
|
||||||
to learn how to connect to the Unleash API from your
|
|
||||||
application or programmatically. Please note it can take
|
|
||||||
up to 1 minute before a new API key is activated.
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
<strong>API URL: </strong>{' '}
|
|
||||||
<pre style={{ display: 'inline' }}>
|
|
||||||
{uiConfig.unleashUrl}/api/
|
|
||||||
</pre>
|
|
||||||
</Alert>
|
|
||||||
|
|
||||||
<ConditionallyRender condition={error} show={renderError()} />
|
<ConditionallyRender condition={error} show={renderError()} />
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
@ -291,7 +228,6 @@ export const ApiTokenList = () => {
|
|||||||
elseShow={renderApiTokens(tokens)}
|
elseShow={renderApiTokens(tokens)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Dialogue
|
<Dialogue
|
||||||
open={showDelete}
|
open={showDelete}
|
||||||
onClick={onDeleteToken}
|
onClick={onDeleteToken}
|
||||||
@ -310,13 +246,11 @@ export const ApiTokenList = () => {
|
|||||||
<code>{delToken?.username}</code>
|
<code>{delToken?.username}</code>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<strong>type</strong>:{' '}
|
<strong>type</strong>: <code>{delToken?.type}</code>
|
||||||
<code>{delToken?.type}</code>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</Dialogue>
|
</Dialogue>
|
||||||
</PageContent>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
|
||||||
|
export const useStyles = makeStyles(theme => ({
|
||||||
|
infoBoxContainer: {
|
||||||
|
marginBottom: 40,
|
||||||
|
},
|
||||||
|
}));
|
@ -0,0 +1,77 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { Button } from '@material-ui/core';
|
||||||
|
import AccessContext from 'contexts/AccessContext';
|
||||||
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
import PageContent from 'component/common/PageContent';
|
||||||
|
import HeaderTitle from 'component/common/HeaderTitle';
|
||||||
|
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||||
|
import {
|
||||||
|
CREATE_API_TOKEN,
|
||||||
|
READ_API_TOKEN,
|
||||||
|
} from 'component/providers/AccessProvider/permissions';
|
||||||
|
import { useStyles } from './ApiTokenPage.styles';
|
||||||
|
import { CREATE_API_TOKEN_BUTTON } from 'utils/testIds';
|
||||||
|
import { Alert } from '@material-ui/lab';
|
||||||
|
import { ApiTokenList } from 'component/admin/apiToken/ApiTokenList/ApiTokenList';
|
||||||
|
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||||
|
|
||||||
|
export const ApiTokenPage = () => {
|
||||||
|
const styles = useStyles();
|
||||||
|
const { hasAccess } = useContext(AccessContext);
|
||||||
|
const { uiConfig } = useUiConfig();
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContent
|
||||||
|
headerContent={
|
||||||
|
<HeaderTitle
|
||||||
|
title="API Access"
|
||||||
|
actions={
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={hasAccess(CREATE_API_TOKEN)}
|
||||||
|
show={
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() =>
|
||||||
|
history.push('/admin/api/create-token')
|
||||||
|
}
|
||||||
|
data-testid={CREATE_API_TOKEN_BUTTON}
|
||||||
|
>
|
||||||
|
New API token
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Alert severity="info" className={styles.infoBoxContainer}>
|
||||||
|
<p>
|
||||||
|
Read the{' '}
|
||||||
|
<a
|
||||||
|
href="https://docs.getunleash.io/docs"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
Getting started guide
|
||||||
|
</a>{' '}
|
||||||
|
to learn how to connect to the Unleash API from your
|
||||||
|
application or programmatically. Please note it can take up
|
||||||
|
to 1 minute before a new API key is activated.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
<strong>API URL: </strong>{' '}
|
||||||
|
<pre style={{ display: 'inline' }}>
|
||||||
|
{uiConfig.unleashUrl}/api/
|
||||||
|
</pre>
|
||||||
|
</Alert>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={hasAccess(READ_API_TOKEN)}
|
||||||
|
show={() => <ApiTokenList />}
|
||||||
|
elseShow={() => <AdminAlert />}
|
||||||
|
/>
|
||||||
|
</PageContent>
|
||||||
|
);
|
||||||
|
};
|
@ -1,5 +1,4 @@
|
|||||||
import { Button } from '@material-ui/core';
|
import { Button } from '@material-ui/core';
|
||||||
import { Alert } from '@material-ui/lab';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import AccessContext from 'contexts/AccessContext';
|
import AccessContext from 'contexts/AccessContext';
|
||||||
@ -10,6 +9,7 @@ import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
|||||||
import AdminMenu from 'component/admin/menu/AdminMenu';
|
import AdminMenu from 'component/admin/menu/AdminMenu';
|
||||||
import { useStyles } from './ProjectRoles.styles';
|
import { useStyles } from './ProjectRoles.styles';
|
||||||
import ProjectRoleList from './ProjectRoleList/ProjectRoleList';
|
import ProjectRoleList from './ProjectRoleList/ProjectRoleList';
|
||||||
|
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||||
|
|
||||||
const ProjectRoles = () => {
|
const ProjectRoles = () => {
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
@ -53,11 +53,7 @@ const ProjectRoles = () => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={hasAccess(ADMIN)}
|
condition={hasAccess(ADMIN)}
|
||||||
show={<ProjectRoleList />}
|
show={<ProjectRoleList />}
|
||||||
elseShow={
|
elseShow={<AdminAlert />}
|
||||||
<Alert severity="error">
|
|
||||||
You need instance admin to access this section.
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,12 +5,12 @@ import PageContent from 'component/common/PageContent/PageContent';
|
|||||||
import AccessContext from 'contexts/AccessContext';
|
import AccessContext from 'contexts/AccessContext';
|
||||||
import ConditionallyRender from 'component/common/ConditionallyRender';
|
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||||
import { Alert } from '@material-ui/lab';
|
|
||||||
import HeaderTitle from 'component/common/HeaderTitle';
|
import HeaderTitle from 'component/common/HeaderTitle';
|
||||||
import { TableActions } from 'component/common/Table/TableActions/TableActions';
|
import { TableActions } from 'component/common/Table/TableActions/TableActions';
|
||||||
import { Button } from '@material-ui/core';
|
import { Button } from '@material-ui/core';
|
||||||
import { useStyles } from './UserAdmin.styles';
|
import { useStyles } from './UserAdmin.styles';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||||
|
|
||||||
const UsersAdmin = () => {
|
const UsersAdmin = () => {
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
@ -63,11 +63,7 @@ const UsersAdmin = () => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={hasAccess(ADMIN)}
|
condition={hasAccess(ADMIN)}
|
||||||
show={<UsersList search={search} />}
|
show={<UsersList search={search} />}
|
||||||
elseShow={
|
elseShow={<AdminAlert />}
|
||||||
<Alert severity="error">
|
|
||||||
You need instance admin to access this section.
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
</div>
|
</div>
|
||||||
|
9
frontend/src/component/common/AdminAlert/AdminAlert.tsx
Normal file
9
frontend/src/component/common/AdminAlert/AdminAlert.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Alert } from '@material-ui/lab';
|
||||||
|
|
||||||
|
export const AdminAlert = () => {
|
||||||
|
return (
|
||||||
|
<Alert severity="error">
|
||||||
|
You need instance admin to access this section.
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
};
|
@ -1,9 +1,9 @@
|
|||||||
import { Alert } from '@material-ui/lab';
|
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||||
import ConditionallyRender from 'component/common/ConditionallyRender';
|
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||||
import AccessContext from 'contexts/AccessContext';
|
import AccessContext from 'contexts/AccessContext';
|
||||||
import { EventHistory } from '../EventHistory/EventHistory';
|
import { EventHistory } from '../EventHistory/EventHistory';
|
||||||
|
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||||
|
|
||||||
export const EventHistoryPage = () => {
|
export const EventHistoryPage = () => {
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
@ -12,11 +12,7 @@ export const EventHistoryPage = () => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={hasAccess(ADMIN)}
|
condition={hasAccess(ADMIN)}
|
||||||
show={<EventHistory />}
|
show={<EventHistory />}
|
||||||
elseShow={
|
elseShow={<AdminAlert />}
|
||||||
<Alert severity="error">
|
|
||||||
You need instance admin to access this section.
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,7 @@ export const UPDATE_ADDON = 'UPDATE_ADDON';
|
|||||||
export const DELETE_ADDON = 'DELETE_ADDON';
|
export const DELETE_ADDON = 'DELETE_ADDON';
|
||||||
export const CREATE_API_TOKEN = 'CREATE_API_TOKEN';
|
export const CREATE_API_TOKEN = 'CREATE_API_TOKEN';
|
||||||
export const DELETE_API_TOKEN = 'DELETE_API_TOKEN';
|
export const DELETE_API_TOKEN = 'DELETE_API_TOKEN';
|
||||||
|
export const READ_API_TOKEN = 'READ_API_TOKEN';
|
||||||
export const DELETE_ENVIRONMENT = 'DELETE_ENVIRONMENT';
|
export const DELETE_ENVIRONMENT = 'DELETE_ENVIRONMENT';
|
||||||
export const UPDATE_ENVIRONMENT = 'UPDATE_ENVIRONMENT';
|
export const UPDATE_ENVIRONMENT = 'UPDATE_ENVIRONMENT';
|
||||||
export const CREATE_FEATURE_STRATEGY = 'CREATE_FEATURE_STRATEGY';
|
export const CREATE_FEATURE_STRATEGY = 'CREATE_FEATURE_STRATEGY';
|
||||||
|
Loading…
Reference in New Issue
Block a user