2021-01-05 04:49:45 +03:00
import React , { useState , useEffect } from "react" ;
2021-01-06 03:51:57 +03:00
import { Table , Tag , Space , Button , Modal , Checkbox , Input , Typography , Tooltip } from 'antd' ;
2021-01-05 04:49:45 +03:00
import { DeleteOutlined , EyeTwoTone , EyeInvisibleOutlined } from '@ant-design/icons' ;
const { Title , Paragraph , Text } = Typography ;
import format from 'date-fns/format'
import {
fetchData ,
ACCESS_TOKENS ,
DELETE_ACCESS_TOKEN ,
CREATE_ACCESS_TOKEN ,
} from "../utils/apis" ;
2021-01-06 03:51:57 +03:00
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' } ,
2021-01-19 04:00:28 +03:00
'HAS_ADMIN_ACCESS' : { name : 'Has admin access' , description : 'Can perform administrative actions such as moderation, get server statuses, etc' , color : 'red' } ,
2021-01-05 22:29:45 +03:00
} ;
2021-01-06 03:51:57 +03:00
function convertScopeStringToTag ( scopeString ) {
if ( ! scopeString || ! availableScopes [ scopeString ] ) {
return null ;
2021-01-05 22:29:45 +03:00
}
2021-01-06 03:51:57 +03:00
const scope = availableScopes [ scopeString ] ;
return (
< Tooltip key = { scopeString } title = { scope . description } >
< Tag color = { scope . color } >
{ scope . name }
< / Tag >
< / Tooltip >
) ;
2021-01-05 22:29:45 +03:00
}
function NewTokenModal ( props ) {
2021-01-17 22:11:58 +03:00
const [ selectedScopes , setSelectedScopes ] = useState ( [ ] ) ;
2021-01-21 09:05:16 +03:00
const [ name , setName ] = useState ( '' ) ;
2021-01-06 03:51:57 +03:00
const scopes = Object . keys ( availableScopes ) . map ( function ( key ) {
return { value : key , label : availableScopes [ key ] . description }
} ) ;
2021-01-05 22:29:45 +03:00
function onChange ( checkedValues ) {
2021-01-17 22:11:58 +03:00
setSelectedScopes ( checkedValues ) ;
2021-01-05 22:29:45 +03:00
}
function saveToken() {
2021-01-21 09:05:16 +03:00
props . onOk ( name , selectedScopes ) ;
2021-01-05 22:29:45 +03:00
2021-01-21 09:05:16 +03:00
// Clear the modal
setSelectedScopes ( [ ] ) ;
setName ( '' ) ;
}
2021-01-05 22:29:45 +03:00
2021-01-17 22:11:58 +03:00
const okButtonProps = {
disabled : selectedScopes.length === 0 || name === ''
} ;
2021-01-21 09:05:16 +03:00
function selectAll() {
setSelectedScopes ( Object . keys ( availableScopes ) ) ;
}
2021-01-05 22:29:45 +03:00
return (
2021-01-17 22:11:58 +03:00
< Modal title = "Create New Access token" visible = { props . visible } onOk = { saveToken } onCancel = { props . onCancel } okButtonProps = { okButtonProps } >
2021-01-05 22:29:45 +03:00
< 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 >
2021-01-21 09:05:16 +03:00
< Checkbox.Group options = { scopes } value = { selectedScopes } onChange = { onChange } / >
< Button onClick = { selectAll } > Select all < / Button >
2021-01-05 22:29:45 +03:00
< / Modal >
)
}
export default function AccessTokens() {
const [ tokens , setTokens ] = useState ( [ ] ) ;
const [ isTokenModalVisible , setIsTokenModalVisible ] = useState ( false ) ;
2021-01-05 04:49:45 +03:00
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 ) = > (
2021-01-21 09:05:16 +03:00
< Input.Password size = "small" bordered = { false } value = { text } / >
2021-01-05 04:49:45 +03:00
)
} ,
{
title : 'Scopes' ,
dataIndex : 'scopes' ,
key : 'scopes' ,
render : scopes = > (
< >
{ scopes . map ( scope = > {
2021-01-06 03:51:57 +03:00
return convertScopeStringToTag ( scope ) ;
2021-01-05 04:49:45 +03:00
} ) }
< / >
) ,
} ,
{
title : 'Last Used' ,
dataIndex : 'lastUsed' ,
key : 'lastUsed' ,
2021-01-05 23:49:19 +03:00
render : ( lastUsed ) = > {
if ( ! lastUsed ) {
return 'Never' ;
}
const dateObject = new Date ( lastUsed ) ;
2021-01-05 04:49:45 +03:00
return format ( dateObject , 'P p' ) ;
} ,
} ,
] ;
const getAccessTokens = async ( ) = > {
try {
const result = await fetchData ( ACCESS_TOKENS ) ;
setTokens ( result ) ;
} catch ( error ) {
handleError ( error ) ;
}
} ;
useEffect ( ( ) = > {
getAccessTokens ( ) ;
2021-01-06 03:43:33 +03:00
} , [ ] ) ;
2021-01-05 04:49:45 +03:00
async function handleDeleteToken ( token ) {
try {
const result = await fetchData ( DELETE_ACCESS_TOKEN , { method : 'POST' , data : { token : token } } ) ;
getAccessTokens ( ) ;
} catch ( error ) {
handleError ( error ) ;
}
}
async function handleSaveToken ( name : string , scopes : string [ ] ) {
try {
2021-01-05 23:49:19 +03:00
const newToken = await fetchData ( CREATE_ACCESS_TOKEN , { method : 'POST' , data : { name : name , scopes : scopes } } ) ;
2021-01-06 03:43:33 +03:00
setTokens ( tokens . concat ( newToken ) ) ;
2021-01-05 04:49:45 +03:00
} catch ( error ) {
handleError ( error ) ;
}
}
function handleError ( error ) {
console . error ( "error" , error ) ;
alert ( error ) ;
}
const showCreateTokenModal = ( ) = > {
setIsTokenModalVisible ( true ) ;
} ;
const handleTokenModalSaveButton = ( name , scopes ) = > {
setIsTokenModalVisible ( false ) ;
handleSaveToken ( name , scopes ) ;
} ;
const handleTokenModalCancel = ( ) = > {
setIsTokenModalVisible ( false ) ;
} ;
return (
< div >
< Title > Access Tokens < / Title >
< Paragraph >
Access tokens are used to allow external , 3 rd 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 >
2021-01-19 06:13:04 +03:00
Read more about how to use these tokens , with examples , at < a href = "https://owncast.online/docs/integrations/" > our documentation < / a > .
2021-01-05 04:49:45 +03:00
< / Paragraph >
< Table rowKey = "token" columns = { columns } dataSource = { tokens } pagination = { false } / >
< Button onClick = { showCreateTokenModal } > Create Access Token < / Button >
< NewTokenModal visible = { isTokenModalVisible } onOk = { handleTokenModalSaveButton } onCancel = { handleTokenModalCancel } / >
< / div >
) ;
}