commit
e5e1688bb4
5 changed files with 112 additions and 47 deletions
|
|
@ -1,29 +1,29 @@
|
|||
.root {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
&:hover .copyButton {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.scroller {
|
||||
overflow-y: auto;
|
||||
border-radius: 2px;
|
||||
padding: 12px 60px 12px 20px;
|
||||
|
||||
&--maxHeight {
|
||||
max-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
.scroller_max-height {
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.root .button {
|
||||
.copyIcon,
|
||||
.copyButton {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.root:hover .button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.root pre {
|
||||
border-radius: 2px;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
.copyButton {
|
||||
opacity: 0;
|
||||
}
|
||||
|
|
@ -1,41 +1,47 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import { Button } from '@grafana/ui';
|
||||
import { Button, Icon, IconButton } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
import { openNotification } from 'utils';
|
||||
|
||||
import styles from './SourceCode.module.css';
|
||||
import styles from './SourceCode.module.scss';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
interface SourceCodeProps {
|
||||
noMaxHeight?: boolean;
|
||||
showClipboardIconOnly?: boolean;
|
||||
showCopyToClipboard?: boolean;
|
||||
children?: any
|
||||
children?: any;
|
||||
}
|
||||
|
||||
const SourceCode: FC<SourceCodeProps> = (props) => {
|
||||
const { children, noMaxHeight = false, showCopyToClipboard = true } = props;
|
||||
const { children, noMaxHeight = false, showClipboardIconOnly = false, showCopyToClipboard = true } = props;
|
||||
const showClipboardCopy = showClipboardIconOnly || showCopyToClipboard;
|
||||
|
||||
return (
|
||||
<div className={cx('root')}>
|
||||
{showCopyToClipboard && (
|
||||
{showClipboardCopy && (
|
||||
<CopyToClipboard
|
||||
text={children as string}
|
||||
onCopy={() => {
|
||||
openNotification('Copied!');
|
||||
}}
|
||||
>
|
||||
<Button className={cx('button')} variant="primary" icon="copy">
|
||||
Copy
|
||||
</Button>
|
||||
{showClipboardIconOnly ? (
|
||||
<IconButton className={cx('copyIcon')} size={'lg'} name="copy" />
|
||||
) : (
|
||||
<Button className={cx('copyButton')} variant="primary" size="xs" icon="copy">
|
||||
Copy
|
||||
</Button>
|
||||
)}
|
||||
</CopyToClipboard>
|
||||
)}
|
||||
<pre
|
||||
className={cx('scroller', {
|
||||
'scroller_max-height': !noMaxHeight,
|
||||
'scroller--maxHeight': !noMaxHeight,
|
||||
})}
|
||||
>
|
||||
<code>{children}</code>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
.token__inputContainer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.token__input {
|
||||
flex-grow: 1;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.token__copyButton {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
|
@ -1,13 +1,20 @@
|
|||
import React, { useCallback, HTMLAttributes, useState } from 'react';
|
||||
|
||||
import { Button, Field, HorizontalGroup, Input, Modal, VerticalGroup } from '@grafana/ui';
|
||||
import { Button, HorizontalGroup, Input, Label, Modal, VerticalGroup } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { get } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||
|
||||
import SourceCode from 'components/SourceCode/SourceCode';
|
||||
import { ApiToken } from 'models/api_token/api_token.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openErrorNotification, openNotification } from 'utils';
|
||||
import { getItem } from 'utils/localStorage';
|
||||
|
||||
import styles from './ApiTokenForm.module.css';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
interface TokenCreationModalProps extends HTMLAttributes<HTMLElement> {
|
||||
visible: boolean;
|
||||
|
|
@ -16,7 +23,7 @@ interface TokenCreationModalProps extends HTMLAttributes<HTMLElement> {
|
|||
}
|
||||
|
||||
const ApiTokenForm = observer((props: TokenCreationModalProps) => {
|
||||
const { visible, onHide = () => {}, onUpdate = () => {} } = props;
|
||||
const { onHide = () => {}, onUpdate = () => {} } = props;
|
||||
const [name, setName] = useState('');
|
||||
const [token, setToken] = useState('');
|
||||
|
||||
|
|
@ -39,30 +46,68 @@ const ApiTokenForm = observer((props: TokenCreationModalProps) => {
|
|||
return (
|
||||
<Modal isOpen closeOnEscape={false} title={token ? 'Your new API Token' : 'Create API Token'} onDismiss={onHide}>
|
||||
<VerticalGroup>
|
||||
<Input maxLength={50} onChange={handleNameChange} autoFocus placeholder="Enter token name" />
|
||||
{token && (
|
||||
<>
|
||||
<Input value={token} disabled />
|
||||
</>
|
||||
)}
|
||||
<HorizontalGroup>
|
||||
{token && (
|
||||
<CopyToClipboard
|
||||
text={token}
|
||||
onCopy={() => {
|
||||
openNotification('Token copied');
|
||||
}}
|
||||
>
|
||||
<Button>Copy Token</Button>
|
||||
</CopyToClipboard>
|
||||
)}
|
||||
<Button disabled={!!token || !name} variant="primary" onClick={onCreateTokenCallback}>
|
||||
Create
|
||||
<Label>Token Name</Label>
|
||||
<div className={cx('token__inputContainer')}>
|
||||
{renderTokenInput()}
|
||||
{renderCopyToClipboard()}
|
||||
</div>
|
||||
|
||||
{renderCurlExample()}
|
||||
|
||||
<HorizontalGroup justify="flex-end">
|
||||
<Button variant="secondary" onClick={() => onHide()}>
|
||||
{token ? 'Close' : 'Cancel'}
|
||||
</Button>
|
||||
{!token && (
|
||||
<Button disabled={!!token || !name} variant="primary" onClick={onCreateTokenCallback}>
|
||||
Create Token
|
||||
</Button>
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
</VerticalGroup>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
function renderTokenInput() {
|
||||
return token ? (
|
||||
<Input value={token} disabled={!!token} className={cx('token__input')} />
|
||||
) : (
|
||||
<Input
|
||||
className={cx('token__input')}
|
||||
maxLength={50}
|
||||
onChange={handleNameChange}
|
||||
placeholder="Enter token name"
|
||||
autoFocus
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function renderCopyToClipboard() {
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<CopyToClipboard text={token} onCopy={() => openNotification('Token copied')}>
|
||||
<Button className={cx('token__copyButton')}>Copy Token</Button>
|
||||
</CopyToClipboard>
|
||||
);
|
||||
}
|
||||
|
||||
function renderCurlExample() {
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<VerticalGroup>
|
||||
<Label>Curl command example</Label>
|
||||
<SourceCode showClipboardIconOnly>{getCurlExample(token)}</SourceCode>
|
||||
</VerticalGroup>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function getCurlExample(token) {
|
||||
return `curl -H "Authorization: ${token}" ${getItem('onCallApiUrl')}/api/internal/v1/alert_receive_channels`;
|
||||
}
|
||||
|
||||
export default ApiTokenForm;
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ class ApiTokens extends React.Component<ApiTokensProps, any> {
|
|||
|
||||
const apiTokens = apiTokenStore.getSearchResult();
|
||||
|
||||
const loading = !apiTokens;
|
||||
|
||||
const { showCreateTokenModal } = this.state;
|
||||
|
||||
const columns = [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue