feat: create blacklist page
This commit is contained in:
parent
8a9de5d185
commit
fd6f1a2fe0
9 changed files with 446 additions and 14 deletions
|
|
@ -1,22 +1,52 @@
|
||||||
const db = require('./db')
|
const db = require('./db')
|
||||||
|
|
||||||
function blocked (address, cryptoCode) {
|
// Get all blacklist rows from the DB "blacklist" table
|
||||||
const sql = `select * from blacklist where address = $1 and crypto_code = $2`
|
const getBlacklist = () => {
|
||||||
return db.any(sql, [
|
return db.any('select * from blacklist').then(res =>
|
||||||
address,
|
res.map(item => ({
|
||||||
cryptoCode
|
cryptoCode: item.crypto_code,
|
||||||
])
|
address: item.address,
|
||||||
|
createdByOperator: item.created_by_operator
|
||||||
|
}))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToUsedAddresses (address, cryptoCode) {
|
// Delete row from blacklist table by crypto code and address
|
||||||
|
const deleteFromBlacklist = (cryptoCode, address) => {
|
||||||
|
return db.none(
|
||||||
|
'delete from blacklist where crypto_code = $1 and address = $2;',
|
||||||
|
[cryptoCode, address]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const insertIntoBlacklist = (cryptoCode, address) => {
|
||||||
|
return db
|
||||||
|
.any(
|
||||||
|
'insert into blacklist(crypto_code, address, created_by_operator) values($1, $2, $3);',
|
||||||
|
[cryptoCode, address, true]
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
return { cryptoCode, address }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function blocked(address, cryptoCode) {
|
||||||
|
const sql = `select * from blacklist where address = $1 and crypto_code = $2`
|
||||||
|
return db.any(sql, [address, cryptoCode])
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToUsedAddresses(address, cryptoCode) {
|
||||||
// ETH reuses addresses
|
// ETH reuses addresses
|
||||||
if (cryptoCode === 'ETH') return Promise.resolve()
|
if (cryptoCode === 'ETH') return Promise.resolve()
|
||||||
|
|
||||||
const sql = `insert into blacklist(crypto_code, address, created_by_operator) values ($1, $2, 'f')`
|
const sql = `insert into blacklist(crypto_code, address, created_by_operator) values ($1, $2, 'f')`
|
||||||
return db.oneOrNone(sql, [
|
return db.oneOrNone(sql, [cryptoCode, address])
|
||||||
cryptoCode,
|
|
||||||
address
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { blocked, addToUsedAddresses }
|
module.exports = {
|
||||||
|
blocked,
|
||||||
|
addToUsedAddresses,
|
||||||
|
getBlacklist,
|
||||||
|
deleteFromBlacklist,
|
||||||
|
insertIntoBlacklist
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ const { machineAction } = require('../machines')
|
||||||
const logs = require('../../logs')
|
const logs = require('../../logs')
|
||||||
const settingsLoader = require('../../new-settings-loader')
|
const settingsLoader = require('../../new-settings-loader')
|
||||||
const tokenManager = require('../../token-manager')
|
const tokenManager = require('../../token-manager')
|
||||||
|
const blacklist = require('../../blacklist')
|
||||||
|
|
||||||
const serverVersion = require('../../../package.json').version
|
const serverVersion = require('../../../package.json').version
|
||||||
|
|
||||||
|
|
@ -18,7 +19,13 @@ const funding = require('../funding')
|
||||||
const supervisor = require('../supervisor')
|
const supervisor = require('../supervisor')
|
||||||
const serverLogs = require('../server-logs')
|
const serverLogs = require('../server-logs')
|
||||||
const pairing = require('../pairing')
|
const pairing = require('../pairing')
|
||||||
const { accounts: accountsConfig, coins, countries, currencies, languages } = require('../config')
|
const {
|
||||||
|
accounts: accountsConfig,
|
||||||
|
coins,
|
||||||
|
countries,
|
||||||
|
currencies,
|
||||||
|
languages
|
||||||
|
} = require('../config')
|
||||||
|
|
||||||
const typeDefs = gql`
|
const typeDefs = gql`
|
||||||
scalar JSON
|
scalar JSON
|
||||||
|
|
@ -206,6 +213,12 @@ const typeDefs = gql`
|
||||||
machineName: String
|
machineName: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Blacklist {
|
||||||
|
createdByOperator: Boolean!
|
||||||
|
cryptoCode: String!
|
||||||
|
address: String!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
countries: [Country]
|
countries: [Country]
|
||||||
currencies: [Currency]
|
currencies: [Currency]
|
||||||
|
|
@ -226,6 +239,7 @@ const typeDefs = gql`
|
||||||
transactionsCsv(from: Date, until: Date, limit: Int, offset: Int): String
|
transactionsCsv(from: Date, until: Date, limit: Int, offset: Int): String
|
||||||
accounts: JSONObject
|
accounts: JSONObject
|
||||||
config: JSONObject
|
config: JSONObject
|
||||||
|
blacklist: [Blacklist]
|
||||||
userTokens: [UserToken]
|
userTokens: [UserToken]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,6 +260,8 @@ const typeDefs = gql`
|
||||||
createPairingTotem(name: String!): String
|
createPairingTotem(name: String!): String
|
||||||
saveAccounts(accounts: JSONObject): JSONObject
|
saveAccounts(accounts: JSONObject): JSONObject
|
||||||
revokeToken(token: String!): UserToken
|
revokeToken(token: String!): UserToken
|
||||||
|
deleteBlacklistRow(cryptoCode: String, address: String): Blacklist
|
||||||
|
insertBlacklistRow(cryptoCode: String!, address: String!): Blacklist
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -285,6 +301,7 @@ const resolvers = {
|
||||||
transactions.batch(from, until, limit, offset).then(parseAsync),
|
transactions.batch(from, until, limit, offset).then(parseAsync),
|
||||||
config: () => settingsLoader.loadLatestConfigOrNone(),
|
config: () => settingsLoader.loadLatestConfigOrNone(),
|
||||||
accounts: () => settingsLoader.loadAccounts(),
|
accounts: () => settingsLoader.loadAccounts(),
|
||||||
|
blacklist: () => blacklist.getBlacklist(),
|
||||||
userTokens: () => tokenManager.getTokenList()
|
userTokens: () => tokenManager.getTokenList()
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
|
|
@ -297,6 +314,10 @@ const resolvers = {
|
||||||
notify()
|
notify()
|
||||||
return it
|
return it
|
||||||
}),
|
}),
|
||||||
|
deleteBlacklistRow: (...[, { cryptoCode, address }]) =>
|
||||||
|
blacklist.deleteFromBlacklist(cryptoCode, address),
|
||||||
|
insertBlacklistRow: (...[, { cryptoCode, address }]) =>
|
||||||
|
blacklist.insertIntoBlacklist(cryptoCode, address),
|
||||||
revokeToken: (...[, { token }]) => tokenManager.revokeToken(token)
|
revokeToken: (...[, { token }]) => tokenManager.revokeToken(token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
183
new-lamassu-admin/src/pages/Blacklist/Blacklist.js
Normal file
183
new-lamassu-admin/src/pages/Blacklist/Blacklist.js
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||||
|
import { Box } from '@material-ui/core'
|
||||||
|
import Grid from '@material-ui/core/Grid'
|
||||||
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import * as R from 'ramda'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
|
import Tooltip from 'src/components/Tooltip'
|
||||||
|
import { Link } from 'src/components/buttons'
|
||||||
|
import { Switch } from 'src/components/inputs'
|
||||||
|
import Sidebar from 'src/components/layout/Sidebar'
|
||||||
|
import TitleSection from 'src/components/layout/TitleSection'
|
||||||
|
import { H4, Label2, P } from 'src/components/typography'
|
||||||
|
import { fromNamespace, toNamespace } from 'src/utils/config'
|
||||||
|
|
||||||
|
import styles from './Blacklist.styles'
|
||||||
|
import BlackListModal from './BlacklistModal'
|
||||||
|
import BlacklistTable from './BlacklistTable'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const groupByCode = R.groupBy(obj => obj.cryptoCode)
|
||||||
|
|
||||||
|
const DELETE_ROW = gql`
|
||||||
|
mutation DeleteBlacklistRow($cryptoCode: String!, $address: String!) {
|
||||||
|
deleteBlacklistRow(cryptoCode: $cryptoCode, address: $address) {
|
||||||
|
cryptoCode
|
||||||
|
address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const GET_BLACKLIST = gql`
|
||||||
|
query getBlacklistData {
|
||||||
|
blacklist {
|
||||||
|
cryptoCode
|
||||||
|
address
|
||||||
|
}
|
||||||
|
cryptoCurrencies {
|
||||||
|
display
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const SAVE_CONFIG = gql`
|
||||||
|
mutation Save($config: JSONObject) {
|
||||||
|
saveConfig(config: $config)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const GET_INFO = gql`
|
||||||
|
query getData {
|
||||||
|
config
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const ADD_ROW = gql`
|
||||||
|
mutation InsertBlacklistRow($cryptoCode: String!, $address: String!) {
|
||||||
|
insertBlacklistRow(cryptoCode: $cryptoCode, address: $address) {
|
||||||
|
cryptoCode
|
||||||
|
address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Blacklist = () => {
|
||||||
|
const { data: blacklistResponse } = useQuery(GET_BLACKLIST)
|
||||||
|
const { data: configData } = useQuery(GET_INFO)
|
||||||
|
const [showModal, setShowModal] = useState(false)
|
||||||
|
const [clickedItem, setClickedItem] = useState({
|
||||||
|
code: 'BTC',
|
||||||
|
display: 'Bitcoin'
|
||||||
|
})
|
||||||
|
const [deleteEntry] = useMutation(DELETE_ROW, {
|
||||||
|
onError: () => console.error('Error while deleting row'),
|
||||||
|
refetchQueries: () => ['getBlacklistData']
|
||||||
|
})
|
||||||
|
|
||||||
|
const [addEntry] = useMutation(ADD_ROW, {
|
||||||
|
onError: () => console.error('Error while adding row'),
|
||||||
|
onCompleted: () => setShowModal(false),
|
||||||
|
refetchQueries: () => ['getBlacklistData']
|
||||||
|
})
|
||||||
|
|
||||||
|
const [saveConfig] = useMutation(SAVE_CONFIG, {
|
||||||
|
refetchQueries: () => ['getData']
|
||||||
|
})
|
||||||
|
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const blacklistData = R.path(['blacklist'])(blacklistResponse) ?? []
|
||||||
|
const availableCurrencies =
|
||||||
|
R.path(['cryptoCurrencies'], blacklistResponse) ?? []
|
||||||
|
|
||||||
|
const formattedData = groupByCode(blacklistData)
|
||||||
|
|
||||||
|
const complianceConfig =
|
||||||
|
configData?.config && fromNamespace('compliance')(configData.config)
|
||||||
|
|
||||||
|
const rejectAddressReuse = complianceConfig?.rejectAddressReuse ?? false
|
||||||
|
|
||||||
|
const addressReuseSave = rawConfig => {
|
||||||
|
const config = toNamespace('compliance')(rawConfig)
|
||||||
|
return saveConfig({ variables: { config } })
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClickSidebarItem = e => {
|
||||||
|
setClickedItem({ code: e.code, display: e.display })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteEntry = (cryptoCode, address) => {
|
||||||
|
deleteEntry({ variables: { cryptoCode, address } })
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleModal = () => setShowModal(!showModal)
|
||||||
|
|
||||||
|
const addToBlacklist = (cryptoCode, address) => {
|
||||||
|
addEntry({ variables: { cryptoCode, address } })
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TitleSection title="Blacklisted addresses">
|
||||||
|
<Link onClick={toggleModal}>Blacklist new addresses</Link>
|
||||||
|
</TitleSection>
|
||||||
|
<Grid container className={classes.grid}>
|
||||||
|
<Sidebar
|
||||||
|
data={availableCurrencies}
|
||||||
|
isSelected={R.propEq('code', clickedItem.code)}
|
||||||
|
displayName={it => it.display}
|
||||||
|
onClick={onClickSidebarItem}
|
||||||
|
/>
|
||||||
|
<div className={classes.content}>
|
||||||
|
<Box display="flex" justifyContent="space-between" mb={3}>
|
||||||
|
<H4 noMargin className={classes.subtitle}>
|
||||||
|
{clickedItem.display
|
||||||
|
? `${clickedItem.display} blacklisted addresses`
|
||||||
|
: ''}{' '}
|
||||||
|
</H4>
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="end"
|
||||||
|
mr="-5px">
|
||||||
|
<P>Reject reused addresses</P>
|
||||||
|
<Switch
|
||||||
|
checked={rejectAddressReuse}
|
||||||
|
onChange={event => {
|
||||||
|
addressReuseSave({ rejectAddressReuse: event.target.checked })
|
||||||
|
}}
|
||||||
|
value={rejectAddressReuse}
|
||||||
|
/>
|
||||||
|
<Label2>{rejectAddressReuse ? 'On' : 'Off'}</Label2>
|
||||||
|
<Tooltip width={304}>
|
||||||
|
<P>
|
||||||
|
The "Reject reused addresses" option means that all addresses
|
||||||
|
that are used once will be automatically rejected if there's
|
||||||
|
an attempt to use them again on a new transaction.
|
||||||
|
</P>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<BlacklistTable
|
||||||
|
data={formattedData}
|
||||||
|
selectedCoin={clickedItem}
|
||||||
|
handleDeleteEntry={handleDeleteEntry}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
{showModal && (
|
||||||
|
<BlackListModal
|
||||||
|
onClose={() => setShowModal(false)}
|
||||||
|
selectedCoin={clickedItem}
|
||||||
|
addToBlacklist={addToBlacklist}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Blacklist
|
||||||
39
new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js
Normal file
39
new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { spacer, fontPrimary, primaryColor, white } from 'src/styling/variables'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
grid: {
|
||||||
|
flex: 1,
|
||||||
|
height: '100%'
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flex: 1,
|
||||||
|
marginLeft: spacer * 6
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
margin: [['auto', 0, spacer * 3, 'auto']]
|
||||||
|
},
|
||||||
|
modalTitle: {
|
||||||
|
lineHeight: '120%',
|
||||||
|
color: primaryColor,
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: fontPrimary,
|
||||||
|
fontWeight: 900
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
white: {
|
||||||
|
color: white
|
||||||
|
},
|
||||||
|
deleteButton: {
|
||||||
|
paddingLeft: 13
|
||||||
|
},
|
||||||
|
addressRow: {
|
||||||
|
marginLeft: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
76
new-lamassu-admin/src/pages/Blacklist/BlacklistModal.js
Normal file
76
new-lamassu-admin/src/pages/Blacklist/BlacklistModal.js
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import { Formik, Form, Field } from 'formik'
|
||||||
|
import * as R from 'ramda'
|
||||||
|
import React from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import Modal from 'src/components/Modal'
|
||||||
|
import { Link } from 'src/components/buttons'
|
||||||
|
import { TextInput } from 'src/components/inputs/formik'
|
||||||
|
import { H3 } from 'src/components/typography'
|
||||||
|
|
||||||
|
import styles from './Blacklist.styles'
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const BlackListModal = ({ onClose, selectedCoin, addToBlacklist }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const handleAddToBlacklist = address => {
|
||||||
|
addToBlacklist(selectedCoin.code, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
const placeholderAddress = {
|
||||||
|
BTC: '1ADwinnimZKGgQ3dpyfoUZvJh4p1UWSSpD',
|
||||||
|
ETH: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
|
||||||
|
LTC: 'LPKvbjwV1Kaksktzkr7TMK3FQtQEEe6Wqa',
|
||||||
|
DASH: 'XqQ7gU8eM76rEfey726cJpT2RGKyJyBrcn',
|
||||||
|
ZEC: 't1KGyyv24eL354C9gjveBGEe8Xz9UoPKvHR',
|
||||||
|
BCH: 'qrd6za97wm03lfyg82w0c9vqgc727rhemg5yd9k3dm'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
closeOnBackdropClick={true}
|
||||||
|
width={676}
|
||||||
|
height={200}
|
||||||
|
handleClose={onClose}
|
||||||
|
open={true}>
|
||||||
|
<Formik
|
||||||
|
initialValues={{
|
||||||
|
address: ''
|
||||||
|
}}
|
||||||
|
validationSchema={Yup.object({
|
||||||
|
address: Yup.string()
|
||||||
|
.trim()
|
||||||
|
.required('An address is required')
|
||||||
|
})}
|
||||||
|
onSubmit={({ address }, { resetForm }) => {
|
||||||
|
handleAddToBlacklist(address)
|
||||||
|
resetForm()
|
||||||
|
}}>
|
||||||
|
<Form id="address-form">
|
||||||
|
<H3>
|
||||||
|
{selectedCoin.display
|
||||||
|
? `Blacklist ${R.toLower(selectedCoin.display)} address`
|
||||||
|
: ''}
|
||||||
|
</H3>
|
||||||
|
<Field
|
||||||
|
name="address"
|
||||||
|
fullWidth
|
||||||
|
autoComplete="off"
|
||||||
|
label="Paste new address to blacklist here"
|
||||||
|
placeholder={`ex: ${placeholderAddress[selectedCoin.code]}`}
|
||||||
|
component={TextInput}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
<div className={classes.footer}>
|
||||||
|
<Link type="submit" form="address-form">
|
||||||
|
Blacklist address
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlackListModal
|
||||||
60
new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js
Normal file
60
new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { makeStyles } from '@material-ui/core/styles'
|
||||||
|
import * as R from 'ramda'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { IconButton } from 'src/components/buttons'
|
||||||
|
import DataTable from 'src/components/tables/DataTable'
|
||||||
|
import { Label1 } from 'src/components/typography'
|
||||||
|
import CopyToClipboard from 'src/pages/Transactions/CopyToClipboard'
|
||||||
|
import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg'
|
||||||
|
|
||||||
|
import styles from './Blacklist.styles'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const BlacklistTable = ({ data, selectedCoin, handleDeleteEntry }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const elements = [
|
||||||
|
{
|
||||||
|
name: 'address',
|
||||||
|
header: <Label1 className={classes.white}>{'Addresses'}</Label1>,
|
||||||
|
width: 800,
|
||||||
|
textAlign: 'left',
|
||||||
|
size: 'sm',
|
||||||
|
view: it => (
|
||||||
|
<div className={classes.addressRow}>
|
||||||
|
<CopyToClipboard>{R.path(['address'], it)}</CopyToClipboard>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'deleteButton',
|
||||||
|
header: <Label1 className={classes.white}>{'Delete'}</Label1>,
|
||||||
|
width: 130,
|
||||||
|
textAlign: 'center',
|
||||||
|
size: 'sm',
|
||||||
|
view: it => (
|
||||||
|
<IconButton
|
||||||
|
className={classes.deleteButton}
|
||||||
|
onClick={() =>
|
||||||
|
handleDeleteEntry(
|
||||||
|
R.path(['cryptoCode'], it),
|
||||||
|
R.path(['address'], it)
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const dataToShow = selectedCoin
|
||||||
|
? data[selectedCoin.code]
|
||||||
|
: data[R.keys(data)[0]]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DataTable data={dataToShow} elements={elements} name="blacklistTable" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlacklistTable
|
||||||
3
new-lamassu-admin/src/pages/Blacklist/index.js
Normal file
3
new-lamassu-admin/src/pages/Blacklist/index.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import Blacklist from './Blacklist'
|
||||||
|
|
||||||
|
export default Blacklist
|
||||||
|
|
@ -10,6 +10,7 @@ import {
|
||||||
|
|
||||||
import { AppContext } from 'src/App'
|
import { AppContext } from 'src/App'
|
||||||
import AuthRegister from 'src/pages/AuthRegister'
|
import AuthRegister from 'src/pages/AuthRegister'
|
||||||
|
import Blacklist from 'src/pages/Blacklist'
|
||||||
import Cashout from 'src/pages/Cashout'
|
import Cashout from 'src/pages/Cashout'
|
||||||
import Commissions from 'src/pages/Commissions'
|
import Commissions from 'src/pages/Commissions'
|
||||||
import { Customers, CustomerProfile } from 'src/pages/Customers'
|
import { Customers, CustomerProfile } from 'src/pages/Customers'
|
||||||
|
|
@ -148,6 +149,12 @@ const tree = [
|
||||||
route: '/compliance/customers',
|
route: '/compliance/customers',
|
||||||
component: Customers
|
component: Customers
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'blacklist',
|
||||||
|
label: 'Blacklist',
|
||||||
|
route: '/compliance/blacklist',
|
||||||
|
component: Blacklist
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'customer',
|
key: 'customer',
|
||||||
route: '/compliance/customer/:id',
|
route: '/compliance/customer/:id',
|
||||||
|
|
|
||||||
13
new-lamassu-admin/src/styling/icons/menu/search-zodiac.svg
Normal file
13
new-lamassu-admin/src/styling/icons/menu/search-zodiac.svg
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="nav-/-primary-/-1440" transform="translate(-1239.000000, -19.000000)" stroke="#1B2559" stroke-width="2">
|
||||||
|
<g id="icon/menu/search" transform="translate(1240.000000, 20.000000)">
|
||||||
|
<path d="M12.3100952,6.15542857 C12.3100952,9.55504762 9.55428571,12.3108571 6.15466667,12.3108571 C2.75580952,12.3108571 -2.72670775e-13,9.55504762 -2.72670775e-13,6.15542857 C-2.72670775e-13,2.75580952 2.75580952,8.08242362e-14 6.15466667,8.08242362e-14 C9.55428571,8.08242362e-14 12.3100952,2.75580952 12.3100952,6.15542857 Z" id="Stroke-1"></path>
|
||||||
|
<line x1="10.5820952" y1="10.5829333" x2="15.2068571" y2="15.2076952" id="Stroke-3" stroke-linecap="round"></line>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
Loading…
Add table
Add a link
Reference in a new issue