Make access token and webhooks buttons look correct

This commit is contained in:
Gabe Kangas
2021-02-10 00:17:16 -08:00
parent 64b41c4a57
commit 8484baac28
2 changed files with 366 additions and 299 deletions

View File

@@ -1,196 +1,228 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect } from 'react';
import { Table, Tag, Space, Button, Modal, Checkbox, Input, Typography, Tooltip } from 'antd';
import { DeleteOutlined, EyeTwoTone, EyeInvisibleOutlined } from '@ant-design/icons';
const { Title, Paragraph, Text } = Typography;
import format from 'date-fns/format'
import format from 'date-fns/format';
import {
fetchData,
ACCESS_TOKENS,
DELETE_ACCESS_TOKEN,
CREATE_ACCESS_TOKEN,
} from "../utils/apis";
import { fetchData, ACCESS_TOKENS, DELETE_ACCESS_TOKEN, CREATE_ACCESS_TOKEN } from '../utils/apis';
const availableScopes = {
'CAN_SEND_SYSTEM_MESSAGES': { name: 'System messages', description: 'You can send official messages on behalf of the system', color: 'purple' },
'CAN_SEND_MESSAGES': { name: 'User chat messages', description: 'You can send messages on behalf of a username', color: 'green' },
'HAS_ADMIN_ACCESS': { name: 'Has admin access', description: 'Can perform administrative actions such as moderation, get server statuses, etc', color: 'red' },
CAN_SEND_SYSTEM_MESSAGES: {
name: 'System messages',
description: 'You can send official messages on behalf of the system',
color: 'purple',
},
CAN_SEND_MESSAGES: {
name: 'User chat messages',
description: 'You can send messages on behalf of a username',
color: 'green',
},
HAS_ADMIN_ACCESS: {
name: 'Has admin access',
description: 'Can perform administrative actions such as moderation, get server statuses, etc',
color: 'red',
},
};
function convertScopeStringToTag(scopeString) {
if (!scopeString || !availableScopes[scopeString]) {
return null;
}
if (!scopeString || !availableScopes[scopeString]) {
return null;
}
const scope = availableScopes[scopeString];
const scope = availableScopes[scopeString];
return (
<Tooltip key={scopeString} title={scope.description}>
<Tag color={scope.color} >
{scope.name}
</Tag>
</Tooltip>
);
return (
<Tooltip key={scopeString} title={scope.description}>
<Tag color={scope.color}>{scope.name}</Tag>
</Tooltip>
);
}
function NewTokenModal(props) {
const [selectedScopes, setSelectedScopes] = useState([]);
const [name, setName] = useState('');
const [selectedScopes, setSelectedScopes] = useState([]);
const [name, setName] = useState('');
const scopes = Object.keys(availableScopes).map(function (key) {
return { value: key, label: availableScopes[key].description }
});
const scopes = Object.keys(availableScopes).map(function (key) {
return { value: key, label: availableScopes[key].description };
});
function onChange(checkedValues) {
setSelectedScopes(checkedValues);
}
function onChange(checkedValues) {
setSelectedScopes(checkedValues);
}
function saveToken() {
props.onOk(name, selectedScopes);
function saveToken() {
props.onOk(name, selectedScopes);
// Clear the modal
setSelectedScopes([]);
setName('');
}
// Clear the modal
setSelectedScopes([]);
setName('');
}
const okButtonProps = {
disabled: selectedScopes.length === 0 || name === ''
};
const okButtonProps = {
disabled: selectedScopes.length === 0 || name === '',
};
function selectAll() {
setSelectedScopes(Object.keys(availableScopes));
}
function selectAll() {
setSelectedScopes(Object.keys(availableScopes));
}
return (
<Modal title="Create New Access token" visible={props.visible} onOk={saveToken} onCancel={props.onCancel} okButtonProps={okButtonProps}>
<p><Input value={name} placeholder="Access token name/description" onChange={(input) => setName(input.currentTarget.value)} /></p>
return (
<Modal
title="Create New Access token"
visible={props.visible}
onOk={saveToken}
onCancel={props.onCancel}
okButtonProps={okButtonProps}
>
<p>
<Input
value={name}
placeholder="Access token name/description"
onChange={input => setName(input.currentTarget.value)}
/>
</p>
<p>
Select the permissions this access token will have. It cannot be edited after it's created.
</p>
<Checkbox.Group options={scopes} value={selectedScopes} onChange={onChange} />
<Button onClick={selectAll}>Select all</Button>
</Modal>
)
<p>
Select the permissions this access token will have. It cannot be edited after it's created.
</p>
<Checkbox.Group options={scopes} value={selectedScopes} onChange={onChange} />
<Button type="text" size="small" onClick={selectAll}>
Select all
</Button>
</Modal>
);
}
export default function AccessTokens() {
const [tokens, setTokens] = useState([]);
const [isTokenModalVisible, setIsTokenModalVisible] = useState(false);
const [tokens, setTokens] = useState([]);
const [isTokenModalVisible, setIsTokenModalVisible] = useState(false);
const columns = [
{
title: '',
key: 'delete',
render: (text, record) => (
<Space size="middle">
<Button onClick={() => handleDeleteToken(record.token)} icon={<DeleteOutlined />} />
</Space>
)
},
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Token',
dataIndex: 'token',
key: 'token',
render: (text, record) => (
<Input.Password size="small" bordered={false} value={text} />
)
},
{
title: 'Scopes',
dataIndex: 'scopes',
key: 'scopes',
render: scopes => (
<>
{scopes.map(scope => {
return convertScopeStringToTag(scope);
})}
</>
),
},
{
title: 'Last Used',
dataIndex: 'lastUsed',
key: 'lastUsed',
render: (lastUsed) => {
if (!lastUsed) {
return 'Never';
}
const dateObject = new Date(lastUsed);
return format(dateObject, 'P p');
},
},
];
const getAccessTokens = async () => {
try {
const result = await fetchData(ACCESS_TOKENS);
setTokens(result);
} catch (error) {
handleError(error);
const columns = [
{
title: '',
key: 'delete',
render: (text, record) => (
<Space size="middle">
<Button onClick={() => handleDeleteToken(record.token)} icon={<DeleteOutlined />} />
</Space>
),
},
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Token',
dataIndex: 'token',
key: 'token',
render: (text, record) => <Input.Password size="small" bordered={false} value={text} />,
},
{
title: 'Scopes',
dataIndex: 'scopes',
key: 'scopes',
render: scopes => (
<>
{scopes.map(scope => {
return convertScopeStringToTag(scope);
})}
</>
),
},
{
title: 'Last Used',
dataIndex: 'lastUsed',
key: 'lastUsed',
render: lastUsed => {
if (!lastUsed) {
return 'Never';
}
};
const dateObject = new Date(lastUsed);
return format(dateObject, 'P p');
},
},
];
useEffect(() => {
getAccessTokens();
}, []);
async function handleDeleteToken(token) {
try {
const result = await fetchData(DELETE_ACCESS_TOKEN, { method: 'POST', data: { token: token } });
getAccessTokens();
} catch (error) {
handleError(error);
}
const getAccessTokens = async () => {
try {
const result = await fetchData(ACCESS_TOKENS);
setTokens(result);
} catch (error) {
handleError(error);
}
};
async function handleSaveToken(name: string, scopes: string[]) {
try {
const newToken = await fetchData(CREATE_ACCESS_TOKEN, { method: 'POST', data: { name: name, scopes: scopes } });
setTokens(tokens.concat(newToken));
} catch (error) {
handleError(error);
}
useEffect(() => {
getAccessTokens();
}, []);
async function handleDeleteToken(token) {
try {
const result = await fetchData(DELETE_ACCESS_TOKEN, {
method: 'POST',
data: { token: token },
});
getAccessTokens();
} catch (error) {
handleError(error);
}
}
function handleError(error) {
console.error("error", error);
alert(error);
async function handleSaveToken(name: string, scopes: string[]) {
try {
const newToken = await fetchData(CREATE_ACCESS_TOKEN, {
method: 'POST',
data: { name: name, scopes: scopes },
});
setTokens(tokens.concat(newToken));
} catch (error) {
handleError(error);
}
}
const showCreateTokenModal = () => {
setIsTokenModalVisible(true);
};
function handleError(error) {
console.error('error', error);
alert(error);
}
const handleTokenModalSaveButton = (name, scopes) => {
setIsTokenModalVisible(false);
handleSaveToken(name, scopes);
};
const showCreateTokenModal = () => {
setIsTokenModalVisible(true);
};
const handleTokenModalCancel = () => {
setIsTokenModalVisible(false);
};
const handleTokenModalSaveButton = (name, scopes) => {
setIsTokenModalVisible(false);
handleSaveToken(name, scopes);
};
return (
<div>
<Title>Access Tokens</Title>
<Paragraph>
Access tokens are used to allow external, 3rd party tools to perform specific actions on your Owncast server.
They should be kept secure and never included in client code, instead they should be kept on a server that you control.
</Paragraph>
<Paragraph>
Read more about how to use these tokens, with examples, at <a href="https://owncast.online/docs/integrations/">our documentation</a>.
</Paragraph>
const handleTokenModalCancel = () => {
setIsTokenModalVisible(false);
};
<Table rowKey="token" columns={columns} dataSource={tokens} pagination={false} />
<Button onClick={showCreateTokenModal}>Create Access Token</Button>
<NewTokenModal visible={isTokenModalVisible} onOk={handleTokenModalSaveButton} onCancel={handleTokenModalCancel} />
</div>
);
return (
<div>
<Title>Access Tokens</Title>
<Paragraph>
Access tokens are used to allow external, 3rd party tools to perform specific actions on
your Owncast server. They should be kept secure and never included in client code, instead
they should be kept on a server that you control.
</Paragraph>
<Paragraph>
Read more about how to use these tokens, with examples, at{' '}
<a href="https://owncast.online/docs/integrations/">our documentation</a>.
</Paragraph>
<Table rowKey="token" columns={columns} dataSource={tokens} pagination={false} />
<br />
<Button type="primary" onClick={showCreateTokenModal}>
Create Access Token
</Button>
<NewTokenModal
visible={isTokenModalVisible}
onOk={handleTokenModalSaveButton}
onCancel={handleTokenModalCancel}
/>
</div>
);
}