feat: add services page
fix: change styles, fix hook trigger, add ux feat: setup custom error messages refactor: conform to new style guide refactor: migrate to graphql refactor: migrate to Ramda fix: update state on mutation refactor: migrate error ux to graphql fix: change structure of accounts config fix: use absolute imports fix: move makeStyles out of components fix: correct Strike behaviour
This commit is contained in:
parent
1dba321052
commit
b9d2341cd1
30 changed files with 2579 additions and 306 deletions
0
bin/insecure-dev.sh
Normal file → Executable file
0
bin/insecure-dev.sh
Normal file → Executable file
124
lib/new-admin/accounts.js
Normal file
124
lib/new-admin/accounts.js
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
|
const db = require('../db')
|
||||||
|
const config = require('./config')
|
||||||
|
const ph = require('../plugin-helper')
|
||||||
|
|
||||||
|
const schemas = ph.loadSchemas()
|
||||||
|
|
||||||
|
function fetchAccounts () {
|
||||||
|
return db.oneOrNone('select data from user_config where type=$1', ['accounts'])
|
||||||
|
.then(row => {
|
||||||
|
// Hard code this for now
|
||||||
|
const accounts = [{
|
||||||
|
code: 'blockcypher',
|
||||||
|
display: 'Blockcypher',
|
||||||
|
fields: [
|
||||||
|
{ code: 'confidenceFactor', display: 'Confidence Factor', fieldType: 'integer', required: true, value: 40 }
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
|
||||||
|
return row
|
||||||
|
? Promise.resolve(row.data.accounts)
|
||||||
|
: db.none('insert into user_config (type, data, valid) values ($1, $2, $3)', ['accounts', { accounts }, true])
|
||||||
|
.then(fetchAccounts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectedAccounts () {
|
||||||
|
const mapAccount = v => v.fieldLocator.fieldType === 'account' &&
|
||||||
|
v.fieldValue.value
|
||||||
|
|
||||||
|
const mapSchema = code => schemas[code]
|
||||||
|
return config.fetchConfig()
|
||||||
|
.then(conf => {
|
||||||
|
const accountCodes = _.uniq(conf.map(mapAccount)
|
||||||
|
.filter(_.identity))
|
||||||
|
|
||||||
|
return _.sortBy(_.get('display'), accountCodes.map(mapSchema)
|
||||||
|
.filter(_.identity))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchAccountSchema (account) {
|
||||||
|
return schemas[account]
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeAccount (oldAccount, newAccount) {
|
||||||
|
if (!newAccount) return oldAccount
|
||||||
|
|
||||||
|
const newFields = newAccount.fields
|
||||||
|
|
||||||
|
const updateWithData = oldField => {
|
||||||
|
const newField = _.find(r => r.code === oldField.code, newFields)
|
||||||
|
const newValue = _.isUndefined(newField) ? oldField.value : newField.value
|
||||||
|
return _.set('value', newValue, oldField)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedFields = oldAccount.fields.map(updateWithData)
|
||||||
|
|
||||||
|
return _.set('fields', updatedFields, oldAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccounts (accountCode) {
|
||||||
|
const schema = fetchAccountSchema(accountCode)
|
||||||
|
if (!schema) return Promise.reject(new Error('No schema for: ' + accountCode))
|
||||||
|
|
||||||
|
return fetchAccounts()
|
||||||
|
.then(accounts => {
|
||||||
|
if (_.isEmpty(accounts)) return [schema]
|
||||||
|
const account = _.find(r => r.code === accountCode, accounts)
|
||||||
|
const mergedAccount = mergeAccount(schema, account)
|
||||||
|
|
||||||
|
return updateAccounts(mergedAccount, accounts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function elideSecrets (account) {
|
||||||
|
const elideSecret = field => {
|
||||||
|
return field.fieldType === 'password'
|
||||||
|
? _.set('value', !_.isEmpty(field.value), field)
|
||||||
|
: field
|
||||||
|
}
|
||||||
|
|
||||||
|
return _.set('fields', account.fields.map(elideSecret), account)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAccount (accountCode) {
|
||||||
|
return getAccounts(accountCode)
|
||||||
|
.then(accounts => _.find(r => r.code === accountCode, accounts))
|
||||||
|
.then(elideSecrets)
|
||||||
|
}
|
||||||
|
|
||||||
|
function save (accounts) {
|
||||||
|
return db.none('update user_config set data=$1 where type=$2', [{ accounts: accounts }, 'accounts'])
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAccounts (newAccount, accounts) {
|
||||||
|
const accountCode = newAccount.code
|
||||||
|
const isPresent = _.some(_.matchesProperty('code', accountCode), accounts)
|
||||||
|
const updateAccount = r => r.code === accountCode
|
||||||
|
? newAccount
|
||||||
|
: r
|
||||||
|
|
||||||
|
return isPresent
|
||||||
|
? _.map(updateAccount, accounts)
|
||||||
|
: _.concat(accounts, newAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAccount (account) {
|
||||||
|
return getAccounts(account.code)
|
||||||
|
.then(accounts => {
|
||||||
|
const merged = mergeAccount(_.find(_.matchesProperty('code', account.code), accounts), account)
|
||||||
|
return save(updateAccounts(merged, accounts))
|
||||||
|
})
|
||||||
|
.then(() => getAccount(account.code))
|
||||||
|
.catch((err) => console.log(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
selectedAccounts,
|
||||||
|
getAccount,
|
||||||
|
updateAccount,
|
||||||
|
fetchAccounts
|
||||||
|
}
|
||||||
654
new-lamassu-admin/package-lock.json
generated
654
new-lamassu-admin/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -71,9 +71,9 @@ const Table = ({ children, className, ...props }) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const THead = ({ children }) => {
|
const THead = ({ children, className }) => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
return <div className={classes.header}>{children}</div>
|
return <div className={classnames(className, classes.header)}>{children}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const TBody = ({ children, className }) => {
|
const TBody = ({ children, className }) => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import React, { memo, useState } from 'react'
|
||||||
|
import { makeStyles } from '@material-ui/core'
|
||||||
|
|
||||||
|
import TextInputFormik from './TextInput'
|
||||||
|
import { styles } from './TextInput.styles'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const mask = /(\+9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,2}){0,1}$/
|
||||||
|
const maskValue = value => value.replace(mask, '$1 $2 $3 $4 $5 $6')
|
||||||
|
|
||||||
|
const PhoneNumberInputFormik = memo(({ ...props }) => {
|
||||||
|
const { onChange, value } = props.field
|
||||||
|
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
// Regex adapted from http://phoneregex.com/
|
||||||
|
|
||||||
|
const [maskedValue, setMaskedValue] = useState(maskValue(value))
|
||||||
|
|
||||||
|
const handleChange = event => {
|
||||||
|
setMaskedValue(maskValue(event.target.value))
|
||||||
|
|
||||||
|
onChange(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className={classes.masked} aria-hidden="true">
|
||||||
|
{maskedValue}
|
||||||
|
</span>
|
||||||
|
<TextInputFormik
|
||||||
|
inputProps={{ maxLength: 17 }}
|
||||||
|
className={classes.maskedInput}
|
||||||
|
onChange={handleChange}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export { PhoneNumberInputFormik, mask, maskValue }
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import React, { memo, useState } from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import { makeStyles } from '@material-ui/core'
|
||||||
|
|
||||||
|
import TextInputFormik from './TextInput'
|
||||||
|
import { styles } from './TextInput.styles'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const SecretInputFormik = memo(({ ...props }) => {
|
||||||
|
const { value } = props.field
|
||||||
|
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const [localTouched, setLocalTouched] = useState(false)
|
||||||
|
|
||||||
|
const handleFocus = event => {
|
||||||
|
setLocalTouched(true)
|
||||||
|
props.onFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
const spanClass = {
|
||||||
|
[classes.secretSpan]: true,
|
||||||
|
[classes.masked]: value && !localTouched,
|
||||||
|
[classes.hideSpan]: !value || localTouched
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputClass = {
|
||||||
|
[classes.maskedInput]: value && !localTouched
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className={classnames(spanClass)} aria-hidden="true">
|
||||||
|
⚬ ⚬ ⚬ This field is set ⚬ ⚬ ⚬
|
||||||
|
</span>
|
||||||
|
<TextInputFormik
|
||||||
|
{...props}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
className={classnames(inputClass)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default SecretInputFormik
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { fontColor, offColor } from 'src/styling/variables'
|
||||||
|
import typographyStyles from 'src/components/typography/styles'
|
||||||
|
|
||||||
|
const { info3 } = typographyStyles
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
masked: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 5,
|
||||||
|
color: fontColor
|
||||||
|
},
|
||||||
|
secretSpan: {
|
||||||
|
extend: info3,
|
||||||
|
color: offColor
|
||||||
|
},
|
||||||
|
hideSpan: {
|
||||||
|
display: 'none'
|
||||||
|
},
|
||||||
|
maskedInput: {
|
||||||
|
'& input': {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
zIndex: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { styles }
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
import React from 'react'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import { makeStyles } from '@material-ui/core'
|
||||||
|
|
||||||
|
import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/white.svg'
|
||||||
|
import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg'
|
||||||
|
import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/comet.svg'
|
||||||
|
import {
|
||||||
|
offColor,
|
||||||
|
tableDisabledHeaderColor,
|
||||||
|
tableNewDisabledHeaderColor,
|
||||||
|
secondaryColorDarker
|
||||||
|
} from 'src/styling/variables'
|
||||||
|
import { Table, THead, TBody, Td, Th } from 'src/components/fake-table/Table'
|
||||||
|
import typographyStyles from 'src/components/typography/styles'
|
||||||
|
|
||||||
|
const { label1, p } = typographyStyles
|
||||||
|
|
||||||
|
const SingleRowTable = ({
|
||||||
|
width = 380,
|
||||||
|
height = 160,
|
||||||
|
title,
|
||||||
|
items,
|
||||||
|
onEdit,
|
||||||
|
disabled,
|
||||||
|
newService,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const editButtonSize = 54
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
wrapper: {
|
||||||
|
width: width,
|
||||||
|
boxShadow: '0 0 4px 0 rgba(0, 0, 0, 0.08)'
|
||||||
|
},
|
||||||
|
buttonTh: {
|
||||||
|
padding: [[0, 16]]
|
||||||
|
},
|
||||||
|
disabledHeader: {
|
||||||
|
backgroundColor: tableDisabledHeaderColor,
|
||||||
|
color: offColor
|
||||||
|
},
|
||||||
|
newDisabledHeader: {
|
||||||
|
backgroundColor: tableNewDisabledHeaderColor
|
||||||
|
},
|
||||||
|
disabledBody: {
|
||||||
|
extend: p,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: 104
|
||||||
|
},
|
||||||
|
itemWrapper: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
marginTop: 16,
|
||||||
|
minHeight: 40,
|
||||||
|
'& > div:last-child': {}
|
||||||
|
},
|
||||||
|
disabledWrapper: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
'& > span:first-child': {
|
||||||
|
display: 'flex'
|
||||||
|
},
|
||||||
|
'& > span:last-child': {
|
||||||
|
paddingLeft: 16
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
extend: label1,
|
||||||
|
color: offColor,
|
||||||
|
marginBottom: 4
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
extend: p
|
||||||
|
},
|
||||||
|
editButton: {
|
||||||
|
border: 'none',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'flex',
|
||||||
|
padding: 0
|
||||||
|
},
|
||||||
|
spanNew: {
|
||||||
|
color: secondaryColorDarker,
|
||||||
|
marginLeft: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const headerClasses = {
|
||||||
|
[classes.disabledHeader]: disabled,
|
||||||
|
[classes.newDisabledHeader]: newService && disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
const bodyClasses = {
|
||||||
|
[classes.disabledBody]: disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{items && (
|
||||||
|
<Table className={classnames(className, classes.wrapper)}>
|
||||||
|
<THead className={classnames(headerClasses)}>
|
||||||
|
<Th size={width - editButtonSize}>
|
||||||
|
{title}
|
||||||
|
{newService && <span className={classes.spanNew}>New</span>}
|
||||||
|
</Th>
|
||||||
|
<Th size={editButtonSize} className={classes.buttonTh}>
|
||||||
|
{!disabled && (
|
||||||
|
<button className={classes.editButton} onClick={onEdit}>
|
||||||
|
<EditIcon />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{disabled && (
|
||||||
|
<button className={classes.editButton}>
|
||||||
|
<DeleteIcon />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</Th>
|
||||||
|
</THead>
|
||||||
|
<TBody className={classnames(bodyClasses)}>
|
||||||
|
<Td size={width}>
|
||||||
|
{!disabled && (
|
||||||
|
<>
|
||||||
|
{items[0] && (
|
||||||
|
<div className={classes.itemWrapper}>
|
||||||
|
<div className={classes.label}>{items[0].label}</div>
|
||||||
|
<div className={classes.item}>{items[0].value}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{items[1] && (
|
||||||
|
<div className={classes.itemWrapper}>
|
||||||
|
<div className={classes.label}>{items[1].label}</div>
|
||||||
|
<div className={classes.item}>{items[1].value}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{disabled && (
|
||||||
|
<div className={classes.disabledWrapper}>
|
||||||
|
<span>
|
||||||
|
<WarningIcon />
|
||||||
|
</span>
|
||||||
|
<span>This service is not being used</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Td>
|
||||||
|
</TBody>
|
||||||
|
</Table>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingleRowTable
|
||||||
250
new-lamassu-admin/src/pages/Services/Bitgo.js
Normal file
250
new-lamassu-admin/src/pages/Services/Bitgo.js
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
import SecretInputFormik from 'src/components/inputs/formik/SecretInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux, formatLong } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
token: {
|
||||||
|
code: 'token',
|
||||||
|
display: 'API Token'
|
||||||
|
},
|
||||||
|
btcWalletId: {
|
||||||
|
code: 'BTCWalletId',
|
||||||
|
display: 'BTC Wallet ID'
|
||||||
|
},
|
||||||
|
btcWalletPassphrase: {
|
||||||
|
code: 'BTCWalletPassphrase',
|
||||||
|
display: 'BTC Wallet Passphrase'
|
||||||
|
},
|
||||||
|
ltcWalletId: {
|
||||||
|
code: 'LTCWalletId',
|
||||||
|
display: 'LTC Wallet ID'
|
||||||
|
},
|
||||||
|
ltcWalletPassphrase: {
|
||||||
|
code: 'LTCWalletPassphrase',
|
||||||
|
display: 'LTC Wallet Passphrase'
|
||||||
|
},
|
||||||
|
zecWalletId: {
|
||||||
|
code: 'ZECWalletId',
|
||||||
|
display: 'ZEC Wallet ID'
|
||||||
|
},
|
||||||
|
zecWalletPassphrase: {
|
||||||
|
code: 'ZECWalletPassphrase',
|
||||||
|
display: 'ZEC Wallet Passphrase'
|
||||||
|
},
|
||||||
|
bchWalletId: {
|
||||||
|
code: 'BCHWalletId',
|
||||||
|
display: 'BCH Wallet ID'
|
||||||
|
},
|
||||||
|
bchWalletPassphrase: {
|
||||||
|
code: 'BCHWalletPassphrase',
|
||||||
|
display: 'BCH Wallet Passphrase'
|
||||||
|
},
|
||||||
|
dashWalletId: {
|
||||||
|
code: 'DASHWalletId',
|
||||||
|
display: 'DASH Wallet ID'
|
||||||
|
},
|
||||||
|
dashWalletPassphrase: {
|
||||||
|
code: 'DASHWalletPassphrase',
|
||||||
|
display: 'DASH Wallet Passphrase'
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
code: 'environment',
|
||||||
|
display: 'Environment'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BitgoCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const token = schema.token
|
||||||
|
const tokenValue = getValue(token.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: token.display,
|
||||||
|
value: formatLong(tokenValue)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="BitGo (Wallet)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const BitgoForm = ({ account, handleSubmit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const token = getValue(schema.token.code)
|
||||||
|
const btcWalletId = getValue(schema.btcWalletId.code)
|
||||||
|
const btcWalletPassphrase = getValue(schema.btcWalletPassphrase.code)
|
||||||
|
const ltcWalletId = getValue(schema.ltcWalletId.code)
|
||||||
|
const ltcWalletPassphrase = getValue(schema.ltcWalletPassphrase.code)
|
||||||
|
const zecWalletId = getValue(schema.zecWalletId.code)
|
||||||
|
const zecWalletPassphrase = getValue(schema.zecWalletPassphrase.code)
|
||||||
|
const bchWalletId = getValue(schema.bchWalletId.code)
|
||||||
|
const bchWalletPassphrase = getValue(schema.bchWalletPassphrase.code)
|
||||||
|
const dashWalletId = getValue(schema.dashWalletId.code)
|
||||||
|
const dashWalletPassphrase = getValue(schema.dashWalletPassphrase.code)
|
||||||
|
const environment = getValue(schema.environment.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
token: token,
|
||||||
|
BTCWalletId: btcWalletId,
|
||||||
|
BTCWalletPassphrase: btcWalletPassphrase,
|
||||||
|
LTCWalletId: ltcWalletId,
|
||||||
|
LTCWalletPassphrase: ltcWalletPassphrase,
|
||||||
|
ZECWalletId: zecWalletId,
|
||||||
|
ZECWalletPassphrase: zecWalletPassphrase,
|
||||||
|
BCHWalletId: bchWalletId,
|
||||||
|
BCHWalletPassphrase: bchWalletPassphrase,
|
||||||
|
DASHWalletId: dashWalletId,
|
||||||
|
DASHWalletPassphrase: dashWalletPassphrase,
|
||||||
|
environment: environment
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
token: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
btcWalletId: Yup.string().max(100, 'Too long'),
|
||||||
|
btcWalletPassphrase: Yup.string().max(100, 'Too long'),
|
||||||
|
ltcWalletId: Yup.string().max(100, 'Too long'),
|
||||||
|
ltcWalletPassphrase: Yup.string().max(100, 'Too long'),
|
||||||
|
zecWalletId: Yup.string().max(100, 'Too long'),
|
||||||
|
zecWalletPassphrase: Yup.string().max(100, 'Too long'),
|
||||||
|
bchWalletId: Yup.string().max(100, 'Too long'),
|
||||||
|
bchWalletPassphrase: Yup.string().max(100, 'Too long'),
|
||||||
|
dashWalletId: Yup.string().max(100, 'Too long'),
|
||||||
|
dashWalletPassphrase: Yup.string().max(100, 'Too long'),
|
||||||
|
environment: Yup.string()
|
||||||
|
.matches(/(prod|test)/)
|
||||||
|
.required('Required')
|
||||||
|
}),
|
||||||
|
validate: values => {
|
||||||
|
const errors = {}
|
||||||
|
|
||||||
|
if (values.btcWalletId && !values.btcWalletPassphrase) {
|
||||||
|
errors.btcWalletPassphrase = 'Required'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.ltcWalletId && !values.ltcWalletPassphrase) {
|
||||||
|
errors.ltcWalletPassphrase = 'Required'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.zecWalletId && !values.zecWalletPassphrase) {
|
||||||
|
errors.zecWalletPassphrase = 'Required'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.bchWalletId && !values.bchWalletPassphrase) {
|
||||||
|
errors.bchWalletPassphrase = 'Required'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.dashWalletId && !values.dashWalletPassphrase) {
|
||||||
|
errors.dashWalletPassphrase = 'Required'
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.token.code,
|
||||||
|
label: schema.token.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.btcWalletId.code,
|
||||||
|
label: schema.btcWalletId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.btcWalletPassphrase.code,
|
||||||
|
label: schema.btcWalletPassphrase.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.ltcWalletId.code,
|
||||||
|
label: schema.ltcWalletId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.ltcWalletPassphrase.code,
|
||||||
|
label: schema.ltcWalletPassphrase.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.zecWalletId.code,
|
||||||
|
label: schema.zecWalletId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.zecWalletPassphrase.code,
|
||||||
|
label: schema.zecWalletPassphrase.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.bchWalletId.code,
|
||||||
|
label: schema.bchWalletId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.bchWalletPassphrase.code,
|
||||||
|
label: schema.bchWalletPassphrase.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.dashWalletId.code,
|
||||||
|
label: schema.dashWalletId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.dashWalletPassphrase.code,
|
||||||
|
label: schema.dashWalletPassphrase.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.environment.code,
|
||||||
|
label: schema.environment.display,
|
||||||
|
placeholder: 'prod or test',
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Bitgo"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { BitgoForm, BitgoCard }
|
||||||
116
new-lamassu-admin/src/pages/Services/Bitstamp.js
Normal file
116
new-lamassu-admin/src/pages/Services/Bitstamp.js
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
import SecretInputFormik from 'src/components/inputs/formik/SecretInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux, formatLong } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
clientId: {
|
||||||
|
code: 'clientId',
|
||||||
|
display: 'Client ID'
|
||||||
|
},
|
||||||
|
key: {
|
||||||
|
code: 'key',
|
||||||
|
display: 'API Key'
|
||||||
|
},
|
||||||
|
secret: {
|
||||||
|
code: 'secret',
|
||||||
|
display: 'API Secret'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BitstampCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const findValue = getValueAux(account)
|
||||||
|
|
||||||
|
const clientId = schema.clientId
|
||||||
|
const key = schema.key
|
||||||
|
|
||||||
|
const clientIdValue = findValue(clientId.code)
|
||||||
|
const keyValue = findValue(key.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: clientId.display,
|
||||||
|
value: formatLong(clientIdValue)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: key.display,
|
||||||
|
value: formatLong(keyValue)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="Bitstamp (Exchange)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const BitstampForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const clientId = getValue(schema.clientId.code)
|
||||||
|
const key = getValue(schema.key.code)
|
||||||
|
const secret = getValue(schema.secret.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
clientId: clientId,
|
||||||
|
key: key,
|
||||||
|
secret: secret
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
clientId: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
key: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
secret: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.clientId.code,
|
||||||
|
label: schema.clientId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.key.code,
|
||||||
|
label: schema.key.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.secret.code,
|
||||||
|
label: schema.secret.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Bitstamp"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { BitstampForm, BitstampCard }
|
||||||
101
new-lamassu-admin/src/pages/Services/Blockcypher.js
Normal file
101
new-lamassu-admin/src/pages/Services/Blockcypher.js
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux, formatLong } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
token: {
|
||||||
|
code: 'token',
|
||||||
|
display: 'API Token'
|
||||||
|
},
|
||||||
|
confidenceFactor: {
|
||||||
|
code: 'confidenceFactor',
|
||||||
|
display: 'Confidence Factor'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BlockcypherCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const token = schema.token
|
||||||
|
const confidenceFactor = schema.confidenceFactor
|
||||||
|
|
||||||
|
const tokenValue = getValue(token.code)
|
||||||
|
const confidenceFactorValue = getValue(confidenceFactor.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: token.display,
|
||||||
|
value: formatLong(tokenValue)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: confidenceFactor.display,
|
||||||
|
value: confidenceFactorValue
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="Blockcypher (Payments)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const BlockcypherForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const token = getValue(schema.token.code)
|
||||||
|
const confidenceFactor = getValue(schema.confidenceFactor.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
token: token,
|
||||||
|
confidenceFactor: confidenceFactor
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
token: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
confidenceFactor: Yup.number()
|
||||||
|
.integer('Please input a positive integer')
|
||||||
|
.positive('Please input a positive integer')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.token.code,
|
||||||
|
label: schema.token.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.confidenceFactor.code,
|
||||||
|
label: schema.confidenceFactor.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Blockcypher"
|
||||||
|
code={code}
|
||||||
|
formik={formik}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { BlockcypherForm, BlockcypherCard }
|
||||||
94
new-lamassu-admin/src/pages/Services/EditService.js
Normal file
94
new-lamassu-admin/src/pages/Services/EditService.js
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { Form, Formik, Field } from 'formik'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import { makeStyles, Paper } from '@material-ui/core'
|
||||||
|
|
||||||
|
import { H2, Info3 } from 'src/components/typography'
|
||||||
|
import { Button } from 'src/components/buttons'
|
||||||
|
import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg'
|
||||||
|
import { ReactComponent as ErrorIcon } from 'src/styling/icons/warning-icon/tomato.svg'
|
||||||
|
|
||||||
|
import { editServiceStyles as styles } from './Services.styles'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const DEFAULT_ERROR_MESSAGE = 'Something went wrong. Please contact support.'
|
||||||
|
|
||||||
|
const EditService = ({
|
||||||
|
title,
|
||||||
|
code,
|
||||||
|
formik,
|
||||||
|
fields,
|
||||||
|
handleClose,
|
||||||
|
save,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const [error, setError] = useState(props.error)
|
||||||
|
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
const submitWrapperClasses = {
|
||||||
|
[classes.submitWrapper]: true,
|
||||||
|
[classes.submitError]: error
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<button onClick={() => handleClose()}>
|
||||||
|
<CloseIcon />
|
||||||
|
</button>
|
||||||
|
<div className={classes.modalHeader}>
|
||||||
|
<H2>{`Edit ${title}`}</H2>
|
||||||
|
</div>
|
||||||
|
<div className={classes.modalBody}>
|
||||||
|
<Formik
|
||||||
|
initialValues={formik.initialValues}
|
||||||
|
validate={formik.validate}
|
||||||
|
validationSchema={formik.validationSchema}
|
||||||
|
onSubmit={values => {
|
||||||
|
save(code, values)
|
||||||
|
.then(m => handleClose())
|
||||||
|
.catch(err => {
|
||||||
|
if (err) setError(true)
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
<Form>
|
||||||
|
<div className={classes.formBody}>
|
||||||
|
{fields &&
|
||||||
|
fields.map((field, idx) => (
|
||||||
|
<div key={idx} className={classes.field}>
|
||||||
|
<Field
|
||||||
|
id={field.name}
|
||||||
|
name={field.name}
|
||||||
|
component={field.component}
|
||||||
|
placeholder={field.placeholder}
|
||||||
|
type={field.type}
|
||||||
|
label={field.label}
|
||||||
|
onFocus={() => {
|
||||||
|
setError(null)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className={classnames(submitWrapperClasses)}>
|
||||||
|
<div className={classes.messageWrapper}>
|
||||||
|
{error && (
|
||||||
|
<div>
|
||||||
|
<ErrorIcon />
|
||||||
|
<Info3 className={classes.message}>
|
||||||
|
{DEFAULT_ERROR_MESSAGE}
|
||||||
|
</Info3>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Button type="submit">Save changes</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</Formik>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditService
|
||||||
117
new-lamassu-admin/src/pages/Services/Infura.js
Normal file
117
new-lamassu-admin/src/pages/Services/Infura.js
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
import SecretInputFormik from 'src/components/inputs/formik/SecretInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux, formatLong } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
apiKey: {
|
||||||
|
code: 'apiKey',
|
||||||
|
display: 'API Key'
|
||||||
|
},
|
||||||
|
apiSecret: {
|
||||||
|
code: 'apiSecret',
|
||||||
|
display: 'API Secret'
|
||||||
|
},
|
||||||
|
endpoint: {
|
||||||
|
code: 'endpoint',
|
||||||
|
display: 'Endpoint'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InfuraCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const apiKey = schema.apiKey
|
||||||
|
const apiSecret = schema.apiSecret
|
||||||
|
|
||||||
|
const apiKeyValue = getValue(apiKey.code)
|
||||||
|
const apiSecretValue = getValue(apiSecret.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: apiKey.display,
|
||||||
|
value: formatLong(apiKeyValue)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: apiSecret.display,
|
||||||
|
value: formatLong(apiSecretValue)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="Infura (Wallet)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const InfuraForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const apiKey = getValue(schema.apiKey.code)
|
||||||
|
const apiSecret = getValue(schema.apiSecret.code)
|
||||||
|
const endpoint = getValue(schema.endpoint.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
apiKey: apiKey,
|
||||||
|
apiSecret: apiSecret,
|
||||||
|
endpoint: endpoint
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
apiKey: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
apiSecret: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
endpoint: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.url('Please input a valid url')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.apiKey.code,
|
||||||
|
label: schema.apiKey.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.apiSecret.code,
|
||||||
|
label: schema.apiSecret.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.endpoint.code,
|
||||||
|
label: schema.endpoint.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Infura"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { InfuraCard, InfuraForm }
|
||||||
126
new-lamassu-admin/src/pages/Services/Itbit.js
Normal file
126
new-lamassu-admin/src/pages/Services/Itbit.js
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
import SecretInputFormik from 'src/components/inputs/formik/SecretInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux, formatLong } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
userId: {
|
||||||
|
code: 'userId',
|
||||||
|
display: 'User ID'
|
||||||
|
},
|
||||||
|
walletId: {
|
||||||
|
code: 'walletId',
|
||||||
|
display: 'Wallet ID'
|
||||||
|
},
|
||||||
|
clientKey: {
|
||||||
|
code: 'clientKey',
|
||||||
|
display: 'Client Key'
|
||||||
|
},
|
||||||
|
clientSecret: {
|
||||||
|
code: 'clientSecret',
|
||||||
|
display: 'Client Secret'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ItbitCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const userId = schema.userId
|
||||||
|
const walletId = schema.walletId
|
||||||
|
|
||||||
|
const userIdValue = getValue(userId.code)
|
||||||
|
const walletIdValue = getValue(walletId.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: userId.display,
|
||||||
|
value: formatLong(userIdValue)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: walletId.display,
|
||||||
|
value: formatLong(walletIdValue)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card account={account} title="itBit ()" items={items} onEdit={onEdit} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const ItbitForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const userId = getValue(schema.userId.code)
|
||||||
|
const walletId = getValue(schema.walletId.code)
|
||||||
|
const clientKey = getValue(schema.clientKey.code)
|
||||||
|
const clientSecret = getValue(schema.clientSecret.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
userId: userId,
|
||||||
|
walletId: walletId,
|
||||||
|
clientKey: clientKey,
|
||||||
|
clientSecret: clientSecret
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
userId: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
walletId: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
clientKey: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
clientSecret: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.userId.code,
|
||||||
|
label: schema.userId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.walletId.code,
|
||||||
|
label: schema.walletId.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.clientKey.code,
|
||||||
|
label: schema.clientKey.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.clientSecret.code,
|
||||||
|
label: schema.clientSecret.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="itBit"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ItbitCard, ItbitForm }
|
||||||
101
new-lamassu-admin/src/pages/Services/Kraken.js
Normal file
101
new-lamassu-admin/src/pages/Services/Kraken.js
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
import SecretInputFormik from 'src/components/inputs/formik/SecretInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux, formatLong } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
apiKey: {
|
||||||
|
code: 'apiKey',
|
||||||
|
display: 'API Key'
|
||||||
|
},
|
||||||
|
privateKey: {
|
||||||
|
code: 'privateKey',
|
||||||
|
display: 'Private Key'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const KrakenCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const apiKey = schema.apiKey
|
||||||
|
const privateKey = schema.privateKey
|
||||||
|
|
||||||
|
const apiKeyValue = getValue(apiKey.code)
|
||||||
|
const privateKeyValue = getValue(privateKey.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
apiKey && {
|
||||||
|
label: apiKey.display,
|
||||||
|
value: formatLong(apiKeyValue)
|
||||||
|
},
|
||||||
|
privateKey && {
|
||||||
|
label: privateKey.display,
|
||||||
|
value: formatLong(privateKeyValue)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="Kraken (Exchange)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const KrakenForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const apiKey = getValue(schema.apiKey.code)
|
||||||
|
const privateKey = getValue(schema.privateKey.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
apiKey: apiKey,
|
||||||
|
privateKey: privateKey
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
apiKey: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
privateKey: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.apiKey.code,
|
||||||
|
label: schema.apiKey.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.privateKey.code,
|
||||||
|
label: schema.privateKey.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Kraken"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { KrakenCard, KrakenForm }
|
||||||
132
new-lamassu-admin/src/pages/Services/Mailgun.js
Normal file
132
new-lamassu-admin/src/pages/Services/Mailgun.js
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
apiKey: {
|
||||||
|
code: 'apiKey',
|
||||||
|
display: 'API Key'
|
||||||
|
},
|
||||||
|
domain: {
|
||||||
|
code: 'domain',
|
||||||
|
display: 'Domain'
|
||||||
|
},
|
||||||
|
fromEmail: {
|
||||||
|
code: 'fromEmail',
|
||||||
|
display: 'From Email'
|
||||||
|
},
|
||||||
|
toEmail: {
|
||||||
|
code: 'toEmail',
|
||||||
|
display: 'To Email'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MailgunCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const fromEmail = schema.fromEmail
|
||||||
|
const toEmail = schema.toEmail
|
||||||
|
|
||||||
|
const fromEmailValue = getValue(fromEmail.code)
|
||||||
|
const toEmailValue = getValue(toEmail.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: fromEmail.display,
|
||||||
|
value: fromEmailValue
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: toEmail.display,
|
||||||
|
value: toEmailValue
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="Mailgun (Email)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const MailgunForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const apiKey = getValue(schema.apiKey.code)
|
||||||
|
const domain = getValue(schema.domain.code)
|
||||||
|
const fromEmail = getValue(schema.fromEmail.code)
|
||||||
|
const toEmail = getValue(schema.toEmail.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
apiKey: apiKey,
|
||||||
|
domain: domain,
|
||||||
|
fromEmail: fromEmail,
|
||||||
|
toEmail: toEmail
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
apiKey: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
domain: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
fromEmail: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.email('Please input a valid email address')
|
||||||
|
.required('Required'),
|
||||||
|
toEmail: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.email('Please input a valid email address')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.apiKey.code,
|
||||||
|
label: schema.apiKey.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.domain.code,
|
||||||
|
label: schema.domain.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.fromEmail.code,
|
||||||
|
label: schema.fromEmail.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.toEmail.code,
|
||||||
|
label: schema.toEmail.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Mailgun"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { MailgunCard, MailgunForm }
|
||||||
242
new-lamassu-admin/src/pages/Services/Services.js
Normal file
242
new-lamassu-admin/src/pages/Services/Services.js
Normal file
|
|
@ -0,0 +1,242 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import * as R from 'ramda'
|
||||||
|
import { gql } from 'apollo-boost'
|
||||||
|
import { makeStyles, Modal } from '@material-ui/core'
|
||||||
|
import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||||
|
|
||||||
|
import Title from 'src/components/Title'
|
||||||
|
|
||||||
|
import { BitgoCard, BitgoForm } from './Bitgo'
|
||||||
|
import { BitstampCard, BitstampForm } from './Bitstamp'
|
||||||
|
import { BlockcypherCard, BlockcypherForm } from './Blockcypher'
|
||||||
|
import { InfuraCard, InfuraForm } from './Infura'
|
||||||
|
import { ItbitCard, ItbitForm } from './Itbit'
|
||||||
|
import { KrakenCard, KrakenForm } from './Kraken'
|
||||||
|
import { MailgunCard, MailgunForm } from './Mailgun'
|
||||||
|
import { StrikeCard, StrikeForm } from './Strike'
|
||||||
|
import { TwilioCard, TwilioForm } from './Twilio'
|
||||||
|
import { servicesStyles as styles } from './Services.styles'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const GET_CONFIG = gql`
|
||||||
|
{
|
||||||
|
config
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const GET_ACCOUNTS = gql`
|
||||||
|
{
|
||||||
|
accounts {
|
||||||
|
code
|
||||||
|
display
|
||||||
|
class
|
||||||
|
cryptos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const SAVE_CONFIG = gql`
|
||||||
|
mutation Save($config: JSONObject) {
|
||||||
|
saveConfig(config: $config)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Services = () => {
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const [modalContent, setModalContent] = useState(null)
|
||||||
|
const [accountsConfig, setAccountsConfig] = useState(null)
|
||||||
|
const [saveConfig, { loading }] = useMutation(SAVE_CONFIG, {
|
||||||
|
onCompleted: data => setAccountsConfig(data.saveConfig.accounts)
|
||||||
|
})
|
||||||
|
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
useQuery(GET_CONFIG, {
|
||||||
|
onCompleted: data => setAccountsConfig(data.config.accounts ?? {})
|
||||||
|
})
|
||||||
|
const { data: accountsResponse } = useQuery(GET_ACCOUNTS)
|
||||||
|
|
||||||
|
const accounts = accountsResponse?.accounts
|
||||||
|
|
||||||
|
const save = (code, it) => {
|
||||||
|
const newAccounts = R.clone(accountsConfig)
|
||||||
|
newAccounts[code] = it
|
||||||
|
return saveConfig({ variables: { config: { accounts: newAccounts } } })
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAccount = code => {
|
||||||
|
return R.mergeDeepLeft(
|
||||||
|
R.find(R.propEq('code', code))(accounts) ?? {},
|
||||||
|
accountsConfig[code] ?? {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOpen = content => {
|
||||||
|
setOpen(true)
|
||||||
|
setModalContent(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = (canClose = true) => {
|
||||||
|
if (canClose && !loading) {
|
||||||
|
setOpen(false)
|
||||||
|
setModalContent(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accounts || !accountsConfig) return null
|
||||||
|
|
||||||
|
const codes = {
|
||||||
|
bitgo: 'bitgo',
|
||||||
|
bitstamp: 'bitstamp',
|
||||||
|
blockcypher: 'blockcypher',
|
||||||
|
infura: 'infura',
|
||||||
|
itbit: 'itbit',
|
||||||
|
kraken: 'kraken',
|
||||||
|
mailgun: 'mailgun',
|
||||||
|
strike: 'strike',
|
||||||
|
twilio: 'twilio'
|
||||||
|
}
|
||||||
|
|
||||||
|
const bitgo = getAccount(codes.bitgo)
|
||||||
|
const bitstamp = getAccount(codes.bitstamp)
|
||||||
|
const blockcypher = getAccount(codes.blockcypher)
|
||||||
|
const infura = getAccount(codes.infura)
|
||||||
|
const itbit = getAccount(codes.itbit)
|
||||||
|
const kraken = getAccount(codes.kraken)
|
||||||
|
const mailgun = getAccount(codes.mailgun)
|
||||||
|
const strike = getAccount(codes.strike)
|
||||||
|
const twilio = getAccount(codes.twilio)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={classes.titleWrapper}>
|
||||||
|
<div className={classes.titleContainer}>
|
||||||
|
<Title>3rd Party Services</Title>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes.mainWrapper}>
|
||||||
|
<BitgoCard
|
||||||
|
account={bitgo}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<BitgoForm
|
||||||
|
account={bitgo}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<BitstampCard
|
||||||
|
account={bitstamp}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<BitstampForm
|
||||||
|
account={bitstamp}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<BlockcypherCard
|
||||||
|
account={blockcypher}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<BlockcypherForm
|
||||||
|
account={blockcypher}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<InfuraCard
|
||||||
|
account={infura}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<InfuraForm
|
||||||
|
account={infura}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ItbitCard
|
||||||
|
account={itbit}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<ItbitForm
|
||||||
|
account={itbit}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<KrakenCard
|
||||||
|
account={kraken}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<KrakenForm
|
||||||
|
account={kraken}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MailgunCard
|
||||||
|
account={mailgun}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<MailgunForm
|
||||||
|
account={mailgun}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<StrikeCard
|
||||||
|
account={strike}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<StrikeForm
|
||||||
|
account={strike}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<TwilioCard
|
||||||
|
account={twilio}
|
||||||
|
onEdit={() =>
|
||||||
|
handleOpen(
|
||||||
|
<TwilioForm
|
||||||
|
account={twilio}
|
||||||
|
handleClose={handleClose}
|
||||||
|
save={save}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{modalContent && (
|
||||||
|
<Modal
|
||||||
|
aria-labelledby="simple-modal-title"
|
||||||
|
aria-describedby="simple-modal-description"
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
className={classes.modal}>
|
||||||
|
<div>{modalContent}</div>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Services
|
||||||
177
new-lamassu-admin/src/pages/Services/Services.styles.js
Normal file
177
new-lamassu-admin/src/pages/Services/Services.styles.js
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
import { white, offColor, errorColor } from 'src/styling/variables'
|
||||||
|
import typographyStyles from 'src/components/typography/styles'
|
||||||
|
import baseStyles from 'src/pages/Logs.styles'
|
||||||
|
|
||||||
|
const { titleWrapper } = baseStyles
|
||||||
|
const { label1, p } = typographyStyles
|
||||||
|
|
||||||
|
const servicesStyles = {
|
||||||
|
titleWrapper,
|
||||||
|
titleContainer: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
addServiceMenu: {
|
||||||
|
width: 215,
|
||||||
|
'& > ul': {
|
||||||
|
padding: [[18, 16, 21, 16]],
|
||||||
|
'& > li': {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
listStyle: 'none',
|
||||||
|
marginBottom: 23,
|
||||||
|
cursor: 'pointer',
|
||||||
|
'& > span:first-child': {
|
||||||
|
extend: p,
|
||||||
|
fontWeight: 'bold'
|
||||||
|
},
|
||||||
|
'& > span:last-child': {
|
||||||
|
extend: label1,
|
||||||
|
color: offColor
|
||||||
|
},
|
||||||
|
'&:last-child': {
|
||||||
|
marginBottom: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mainWrapper: {
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap'
|
||||||
|
},
|
||||||
|
modal: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
'& > div': {
|
||||||
|
outline: 'none'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modalHeader: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
'& button': {
|
||||||
|
border: 'none',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modalBody: {
|
||||||
|
'& > form': {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
position: 'relative',
|
||||||
|
minHeight: 400,
|
||||||
|
'& > div:last-child': {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
flex: 'auto',
|
||||||
|
alignSelf: 'flex-end',
|
||||||
|
'& > button': {
|
||||||
|
marginTop: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
paper: {
|
||||||
|
position: 'absolute',
|
||||||
|
backgroundColor: white,
|
||||||
|
outline: '0 none',
|
||||||
|
padding: [[16, 20, 32, 24]]
|
||||||
|
},
|
||||||
|
inputField: {
|
||||||
|
width: 434
|
||||||
|
},
|
||||||
|
formLabel: {
|
||||||
|
extend: label1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const editServiceStyles = {
|
||||||
|
paper: {
|
||||||
|
padding: [[5, 20, 32, 24]],
|
||||||
|
position: 'relative',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
minHeight: 524,
|
||||||
|
overflow: 'hidden',
|
||||||
|
'& > button': {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 16,
|
||||||
|
right: 16,
|
||||||
|
border: 'none',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
cursor: 'pointer',
|
||||||
|
'& svg': {
|
||||||
|
width: 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& form': {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexGrow: 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modalHeader: {
|
||||||
|
display: 'flex',
|
||||||
|
marginBottom: 14
|
||||||
|
},
|
||||||
|
modalBody: {
|
||||||
|
display: 'flex',
|
||||||
|
flexGrow: 2
|
||||||
|
},
|
||||||
|
formBody: {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
position: 'relative',
|
||||||
|
'& > div': {
|
||||||
|
width: 434
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submitWrapper: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
flexGrow: 2,
|
||||||
|
marginTop: 32,
|
||||||
|
'& > div': {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
width: '100%',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
'& > button': {
|
||||||
|
'&:active': {
|
||||||
|
marginTop: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submitError: {
|
||||||
|
'& > div': {
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
messageWrapper: {
|
||||||
|
'& > div': {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
'& > svg': {
|
||||||
|
marginRight: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
color: errorColor,
|
||||||
|
margin: 0,
|
||||||
|
whiteSpace: 'break-spaces',
|
||||||
|
width: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { servicesStyles, editServiceStyles }
|
||||||
79
new-lamassu-admin/src/pages/Services/Strike.js
Normal file
79
new-lamassu-admin/src/pages/Services/Strike.js
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import SecretInputFormik from 'src/components/inputs/formik/SecretInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux, formatLong } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
token: {
|
||||||
|
code: 'token',
|
||||||
|
display: 'API Token'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const StrikeCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const token = schema.token
|
||||||
|
|
||||||
|
const tokenValue = getValue(token.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: token.display,
|
||||||
|
value: formatLong(tokenValue)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="Strike (Lightning Payments)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const StrikeForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const code = 'strike'
|
||||||
|
const token = getValue(schema.token.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
token: token
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
token: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.token.code,
|
||||||
|
label: schema.token.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Strike"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { StrikeCard, StrikeForm }
|
||||||
131
new-lamassu-admin/src/pages/Services/Twilio.js
Normal file
131
new-lamassu-admin/src/pages/Services/Twilio.js
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
import TextInputFormik from 'src/components/inputs/formik/TextInput'
|
||||||
|
import SecretInputFormik from 'src/components/inputs/formik/SecretInput'
|
||||||
|
|
||||||
|
import { Card, getValue as getValueAux } from './aux'
|
||||||
|
import EditService from './EditService'
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
accountSid: {
|
||||||
|
code: 'accountSid',
|
||||||
|
display: 'Account SID'
|
||||||
|
},
|
||||||
|
authToken: {
|
||||||
|
code: 'authToken',
|
||||||
|
display: 'Auth Token'
|
||||||
|
},
|
||||||
|
fromNumber: {
|
||||||
|
code: 'fromNumber',
|
||||||
|
display: 'From Number'
|
||||||
|
},
|
||||||
|
toNumber: {
|
||||||
|
code: 'toNumber',
|
||||||
|
display: 'To Number'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const TwilioCard = memo(({ account, onEdit, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const fromNumber = schema.fromNumber
|
||||||
|
const toNumber = schema.toNumber
|
||||||
|
|
||||||
|
const fromNumberValue = getValue(fromNumber.code)
|
||||||
|
const toNumberValue = getValue(toNumber.code)
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
label: fromNumber.display,
|
||||||
|
value: fromNumberValue
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: toNumber.display,
|
||||||
|
value: toNumberValue
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
account={account}
|
||||||
|
title="Twilio (SMS)"
|
||||||
|
items={items}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const TwilioForm = ({ account, ...props }) => {
|
||||||
|
const getValue = getValueAux(account)
|
||||||
|
|
||||||
|
const { code } = account
|
||||||
|
const accountSid = getValue(schema.accountSid.code)
|
||||||
|
const authToken = getValue(schema.authToken.code)
|
||||||
|
const fromNumber = getValue(schema.fromNumber.code)
|
||||||
|
const toNumber = getValue(schema.toNumber.code)
|
||||||
|
|
||||||
|
const formik = {
|
||||||
|
initialValues: {
|
||||||
|
accountSid: accountSid,
|
||||||
|
authToken: authToken,
|
||||||
|
fromNumber: fromNumber,
|
||||||
|
toNumber: toNumber
|
||||||
|
},
|
||||||
|
validationSchema: Yup.object().shape({
|
||||||
|
accountSid: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
authToken: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
fromNumber: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required'),
|
||||||
|
toNumber: Yup.string()
|
||||||
|
.max(100, 'Too long')
|
||||||
|
.required('Required')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{
|
||||||
|
name: schema.accountSid.code,
|
||||||
|
label: schema.accountSid.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.authToken.code,
|
||||||
|
label: schema.authToken.display,
|
||||||
|
type: 'text',
|
||||||
|
component: SecretInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.fromNumber.code,
|
||||||
|
label: schema.fromNumber.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: schema.toNumber.code,
|
||||||
|
label: schema.toNumber.display,
|
||||||
|
type: 'text',
|
||||||
|
component: TextInputFormik
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EditService
|
||||||
|
title="Twilio"
|
||||||
|
formik={formik}
|
||||||
|
code={code}
|
||||||
|
fields={fields}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { TwilioCard, TwilioForm }
|
||||||
44
new-lamassu-admin/src/pages/Services/aux.js
Normal file
44
new-lamassu-admin/src/pages/Services/aux.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import React from 'react'
|
||||||
|
import * as R from 'ramda'
|
||||||
|
import { makeStyles } from '@material-ui/core'
|
||||||
|
|
||||||
|
import SingleRowTable from 'src/components/single-row-table/SingleRowTable'
|
||||||
|
|
||||||
|
const getValue = R.curry((account, code) => account[code] ?? '')
|
||||||
|
|
||||||
|
const formatLong = value => {
|
||||||
|
if (!value) return ''
|
||||||
|
if (value.length <= 20) return value
|
||||||
|
|
||||||
|
return `${value.slice(0, 8)}(...)${value.slice(
|
||||||
|
value.length - 8,
|
||||||
|
value.length
|
||||||
|
)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
card: {
|
||||||
|
margin: [[0, 30, 32, 0]],
|
||||||
|
paddingBottom: 24,
|
||||||
|
'&:nth-child(3n+3)': {
|
||||||
|
marginRight: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
|
const Card = ({ account, title, items, onEdit, ...props }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SingleRowTable
|
||||||
|
title={title}
|
||||||
|
items={items}
|
||||||
|
className={classes.card}
|
||||||
|
onEdit={onEdit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Card, getValue, formatLong }
|
||||||
|
|
@ -10,6 +10,8 @@ import { comet } from 'src/styling/variables'
|
||||||
|
|
||||||
import { cpcStyles } from './Transactions.styles'
|
import { cpcStyles } from './Transactions.styles'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(cpcStyles)
|
||||||
|
|
||||||
const CopyToClipboard = ({ className, children, ...props }) => {
|
const CopyToClipboard = ({ className, children, ...props }) => {
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
const [anchorEl, setAnchorEl] = useState(null)
|
||||||
|
|
||||||
|
|
@ -17,8 +19,6 @@ const CopyToClipboard = ({ className, children, ...props }) => {
|
||||||
if (anchorEl) setTimeout(() => setAnchorEl(null), 3000)
|
if (anchorEl) setTimeout(() => setAnchorEl(null), 3000)
|
||||||
}, [anchorEl])
|
}, [anchorEl])
|
||||||
|
|
||||||
const useStyles = makeStyles(cpcStyles)
|
|
||||||
|
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
const handleClick = event => {
|
const handleClick = event => {
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,18 @@ import { onlyFirstToUpper } from 'src/utils/string'
|
||||||
import CopyToClipboard from './CopyToClipboard'
|
import CopyToClipboard from './CopyToClipboard'
|
||||||
import { detailsRowStyles, labelStyles } from './Transactions.styles'
|
import { detailsRowStyles, labelStyles } from './Transactions.styles'
|
||||||
|
|
||||||
const Label = ({ children }) => {
|
const labelUseStyles = makeStyles(labelStyles)
|
||||||
const useStyles = makeStyles(labelStyles)
|
|
||||||
|
|
||||||
const classes = useStyles()
|
const Label = ({ children }) => {
|
||||||
|
const classes = labelUseStyles()
|
||||||
|
|
||||||
return <div className={classes.label}>{children}</div>
|
return <div className={classes.label}>{children}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const DetailsRow = ({ it: tx, ...props }) => {
|
const detailsUseStyles = makeStyles(detailsRowStyles)
|
||||||
const useStyles = makeStyles(detailsRowStyles)
|
|
||||||
|
|
||||||
const classes = useStyles()
|
const DetailsRow = ({ it: tx, ...props }) => {
|
||||||
|
const classes = detailsUseStyles()
|
||||||
|
|
||||||
const addr = tx.toAddress
|
const addr = tx.toAddress
|
||||||
const txHash = tx.txHash
|
const txHash = tx.txHash
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import { toUnit } from 'src/utils/coin'
|
||||||
import DetailsRow from './DetailsCard'
|
import DetailsRow from './DetailsCard'
|
||||||
import { mainStyles } from './Transactions.styles'
|
import { mainStyles } from './Transactions.styles'
|
||||||
|
|
||||||
|
const useStyles = makeStyles(mainStyles)
|
||||||
|
|
||||||
// TODO customerIdCardData
|
// TODO customerIdCardData
|
||||||
const GET_TRANSACTIONS = gql`
|
const GET_TRANSACTIONS = gql`
|
||||||
{
|
{
|
||||||
|
|
@ -49,8 +51,6 @@ const GET_TRANSACTIONS = gql`
|
||||||
const Transactions = () => {
|
const Transactions = () => {
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
const [anchorEl, setAnchorEl] = useState(null)
|
||||||
|
|
||||||
const useStyles = makeStyles(mainStyles)
|
|
||||||
|
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
const { data: txResponse } = useQuery(GET_TRANSACTIONS)
|
const { data: txResponse } = useQuery(GET_TRANSACTIONS)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import Locales from 'src/pages/Locales'
|
||||||
import Logs from 'src/pages/Logs'
|
import Logs from 'src/pages/Logs'
|
||||||
import ServerLogs from 'src/pages/ServerLogs'
|
import ServerLogs from 'src/pages/ServerLogs'
|
||||||
import Transactions from 'src/pages/Transactions/Transactions'
|
import Transactions from 'src/pages/Transactions/Transactions'
|
||||||
|
import Services from 'src/pages/Services/Services'
|
||||||
import AuthRegister from 'src/pages/AuthRegister'
|
import AuthRegister from 'src/pages/AuthRegister'
|
||||||
|
|
||||||
const tree = [
|
const tree = [
|
||||||
|
|
@ -38,7 +39,12 @@ const tree = [
|
||||||
label: 'Commissions',
|
label: 'Commissions',
|
||||||
route: '/settings/commissions'
|
route: '/settings/commissions'
|
||||||
},
|
},
|
||||||
{ key: 'locale', label: 'Locale', route: '/settings/locale' }
|
{ key: 'locale', label: 'Locale', route: '/settings/locale' },
|
||||||
|
{
|
||||||
|
key: 'services',
|
||||||
|
label: '3rd party services',
|
||||||
|
route: '/settings/3rd-party-services'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
// compliance: { label: 'Compliance', children: [{ label: 'Locale', route: '/locale' }] }
|
// compliance: { label: 'Compliance', children: [{ label: 'Locale', route: '/locale' }] }
|
||||||
|
|
@ -65,6 +71,7 @@ const Routes = () => (
|
||||||
/>
|
/>
|
||||||
<Route path="/settings/commissions" component={Commissions} />
|
<Route path="/settings/commissions" component={Commissions} />
|
||||||
<Route path="/settings/locale" component={Locales} />
|
<Route path="/settings/locale" component={Locales} />
|
||||||
|
<Route path="/settings/3rd-party-services" component={Services} />
|
||||||
<Route path="/maintenance/logs" component={Logs} />
|
<Route path="/maintenance/logs" component={Logs} />
|
||||||
<Route path="/maintenance/funding" component={Funding} />
|
<Route path="/maintenance/funding" component={Funding} />
|
||||||
<Route path="/maintenance/server-logs" component={ServerLogs} />
|
<Route path="/maintenance/server-logs" component={ServerLogs} />
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,17 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
<title>icon/action/close/zodiac</title>
|
viewBox="0 0 18 18" style="enable-background:new 0 0 18 18;" xml:space="preserve">
|
||||||
<desc>Created with Sketch.</desc>
|
<style type="text/css">
|
||||||
<defs>
|
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#1B2559;}
|
||||||
<path d="M11.10567,8.99966734 L17.5616855,15.4562245 C18.1453995,16.0371533 18.1457502,16.9810221 17.5632744,17.5635465 C17.2826878,17.8441564 16.9043531,17.9996031 16.509308,17.9996031 C16.1150437,17.9996031 15.7367759,17.8439272 15.4563692,17.5634971 L8.99995005,11.1055617 L2.54567824,17.5603569 C2.26578723,17.8430155 1.88614994,17.9996031 1.48961505,17.9996031 C1.09473832,17.9996031 0.717380733,17.844225 0.436725633,17.5635465 C-0.145575211,16.9811971 -0.145575211,16.0373273 0.436725633,15.4578096 L6.89433001,8.99966707 L0.438314479,2.54310994 C-0.145399464,1.96218116 -0.145750215,1.01831232 0.436725633,0.435787934 C1.01746304,-0.144997872 1.95893893,-0.144997872 2.54250446,0.435787934 L8.99995074,6.89377234 L15.4580075,0.434202817 C16.0398949,-0.144908147 16.9801496,-0.144559181 17.5632744,0.435787934 C18.1455752,1.0181373 18.1455752,1.96200713 17.5632744,2.54152483 L11.10567,8.99966734 Z" id="path-1"></path>
|
</style>
|
||||||
<rect id="path-3" x="0" y="0" width="18" height="18"></rect>
|
<title>icon/action/close/zodiac</title>
|
||||||
</defs>
|
<desc>Created with Sketch.</desc>
|
||||||
<g id="icon/action/close/zodiac" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
<g id="color_x2F_primary_x2F_zodiac" transform="translate(-0.000000, 0.000000)">
|
||||||
<g id="color/primary/zodiac" transform="translate(-0.000000, 0.000000)">
|
<g id="Mask">
|
||||||
<mask id="mask-2" fill="white">
|
<path id="path-1_1_" class="st0" d="M11.1,9l6.5,6.5c0.6,0.6,0.6,1.5,0,2.1c-0.3,0.3-0.7,0.4-1.1,0.4c-0.4,0-0.8-0.2-1.1-0.4
|
||||||
<use xlink:href="#path-1"></use>
|
L9,11.1l-6.5,6.5C2.3,17.8,1.9,18,1.5,18c-0.4,0-0.8-0.2-1.1-0.4c-0.6-0.6-0.6-1.5,0-2.1L6.9,9L0.4,2.5C-0.1,2-0.1,1,0.4,0.4
|
||||||
</mask>
|
C1-0.1,2-0.1,2.5,0.4L9,6.9l6.5-6.5c0.6-0.6,1.5-0.6,2.1,0c0.6,0.6,0.6,1.5,0,2.1L11.1,9z"/>
|
||||||
<use id="Mask" fill="#1B2559" xlink:href="#path-1"></use>
|
|
||||||
<g mask="url(#mask-2)">
|
|
||||||
<mask id="mask-4" fill="white">
|
|
||||||
<use xlink:href="#path-3"></use>
|
|
||||||
</mask>
|
|
||||||
<use id="Background" fill="#1B2559" fill-rule="evenodd" xlink:href="#path-3"></use>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
</g>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 964 B |
12
new-lamassu-admin/src/styling/icons/warning-icon/comet.svg
Normal file
12
new-lamassu-admin/src/styling/icons/warning-icon/comet.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" 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 -->
|
||||||
|
<title>icon/warning-icon/comet</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="icon/warning-icon/comet">
|
||||||
|
<rect id="Rectangle" stroke="#5F668A" stroke-width="2" x="1" y="1" width="22" height="22" rx="11"></rect>
|
||||||
|
<path d="M11.2971429,14.4857143 L11.1085714,5.82857143 L13.3714286,5.82857143 L13.2,14.4857143 L11.2971429,14.4857143 Z M11.1942857,18 L11.1942857,15.9771429 L13.3028571,15.9771429 L13.3028571,18 L11.1942857,18 Z" id="!" fill="#5F668A" fill-rule="nonzero"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 877 B |
12
new-lamassu-admin/src/styling/icons/warning-icon/tomato.svg
Normal file
12
new-lamassu-admin/src/styling/icons/warning-icon/tomato.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" 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 -->
|
||||||
|
<title>icon/warning-icon/tomato</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="icon/warning-icon/tomato">
|
||||||
|
<rect id="Rectangle" stroke="#FF584A" stroke-width="2" x="1" y="1" width="22" height="22" rx="11"></rect>
|
||||||
|
<path d="M11.2971429,14.4857143 L11.1085714,5.82857143 L13.3714286,5.82857143 L13.2,14.4857143 L11.2971429,14.4857143 Z M11.1942857,18 L11.1942857,15.9771429 L13.3028571,15.9771429 L13.3028571,18 L11.1942857,18 Z" id="!" fill="#FF584A" fill-rule="nonzero"></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 879 B |
|
|
@ -103,6 +103,8 @@ const tableSmCellHeight = 30
|
||||||
const tableLgCellHeight = 76
|
const tableLgCellHeight = 76
|
||||||
|
|
||||||
const tableHeaderColor = primaryColor
|
const tableHeaderColor = primaryColor
|
||||||
|
const tableDisabledHeaderColor = zircon
|
||||||
|
const tableNewDisabledHeaderColor = spring3
|
||||||
const tableCellColor = white
|
const tableCellColor = white
|
||||||
const tableErrorColor = mistyRose
|
const tableErrorColor = mistyRose
|
||||||
const tableSuccessColor = spring3
|
const tableSuccessColor = spring3
|
||||||
|
|
@ -172,6 +174,8 @@ export {
|
||||||
tableSmCellHeight,
|
tableSmCellHeight,
|
||||||
tableLgCellHeight,
|
tableLgCellHeight,
|
||||||
tableHeaderColor,
|
tableHeaderColor,
|
||||||
|
tableDisabledHeaderColor,
|
||||||
|
tableNewDisabledHeaderColor,
|
||||||
tableCellColor,
|
tableCellColor,
|
||||||
tableErrorColor,
|
tableErrorColor,
|
||||||
tableSuccessColor
|
tableSuccessColor
|
||||||
|
|
|
||||||
19
package-lock.json
generated
19
package-lock.json
generated
|
|
@ -58,7 +58,7 @@
|
||||||
"@ava/babel-preset-stage-4": {
|
"@ava/babel-preset-stage-4": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ava/babel-preset-stage-4/-/babel-preset-stage-4-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ava/babel-preset-stage-4/-/babel-preset-stage-4-1.1.0.tgz",
|
||||||
"integrity": "sha1-rmC+iBoLq/fTX1Krp3DR9hlPdr0=",
|
"integrity": "sha512-oWqTnIGXW3k72UFidXzW0ONlO7hnO9x02S/QReJ7NBGeiBH9cUHY9+EfV6C8PXC6YJH++WrliEq03wMSJGNZFg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"babel-plugin-check-es2015-constants": "^6.8.0",
|
"babel-plugin-check-es2015-constants": "^6.8.0",
|
||||||
|
|
@ -4070,7 +4070,7 @@
|
||||||
},
|
},
|
||||||
"dotenv": {
|
"dotenv": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "http://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
|
||||||
"integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0="
|
"integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0="
|
||||||
},
|
},
|
||||||
"drbg.js": {
|
"drbg.js": {
|
||||||
|
|
@ -6230,7 +6230,7 @@
|
||||||
"globals": {
|
"globals": {
|
||||||
"version": "9.18.0",
|
"version": "9.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
|
||||||
"integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=",
|
"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"globby": {
|
"globby": {
|
||||||
|
|
@ -6257,7 +6257,7 @@
|
||||||
"got": {
|
"got": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz",
|
||||||
"integrity": "sha1-BUUP2ECU5rvqVvRRpDqcKJFmOFo=",
|
"integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"decompress-response": "^3.2.0",
|
"decompress-response": "^3.2.0",
|
||||||
"duplexer3": "^0.1.4",
|
"duplexer3": "^0.1.4",
|
||||||
|
|
@ -7146,7 +7146,7 @@
|
||||||
"hullabaloo-config-manager": {
|
"hullabaloo-config-manager": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/hullabaloo-config-manager/-/hullabaloo-config-manager-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/hullabaloo-config-manager/-/hullabaloo-config-manager-1.1.1.tgz",
|
||||||
"integrity": "sha1-HZEXgTEprQNf2ehHfq8GaREmn+M=",
|
"integrity": "sha512-ztKnkZV0TmxnumCDHHgLGNiDnotu4EHCp9YMkznWuo4uTtCyJ+cu+RNcxUeXYKTllpvLFWnbfWry09yzszgg+A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"dot-prop": "^4.1.0",
|
"dot-prop": "^4.1.0",
|
||||||
|
|
@ -7668,7 +7668,7 @@
|
||||||
"isurl": {
|
"isurl": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz",
|
||||||
"integrity": "sha1-sn9PSfPNqj6kSgpbfzRi5u3DnWc=",
|
"integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-to-string-tag-x": "^1.2.0",
|
"has-to-string-tag-x": "^1.2.0",
|
||||||
"is-object": "^1.0.1"
|
"is-object": "^1.0.1"
|
||||||
|
|
@ -8586,7 +8586,7 @@
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
|
|
@ -9163,7 +9163,7 @@
|
||||||
"p-cancelable": {
|
"p-cancelable": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz",
|
||||||
"integrity": "sha1-ueEjgAvOu3rBOkeb4ZW1B7mNMPo="
|
"integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw=="
|
||||||
},
|
},
|
||||||
"p-each-series": {
|
"p-each-series": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|
@ -12642,7 +12642,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/web3/-/web3-0.20.6.tgz",
|
"resolved": "https://registry.npmjs.org/web3/-/web3-0.20.6.tgz",
|
||||||
"integrity": "sha1-PpcwauAk+yThCj11yIQwJWIhUSA=",
|
"integrity": "sha1-PpcwauAk+yThCj11yIQwJWIhUSA=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934",
|
|
||||||
"crypto-js": "^3.1.4",
|
"crypto-js": "^3.1.4",
|
||||||
"utf8": "^2.1.1",
|
"utf8": "^2.1.1",
|
||||||
"xhr2": "*",
|
"xhr2": "*",
|
||||||
|
|
@ -12651,7 +12650,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bignumber.js": {
|
"bignumber.js": {
|
||||||
"version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934",
|
"version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934",
|
||||||
"from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git"
|
"from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue