Merge remote-tracking branch 'upstream/release-7.5.0' into dev

This commit is contained in:
Taranto 2021-01-05 10:54:56 +00:00
commit 9ed3bc50e4
36 changed files with 320 additions and 198 deletions

View file

@ -1,8 +1,8 @@
const db = require('./db') const db = require('./db')
// Get all blacklist rows from the DB "blacklist" table // Get all blacklist rows from the DB "blacklist" table that were manually inserted by the operator
const getBlacklist = () => { const getBlacklist = () => {
return db.any('select * from blacklist').then(res => return db.any(`SELECT * FROM blacklist WHERE created_by_operator = 't'`).then(res =>
res.map(item => ({ res.map(item => ({
cryptoCode: item.crypto_code, cryptoCode: item.crypto_code,
address: item.address, address: item.address,
@ -21,13 +21,10 @@ const deleteFromBlacklist = (cryptoCode, address) => {
const insertIntoBlacklist = (cryptoCode, address) => { const insertIntoBlacklist = (cryptoCode, address) => {
return db return db
.any( .none(
'insert into blacklist(crypto_code, address, created_by_operator) values($1, $2, $3);', 'insert into blacklist(crypto_code, address, created_by_operator) values($1, $2, $3);',
[cryptoCode, address, true] [cryptoCode, address, true]
) )
.then(() => {
return { cryptoCode, address }
})
} }
function blocked(address, cryptoCode) { function blocked(address, cryptoCode) {

View file

@ -15,9 +15,9 @@ server.applyMiddleware({ app })
app.use(bodyParser.json()) app.use(bodyParser.json())
function run () { function run () {
const serverLog = `lamassu-admin-server listening on port ${8080}${server.graphqlPath}` const serverLog = `lamassu-admin-server listening on port ${9010}${server.graphqlPath}`
app.listen(8080, () => console.log(serverLog)) app.listen(9010, () => console.log(serverLog))
} }
module.exports = { run } module.exports = { run }

View file

@ -10,7 +10,7 @@ const customers = require('../../customers')
const { machineAction } = require('../machines') 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 blacklist = require('../../blacklist')
const machineEventsByIdBatch = require("../../postgresql_interface").machineEventsByIdBatch const machineEventsByIdBatch = require("../../postgresql_interface").machineEventsByIdBatch
@ -254,7 +254,7 @@ const typeDefs = gql`
accounts: JSONObject accounts: JSONObject
config: JSONObject config: JSONObject
blacklist: [Blacklist] blacklist: [Blacklist]
userTokens: [UserToken] # userTokens: [UserToken]
} }
enum MachineAction { enum MachineAction {
@ -276,7 +276,7 @@ const typeDefs = gql`
saveAccounts(accounts: JSONObject): JSONObject saveAccounts(accounts: JSONObject): JSONObject
resetAccounts(schemaVersion: Int): JSONObject resetAccounts(schemaVersion: Int): JSONObject
migrateConfigAndAccounts: JSONObject migrateConfigAndAccounts: JSONObject
revokeToken(token: String!): UserToken # revokeToken(token: String!): UserToken
deleteBlacklistRow(cryptoCode: String!, address: String!): Blacklist deleteBlacklistRow(cryptoCode: String!, address: String!): Blacklist
insertBlacklistRow(cryptoCode: String!, address: String!): Blacklist insertBlacklistRow(cryptoCode: String!, address: String!): Blacklist
} }
@ -328,7 +328,7 @@ const resolvers = {
config: () => settingsLoader.loadLatestConfigOrNone(), config: () => settingsLoader.loadLatestConfigOrNone(),
accounts: () => settingsLoader.loadAccounts(), accounts: () => settingsLoader.loadAccounts(),
blacklist: () => blacklist.getBlacklist(), blacklist: () => blacklist.getBlacklist(),
userTokens: () => tokenManager.getTokenList() // userTokens: () => tokenManager.getTokenList()
}, },
Mutation: { Mutation: {
machineAction: (...[, { deviceId, action, cassette1, cassette2, newName }]) => machineAction({ deviceId, action, cassette1, cassette2, newName }), machineAction: (...[, { deviceId, action, cassette1, cassette2, newName }]) => machineAction({ deviceId, action, cassette1, cassette2, newName }),
@ -350,7 +350,7 @@ const resolvers = {
blacklist.deleteFromBlacklist(cryptoCode, address), blacklist.deleteFromBlacklist(cryptoCode, address),
insertBlacklistRow: (...[, { cryptoCode, address }]) => insertBlacklistRow: (...[, { cryptoCode, address }]) =>
blacklist.insertIntoBlacklist(cryptoCode, address), blacklist.insertIntoBlacklist(cryptoCode, address),
revokeToken: (...[, { token }]) => tokenManager.revokeToken(token) // revokeToken: (...[, { token }]) => tokenManager.revokeToken(token)
} }
} }

View file

@ -1,24 +1,29 @@
module.exports = { module.exports = {
extends: [ extends: ['react-app', 'prettier-standard', 'prettier/react'],
'react-app',
'prettier-standard',
'prettier/react',
],
plugins: ['import'], plugins: ['import'],
settings: { settings: {
'import/resolver': { 'import/resolver': {
alias: [ alias: [['src', './src']]
['src', './src']
]
} }
}, },
rules: { rules: {
'import/order': ['error', { 'import/no-anonymous-default-export': [2, { allowObject: true }],
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], 'import/order': [
alphabetize: { 'error',
order: 'asc' {
}, groups: [
'newlines-between': 'always', 'builtin',
}] 'external',
} 'internal',
'parent',
'sibling',
'index'
],
alphabetize: {
order: 'asc'
},
'newlines-between': 'always'
}
]
}
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "lamassu-admin", "name": "lamassu-admin",
"version": "0.1.0", "version": "0.2.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View file

@ -1,6 +1,6 @@
{ {
"name": "lamassu-admin", "name": "lamassu-admin",
"version": "0.1.0", "version": "0.2.0",
"license": "unlicense", "license": "unlicense",
"dependencies": { "dependencies": {
"@apollo/react-hooks": "^3.1.3", "@apollo/react-hooks": "^3.1.3",

View file

@ -15,6 +15,8 @@ import styles from './Header.styles'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const Subheader = ({ item, classes }) => { const Subheader = ({ item, classes }) => {
const [prev, setPrev] = useState(null)
return ( return (
<div className={classes.subheader}> <div className={classes.subheader}>
<div className={classes.content}> <div className={classes.content}>
@ -23,9 +25,14 @@ const Subheader = ({ item, classes }) => {
{item.children.map((it, idx) => ( {item.children.map((it, idx) => (
<li key={idx} className={classes.subheaderLi}> <li key={idx} className={classes.subheaderLi}>
<NavLink <NavLink
to={it.route} to={{ pathname: it.route, state: { prev } }}
className={classes.subheaderLink} className={classes.subheaderLink}
activeClassName={classes.activeSubheaderLink}> activeClassName={classes.activeSubheaderLink}
isActive={match => {
if (!match) return false
setPrev(it.route)
return true
}}>
{it.label} {it.label}
</NavLink> </NavLink>
</li> </li>

View file

@ -73,14 +73,15 @@ const Blacklist = () => {
code: 'BTC', code: 'BTC',
display: 'Bitcoin' display: 'Bitcoin'
}) })
const [errorMsg, setErrorMsg] = useState(null)
const [deleteEntry] = useMutation(DELETE_ROW, { const [deleteEntry] = useMutation(DELETE_ROW, {
onError: () => console.error('Error while deleting row'), onError: () => console.error('Error while deleting row'),
refetchQueries: () => ['getBlacklistData'] refetchQueries: () => ['getBlacklistData']
}) })
const [addEntry] = useMutation(ADD_ROW, { const [addEntry] = useMutation(ADD_ROW, {
onError: () => console.error('Error while adding row'), onError: () => console.log('Error while adding row'),
onCompleted: () => setShowModal(false),
refetchQueries: () => ['getBlacklistData'] refetchQueries: () => ['getBlacklistData']
}) })
@ -114,14 +115,30 @@ const Blacklist = () => {
deleteEntry({ variables: { cryptoCode, address } }) deleteEntry({ variables: { cryptoCode, address } })
} }
const addToBlacklist = (cryptoCode, address) => { const addToBlacklist = async (cryptoCode, address) => {
addEntry({ variables: { cryptoCode, address } }) setErrorMsg(null)
const res = await addEntry({ variables: { cryptoCode, address } })
if (!res.errors) {
return setShowModal(false)
}
const duplicateKeyError = res.errors.some(e => {
return e.message.includes('duplicate')
})
if (duplicateKeyError) {
setErrorMsg('This address is already being blocked')
} else {
setErrorMsg('Server error')
}
} }
return ( return (
<> <>
<TitleSection title="Blacklisted addresses"> <TitleSection title="Blacklisted addresses">
<Link onClick={() => setShowModal(false)}>Blacklist new addresses</Link> <div>
<Link onClick={() => setShowModal(true)}>
Blacklist new addresses
</Link>
</div>
</TitleSection> </TitleSection>
<Grid container className={classes.grid}> <Grid container className={classes.grid}>
<Sidebar <Sidebar
@ -169,7 +186,11 @@ const Blacklist = () => {
</Grid> </Grid>
{showModal && ( {showModal && (
<BlackListModal <BlackListModal
onClose={() => setShowModal(false)} onClose={() => {
setErrorMsg(null)
setShowModal(false)
}}
errorMsg={errorMsg}
selectedCoin={clickedItem} selectedCoin={clickedItem}
addToBlacklist={addToBlacklist} addToBlacklist={addToBlacklist}
/> />

View file

@ -1,6 +1,11 @@
import { spacer, fontPrimary, primaryColor, white } from 'src/styling/variables' import {
spacer,
export default { fontPrimary,
primaryColor,
white,
errorColor
} from 'src/styling/variables'
const styles = {
grid: { grid: {
flex: 1, flex: 1,
height: '100%' height: '100%'
@ -35,5 +40,10 @@ export default {
}, },
addressRow: { addressRow: {
marginLeft: 8 marginLeft: 8
},
error: {
color: errorColor
} }
} }
export default styles

View file

@ -12,13 +12,16 @@ import { H3 } from 'src/components/typography'
import styles from './Blacklist.styles' import styles from './Blacklist.styles'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const BlackListModal = ({ onClose, selectedCoin, addToBlacklist }) => { const BlackListModal = ({
onClose,
selectedCoin,
addToBlacklist,
errorMsg
}) => {
const classes = useStyles() const classes = useStyles()
const handleAddToBlacklist = address => { const handleAddToBlacklist = address => {
addToBlacklist(selectedCoin.code, address) addToBlacklist(selectedCoin.code, address)
} }
const placeholderAddress = { const placeholderAddress = {
BTC: '1ADwinnimZKGgQ3dpyfoUZvJh4p1UWSSpD', BTC: '1ADwinnimZKGgQ3dpyfoUZvJh4p1UWSSpD',
ETH: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F', ETH: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F',
@ -45,7 +48,7 @@ const BlackListModal = ({ onClose, selectedCoin, addToBlacklist }) => {
.required('An address is required') .required('An address is required')
})} })}
onSubmit={({ address }, { resetForm }) => { onSubmit={({ address }, { resetForm }) => {
handleAddToBlacklist(address) handleAddToBlacklist(address.trim())
resetForm() resetForm()
}}> }}>
<Form id="address-form"> <Form id="address-form">
@ -54,6 +57,7 @@ const BlackListModal = ({ onClose, selectedCoin, addToBlacklist }) => {
? `Blacklist ${R.toLower(selectedCoin.display)} address` ? `Blacklist ${R.toLower(selectedCoin.display)} address`
: ''} : ''}
</H3> </H3>
<span className={classes.error}>{errorMsg}</span>
<Field <Field
name="address" name="address"
fullWidth fullWidth

View file

@ -10,6 +10,8 @@ import {
} from 'src/pages/Customers/components/propertyCard' } from 'src/pages/Customers/components/propertyCard'
import { ifNotNull } from 'src/utils/nullCheck' import { ifNotNull } from 'src/utils/nullCheck'
import { getName } from '../helper'
import Field from './Field' import Field from './Field'
const IdDataCard = memo(({ customerData, updateCustomer }) => { const IdDataCard = memo(({ customerData, updateCustomer }) => {
@ -21,9 +23,7 @@ const IdDataCard = memo(({ customerData, updateCustomer }) => {
const elements = [ const elements = [
{ {
header: 'Name', header: 'Name',
display: `${R.path(['firstName'])(idData)} ${R.path(['lastName'])( display: `${getName(customerData)}`,
idData
)}`,
size: 190 size: 190
}, },
{ {

View file

@ -3,9 +3,9 @@ import React, { useContext, useState } from 'react'
import * as Yup from 'yup' import * as Yup from 'yup'
import PromptWhenDirty from 'src/components/PromptWhenDirty' import PromptWhenDirty from 'src/components/PromptWhenDirty'
import { transformNumber } from 'src/utils/number'
import NotificationsCtx from '../NotificationsContext' import NotificationsCtx from '../NotificationsContext'
import { transformNumber } from '../helper'
import Header from './EditHeader' import Header from './EditHeader'
import EditableNumber from './EditableNumber' import EditableNumber from './EditableNumber'

View file

@ -1,6 +0,0 @@
import _ from 'lodash/fp'
const transformNumber = value =>
_.isNumber(value) && !_.isNaN(value) ? value : null
export { transformNumber }

View file

@ -5,9 +5,9 @@ import * as Yup from 'yup'
import { Table as EditableTable } from 'src/components/editableTable' import { Table as EditableTable } from 'src/components/editableTable'
import { NumberInput } from 'src/components/inputs/formik' import { NumberInput } from 'src/components/inputs/formik'
import Autocomplete from 'src/components/inputs/formik/Autocomplete.js' import Autocomplete from 'src/components/inputs/formik/Autocomplete.js'
import { transformNumber } from 'src/utils/number'
import NotificationsCtx from '../NotificationsContext' import NotificationsCtx from '../NotificationsContext'
import { transformNumber } from '../helper'
const HIGH_BALANCE_KEY = 'highBalance' const HIGH_BALANCE_KEY = 'highBalance'
const LOW_BALANCE_KEY = 'lowBalance' const LOW_BALANCE_KEY = 'lowBalance'

View file

@ -5,12 +5,12 @@ import * as Yup from 'yup'
import PromptWhenDirty from 'src/components/PromptWhenDirty' import PromptWhenDirty from 'src/components/PromptWhenDirty'
import { TL2 } from 'src/components/typography' import { TL2 } from 'src/components/typography'
import { transformNumber } from 'src/utils/number'
import { Cashbox } from '../../../components/inputs/cashbox/Cashbox' import { Cashbox } from '../../../components/inputs/cashbox/Cashbox'
import NotificationsCtx from '../NotificationsContext' import NotificationsCtx from '../NotificationsContext'
import Header from '../components/EditHeader' import Header from '../components/EditHeader'
import EditableNumber from '../components/EditableNumber' import EditableNumber from '../components/EditableNumber'
import { transformNumber } from '../helper'
import styles from './FiatBalanceAlerts.styles.js' import styles from './FiatBalanceAlerts.styles.js'

View file

@ -5,9 +5,9 @@ import * as Yup from 'yup'
import { Table as EditableTable } from 'src/components/editableTable' import { Table as EditableTable } from 'src/components/editableTable'
import { NumberInput } from 'src/components/inputs/formik/' import { NumberInput } from 'src/components/inputs/formik/'
import Autocomplete from 'src/components/inputs/formik/Autocomplete' import Autocomplete from 'src/components/inputs/formik/Autocomplete'
import { transformNumber } from 'src/utils/number'
import NotificationsCtx from '../NotificationsContext' import NotificationsCtx from '../NotificationsContext'
import { transformNumber } from '../helper'
const CASSETTE_1_KEY = 'fiatBalanceCassette1' const CASSETTE_1_KEY = 'fiatBalanceCassette1'
const CASSETTE_2_KEY = 'fiatBalanceCassette2' const CASSETTE_2_KEY = 'fiatBalanceCassette2'

View file

@ -6,7 +6,7 @@ import {
Autocomplete Autocomplete
} from 'src/components/inputs/formik' } from 'src/components/inputs/formik'
export default code => ({ const singleBitgo = code => ({
code: 'bitgo', code: 'bitgo',
name: 'BitGo', name: 'BitGo',
title: 'BitGo (Wallet)', title: 'BitGo (Wallet)',
@ -53,3 +53,5 @@ export default code => ({
.required() .required()
}) })
}) })
export default singleBitgo

View file

@ -216,7 +216,7 @@ const Wizard = ({ onClose, save, error, currency }) => {
onSubmit={onContinue} onSubmit={onContinue}
initialValues={stepOptions.initialValues} initialValues={stepOptions.initialValues}
validationSchema={stepOptions.schema}> validationSchema={stepOptions.schema}>
<Form onChange={console.log} className={classes.form}> <Form className={classes.form}>
<GetValues setValues={setLiveValues} /> <GetValues setValues={setLiveValues} />
<stepOptions.Component /> <stepOptions.Component />
<div className={classes.submit}> <div className={classes.submit}>

View file

@ -7,9 +7,9 @@ import * as Yup from 'yup'
import { TextInput, RadioGroup } from 'src/components/inputs/formik' import { TextInput, RadioGroup } from 'src/components/inputs/formik'
import { H4, Label2, Label1, Info2 } from 'src/components/typography' import { H4, Label2, Label1, Info2 } from 'src/components/typography'
import { errorColor } from 'src/styling/variables'
// import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg' // import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
// import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg' // import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
import { errorColor } from 'src/styling/variables'
const useStyles = makeStyles({ const useStyles = makeStyles({
radioLabel: { radioLabel: {
@ -72,13 +72,28 @@ const useStyles = makeStyles({
const triggerType = Yup.string().required() const triggerType = Yup.string().required()
const threshold = Yup.object().shape({ const threshold = Yup.object().shape({
threshold: Yup.number(), threshold: Yup.number(),
thresholdDays: Yup.number() thresholdDays: Yup.number().test({
test(val) {
const { triggerType } = this.parent
const requireThrehsold = ['txVolume', 'txVelocity']
if (R.isEmpty(val) && R.includes(triggerType, requireThrehsold)) {
return this.createError()
}
return true
}
})
}) })
const requirement = Yup.object().shape({ const requirement = Yup.object().shape({
requirement: Yup.string().required(), requirement: Yup.string().required(),
suspensionDays: Yup.number().when('requirement', { suspensionDays: Yup.number().when('requirement', {
is: 'suspend', is: 'suspend',
then: Yup.number().required() then: Yup.number().required(),
otherwise: Yup.number()
.nullable()
.transform(() => null)
}) })
}) })

View file

@ -1,6 +1,6 @@
import { makeStyles } from '@material-ui/core' import { makeStyles } from '@material-ui/core'
import React from 'react' import React from 'react'
import OperatorInfo from 'src/pages/OperatorInfo/OperatorInfo' // import OperatorInfo from 'src/pages/OperatorInfo'
import styles from 'src/pages/AddMachine/styles' import styles from 'src/pages/AddMachine/styles'
@ -11,7 +11,7 @@ function WizardOperatorInfo() {
return ( return (
<div className={classes.wrapper}> <div className={classes.wrapper}>
<OperatorInfo wizard={true}></OperatorInfo> {/* <OperatorInfo wizard={true}></OperatorInfo> */}
</div> </div>
) )
} }

View file

@ -1,6 +1,10 @@
import Fade from '@material-ui/core/Fade'
import Slide from '@material-ui/core/Slide'
import { makeStyles } from '@material-ui/core/styles'
import * as R from 'ramda' import * as R from 'ramda'
import React, { useContext } from 'react' import React, { useContext } from 'react'
import { import {
matchPath,
Route, Route,
Redirect, Redirect,
Switch, Switch,
@ -27,13 +31,22 @@ import ReceiptPrinting from 'src/pages/OperatorInfo/ReceiptPrinting'
import TermsConditions from 'src/pages/OperatorInfo/TermsConditions' import TermsConditions from 'src/pages/OperatorInfo/TermsConditions'
import ServerLogs from 'src/pages/ServerLogs' import ServerLogs from 'src/pages/ServerLogs'
import Services from 'src/pages/Services/Services' import Services from 'src/pages/Services/Services'
import TokenManagement from 'src/pages/TokenManagement/TokenManagement' // import TokenManagement from 'src/pages/TokenManagement/TokenManagement'
import Transactions from 'src/pages/Transactions/Transactions' import Transactions from 'src/pages/Transactions/Transactions'
import Triggers from 'src/pages/Triggers' import Triggers from 'src/pages/Triggers'
import WalletSettings from 'src/pages/Wallet/Wallet' import WalletSettings from 'src/pages/Wallet/Wallet'
import Wizard from 'src/pages/Wizard' import Wizard from 'src/pages/Wizard'
import { namespaces } from 'src/utils/config' import { namespaces } from 'src/utils/config'
const useStyles = makeStyles({
wrapper: {
flex: 1,
display: 'flex',
flexDirection: 'column',
height: '100%'
}
})
const tree = [ const tree = [
{ {
key: 'transactions', key: 'transactions',
@ -131,7 +144,14 @@ const tree = [
route: '/settings/operator-info', route: '/settings/operator-info',
title: 'Operator Information', title: 'Operator Information',
get component() { get component() {
return () => <Redirect to={this.children[0].route} /> return () => (
<Redirect
to={{
pathname: this.children[0].route,
state: { prev: this.state?.prev }
}}
/>
)
}, },
children: [ children: [
{ {
@ -194,23 +214,23 @@ const tree = [
component: CustomerProfile component: CustomerProfile
} }
] ]
},
{
key: 'system',
label: 'System',
route: '/system',
get component() {
return () => <Redirect to={this.children[0].route} />
},
children: [
{
key: 'token-management',
label: 'Token Management',
route: '/system/token-management',
component: TokenManagement
}
]
} }
// {
// key: 'system',
// label: 'System',
// route: '/system',
// get component() {
// return () => <Redirect to={this.children[0].route} />
// },
// children: [
// {
// key: 'token-management',
// label: 'Token Management',
// route: '/system/token-management',
// component: TokenManagement
// }
// ]
// }
] ]
const map = R.map(R.when(R.has('children'), R.prop('children'))) const map = R.map(R.when(R.has('children'), R.prop('children')))
@ -243,8 +263,11 @@ const getParent = route =>
)(flattened) )(flattened)
const Routes = () => { const Routes = () => {
const classes = useStyles()
const history = useHistory() const history = useHistory()
const location = useLocation() const location = useLocation()
const { wizardTested } = useContext(AppContext) const { wizardTested } = useContext(AppContext)
const dontTriggerPages = ['/404', '/register', '/wizard'] const dontTriggerPages = ['/404', '/register', '/wizard']
@ -253,6 +276,19 @@ const Routes = () => {
history.push('/wizard') history.push('/wizard')
} }
const Transition = location.state ? Slide : Fade
const transitionProps =
Transition === Slide
? {
direction:
R.findIndex(R.propEq('route', location.state.prev))(leafRoutes) >
R.findIndex(R.propEq('route', location.pathname))(leafRoutes)
? 'right'
: 'left'
}
: { timeout: 400 }
return ( return (
<Switch> <Switch>
<Route exact path="/"> <Route exact path="/">
@ -263,7 +299,18 @@ const Routes = () => {
<Route path="/configmigration" component={ConfigMigration} /> <Route path="/configmigration" component={ConfigMigration} />
{flattened.map(({ route, component: Page, key }) => ( {flattened.map(({ route, component: Page, key }) => (
<Route path={route} key={key}> <Route path={route} key={key}>
<Page name={key} /> <Transition
className={classes.wrapper}
{...transitionProps}
in={!!matchPath(location.pathname, { path: route })}
mountOnEnter
unmountOnExit
children={
<div className={classes.wrapper}>
<Page name={key} />
</div>
}
/>
</Route> </Route>
))} ))}
<Route path="/404" /> <Route path="/404" />

View file

@ -0,0 +1,7 @@
import * as R from 'ramda'
const isValidNumber = R.both(R.is(Number), R.complement(R.equals(NaN)))
const transformNumber = value => (isValidNumber(value) ? value : null)
export { transformNumber }

196
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "lamassu-server", "name": "lamassu-server",
"version": "7.5.0-beta.0", "version": "7.5.0-beta.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -57,25 +57,24 @@
} }
}, },
"@babel/core": { "@babel/core": {
"version": "7.12.9", "version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz",
"integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.10.4", "@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5", "@babel/generator": "^7.12.10",
"@babel/helper-module-transforms": "^7.12.1", "@babel/helper-module-transforms": "^7.12.1",
"@babel/helpers": "^7.12.5", "@babel/helpers": "^7.12.5",
"@babel/parser": "^7.12.7", "@babel/parser": "^7.12.10",
"@babel/template": "^7.12.7", "@babel/template": "^7.12.7",
"@babel/traverse": "^7.12.9", "@babel/traverse": "^7.12.10",
"@babel/types": "^7.12.7", "@babel/types": "^7.12.10",
"convert-source-map": "^1.7.0", "convert-source-map": "^1.7.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.1", "gensync": "^1.0.0-beta.1",
"json5": "^2.1.2", "json5": "^2.1.2",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"resolve": "^1.3.2",
"semver": "^5.4.1", "semver": "^5.4.1",
"source-map": "^0.5.0" "source-map": "^0.5.0"
}, },
@ -110,12 +109,12 @@
} }
}, },
"@babel/generator": { "@babel/generator": {
"version": "7.12.5", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz",
"integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.12.5", "@babel/types": "^7.12.11",
"jsesc": "^2.5.1", "jsesc": "^2.5.1",
"source-map": "^0.5.0" "source-map": "^0.5.0"
}, },
@ -129,23 +128,23 @@
} }
}, },
"@babel/helper-function-name": { "@babel/helper-function-name": {
"version": "7.10.4", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz",
"integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-get-function-arity": "^7.10.4", "@babel/helper-get-function-arity": "^7.12.10",
"@babel/template": "^7.10.4", "@babel/template": "^7.12.7",
"@babel/types": "^7.10.4" "@babel/types": "^7.12.11"
} }
}, },
"@babel/helper-get-function-arity": { "@babel/helper-get-function-arity": {
"version": "7.10.4", "version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz",
"integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.10.4" "@babel/types": "^7.12.10"
} }
}, },
"@babel/helper-member-expression-to-functions": { "@babel/helper-member-expression-to-functions": {
@ -184,12 +183,12 @@
} }
}, },
"@babel/helper-optimise-call-expression": { "@babel/helper-optimise-call-expression": {
"version": "7.12.7", "version": "7.12.10",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz",
"integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.12.7" "@babel/types": "^7.12.10"
} }
}, },
"@babel/helper-plugin-utils": { "@babel/helper-plugin-utils": {
@ -199,15 +198,15 @@
"dev": true "dev": true
}, },
"@babel/helper-replace-supers": { "@babel/helper-replace-supers": {
"version": "7.12.5", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz",
"integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-member-expression-to-functions": "^7.12.1", "@babel/helper-member-expression-to-functions": "^7.12.7",
"@babel/helper-optimise-call-expression": "^7.10.4", "@babel/helper-optimise-call-expression": "^7.12.10",
"@babel/traverse": "^7.12.5", "@babel/traverse": "^7.12.10",
"@babel/types": "^7.12.5" "@babel/types": "^7.12.11"
} }
}, },
"@babel/helper-simple-access": { "@babel/helper-simple-access": {
@ -220,12 +219,12 @@
} }
}, },
"@babel/helper-split-export-declaration": { "@babel/helper-split-export-declaration": {
"version": "7.11.0", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz",
"integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.11.0" "@babel/types": "^7.12.11"
} }
}, },
"@babel/helper-validator-identifier": { "@babel/helper-validator-identifier": {
@ -257,9 +256,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.12.7", "version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz",
"integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==", "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==",
"dev": true "dev": true
}, },
"@babel/plugin-syntax-async-generators": { "@babel/plugin-syntax-async-generators": {
@ -397,22 +396,31 @@
} }
}, },
"@babel/traverse": { "@babel/traverse": {
"version": "7.12.9", "version": "7.12.12",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz",
"integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.10.4", "@babel/code-frame": "^7.12.11",
"@babel/generator": "^7.12.5", "@babel/generator": "^7.12.11",
"@babel/helper-function-name": "^7.10.4", "@babel/helper-function-name": "^7.12.11",
"@babel/helper-split-export-declaration": "^7.11.0", "@babel/helper-split-export-declaration": "^7.12.11",
"@babel/parser": "^7.12.7", "@babel/parser": "^7.12.11",
"@babel/types": "^7.12.7", "@babel/types": "^7.12.12",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0", "globals": "^11.1.0",
"lodash": "^4.17.19" "lodash": "^4.17.19"
}, },
"dependencies": { "dependencies": {
"@babel/code-frame": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
"integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true,
"requires": {
"@babel/highlight": "^7.10.4"
}
},
"debug": { "debug": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@ -431,14 +439,22 @@
} }
}, },
"@babel/types": { "@babel/types": {
"version": "7.12.7", "version": "7.12.12",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.10.4", "@babel/helper-validator-identifier": "^7.12.11",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
"integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
"dev": true
}
} }
}, },
"@bcoe/v8-coverage": { "@bcoe/v8-coverage": {
@ -1170,9 +1186,9 @@
} }
}, },
"@types/babel__traverse": { "@types/babel__traverse": {
"version": "7.0.16", "version": "7.11.0",
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.16.tgz", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz",
"integrity": "sha512-S63Dt4CZOkuTmpLGGWtT/mQdVORJOpx6SZWGVaP56dda/0Nx5nEe82K7/LAm8zYr6SfMq+1N2OreIOrHAx656w==", "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/types": "^7.3.0" "@babel/types": "^7.3.0"
@ -1407,9 +1423,9 @@
} }
}, },
"@types/prettier": { "@types/prettier": {
"version": "2.1.5", "version": "2.1.6",
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.6.tgz",
"integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", "integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA==",
"dev": true "dev": true
}, },
"@types/qs": { "@types/qs": {
@ -1454,18 +1470,18 @@
} }
}, },
"@types/yargs": { "@types/yargs": {
"version": "15.0.11", "version": "15.0.12",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.11.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.12.tgz",
"integrity": "sha512-jfcNBxHFYJ4nPIacsi3woz1+kvUO6s1CyeEhtnDHBjHUMNj5UlW2GynmnSgiJJEdNg9yW5C8lfoNRZrHGv5EqA==", "integrity": "sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/yargs-parser": "*" "@types/yargs-parser": "*"
} }
}, },
"@types/yargs-parser": { "@types/yargs-parser": {
"version": "15.0.0", "version": "20.2.0",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz",
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==",
"dev": true "dev": true
}, },
"@wry/equality": { "@wry/equality": {
@ -2537,9 +2553,9 @@
} }
}, },
"babel-preset-current-node-syntax": { "babel-preset-current-node-syntax": {
"version": "1.0.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
"integrity": "sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q==", "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-async-generators": "^7.8.4",
@ -4773,6 +4789,11 @@
"whatwg-url": "^8.0.0" "whatwg-url": "^8.0.0"
} }
}, },
"dataloader": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz",
"integrity": "sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ=="
},
"date-fns": { "date-fns": {
"version": "2.16.1", "version": "2.16.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
@ -6131,25 +6152,6 @@
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
"integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
"dasherize": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz",
"integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg="
},
"data-uri-to-buffer": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz",
"integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ=="
},
"dataloader": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz",
"integrity": "sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ=="
},
"date-fns": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
"integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==",
"dev": true "dev": true
}, },
"expand-brackets": { "expand-brackets": {
@ -10756,9 +10758,9 @@
"dev": true "dev": true
}, },
"node-notifier": { "node-notifier": {
"version": "8.0.0", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz",
"integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==",
"dev": true, "dev": true,
"optional": true, "optional": true,
"requires": { "requires": {
@ -10771,9 +10773,9 @@
}, },
"dependencies": { "dependencies": {
"uuid": { "uuid": {
"version": "8.3.1", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
@ -15324,9 +15326,9 @@
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}, },
"v8-to-istanbul": { "v8-to-istanbul": {
"version": "7.0.0", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz",
"integrity": "sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA==", "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/istanbul-lib-coverage": "^2.0.1", "@types/istanbul-lib-coverage": "^2.0.1",

View file

@ -2,7 +2,7 @@
"name": "lamassu-server", "name": "lamassu-server",
"description": "bitcoin atm client server protocol module", "description": "bitcoin atm client server protocol module",
"keywords": [], "keywords": [],
"version": "7.5.0-beta.0", "version": "7.5.0-beta.1",
"license": "Unlicense", "license": "Unlicense",
"author": "Lamassu (https://lamassu.is)", "author": "Lamassu (https://lamassu.is)",
"dependencies": { "dependencies": {

View file

@ -1,13 +1,13 @@
{ {
"files": { "files": {
"main.js": "/static/js/main.d0c68b02.chunk.js", "main.js": "/static/js/main.0f20b202.chunk.js",
"main.js.map": "/static/js/main.d0c68b02.chunk.js.map", "main.js.map": "/static/js/main.0f20b202.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.f0000622.js", "runtime-main.js": "/static/js/runtime-main.f0000622.js",
"runtime-main.js.map": "/static/js/runtime-main.f0000622.js.map", "runtime-main.js.map": "/static/js/runtime-main.f0000622.js.map",
"static/js/2.e506a40f.chunk.js": "/static/js/2.e506a40f.chunk.js", "static/js/2.c456abde.chunk.js": "/static/js/2.c456abde.chunk.js",
"static/js/2.e506a40f.chunk.js.map": "/static/js/2.e506a40f.chunk.js.map", "static/js/2.c456abde.chunk.js.map": "/static/js/2.c456abde.chunk.js.map",
"index.html": "/index.html", "index.html": "/index.html",
"static/js/2.e506a40f.chunk.js.LICENSE.txt": "/static/js/2.e506a40f.chunk.js.LICENSE.txt", "static/js/2.c456abde.chunk.js.LICENSE.txt": "/static/js/2.c456abde.chunk.js.LICENSE.txt",
"static/media/cash-in.c06970a7.svg": "/static/media/cash-in.c06970a7.svg", "static/media/cash-in.c06970a7.svg": "/static/media/cash-in.c06970a7.svg",
"static/media/cash-out.f029ae96.svg": "/static/media/cash-out.f029ae96.svg", "static/media/cash-out.f029ae96.svg": "/static/media/cash-out.f029ae96.svg",
"static/media/cashout-cassette-1.fac6c691.svg": "/static/media/cashout-cassette-1.fac6c691.svg", "static/media/cashout-cassette-1.fac6c691.svg": "/static/media/cashout-cassette-1.fac6c691.svg",
@ -53,6 +53,7 @@
"static/media/white.958fe55d.svg": "/static/media/white.958fe55d.svg", "static/media/white.958fe55d.svg": "/static/media/white.958fe55d.svg",
"static/media/white.9814829c.svg": "/static/media/white.9814829c.svg", "static/media/white.9814829c.svg": "/static/media/white.9814829c.svg",
"static/media/white.aa3a2aa4.svg": "/static/media/white.aa3a2aa4.svg", "static/media/white.aa3a2aa4.svg": "/static/media/white.aa3a2aa4.svg",
"static/media/white.cc7667ff.svg": "/static/media/white.cc7667ff.svg",
"static/media/white.d630943a.svg": "/static/media/white.d630943a.svg", "static/media/white.d630943a.svg": "/static/media/white.d630943a.svg",
"static/media/white.e72682b5.svg": "/static/media/white.e72682b5.svg", "static/media/white.e72682b5.svg": "/static/media/white.e72682b5.svg",
"static/media/white.e8851a0a.svg": "/static/media/white.e8851a0a.svg", "static/media/white.e8851a0a.svg": "/static/media/white.e8851a0a.svg",
@ -80,7 +81,7 @@
}, },
"entrypoints": [ "entrypoints": [
"static/js/runtime-main.f0000622.js", "static/js/runtime-main.f0000622.js",
"static/js/2.e506a40f.chunk.js", "static/js/2.c456abde.chunk.js",
"static/js/main.d0c68b02.chunk.js" "static/js/main.0f20b202.chunk.js"
] ]
} }

View file

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Lamassu Admin</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root" class="root"></div><script>!function(e){function r(r){for(var n,a,l=r[0],i=r[1],f=r[2],c=0,s=[];c<l.length;c++)a=l[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var i=t[l];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/";var l=this["webpackJsonplamassu-admin"]=this["webpackJsonplamassu-admin"]||[],i=l.push.bind(l);l.push=r,l=l.slice();for(var f=0;f<l.length;f++)r(l[f]);var p=i;t()}([])</script><script src="/static/js/2.e506a40f.chunk.js"></script><script src="/static/js/main.d0c68b02.chunk.js"></script></body></html> <!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Lamassu Admin</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root" class="root"></div><script>!function(e){function r(r){for(var n,a,l=r[0],i=r[1],f=r[2],c=0,s=[];c<l.length;c++)a=l[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var i=t[l];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/";var l=this["webpackJsonplamassu-admin"]=this["webpackJsonplamassu-admin"]||[],i=l.push.bind(l);l.push=r,l=l.slice();for(var f=0;f<l.length;f++)r(l[f]);var p=i;t()}([])</script><script src="/static/js/2.c456abde.chunk.js"></script><script src="/static/js/main.0f20b202.chunk.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="12px" height="12px" viewBox="0 0 12 12" 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="icon/button/add/white" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<path d="M11.5384615,6 C11.5384615,9.05815385 9.05815385,11.5384615 6,11.5384615 C2.94184615,11.5384615 0.461538462,9.05815385 0.461538462,6 C0.461538462,2.94184615 2.94184615,0.461538462 6,0.461538462 C9.05815385,0.461538462 11.5384615,2.94184615 11.5384615,6 Z" id="Stroke-1" stroke="#FFFFFF"></path>
<line x1="6" y1="3.69230769" x2="6" y2="8.30769231" id="Stroke-3" stroke="#FFFFFF"></line>
<line x1="3.69230769" y1="6" x2="8.30769231" y2="6" id="Stroke-5" stroke="#FFFFFF"></line>
</g>
</svg>

After

Width:  |  Height:  |  Size: 956 B