From 7d9c46824229c66a14f03603e38db3eead4d316b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 24 May 2022 18:32:38 +0100 Subject: [PATCH 001/119] fix: remove cash-in transaction retry --- lib/cash-in/cash-in-tx.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 8f7703cb..cc676554 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -148,18 +148,17 @@ function postProcess (r, pi, isBlacklisted, addressReuse, walletScore) { } }) .catch(err => { - // Important: We don't know what kind of error this is - // so not safe to assume that funds weren't sent. - // Therefore, don't set sendPending to false except for - // errors (like InsufficientFundsError) that are guaranteed - // not to send. - const sendPending = err.name !== 'InsufficientFundsError' + // Important: We don't know what kind of error this is + // so not safe to assume that funds weren't sent. + + // Setting sendPending to true ensures that the transaction gets + // silently terminated and no retries are done return { sendTime: 'now()^', error: err.message, errorCode: err.name, - sendPending + sendPending: true } }) .then(sendRec => { From 5567f7800538143c0b4b7c7f41d687b262ad9419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 14 Jun 2022 18:17:15 +0100 Subject: [PATCH 002/119] fix: locales wizard account save function --- new-lamassu-admin/src/pages/Locales/Locales.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/new-lamassu-admin/src/pages/Locales/Locales.js b/new-lamassu-admin/src/pages/Locales/Locales.js index 3a820c8a..1afdf1ce 100644 --- a/new-lamassu-admin/src/pages/Locales/Locales.js +++ b/new-lamassu-admin/src/pages/Locales/Locales.js @@ -61,8 +61,9 @@ const GET_DATA = gql` ` const SAVE_CONFIG = gql` - mutation Save($config: JSONObject) { + mutation Save($config: JSONObject, $accounts: JSONObject) { saveConfig(config: $config) + saveAccounts(accounts: $accounts) } ` @@ -134,9 +135,9 @@ const Locales = ({ name: SCREEN_KEY }) => { return save(newConfig) } - const save = config => { + const save = (config, accounts) => { setDataToSave(null) - return saveConfig({ variables: { config } }) + return saveConfig({ variables: { config, accounts } }) } const saveOverrides = it => { @@ -162,8 +163,8 @@ const Locales = ({ name: SCREEN_KEY }) => { const onEditingDefault = (it, editing) => setEditingDefault(editing) const onEditingOverrides = (it, editing) => setEditingOverrides(editing) - const wizardSave = it => - save(toNamespace(namespaces.WALLETS)(it)).then(it => { + const wizardSave = (config, accounts) => + save(toNamespace(namespaces.WALLETS)(config), accounts).then(it => { onChangeFunction() setOnChangeFunction(null) return it From e9a7cf2903e3a34637cc7e733827a304f53ca8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Fri, 1 Jul 2022 18:09:01 +0100 Subject: [PATCH 003/119] fix: add fallbackfee and rpcworkqueue values on bitcoind.conf --- lib/blockchain/bitcoin.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/blockchain/bitcoin.js b/lib/blockchain/bitcoin.js index 12c96815..80b6dd3a 100644 --- a/lib/blockchain/bitcoin.js +++ b/lib/blockchain/bitcoin.js @@ -55,6 +55,20 @@ function updateCore (coinRec, isCurrentlyRunning) { common.es(`echo "\nlistenonion=0" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`) } + if (common.es(`grep "fallbackfee=" ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf || true`)) { + common.logger.info(`fallbackfee already defined, skipping...`) + } else { + common.logger.info(`Setting 'fallbackfee=0.00005' in config file...`) + common.es(`echo "\nfallbackfee=0.00005" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`) + } + + if (common.es(`grep "rpcworkqueue=" ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf || true`)) { + common.logger.info(`rpcworkqueue already defined, skipping...`) + } else { + common.logger.info(`Setting 'rpcworkqueue=2000' in config file...`) + common.es(`echo "\nrpcworkqueue=2000" >> ${BLOCKCHAIN_DIR}/bitcoin/bitcoin.conf`) + } + if (isCurrentlyRunning && !isDevMode()) { common.logger.info('Starting wallet...') common.es(`sudo supervisorctl start bitcoin`) From 8bd481c8e42880b0f36d67ac2b03364040150eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Wed, 20 Jul 2022 18:29:05 +0100 Subject: [PATCH 004/119] fix: transaction details ID button popper positioning --- new-lamassu-admin/src/components/Popper.js | 46 +++++++++++++------ .../src/components/buttons/IDButton.js | 6 ++- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/new-lamassu-admin/src/components/Popper.js b/new-lamassu-admin/src/components/Popper.js index db01740d..a933e39d 100644 --- a/new-lamassu-admin/src/components/Popper.js +++ b/new-lamassu-admin/src/components/Popper.js @@ -105,20 +105,29 @@ const Popover = ({ const classes = useStyles() - const arrowClasses = { + const getArrowClasses = placement => ({ [classes.arrow]: true, - [classes.arrowBottom]: props.placement === 'bottom', - [classes.arrowTop]: props.placement === 'top', - [classes.arrowRight]: props.placement === 'right', - [classes.arrowLeft]: props.placement === 'left' + [classes.arrowBottom]: placement === 'bottom', + [classes.arrowTop]: placement === 'top', + [classes.arrowRight]: placement === 'right', + [classes.arrowLeft]: placement === 'left' + }) + + const flipPlacements = { + top: ['bottom'], + bottom: ['top'], + left: ['right'], + right: ['left'] } - const modifiers = R.merge(props.modifiers, { + const modifiers = R.mergeDeepLeft(props.modifiers, { flip: { - enabled: false + enabled: R.defaultTo(false, props.flip), + allowedAutoPlacements: flipPlacements[props.placement], + boundary: 'clippingParents' }, preventOverflow: { - enabled: true, + enabled: R.defaultTo(true, props.preventOverflow), boundariesElement: 'scrollParent' }, offset: { @@ -126,7 +135,7 @@ const Popover = ({ offset: '0, 10' }, arrow: { - enabled: true, + enabled: R.defaultTo(true, props.showArrow), element: arrowRef }, computeStyle: { @@ -134,6 +143,12 @@ const Popover = ({ } }) + if (props.preventOverflow === false) { + modifiers.hide = { + enabled: false + } + } + return ( <> - - - {children} - + {({ placement }) => ( + + + {children} + + )} ) diff --git a/new-lamassu-admin/src/components/buttons/IDButton.js b/new-lamassu-admin/src/components/buttons/IDButton.js index e6e9b55a..15c55602 100644 --- a/new-lamassu-admin/src/components/buttons/IDButton.js +++ b/new-lamassu-admin/src/components/buttons/IDButton.js @@ -56,7 +56,8 @@ const styles = { alignItems: 'center', borderRadius: 4, '& img': { - maxHeight: 145 + height: 145, + minWidth: 200 } } } @@ -127,7 +128,8 @@ const IDButton = memo( anchorEl={anchorEl} onClose={handleClose} arrowSize={3} - placement="top"> + placement="top" + flip>
{children}
From 61130157563e3d57f03f5a820e850aaae3bf956a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 12 Jul 2022 18:09:56 +0100 Subject: [PATCH 005/119] fix: add click away listener to tooltips --- new-lamassu-admin/src/components/Tooltip.js | 47 ++++++++++----------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/new-lamassu-admin/src/components/Tooltip.js b/new-lamassu-admin/src/components/Tooltip.js index 2fa5b7f9..3808c286 100644 --- a/new-lamassu-admin/src/components/Tooltip.js +++ b/new-lamassu-admin/src/components/Tooltip.js @@ -69,30 +69,29 @@ const HoverableTooltip = memo(({ parentElements, children, width }) => { const handler = usePopperHandler(width) return ( -
- {!R.isNil(parentElements) && ( -
- {parentElements} -
- )} - {R.isNil(parentElements) && ( - - )} - -
{children}
-
-
+ +
+ {!R.isNil(parentElements) && ( +
+ {parentElements} +
+ )} + {R.isNil(parentElements) && ( + + )} + +
{children}
+
+
+
) }) From 4dc4d14742e187513ad515e1765713927197acd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Mon, 1 Aug 2022 12:23:02 +0100 Subject: [PATCH 006/119] fix: export all transactions to CSV --- lib/new-admin/services/transactions.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index 733fcad9..58983305 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -51,6 +51,7 @@ function batch ( simplified ) { const packager = _.flow(_.flatten, _.orderBy(_.property('created'), ['desc']), _.map(camelize), addProfits, addNames) + const isCsvExport = _.isBoolean(simplified) const cashInSql = `SELECT 'cashIn' AS tx_class, txs.*, c.phone AS customer_phone, @@ -80,7 +81,7 @@ function batch ( AND ($12 is null or txs.to_address = $12) AND ($13 is null or txs.txStatus = $13) ${excludeTestingCustomers ? `AND c.is_test_customer is false` : ``} - AND (error IS NOT null OR tb.error_message IS NOT null OR fiat > 0) + ${isCsvExport ? '' : 'AND (error IS NOT null OR tb.error_message IS NOT null OR fiat > 0)'} ORDER BY created DESC limit $4 offset $5` const cashOutSql = `SELECT 'cashOut' AS tx_class, @@ -114,7 +115,7 @@ function batch ( AND ($13 is null or txs.txStatus = $13) AND ($14 is null or txs.swept = $14) ${excludeTestingCustomers ? `AND c.is_test_customer is false` : ``} - AND (fiat > 0) + ${isCsvExport ? '' : 'AND fiat > 0'} ORDER BY created DESC limit $4 offset $5` // The swept filter is cash-out only, so omit the cash-in query entirely From eed09b52ca75aa92471fa3da998b9d4aed84fe38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Tue, 2 Aug 2022 15:50:48 +0100 Subject: [PATCH 007/119] refactor: simplified CSV testing --- lib/new-admin/services/transactions.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index 58983305..5ecf5c05 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -141,14 +141,14 @@ function batch ( return Promise.all(promises) .then(packager) - .then(res => { - if (simplified) return simplifiedBatch(res) + .then(res => + !isCsvExport ? res : // GQL transactions and transactionsCsv both use this function and // if we don't check for the correct simplified value, the Transactions page polling // will continuously build a csv in the background - else if (simplified === false) return advancedBatch(res) - return res - }) + simplified ? simplifiedBatch(res) : + advancedBatch(res) + ) } function advancedBatch (data) { From 753595e0df1729636ba721ac2426c068474c1b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Mon, 12 Sep 2022 16:37:47 +0100 Subject: [PATCH 008/119] fix: don't export empty transactions to simplified CSV --- lib/new-admin/services/transactions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index 5ecf5c05..439c0a3e 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -81,7 +81,7 @@ function batch ( AND ($12 is null or txs.to_address = $12) AND ($13 is null or txs.txStatus = $13) ${excludeTestingCustomers ? `AND c.is_test_customer is false` : ``} - ${isCsvExport ? '' : 'AND (error IS NOT null OR tb.error_message IS NOT null OR fiat > 0)'} + ${isCsvExport && !simplified ? '' : 'AND (error IS NOT null OR tb.error_message IS NOT null OR fiat > 0)'} ORDER BY created DESC limit $4 offset $5` const cashOutSql = `SELECT 'cashOut' AS tx_class, From 65e5c12b9221423e01feb8f1b3142ac3e834ce5c Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 26 Sep 2022 14:40:59 +0200 Subject: [PATCH 009/119] fix: display error status --- .../src/pages/Transactions/CopyToClipboard.js | 4 +++- .../src/pages/Transactions/DetailsCard.js | 15 ++++++++------- .../src/pages/Transactions/DetailsCard.styles.js | 4 ++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js b/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js index 1c14a2e3..b6c63914 100644 --- a/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js +++ b/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js @@ -17,6 +17,7 @@ const CopyToClipboard = ({ buttonClassname, children, wrapperClassname, + removeSpace = true, ...props }) => { const [anchorEl, setAnchorEl] = useState(null) @@ -46,7 +47,8 @@ const CopyToClipboard = ({ {children}
- +
- {getStatusDetails(tx) ? ( - -

{getStatusDetails(tx)}

-
- ) : ( - errorElements - )} + {errorElements} {((tx.txClass === 'cashOut' && getStatus(tx) === 'Pending') || (tx.txClass === 'cashIn' && getStatus(tx) === 'Batched')) && ( Date: Thu, 20 Oct 2022 23:25:33 +0200 Subject: [PATCH 010/119] fix: typeface --- new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js index a55d40db..e7ec6e01 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.styles.js @@ -1,7 +1,7 @@ import typographyStyles from 'src/components/typography/styles' import { offColor, comet, white, tomato } from 'src/styling/variables' -const { p } = typographyStyles +const { p, label3 } = typographyStyles export default { wrapper: { @@ -139,6 +139,7 @@ export default { width: 250 }, errorCopy: { + extend: label3, lineBreak: 'normal', maxWidth: 180 } From f079a2926b3a528a453f3ec7ea31475ce643c423 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Wed, 10 Aug 2022 23:20:45 +0200 Subject: [PATCH 011/119] feat: add period of three days --- new-lamassu-admin/src/pages/Analytics/Analytics.js | 2 ++ .../src/pages/Analytics/graphs/OverTimeDotGraph.js | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index b7eed8fa..2e0afc7f 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -34,11 +34,13 @@ const REPRESENTING_OPTIONS = [ ] const PERIOD_OPTIONS = [ { code: 'day', display: 'Last 24 hours' }, + { code: 'threeDays', display: 'Last 3 days' }, { code: 'week', display: 'Last 7 days' }, { code: 'month', display: 'Last 30 days' } ] const TIME_OPTIONS = { day: DAY, + threeDays: 3 * DAY, week: WEEK, month: MONTH } diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js index acd7a181..2dad847c 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js @@ -46,6 +46,7 @@ const Graph = ({ const periodDomains = { day: [NOW - DAY, NOW], + threeDays: [NOW - 3 * DAY, NOW], week: [NOW - WEEK, NOW], month: [NOW - MONTH, NOW] } @@ -58,6 +59,12 @@ const Graph = ({ tick: d3.utcHour.every(1), labelFormat: '%H:%M' }, + threeDays: { + freq: 12, + step: 6 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%a %d' + }, week: { freq: 7, step: 24 * 60 * 60 * 1000, From 80715259b1af76e06fe59c1ba1d1e8ef556ecb20 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Thu, 11 Aug 2022 20:19:59 +0200 Subject: [PATCH 012/119] feat: add y log scale --- .../src/pages/Analytics/Analytics.styles.js | 24 ++++++- .../components/wrappers/OverTimeWrapper.js | 11 ++- .../src/pages/Analytics/graphs/Graph.js | 4 +- .../Analytics/graphs/OverTimeDotGraph.js | 69 +++++++++++-------- 4 files changed, 75 insertions(+), 33 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js b/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js index 089547f8..8274d929 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.styles.js @@ -1,4 +1,14 @@ -import { offDarkColor, tomato, neon, java } from 'src/styling/variables' +import { + offColor, + offDarkColor, + tomato, + neon, + java +} from 'src/styling/variables' + +import typographyStyles from '../../components/typography/styles' + +const { label1 } = typographyStyles const styles = { overviewLegend: { @@ -135,6 +145,18 @@ const styles = { topMachinesRadio: { display: 'flex', flexDirection: 'row' + }, + graphHeaderSwitchBox: { + display: 'flex', + flexDirection: 'column', + '& > *': { + margin: 0 + }, + '& > :first-child': { + marginBottom: 2, + extend: label1, + color: offColor + } } } diff --git a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js index 502d817a..def8fe90 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js +++ b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js @@ -1,8 +1,8 @@ import { Box } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' -import React from 'react' +import React, { useState } from 'react' -import { Select } from 'src/components/inputs' +import { Select, Switch } from 'src/components/inputs' import { H2 } from 'src/components/typography' import { primaryColor } from 'src/styling/variables' @@ -25,6 +25,8 @@ const OverTimeDotGraphHeader = ({ }) => { const classes = useStyles() + const [logarithmic, setLogarithmic] = useState() + const legend = { cashIn:
, cashOut:
, @@ -57,6 +59,10 @@ const OverTimeDotGraphHeader = ({
+
+ Log. scale + setLogarithmic(event.target.checked)} /> +
+
+
+ + + ) +} + +export default VolumeOverTimeGraphHeader diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js b/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js index 720ee687..18ac8fdf 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/Graph.js @@ -5,6 +5,7 @@ import GraphTooltip from '../components/tooltips/GraphTooltip' import HourOfDayBarGraph from './HourOfDayBarGraph' import OverTimeDotGraph from './OverTimeDotGraph' +import OverTimeLineGraph from './OverTimeLineGraph' import TopMachinesBarGraph from './TopMachinesBarGraph' const GraphWrapper = ({ @@ -37,6 +38,19 @@ const GraphWrapper = ({ log={log} /> ) + case 'volumeOverTime': + return ( + + ) case 'topMachinesVolume': return ( { + const ref = useRef(null) + + const GRAPH_POPOVER_WIDTH = 150 + const GRAPH_POPOVER_MARGIN = 25 + const GRAPH_HEIGHT = 401 + const GRAPH_WIDTH = 1163 + const GRAPH_MARGIN = useMemo( + () => ({ + top: 25, + right: 3.5, + bottom: 27, + left: 36.5 + }), + [] + ) + + const offset = getTimezoneOffset(timezone) + const NOW = Date.now() + offset + + const periodDomains = { + day: [NOW - DAY, NOW], + threeDays: [NOW - 3 * DAY, NOW], + week: [NOW - WEEK, NOW], + month: [NOW - MONTH, NOW] + } + + const dataPoints = useMemo( + () => ({ + day: { + freq: 24, + step: 60 * 60 * 1000, + tick: d3.utcHour.every(1), + labelFormat: '%H:%M' + }, + threeDays: { + freq: 12, + step: 6 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%a %d' + }, + week: { + freq: 7, + step: 24 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%a %d' + }, + month: { + freq: 30, + step: 24 * 60 * 60 * 1000, + tick: d3.utcDay.every(1), + labelFormat: '%d' + } + }), + [] + ) + + const getPastAndCurrentDayLabels = useCallback(d => { + const currentDate = new Date(d) + const currentDateDay = currentDate.getUTCDate() + const currentDateWeekday = currentDate.getUTCDay() + const currentDateMonth = currentDate.getUTCMonth() + + const previousDate = new Date(currentDate.getTime()) + previousDate.setUTCDate(currentDateDay - 1) + + const previousDateDay = previousDate.getUTCDate() + const previousDateWeekday = previousDate.getUTCDay() + const previousDateMonth = previousDate.getUTCMonth() + + const daysOfWeek = Array.from(Array(7)).map((_, i) => + format('EEE', add({ days: i }, startOfWeek(new Date()))) + ) + + const months = Array.from(Array(12)).map((_, i) => + format('LLL', add({ months: i }, startOfYear(new Date()))) + ) + + return { + previous: + currentDateMonth !== previousDateMonth + ? months[previousDateMonth] + : `${daysOfWeek[previousDateWeekday]} ${previousDateDay}`, + current: + currentDateMonth !== previousDateMonth + ? months[currentDateMonth] + : `${daysOfWeek[currentDateWeekday]} ${currentDateDay}` + } + }, []) + + const buildTicks = useCallback( + domain => { + const points = [] + + const roundDate = d => { + const step = dataPoints[period.code].step + return new Date(Math.ceil(d.valueOf() / step) * step) + } + + for (let i = 0; i <= dataPoints[period.code].freq; i++) { + const stepDate = new Date(NOW - i * dataPoints[period.code].step) + if (roundDate(stepDate) > domain[1]) continue + if (stepDate < domain[0]) continue + points.push(roundDate(stepDate)) + } + + return points + }, + [NOW, dataPoints, period.code] + ) + + const buildAreas = useCallback( + domain => { + const points = [] + + points.push(domain[1]) + + const roundDate = d => { + const step = dataPoints[period.code].step + return new Date(Math.ceil(d.valueOf() / step) * step) + } + + for (let i = 0; i <= dataPoints[period.code].freq; i++) { + const stepDate = new Date(NOW - i * dataPoints[period.code].step) + if (roundDate(stepDate) > new Date(domain[1])) continue + if (stepDate < new Date(domain[0])) continue + points.push(roundDate(stepDate)) + } + + points.push(domain[0]) + + return points + }, + [NOW, dataPoints, period.code] + ) + + const x = d3 + .scaleUtc() + .domain(periodDomains[period.code]) + .range([GRAPH_MARGIN.left, GRAPH_WIDTH - GRAPH_MARGIN.right]) + + // Create a second X axis for mouseover events to be placed correctly across the entire graph width and not limited by X's domain + const x2 = d3 + .scaleUtc() + .domain(periodDomains[period.code]) + .range([GRAPH_MARGIN.left, GRAPH_WIDTH]) + + const bins = buildAreas(x.domain()) + .sort((a, b) => compareDesc(a.date, b.date)) + .map(addMilliseconds(-dataPoints[period.code].step)) + .map((date, i, dates) => { + // move first and last bin in such way + // that all bin have uniform width + if (i === 0) + return addMilliseconds(dataPoints[period.code].step, dates[1]) + else if (i === dates.length - 1) + return addMilliseconds( + -dataPoints[period.code].step, + dates[dates.length - 2] + ) + else return date + }) + .map(date => { + const middleOfBin = addMilliseconds( + dataPoints[period.code].step / 2, + date + ) + + const txs = data.filter(tx => { + const txCreated = new Date(tx.created) + const shift = new Date(txCreated.getTime() + offset) + + return ( + Math.abs(differenceInMilliseconds(shift, middleOfBin)) < + dataPoints[period.code].step / 2 + ) + }) + + const cashIn = txs + .filter(tx => tx.txClass === 'cashIn') + .reduce((sum, tx) => sum + new BigNumber(tx.fiat).toNumber(), 0) + + const cashOut = txs + .filter(tx => tx.txClass === 'cashOut') + .reduce((sum, tx) => sum + new BigNumber(tx.fiat).toNumber(), 0) + + return { date: middleOfBin, cashIn, cashOut } + }) + + const min = d3.min(bins, d => Math.min(d.cashIn, d.cashOut)) ?? 0 + const max = d3.max(bins, d => Math.max(d.cashIn, d.cashOut)) ?? 1000 + + const yLin = d3 + .scaleLinear() + .domain([0, (max === min ? min + 1000 : max) * 1.03]) + .nice() + .range([GRAPH_HEIGHT - GRAPH_MARGIN.bottom, GRAPH_MARGIN.top]) + + const yLog = d3 + .scaleLog() + .domain([ + min === 0 ? 1 : min * 0.9, + (max === min ? min + Math.pow(10, 2 * min + 1) : max) * 2 + ]) + .clamp(true) + .range([GRAPH_HEIGHT - GRAPH_MARGIN.bottom, GRAPH_MARGIN.top]) + + const y = log ? yLog : yLin + + const getAreaInterval = (breakpoints, dataLimits, graphLimits) => { + const fullBreakpoints = [ + graphLimits[1], + ...R.filter(it => it > dataLimits[0] && it < dataLimits[1], breakpoints), + dataLimits[0] + ] + + const intervals = [] + for (let i = 0; i < fullBreakpoints.length - 1; i++) { + intervals.push([fullBreakpoints[i], fullBreakpoints[i + 1]]) + } + + return intervals + } + + const getAreaIntervalByX = (intervals, xValue) => { + return R.find(it => xValue <= it[0] && xValue >= it[1], intervals) ?? [0, 0] + } + + const getDateIntervalByX = (areas, intervals, xValue) => { + const flattenIntervals = R.uniq(R.flatten(intervals)) + + // flattenIntervals and areas should have the same number of elements + for (let i = intervals.length - 1; i >= 0; i--) { + if (xValue < flattenIntervals[i]) { + return [areas[i], areas[i + 1]] + } + } + } + + const buildXAxis = useCallback( + g => + g + .attr( + 'transform', + `translate(0, ${GRAPH_HEIGHT - GRAPH_MARGIN.bottom})` + ) + .call( + d3 + .axisBottom(x) + .ticks(dataPoints[period.code].tick) + .tickFormat(d => { + return d3.timeFormat(dataPoints[period.code].labelFormat)( + d.getTime() + d.getTimezoneOffset() * MINUTE + ) + }) + .tickSizeOuter(0) + ) + .call(g => + g + .select('.domain') + .attr('stroke', primaryColor) + .attr('stroke-width', 1) + ), + [GRAPH_MARGIN, dataPoints, period.code, x] + ) + + const buildYAxis = useCallback( + g => + g + .attr('transform', `translate(${GRAPH_MARGIN.left}, 0)`) + .call( + d3 + .axisLeft(y) + .ticks(GRAPH_HEIGHT / 100) + .tickSizeOuter(0) + .tickFormat(d => { + if (log && !['1', '2', '5'].includes(d.toString()[0])) return '' + + if (d > 999) return Math.floor(d / 1000) + 'k' + else return d + }) + ) + .select('.domain') + .attr('stroke', primaryColor) + .attr('stroke-width', 1), + [GRAPH_MARGIN, y, log] + ) + + const buildGrid = useCallback( + g => { + g.attr('stroke', subheaderDarkColor) + .attr('fill', subheaderDarkColor) + // Vertical lines + .call(g => + g + .append('g') + .selectAll('line') + .data(buildTicks(x.domain())) + .join('line') + .attr('x1', d => 0.5 + x(d)) + .attr('x2', d => 0.5 + x(d)) + .attr('y1', GRAPH_MARGIN.top) + .attr('y2', GRAPH_HEIGHT - GRAPH_MARGIN.bottom) + ) + // Horizontal lines + .call(g => + g + .append('g') + .selectAll('line') + .data( + d3 + .axisLeft(y) + .scale() + .ticks(GRAPH_HEIGHT / 100) + ) + .join('line') + .attr('y1', d => 0.5 + y(d)) + .attr('y2', d => 0.5 + y(d)) + .attr('x1', GRAPH_MARGIN.left) + .attr('x2', GRAPH_WIDTH) + ) + // Vertical transparent rectangles for events + .call(g => + g + .append('g') + .selectAll('line') + .data(buildAreas(x.domain())) + .join('rect') + .attr('x', d => x(d)) + .attr('y', GRAPH_MARGIN.top) + .attr('width', d => { + const xValue = Math.round(x(d) * 100) / 100 + const intervals = getAreaInterval( + buildAreas(x.domain()).map(it => Math.round(x(it) * 100) / 100), + x.range(), + x2.range() + ) + const interval = getAreaIntervalByX(intervals, xValue) + return Math.round((interval[0] - interval[1]) * 100) / 100 + }) + .attr( + 'height', + GRAPH_HEIGHT - GRAPH_MARGIN.bottom - GRAPH_MARGIN.top + ) + .attr('stroke', 'transparent') + .attr('fill', 'transparent') + .on('mouseover', d => { + const xValue = Math.round(d.target.x.baseVal.value * 100) / 100 + const areas = buildAreas(x.domain()) + const intervals = getAreaInterval( + buildAreas(x.domain()).map(it => Math.round(x(it) * 100) / 100), + x.range(), + x2.range() + ) + + const dateInterval = getDateIntervalByX(areas, intervals, xValue) + if (!dateInterval) return + const filteredData = data.filter(it => { + const created = new Date(it.created) + const tzCreated = created.setTime(created.getTime() + offset) + return ( + tzCreated > new Date(dateInterval[1]) && + tzCreated <= new Date(dateInterval[0]) + ) + }) + + const rectXCoords = { + left: R.clone(d.target.getBoundingClientRect().x), + right: R.clone( + d.target.getBoundingClientRect().x + + d.target.getBoundingClientRect().width + ) + } + + const xCoord = + d.target.x.baseVal.value < 0.75 * GRAPH_WIDTH + ? rectXCoords.right + GRAPH_POPOVER_MARGIN + : rectXCoords.left - + GRAPH_POPOVER_WIDTH - + GRAPH_POPOVER_MARGIN + const yCoord = R.clone(d.target.getBoundingClientRect().y) + + setSelectionDateInterval(dateInterval) + setSelectionData(filteredData) + setSelectionCoords({ + x: Math.round(xCoord), + y: Math.round(yCoord) + }) + + d3.select(d.target).attr('fill', subheaderColor) + }) + .on('mouseleave', d => { + d3.select(d.target).attr('fill', 'transparent') + setSelectionDateInterval(null) + setSelectionData(null) + setSelectionCoords(null) + }) + ) + // Thick vertical lines + .call(g => + g + .append('g') + .selectAll('line') + .data( + buildTicks(x.domain()).filter(x => { + if (period.code === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + ) + .join('line') + .attr('class', 'dateSeparator') + .attr('x1', d => 0.5 + x(d)) + .attr('x2', d => 0.5 + x(d)) + .attr('y1', GRAPH_MARGIN.top - 50) + .attr('y2', GRAPH_HEIGHT - GRAPH_MARGIN.bottom) + .attr('stroke-width', 5) + .join('text') + ) + // Left side breakpoint label + .call(g => { + const separator = d3 + ?.select('.dateSeparator') + ?.node() + ?.getBBox() + + if (!separator) return + + const breakpoint = buildTicks(x.domain()).filter(x => { + if (period.code === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + + const labels = getPastAndCurrentDayLabels(breakpoint) + + return g + .append('text') + .attr('x', separator.x - 10) + .attr('y', separator.y + 33) + .attr('text-anchor', 'end') + .attr('dy', '.25em') + .text(labels.previous) + }) + // Right side breakpoint label + .call(g => { + const separator = d3 + ?.select('.dateSeparator') + ?.node() + ?.getBBox() + + if (!separator) return + + const breakpoint = buildTicks(x.domain()).filter(x => { + if (period.code === 'day') return x.getUTCHours() === 0 + return x.getUTCDate() === 1 + }) + + const labels = getPastAndCurrentDayLabels(breakpoint) + + return g + .append('text') + .attr('x', separator.x + 10) + .attr('y', separator.y + 33) + .attr('text-anchor', 'start') + .attr('dy', '.25em') + .text(labels.current) + }) + }, + [ + GRAPH_MARGIN, + buildTicks, + getPastAndCurrentDayLabels, + x, + x2, + y, + period, + buildAreas, + data, + offset, + setSelectionCoords, + setSelectionData, + setSelectionDateInterval + ] + ) + + const formatTicksText = useCallback( + () => + d3 + .selectAll('.tick text') + .style('stroke', fontColor) + .style('fill', fontColor) + .style('stroke-width', 0.5) + .style('font-family', fontSecondary), + [] + ) + + const formatText = useCallback( + () => + d3 + .selectAll('text') + .style('stroke', offColor) + .style('fill', offColor) + .style('stroke-width', 0.5) + .style('font-family', fontSecondary), + [] + ) + + const formatTicks = useCallback(() => { + d3.selectAll('.tick line') + .style('stroke', primaryColor) + .style('fill', primaryColor) + }, []) + + const drawData = useCallback( + g => { + g.append('clipPath') + .attr('id', 'clip-path') + .append('rect') + .attr('x', GRAPH_MARGIN.left) + .attr('y', GRAPH_MARGIN.top) + .attr('width', GRAPH_WIDTH) + .attr('height', GRAPH_HEIGHT - GRAPH_MARGIN.bottom - GRAPH_MARGIN.top) + .attr('fill', java) + + g.append('g') + .attr('clip-path', 'url(#clip-path)') + .selectAll('circle .cashIn') + .data(bins) + .join('circle') + .attr('cx', d => x(d.date)) + .attr('cy', d => y(d.cashIn)) + .attr('fill', java) + .attr('r', 3.5) + + g.append('g') + .attr('clip-path', 'url(#clip-path)') + .selectAll('circle .cashIn') + .data(bins) + .join('circle') + .attr('cx', d => x(d.date)) + .attr('cy', d => y(d.cashOut)) + .attr('fill', neon) + .attr('r', 3.5) + + g.append('path') + .datum(bins) + .attr('fill', 'none') + .attr('stroke', java) + .attr('stroke-width', 3) + .attr('clip-path', 'url(#clip-path)') + .attr( + 'd', + d3 + .line() + .curve(d3.curveMonotoneX) + .x(d => x(d.date)) + .y(d => y(d.cashIn)) + ) + + g.append('path') + .datum(bins) + .attr('fill', 'none') + .attr('stroke', neon) + .attr('stroke-width', 3) + .attr('clip-path', 'url(#clip-path)') + .attr( + 'd', + d3 + .line() + .curve(d3.curveMonotoneX) + .x(d => x(d.date)) + .y(d => y(d.cashOut)) + ) + }, + [x, y, bins, GRAPH_MARGIN] + ) + + const drawChart = useCallback(() => { + const svg = d3 + .select(ref.current) + .attr('viewBox', [0, 0, GRAPH_WIDTH, GRAPH_HEIGHT]) + + svg.append('g').call(buildGrid) + svg.append('g').call(drawData) + svg.append('g').call(buildXAxis) + svg.append('g').call(buildYAxis) + svg.append('g').call(formatTicksText) + svg.append('g').call(formatText) + svg.append('g').call(formatTicks) + + return svg.node() + }, [ + buildGrid, + buildXAxis, + buildYAxis, + drawData, + formatText, + formatTicks, + formatTicksText + ]) + + useEffect(() => { + d3.select(ref.current) + .selectAll('*') + .remove() + drawChart() + }, [drawChart]) + + return +} + +export default memo( + Graph, + (prev, next) => + R.equals(prev.period, next.period) && + R.equals(prev.selectedMachine, next.selectedMachine) && + R.equals(prev.log, next.log) +) From b5e798339be008144a3b04c65391965c5ceed76a Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 15 Aug 2022 14:33:54 +0200 Subject: [PATCH 014/119] fix: use `k` for thousands fix: graph tooltip for `threeDays` interval fix: y domain for log graph fix: line graph drawing order fix: line graph dots --- .../components/tooltips/GraphTooltip.js | 9 ++++-- .../Analytics/graphs/OverTimeDotGraph.js | 8 +++-- .../Analytics/graphs/OverTimeLineGraph.js | 32 ++++++++++--------- .../Graphs/RefScatterplot.js | 12 ++++++- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js index 89208a4a..02b1ab19 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js +++ b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js @@ -29,12 +29,14 @@ const GraphTooltip = ({ formatDate( dateInterval[1], null, - period.code === 'day' ? 'MMM d, HH:mm' : 'MMM d' + R.includes(period.code, ['day', 'threeDays']) + ? 'MMM d, HH:mm' + : 'MMM d' ), formatDate( dateInterval[0], null, - period.code === 'day' ? 'HH:mm' : 'MMM d' + R.includes(period.code, ['day', 'threeDays']) ? 'HH:mm' : 'MMM d' ) ] : [ @@ -56,7 +58,8 @@ const GraphTooltip = ({ return ( - {period.code === 'day' || R.includes('hourOfDay', representing.code) + {R.includes(period.code, ['day', 'threeDays']) || + R.includes('hourOfDay', representing.code) ? `${formattedDateInterval[0]} - ${formattedDateInterval[1]}` : `${formattedDateInterval[0]}`} diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js index 1b86af23..bf705a09 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js @@ -15,6 +15,7 @@ import { fontSecondary, subheaderColor } from 'src/styling/variables' +import { numberToFiatAmount } from 'src/utils/number' import { MINUTE, DAY, WEEK, MONTH } from 'src/utils/time' const Graph = ({ @@ -37,7 +38,7 @@ const Graph = ({ top: 25, right: 3.5, bottom: 27, - left: 36.5 + left: 38 }), [] ) @@ -260,8 +261,9 @@ const Graph = ({ .tickFormat(d => { if (log && !['1', '2', '5'].includes(d.toString()[0])) return '' - if (d > 1000) return Math.floor(d / 1000) + 'k' - else return d + if (d >= 1000) return numberToFiatAmount(d / 1000) + 'k' + + return numberToFiatAmount(d) }) ) .select('.domain') diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js index f2ac39fa..6c5613a1 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeLineGraph.js @@ -23,6 +23,7 @@ import { fontSecondary, subheaderColor } from 'src/styling/variables' +import { numberToFiatAmount } from 'src/utils/number' import { MINUTE, DAY, WEEK, MONTH } from 'src/utils/time' const Graph = ({ @@ -45,7 +46,7 @@ const Graph = ({ top: 25, right: 3.5, bottom: 27, - left: 36.5 + left: 38 }), [] ) @@ -234,7 +235,7 @@ const Graph = ({ const yLog = d3 .scaleLog() .domain([ - min === 0 ? 1 : min * 0.9, + min === 0 ? 0.9 : min * 0.9, (max === min ? min + Math.pow(10, 2 * min + 1) : max) * 2 ]) .clamp(true) @@ -311,8 +312,9 @@ const Graph = ({ .tickFormat(d => { if (log && !['1', '2', '5'].includes(d.toString()[0])) return '' - if (d > 999) return Math.floor(d / 1000) + 'k' - else return d + if (d >= 1000) return numberToFiatAmount(d / 1000) + 'k' + + return numberToFiatAmount(d) }) ) .select('.domain') @@ -564,17 +566,7 @@ const Graph = ({ .attr('cx', d => x(d.date)) .attr('cy', d => y(d.cashIn)) .attr('fill', java) - .attr('r', 3.5) - - g.append('g') - .attr('clip-path', 'url(#clip-path)') - .selectAll('circle .cashIn') - .data(bins) - .join('circle') - .attr('cx', d => x(d.date)) - .attr('cy', d => y(d.cashOut)) - .attr('fill', neon) - .attr('r', 3.5) + .attr('r', d => (d.cashIn === 0 ? 0 : 3.5)) g.append('path') .datum(bins) @@ -591,6 +583,16 @@ const Graph = ({ .y(d => y(d.cashIn)) ) + g.append('g') + .attr('clip-path', 'url(#clip-path)') + .selectAll('circle .cashIn') + .data(bins) + .join('circle') + .attr('cx', d => x(d.date)) + .attr('cy', d => y(d.cashOut)) + .attr('fill', neon) + .attr('r', d => (d.cashOut === 0 ? 0 : 3.5)) + g.append('path') .datum(bins) .attr('fill', 'none') diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js index 9d3d288d..6148c966 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefScatterplot.js @@ -12,6 +12,7 @@ import { fontSecondary, backgroundColor } from 'src/styling/variables' +import { numberToFiatAmount } from 'src/utils/number' import { MINUTE, DAY, WEEK, MONTH } from 'src/utils/time' const Graph = ({ data, timeFrame, timezone }) => { @@ -172,7 +173,16 @@ const Graph = ({ data, timeFrame, timezone }) => { g => g .attr('transform', `translate(${GRAPH_MARGIN.left}, 0)`) - .call(d3.axisLeft(y).ticks(5)) + .call( + d3 + .axisLeft(y) + .ticks(5) + .tickFormat(d => { + if (d >= 1000) return numberToFiatAmount(d / 1000) + 'k' + + return numberToFiatAmount(d) + }) + ) .call(g => g.select('.domain').remove()) .selectAll('text') .attr('dy', '-0.25rem'), From 1d37608a191dfd0e565278e3917e8890607195ba Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 15 Aug 2022 16:13:25 +0200 Subject: [PATCH 015/119] feat: change average to median --- .../src/pages/Analytics/Analytics.js | 18 ++++++++---------- .../components/wrappers/OverTimeWrapper.js | 4 ++-- .../pages/Analytics/graphs/OverTimeDotGraph.js | 8 ++++---- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index 5e8d94bd..2bf8e278 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -227,13 +227,11 @@ const Analytics = () => { previous: filteredData(period.code).previous.length } - const avgAmount = { - current: - R.sum(R.map(d => d.fiat, filteredData(period.code).current)) / - (txs.current === 0 ? 1 : txs.current), - previous: - R.sum(R.map(d => d.fiat, filteredData(period.code).previous)) / - (txs.previous === 0 ? 1 : txs.previous) + const median = values => (values.length === 0 ? 0 : R.median(values)) + + const medianAmount = { + current: median(R.map(d => d.fiat, filteredData(period.code).current)), + previous: median(R.map(d => d.fiat, filteredData(period.code).previous)) } const txVolume = { @@ -365,9 +363,9 @@ const Analytics = () => { />
diff --git a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js index def8fe90..6efaaf40 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js +++ b/new-lamassu-admin/src/pages/Analytics/components/wrappers/OverTimeWrapper.js @@ -31,7 +31,7 @@ const OverTimeDotGraphHeader = ({ cashIn:
, cashOut:
, transaction:
, - average: ( + median: ( - +
diff --git a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js index bf705a09..9da30a97 100644 --- a/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js +++ b/new-lamassu-admin/src/pages/Analytics/graphs/OverTimeDotGraph.js @@ -498,9 +498,9 @@ const Graph = ({ const buildAvg = useCallback( g => { - const mean = d3.mean(data, d => new BigNumber(d.fiat).toNumber()) ?? 0 + const median = d3.median(data, d => new BigNumber(d.fiat).toNumber()) ?? 0 - if (log && mean === 0) return + if (log && median === 0) return g.attr('stroke', primaryColor) .attr('stroke-width', 3) @@ -508,8 +508,8 @@ const Graph = ({ .call(g => g .append('line') - .attr('y1', 0.5 + y(mean)) - .attr('y2', 0.5 + y(mean)) + .attr('y1', 0.5 + y(median)) + .attr('y2', 0.5 + y(median)) .attr('x1', GRAPH_MARGIN.left) .attr('x2', GRAPH_WIDTH) ) From 909fbb7ae21635160920ac5705c0a391833ed158 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 15 Aug 2022 17:42:56 +0200 Subject: [PATCH 016/119] fix: tooltip format --- .../components/tooltips/GraphTooltip.js | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js index 02b1ab19..ff32a290 100644 --- a/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js +++ b/new-lamassu-admin/src/pages/Analytics/components/tooltips/GraphTooltip.js @@ -26,20 +26,12 @@ const GraphTooltip = ({ const formattedDateInterval = !R.includes('hourOfDay', representing.code) ? [ - formatDate( - dateInterval[1], - null, - R.includes(period.code, ['day', 'threeDays']) - ? 'MMM d, HH:mm' - : 'MMM d' - ), - formatDate( - dateInterval[0], - null, - R.includes(period.code, ['day', 'threeDays']) ? 'HH:mm' : 'MMM d' - ) + formatDate(dateInterval[1], null, 'MMM d'), + formatDate(dateInterval[1], null, 'HH:mm'), + formatDate(dateInterval[0], null, 'HH:mm') ] : [ + formatDate(dateInterval[1], null, 'MMM d'), formatDateNonUtc(dateInterval[1], 'HH:mm'), formatDateNonUtc(dateInterval[0], 'HH:mm') ] @@ -57,11 +49,11 @@ const GraphTooltip = ({ return ( + {!R.includes('hourOfDay', representing.code) && ( + {`${formattedDateInterval[0]}`} + )} - {R.includes(period.code, ['day', 'threeDays']) || - R.includes('hourOfDay', representing.code) - ? `${formattedDateInterval[0]} - ${formattedDateInterval[1]}` - : `${formattedDateInterval[0]}`} + {`${formattedDateInterval[1]} - ${formattedDateInterval[2]}`}

{R.length(data)}{' '} From a247b3661eb7395bcc13a793587b97daf1a79d2b Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Thu, 28 Jul 2022 20:24:18 +0200 Subject: [PATCH 017/119] fix: photo roll height --- new-lamassu-admin/src/components/Carousel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/components/Carousel.js b/new-lamassu-admin/src/components/Carousel.js index 5e0475aa..f093eef3 100644 --- a/new-lamassu-admin/src/components/Carousel.js +++ b/new-lamassu-admin/src/components/Carousel.js @@ -13,9 +13,10 @@ const useStyles = makeStyles({ display: 'flex' }, imgInner: { - objectFit: 'cover', + objectFit: 'contain', objectPosition: 'center', width: 500, + height: 400, marginBottom: 40 } }) From e3fe2bc04eeea1e2230f47f4cd97776e148a975d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 31 May 2022 23:05:48 +0100 Subject: [PATCH 018/119] feat: allow for edited customer photos to be previewed --- .../src/pages/Customers/CustomerData.js | 78 +++++++++++++------ .../Customers/components/EditableCard.js | 17 ++-- 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/new-lamassu-admin/src/pages/Customers/CustomerData.js b/new-lamassu-admin/src/pages/Customers/CustomerData.js index b605eb07..af232e7f 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerData.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerData.js @@ -77,6 +77,8 @@ const CustomerData = ({ }) => { const classes = useStyles() const [listView, setListView] = useState(false) + const [previewPhoto, setPreviewPhoto] = useState(null) + const [previewCard, setPreviewCard] = useState(null) const idData = R.path(['idCardData'])(customer) const rawExpirationDate = R.path(['expirationDate'])(idData) @@ -213,9 +215,6 @@ const CustomerData = ({ { title: 'Name', titleIcon: , - authorize: () => {}, - reject: () => {}, - save: () => {}, isAvailable: false, editable: true }, @@ -226,7 +225,7 @@ const CustomerData = ({ authorize: () => updateCustomer({ sanctionsOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ sanctionsOverride: OVERRIDE_REJECTED }), - children: {sanctionsDisplay}, + children: () => {sanctionsDisplay}, isAvailable: !R.isNil(sanctions), editable: true }, @@ -238,20 +237,33 @@ const CustomerData = ({ authorize: () => updateCustomer({ frontCameraOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ frontCameraOverride: OVERRIDE_REJECTED }), - save: values => - replacePhoto({ + save: values => { + setPreviewPhoto(null) + return replacePhoto({ newPhoto: values.frontCamera, photoType: 'frontCamera' - }), + }) + }, + cancel: () => setPreviewPhoto(null), deleteEditedData: () => deleteEditedData({ frontCamera: null }), - children: customer.frontCameraPath ? ( - - ) : null, + children: values => { + if (values.frontCamera !== previewPhoto) { + setPreviewPhoto(values.frontCamera) + } + + return customer.frontCameraPath ? ( + + ) : null + }, hasImage: true, validationSchema: customerDataSchemas.frontCamera, initialValues: initialValues.frontCamera, @@ -266,18 +278,33 @@ const CustomerData = ({ authorize: () => updateCustomer({ idCardPhotoOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ idCardPhotoOverride: OVERRIDE_REJECTED }), - save: values => - replacePhoto({ + save: values => { + setPreviewCard(null) + return replacePhoto({ newPhoto: values.idCardPhoto, photoType: 'idCardPhoto' - }), + }) + }, + cancel: () => setPreviewCard(null), deleteEditedData: () => deleteEditedData({ idCardPhoto: null }), - children: customer.idCardPhotoPath ? ( - - ) : null, + children: values => { + if (values.idCardPhoto !== previewCard) { + setPreviewCard(values.idCardPhoto) + } + + return customer.idCardPhotoPath ? ( + + ) : null + }, hasImage: true, validationSchema: customerDataSchemas.idCardPhoto, initialValues: initialValues.idCardPhoto, @@ -292,6 +319,7 @@ const CustomerData = ({ authorize: () => updateCustomer({ usSsnOverride: OVERRIDE_AUTHORIZED }), reject: () => updateCustomer({ usSsnOverride: OVERRIDE_REJECTED }), save: values => editCustomer(values), + children: () => {}, deleteEditedData: () => deleteEditedData({ usSsn: null }), validationSchema: customerDataSchemas.usSsn, initialValues: initialValues.usSsn, @@ -427,6 +455,7 @@ const CustomerData = ({ titleIcon, fields, save, + cancel, deleteEditedData, retrieveAdditionalData, children, @@ -453,6 +482,7 @@ const CustomerData = ({ validationSchema={validationSchema} initialValues={initialValues} save={save} + cancel={cancel} deleteEditedData={deleteEditedData} retrieveAdditionalData={retrieveAdditionalData} editable={editable}> diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 1dc71165..3ea7a03f 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -3,7 +3,7 @@ import { makeStyles } from '@material-ui/core/styles' import classnames from 'classnames' import { Form, Formik, Field as FormikField } from 'formik' import * as R from 'ramda' -import { useState, React } from 'react' +import { useState, React, useRef } from 'react' import ErrorMessage from 'src/components/ErrorMessage' import PromptWhenDirty from 'src/components/PromptWhenDirty' @@ -132,14 +132,15 @@ const ReadOnlyField = ({ field, value, ...props }) => { const EditableCard = ({ fields, - save, - authorize, + save = () => {}, + cancel = () => {}, + authorize = () => {}, hasImage, - reject, + reject = () => {}, state, title, titleIcon, - children, + children = () => {}, validationSchema, initialValues, deleteEditedData, @@ -149,6 +150,8 @@ const EditableCard = ({ }) => { const classes = useStyles() + const formRef = useRef() + const [editing, setEditing] = useState(false) const [input, setInput] = useState(null) const [error, setError] = useState(null) @@ -187,8 +190,9 @@ const EditableCard = ({

)}
- {children} + {children(formRef.current?.values ?? {})} cancel()} type="reset"> Cancel From 37e235452b5c5ba1f4463a3fc493a56e6fe46c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Fri, 16 Sep 2022 05:26:30 +0100 Subject: [PATCH 019/119] feat: add robots.txt to lamassu-server and lamassu-admin fix: fail fast on lamassu-server default route access --- lib/routes.js | 9 +++++++++ new-lamassu-admin/public/robots.txt | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 new-lamassu-admin/public/robots.txt diff --git a/lib/routes.js b/lib/routes.js index 6248fc8e..7cc6bb5b 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -56,6 +56,15 @@ app.use(nocache()) app.use(express.json({ limit: '2mb' })) app.use(morgan(':method :url :status :response-time ms -- :req[content-length]/:res[content-length] b', { stream: logger.stream })) +app.use('/robots.txt', (req, res) => { + res.type('text/plain') + res.send("User-agent: *\nDisallow: /") +}) + +app.get('/', (req, res) => { + res.status(404).json({ error: 'No such route' }) +}) + // app /pair and /ca routes app.use('/', pairingRoutes) diff --git a/new-lamassu-admin/public/robots.txt b/new-lamassu-admin/public/robots.txt new file mode 100644 index 00000000..77470cb3 --- /dev/null +++ b/new-lamassu-admin/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file From 04052bfc8e0256915fc616f93ecbc0e858a0c243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 6 Oct 2022 19:17:03 +0100 Subject: [PATCH 020/119] fix: remove JSON from 404 response --- lib/routes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 7cc6bb5b..49ddddf2 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -62,7 +62,7 @@ app.use('/robots.txt', (req, res) => { }) app.get('/', (req, res) => { - res.status(404).json({ error: 'No such route' }) + res.sendStatus(404) }) // app /pair and /ca routes From c77fda262355652e9c18aa2733e0645d42ad2ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 7 Jul 2022 19:28:33 +0100 Subject: [PATCH 021/119] feat: add button to check against OFAC sanction list --- lib/customers.js | 1 + lib/new-admin/admin-server.js | 3 +- lib/new-admin/graphql/resolvers/index.js | 2 ++ .../graphql/resolvers/sanctions.resolver.js | 14 ++++++++++ lib/new-admin/graphql/types/index.js | 2 ++ lib/new-admin/graphql/types/sanctions.type.js | 13 +++++++++ lib/new-admin/middlewares/index.js | 2 ++ .../middlewares/loadSanctionLists.js | 28 +++++++++++++++++++ .../src/pages/Customers/CustomerData.js | 15 ++++++++-- .../src/pages/Customers/CustomerProfile.js | 26 ++++++++++++++++- .../Customers/components/EditableCard.js | 13 ++++++++- 11 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 lib/new-admin/graphql/resolvers/sanctions.resolver.js create mode 100644 lib/new-admin/graphql/types/sanctions.type.js create mode 100644 lib/new-admin/middlewares/loadSanctionLists.js diff --git a/lib/customers.js b/lib/customers.js index d7975972..23542928 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -114,6 +114,7 @@ function update (id, data, userToken) { async function updateCustomer (id, data, userToken) { const formattedData = _.pick( [ + 'sanctions', 'authorized_override', 'id_card_photo_override', 'id_card_data_override', diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index 3b13daf8..e2a7ab70 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -20,7 +20,7 @@ const { typeDefs, resolvers } = require('./graphql/schema') const findOperatorId = require('../middlewares/operatorId') const computeSchema = require('../compute-schema') const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants') -const { session, cleanUserSessions, buildApolloContext } = require('./middlewares') +const { session, cleanUserSessions, buildApolloContext, loadSanctionLists } = require('./middlewares') const devMode = require('minimist')(process.argv.slice(2)).dev @@ -48,6 +48,7 @@ app.use(express.static(path.resolve(__dirname, '..', '..', 'public'))) app.use(cleanUserSessions(USER_SESSIONS_CLEAR_INTERVAL)) app.use(computeSchema) app.use(findOperatorId) +app.use(loadSanctionLists) app.use(session) app.use(graphqlUploadExpress()) diff --git a/lib/new-admin/graphql/resolvers/index.js b/lib/new-admin/graphql/resolvers/index.js index 81e79614..a20d9216 100644 --- a/lib/new-admin/graphql/resolvers/index.js +++ b/lib/new-admin/graphql/resolvers/index.js @@ -14,6 +14,7 @@ const machine = require('./machine.resolver') const notification = require('./notification.resolver') const pairing = require('./pairing.resolver') const rates = require('./rates.resolver') +const sanctions = require('./sanctions.resolver') const scalar = require('./scalar.resolver') const settings = require('./settings.resolver') const sms = require('./sms.resolver') @@ -37,6 +38,7 @@ const resolvers = [ notification, pairing, rates, + sanctions, scalar, settings, sms, diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js new file mode 100644 index 00000000..9bd211dd --- /dev/null +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -0,0 +1,14 @@ +const _ = require('lodash/fp') +const ofac = require('../../../ofac') + +const resolvers = { + Query: { + checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => { + const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) + + return { ofacSanctioned: _.size(ofacMatches) > 0 } + } + } +} + +module.exports = resolvers diff --git a/lib/new-admin/graphql/types/index.js b/lib/new-admin/graphql/types/index.js index a1886a28..f4794b67 100644 --- a/lib/new-admin/graphql/types/index.js +++ b/lib/new-admin/graphql/types/index.js @@ -14,6 +14,7 @@ const machine = require('./machine.type') const notification = require('./notification.type') const pairing = require('./pairing.type') const rates = require('./rates.type') +const sanctions = require('./sanctions.type') const scalar = require('./scalar.type') const settings = require('./settings.type') const sms = require('./sms.type') @@ -37,6 +38,7 @@ const types = [ notification, pairing, rates, + sanctions, scalar, settings, sms, diff --git a/lib/new-admin/graphql/types/sanctions.type.js b/lib/new-admin/graphql/types/sanctions.type.js new file mode 100644 index 00000000..76a5e572 --- /dev/null +++ b/lib/new-admin/graphql/types/sanctions.type.js @@ -0,0 +1,13 @@ +const { gql } = require('apollo-server-express') + +const typeDef = gql` + type SanctionMatches { + ofacSanctioned: Boolean + } + + type Query { + checkAgainstSanctions(firstName: String, lastName: String, birthdate: String): SanctionMatches @auth + } +` + +module.exports = typeDef diff --git a/lib/new-admin/middlewares/index.js b/lib/new-admin/middlewares/index.js index cedba31c..21cd4751 100644 --- a/lib/new-admin/middlewares/index.js +++ b/lib/new-admin/middlewares/index.js @@ -1,9 +1,11 @@ const cleanUserSessions = require('./cleanUserSessions') const buildApolloContext = require('./context') +const loadSanctionLists = require('./loadSanctionLists') const session = require('./session') module.exports = { cleanUserSessions, buildApolloContext, + loadSanctionLists, session } diff --git a/lib/new-admin/middlewares/loadSanctionLists.js b/lib/new-admin/middlewares/loadSanctionLists.js new file mode 100644 index 00000000..48d2c0b8 --- /dev/null +++ b/lib/new-admin/middlewares/loadSanctionLists.js @@ -0,0 +1,28 @@ +const logger = require('../../logger') +const sanctions = require('../../ofac') + +const sanctionStatus = { + loaded: false, + timestamp: null +} + +const loadSanctionLists = (req, res, next) => { + if (!sanctionStatus.loaded) { + logger.info('No sanction lists loaded. Loading sanctions...') + return sanctions.load() + .then(() => { + logger.info('OFAC sanction list loaded!') + sanctionStatus.loaded = true + sanctionStatus.timestamp = Date.now() + return next() + }) + .catch(e => { + logger.error('Couldn\'t load OFAC sanction list!') + return next(e) + }) + } + + return next() +} + +module.exports = loadSanctionLists diff --git a/new-lamassu-admin/src/pages/Customers/CustomerData.js b/new-lamassu-admin/src/pages/Customers/CustomerData.js index b605eb07..affe5159 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerData.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerData.js @@ -73,7 +73,8 @@ const CustomerData = ({ authorizeCustomRequest, updateCustomEntry, retrieveAdditionalDataDialog, - setRetrieve + setRetrieve, + checkAgainstSanctions }) => { const classes = useStyles() const [listView, setListView] = useState(false) @@ -172,6 +173,14 @@ const CustomerData = ({ idCardData: R.merge(idData, formatDates(values)) }), validationSchema: customerDataSchemas.idCardData, + checkAgainstSanctions: () => + checkAgainstSanctions({ + variables: { + firstName: initialValues.idCardData.firstName, + lastName: initialValues.idCardData.lastName, + birthdate: R.replace(/-/g, '')(initialValues.idCardData.dateOfBirth) + } + }), initialValues: initialValues.idCardData, isAvailable: !R.isNil(idData), editable: true @@ -434,7 +443,8 @@ const CustomerData = ({ initialValues, hasImage, hasAdditionalData, - editable + editable, + checkAgainstSanctions }, idx ) => { @@ -455,6 +465,7 @@ const CustomerData = ({ save={save} deleteEditedData={deleteEditedData} retrieveAdditionalData={retrieveAdditionalData} + checkAgainstSanctions={checkAgainstSanctions} editable={editable}> ) } diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js index d9256f3b..3c03cb4f 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js @@ -1,4 +1,4 @@ -import { useQuery, useMutation } from '@apollo/react-hooks' +import { useQuery, useMutation, useLazyQuery } from '@apollo/react-hooks' import { makeStyles, Breadcrumbs, @@ -292,6 +292,22 @@ const GET_ACTIVE_CUSTOM_REQUESTS = gql` } ` +const CHECK_AGAINST_SANCTIONS = gql` + query checkAgainstSanctions( + $firstName: String + $lastName: String + $birthdate: String + ) { + checkAgainstSanctions( + firstName: $firstName + lastName: $lastName + birthdate: $birthdate + ) { + ofacSanctioned + } + } +` + const CustomerProfile = memo(() => { const history = useHistory() @@ -400,6 +416,13 @@ const CustomerProfile = memo(() => { onCompleted: () => getCustomer() }) + const [checkAgainstSanctions] = useLazyQuery(CHECK_AGAINST_SANCTIONS, { + onCompleted: ({ checkAgainstSanctions: { ofacSanctioned } }) => + updateCustomer({ + sanctions: !ofacSanctioned + }) + }) + const updateCustomer = it => setCustomer({ variables: { @@ -662,6 +685,7 @@ const CustomerProfile = memo(() => { authorizeCustomRequest={authorizeCustomRequest} updateCustomEntry={updateCustomEntry} setRetrieve={setRetrieve} + checkAgainstSanctions={checkAgainstSanctions} retrieveAdditionalDataDialog={ { diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 1dc71165..ce5c85bd 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -145,7 +145,8 @@ const EditableCard = ({ deleteEditedData, retrieveAdditionalData, hasAdditionalData = true, - editable + editable, + checkAgainstSanctions }) => { const classes = useStyles() @@ -273,6 +274,16 @@ const EditableCard = ({ Retrieve API data )} + {checkAgainstSanctions && ( + checkAgainstSanctions()}> + Check against OFAC sanction list + + )} {editable && ( Date: Fri, 8 Jul 2022 18:17:30 +0100 Subject: [PATCH 022/119] fix: remove sanction loader middleware --- lib/new-admin/admin-server.js | 3 +- .../graphql/resolvers/sanctions.resolver.js | 34 ++++++++++++++++--- lib/new-admin/middlewares/index.js | 2 -- .../middlewares/loadSanctionLists.js | 28 --------------- 4 files changed, 30 insertions(+), 37 deletions(-) delete mode 100644 lib/new-admin/middlewares/loadSanctionLists.js diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index e2a7ab70..3b13daf8 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -20,7 +20,7 @@ const { typeDefs, resolvers } = require('./graphql/schema') const findOperatorId = require('../middlewares/operatorId') const computeSchema = require('../compute-schema') const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants') -const { session, cleanUserSessions, buildApolloContext, loadSanctionLists } = require('./middlewares') +const { session, cleanUserSessions, buildApolloContext } = require('./middlewares') const devMode = require('minimist')(process.argv.slice(2)).dev @@ -48,7 +48,6 @@ app.use(express.static(path.resolve(__dirname, '..', '..', 'public'))) app.use(cleanUserSessions(USER_SESSIONS_CLEAR_INTERVAL)) app.use(computeSchema) app.use(findOperatorId) -app.use(loadSanctionLists) app.use(session) app.use(graphqlUploadExpress()) diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js index 9bd211dd..3945516a 100644 --- a/lib/new-admin/graphql/resolvers/sanctions.resolver.js +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -1,13 +1,37 @@ const _ = require('lodash/fp') +const logger = require('../../../logger') const ofac = require('../../../ofac') +const T = require('../../../time') + +const sanctionStatus = { + loaded: false, + timestamp: null +} + +const loadOrUpdateSanctions = () => { + if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.minute)) { + logger.info('No sanction lists loaded. Loading sanctions...') + return ofac.load() + .then(() => { + logger.info('OFAC sanction list loaded!') + sanctionStatus.loaded = true + sanctionStatus.timestamp = Date.now() + }) + .catch(e => { + logger.error('Couldn\'t load OFAC sanction list!') + }) + } + + return Promise.resolve() +} const resolvers = { Query: { - checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => { - const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) - - return { ofacSanctioned: _.size(ofacMatches) > 0 } - } + checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => loadOrUpdateSanctions() + .then(() => { + const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) + return { ofacSanctioned: _.size(ofacMatches) > 0 } + }) } } diff --git a/lib/new-admin/middlewares/index.js b/lib/new-admin/middlewares/index.js index 21cd4751..cedba31c 100644 --- a/lib/new-admin/middlewares/index.js +++ b/lib/new-admin/middlewares/index.js @@ -1,11 +1,9 @@ const cleanUserSessions = require('./cleanUserSessions') const buildApolloContext = require('./context') -const loadSanctionLists = require('./loadSanctionLists') const session = require('./session') module.exports = { cleanUserSessions, buildApolloContext, - loadSanctionLists, session } diff --git a/lib/new-admin/middlewares/loadSanctionLists.js b/lib/new-admin/middlewares/loadSanctionLists.js deleted file mode 100644 index 48d2c0b8..00000000 --- a/lib/new-admin/middlewares/loadSanctionLists.js +++ /dev/null @@ -1,28 +0,0 @@ -const logger = require('../../logger') -const sanctions = require('../../ofac') - -const sanctionStatus = { - loaded: false, - timestamp: null -} - -const loadSanctionLists = (req, res, next) => { - if (!sanctionStatus.loaded) { - logger.info('No sanction lists loaded. Loading sanctions...') - return sanctions.load() - .then(() => { - logger.info('OFAC sanction list loaded!') - sanctionStatus.loaded = true - sanctionStatus.timestamp = Date.now() - return next() - }) - .catch(e => { - logger.error('Couldn\'t load OFAC sanction list!') - return next(e) - }) - } - - return next() -} - -module.exports = loadSanctionLists From 30a43869ec860f9232b9183d2a40faf28803db13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Mon, 11 Jul 2022 02:06:14 +0100 Subject: [PATCH 023/119] fix: increase OFAC list update timer --- lib/new-admin/graphql/resolvers/sanctions.resolver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js index 3945516a..95cf2d88 100644 --- a/lib/new-admin/graphql/resolvers/sanctions.resolver.js +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -9,7 +9,7 @@ const sanctionStatus = { } const loadOrUpdateSanctions = () => { - if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.minute)) { + if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.day)) { logger.info('No sanction lists loaded. Loading sanctions...') return ofac.load() .then(() => { From cec02c52ba68118195c39c9ea2e47d2e9730deef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Sat, 8 Oct 2022 01:08:29 +0100 Subject: [PATCH 024/119] fix: resolve full sanction checking flow in the backend --- .../graphql/resolvers/sanctions.resolver.js | 37 +++------------- lib/new-admin/graphql/types/sanctions.type.js | 2 +- lib/sanctions.js | 44 +++++++++++++++++++ .../src/pages/Customers/CustomerData.js | 4 +- .../src/pages/Customers/CustomerProfile.js | 17 ++----- 5 files changed, 55 insertions(+), 49 deletions(-) create mode 100644 lib/sanctions.js diff --git a/lib/new-admin/graphql/resolvers/sanctions.resolver.js b/lib/new-admin/graphql/resolvers/sanctions.resolver.js index 95cf2d88..bb1a8862 100644 --- a/lib/new-admin/graphql/resolvers/sanctions.resolver.js +++ b/lib/new-admin/graphql/resolvers/sanctions.resolver.js @@ -1,37 +1,12 @@ -const _ = require('lodash/fp') -const logger = require('../../../logger') -const ofac = require('../../../ofac') -const T = require('../../../time') - -const sanctionStatus = { - loaded: false, - timestamp: null -} - -const loadOrUpdateSanctions = () => { - if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.day)) { - logger.info('No sanction lists loaded. Loading sanctions...') - return ofac.load() - .then(() => { - logger.info('OFAC sanction list loaded!') - sanctionStatus.loaded = true - sanctionStatus.timestamp = Date.now() - }) - .catch(e => { - logger.error('Couldn\'t load OFAC sanction list!') - }) - } - - return Promise.resolve() -} +const sanctions = require('../../../sanctions') +const authentication = require('../modules/userManagement') const resolvers = { Query: { - checkAgainstSanctions: (...[, { firstName, lastName, birthdate }]) => loadOrUpdateSanctions() - .then(() => { - const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) - return { ofacSanctioned: _.size(ofacMatches) > 0 } - }) + checkAgainstSanctions: (...[, { customerId }, context]) => { + const token = authentication.getToken(context) + return sanctions.checkByUser(customerId, token) + } } } diff --git a/lib/new-admin/graphql/types/sanctions.type.js b/lib/new-admin/graphql/types/sanctions.type.js index 76a5e572..b7899da6 100644 --- a/lib/new-admin/graphql/types/sanctions.type.js +++ b/lib/new-admin/graphql/types/sanctions.type.js @@ -6,7 +6,7 @@ const typeDef = gql` } type Query { - checkAgainstSanctions(firstName: String, lastName: String, birthdate: String): SanctionMatches @auth + checkAgainstSanctions(customerId: ID): SanctionMatches @auth } ` diff --git a/lib/sanctions.js b/lib/sanctions.js new file mode 100644 index 00000000..34b1b7fd --- /dev/null +++ b/lib/sanctions.js @@ -0,0 +1,44 @@ +const _ = require('lodash/fp') +const ofac = require('./ofac') +const T = require('./time') +const logger = require('./logger') +const customers = require('./customers') + +const sanctionStatus = { + loaded: false, + timestamp: null +} + +const loadOrUpdateSanctions = () => { + if (!sanctionStatus.loaded || (sanctionStatus.timestamp && Date.now() > sanctionStatus.timestamp + T.day)) { + logger.info('No sanction lists loaded. Loading sanctions...') + return ofac.load() + .then(() => { + logger.info('OFAC sanction list loaded!') + sanctionStatus.loaded = true + sanctionStatus.timestamp = Date.now() + }) + .catch(e => { + logger.error('Couldn\'t load OFAC sanction list!') + }) + } + + return Promise.resolve() +} + +const checkByUser = (customerId, userToken) => { + return Promise.all([loadOrUpdateSanctions(), customers.getCustomerById(customerId)]) + .then(([, customer]) => { + const { firstName, lastName, dateOfBirth } = customer?.idCardData + const birthdate = _.replace(/-/g, '')(dateOfBirth) + const ofacMatches = ofac.match({ firstName, lastName }, birthdate, { threshold: 0.85, fullNameThreshold: 0.95, debug: false }) + const isOfacSanctioned = _.size(ofacMatches) > 0 + customers.updateCustomer(customerId, { sanctions: !isOfacSanctioned }, userToken) + + return { ofacSanctioned: isOfacSanctioned } + }) +} + +module.exports = { + checkByUser +} diff --git a/new-lamassu-admin/src/pages/Customers/CustomerData.js b/new-lamassu-admin/src/pages/Customers/CustomerData.js index affe5159..5edbe829 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerData.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerData.js @@ -176,9 +176,7 @@ const CustomerData = ({ checkAgainstSanctions: () => checkAgainstSanctions({ variables: { - firstName: initialValues.idCardData.firstName, - lastName: initialValues.idCardData.lastName, - birthdate: R.replace(/-/g, '')(initialValues.idCardData.dateOfBirth) + customerId: R.path(['id'])(customer) } }), initialValues: initialValues.idCardData, diff --git a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js index 3c03cb4f..44478022 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomerProfile.js +++ b/new-lamassu-admin/src/pages/Customers/CustomerProfile.js @@ -293,16 +293,8 @@ const GET_ACTIVE_CUSTOM_REQUESTS = gql` ` const CHECK_AGAINST_SANCTIONS = gql` - query checkAgainstSanctions( - $firstName: String - $lastName: String - $birthdate: String - ) { - checkAgainstSanctions( - firstName: $firstName - lastName: $lastName - birthdate: $birthdate - ) { + query checkAgainstSanctions($customerId: ID) { + checkAgainstSanctions(customerId: $customerId) { ofacSanctioned } } @@ -417,10 +409,7 @@ const CustomerProfile = memo(() => { }) const [checkAgainstSanctions] = useLazyQuery(CHECK_AGAINST_SANCTIONS, { - onCompleted: ({ checkAgainstSanctions: { ofacSanctioned } }) => - updateCustomer({ - sanctions: !ofacSanctioned - }) + onCompleted: () => getCustomer() }) const updateCustomer = it => From 7bf7e49cf733c2c0f2f3fb96e01822ba6a217443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Sun, 12 Mar 2023 20:20:24 +0000 Subject: [PATCH 025/119] fix: CEX.IO missing credential UID --- new-lamassu-admin/src/pages/Services/schemas/cex.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/new-lamassu-admin/src/pages/Services/schemas/cex.js b/new-lamassu-admin/src/pages/Services/schemas/cex.js index 2c67aa1c..3cfacbd7 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/cex.js +++ b/new-lamassu-admin/src/pages/Services/schemas/cex.js @@ -17,6 +17,13 @@ export default { face: true, long: true }, + { + code: 'uid', + display: 'User ID', + component: TextInputFormik, + face: true, + long: true + }, { code: 'privateKey', display: 'Private Key', @@ -28,6 +35,9 @@ export default { apiKey: Yup.string('The API key must be a string') .max(100, 'The API key is too long') .required('The API key is required'), + uid: Yup.string('The User ID must be a string') + .max(100, 'The User ID is too long') + .required('The User ID is required'), privateKey: Yup.string('The private key must be a string') .max(100, 'The private key is too long') .test(secretTest(account?.privateKey, 'private key')) From 2f8d02cd7eacfdb2086a6de25626fde70716c76f Mon Sep 17 00:00:00 2001 From: josepfo Date: Tue, 17 Jan 2023 18:29:06 +0000 Subject: [PATCH 026/119] fix: hide replace button if state is pending --- .../src/pages/Customers/components/EditableCard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 1dc71165..02dbbe57 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -314,7 +314,7 @@ const EditableCard = ({ {editing && (
- {hasImage && ( + {hasImage && state !== OVERRIDE_PENDING && ( Date: Mon, 7 Nov 2022 18:55:35 +0100 Subject: [PATCH 027/119] fix: table scrollbar offsetting columns --- new-lamassu-admin/src/styling/global/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/new-lamassu-admin/src/styling/global/index.js b/new-lamassu-admin/src/styling/global/index.js index 4e5083ef..ceebff20 100644 --- a/new-lamassu-admin/src/styling/global/index.js +++ b/new-lamassu-admin/src/styling/global/index.js @@ -64,6 +64,9 @@ export default { // forcing styling onto inner container '.ReactVirtualized__Grid__innerScrollContainer': { overflow: 'inherit !important' + }, + '.ReactVirtualized__Grid.ReactVirtualized__List': { + overflowY: 'overlay !important' } } } From 72eb8517312c025f58c43019e0a062498ff38692 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Tue, 13 Dec 2022 11:32:59 +0100 Subject: [PATCH 028/119] fix: standardize caps --- .../src/components/editableTable/Header.js | 4 ++-- .../machineActions/MachineActions.js | 2 +- .../src/pages/Cashout/WizardStep.js | 2 +- .../Commissions/components/CommissionsList.js | 4 ++-- .../src/pages/Customers/CustomersList.js | 2 +- .../Customers/components/CustomerSidebar.js | 2 +- new-lamassu-admin/src/pages/Funding.js | 2 +- new-lamassu-admin/src/pages/MachineLogs.js | 2 +- .../src/pages/Maintenance/CashUnits.js | 2 +- .../src/pages/Maintenance/CashboxHistory.js | 2 +- .../pages/Maintenance/MachineDetailsCard.js | 4 ++-- .../src/pages/Maintenance/MachineStatus.js | 6 ++--- .../sections/CryptoBalanceAlerts.js | 4 ++-- .../src/pages/Notifications/sections/Setup.js | 6 ++--- .../src/pages/OperatorInfo/ContactInfo.js | 4 ++-- .../src/pages/OperatorInfo/ReceiptPrinting.js | 2 +- .../src/pages/Services/Services.js | 2 +- .../SessionManagement/SessionManagement.js | 2 +- .../pages/UserManagement/UserManagement.js | 2 +- new-lamassu-admin/src/pages/Wallet/Wallet.js | 2 +- new-lamassu-admin/src/pages/Wallet/helper.js | 10 ++++----- .../src/routing/lamassu.routes.js | 22 +++++++++---------- new-lamassu-admin/src/routing/pazuz.routes.js | 14 ++++++------ new-lamassu-admin/src/utils/string.js | 10 ++++++++- 24 files changed, 61 insertions(+), 53 deletions(-) diff --git a/new-lamassu-admin/src/components/editableTable/Header.js b/new-lamassu-admin/src/components/editableTable/Header.js index 07efcdac..b6ca9b2c 100644 --- a/new-lamassu-admin/src/components/editableTable/Header.js +++ b/new-lamassu-admin/src/components/editableTable/Header.js @@ -9,7 +9,7 @@ import { TDoubleLevelHead, ThDoubleLevel } from 'src/components/fake-table/Table' -import { startCase } from 'src/utils/string' +import { sentenceCase } from 'src/utils/string' import TableCtx from './Context' @@ -99,7 +99,7 @@ const Header = () => { <>{attachOrderedByToComplexHeader(header) ?? header} ) : ( - {!R.isNil(display) ? display : startCase(name)}{' '} + {!R.isNil(display) ? display : sentenceCase(name)}{' '} {!R.isNil(orderedBy) && R.equals(name, orderedBy.code) && '-'} )} diff --git a/new-lamassu-admin/src/components/machineActions/MachineActions.js b/new-lamassu-admin/src/components/machineActions/MachineActions.js index d9ede4f1..d62833a0 100644 --- a/new-lamassu-admin/src/components/machineActions/MachineActions.js +++ b/new-lamassu-admin/src/components/machineActions/MachineActions.js @@ -187,7 +187,7 @@ const MachineActions = memo(({ machine, onActionSuccess }) => { display: 'Restart services for' }) }}> - Restart Services + Restart services {machine.model === 'aveiro' && ( Default Commissions diff --git a/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js b/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js index 9ea641a1..ebf4f82e 100644 --- a/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js +++ b/new-lamassu-admin/src/pages/Commissions/components/CommissionsList.js @@ -37,7 +37,7 @@ const SHOW_ALL = { const ORDER_OPTIONS = [ { code: 'machine', - display: 'Machine Name' + display: 'Machine name' }, { code: 'cryptoCurrencies', @@ -53,7 +53,7 @@ const ORDER_OPTIONS = [ }, { code: 'fixedFee', - display: 'Fixed Fee' + display: 'Fixed fee' }, { code: 'minimumTx', diff --git a/new-lamassu-admin/src/pages/Customers/CustomersList.js b/new-lamassu-admin/src/pages/Customers/CustomersList.js index a7ed2a92..df39f4d9 100644 --- a/new-lamassu-admin/src/pages/Customers/CustomersList.js +++ b/new-lamassu-admin/src/pages/Customers/CustomersList.js @@ -36,7 +36,7 @@ const CustomersList = ({ view: getName }, { - header: 'Total TXs', + header: 'Total Txs', width: 126, textAlign: 'right', view: it => `${Number.parseInt(it.totalTxs)}` diff --git a/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js b/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js index 6bcf3444..a698a218 100644 --- a/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js +++ b/new-lamassu-admin/src/pages/Customers/components/CustomerSidebar.js @@ -26,7 +26,7 @@ const CustomerSidebar = ({ isSelected, onClick }) => { }, { code: 'customerData', - display: 'Customer Data', + display: 'Customer data', Icon: CustomerDataIcon, InverseIcon: CustomerDataReversedIcon }, diff --git a/new-lamassu-admin/src/pages/Funding.js b/new-lamassu-admin/src/pages/Funding.js index e642aaf3..9462ea1c 100644 --- a/new-lamassu-admin/src/pages/Funding.js +++ b/new-lamassu-admin/src/pages/Funding.js @@ -164,7 +164,7 @@ const Funding = () => { {funding.length && (
- Total Crypto Balance + Total crypto balance {getConfirmedTotal(funding)} diff --git a/new-lamassu-admin/src/pages/MachineLogs.js b/new-lamassu-admin/src/pages/MachineLogs.js index d06f4a2c..88bc6478 100644 --- a/new-lamassu-admin/src/pages/MachineLogs.js +++ b/new-lamassu-admin/src/pages/MachineLogs.js @@ -111,7 +111,7 @@ const Logs = () => { <>
- Machine Logs + Machine logs {logsResponse && (
{ !dataLoading && ( <> { }, { name: 'billCount', - header: 'Bill Count', + header: 'Bill count', width: 115, textAlign: 'left', input: NumberInput, diff --git a/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js index 0aaf1ea2..5551f009 100644 --- a/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js +++ b/new-lamassu-admin/src/pages/Maintenance/MachineDetailsCard.js @@ -92,7 +92,7 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess, timezone }) => { - + {modelPrettifier[machine.model]} @@ -126,7 +126,7 @@ const MachineDetailsRow = ({ it: machine, onActionSuccess, timezone }) => { - + {machine.packetLoss ? new BigNumber(machine.packetLoss).toFixed(3).toString() + diff --git a/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js b/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js index 035f2d33..e50eaf5c 100644 --- a/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js +++ b/new-lamassu-admin/src/pages/Maintenance/MachineStatus.js @@ -74,7 +74,7 @@ const MachineStatus = () => { const elements = [ { - header: 'Machine Name', + header: 'Machine name', width: 250, size: 'sm', textAlign: 'left', @@ -111,7 +111,7 @@ const MachineStatus = () => { : 'unknown' }, { - header: 'Software Version', + header: 'Software version', width: 200, size: 'sm', textAlign: 'left', @@ -134,7 +134,7 @@ const MachineStatus = () => { <>
- Machine Status + Machine status
diff --git a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js index 270a9edb..a626020b 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceAlerts.js @@ -32,7 +32,7 @@ const CryptoBalanceAlerts = ({ section, fieldWidth }) => { section={section} decoration={currency} className={classes.cryptoBalanceAlertsForm} - title="Default (Low Balance)" + title="Default (Low balance)" label="Alert me under" editing={isEditing(LOW_BALANCE_KEY)} disabled={isDisabled(LOW_BALANCE_KEY)} @@ -49,7 +49,7 @@ const CryptoBalanceAlerts = ({ section, fieldWidth }) => { save={save} decoration={currency} className={classes.cryptoBalanceAlertsSecondForm} - title="Default (High Balance)" + title="Default (High balance)" label="Alert me over" editing={isEditing(HIGH_BALANCE_KEY)} disabled={isDisabled(HIGH_BALANCE_KEY)} diff --git a/new-lamassu-admin/src/pages/Notifications/sections/Setup.js b/new-lamassu-admin/src/pages/Notifications/sections/Setup.js index 2e8d7583..cd512b9e 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/Setup.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/Setup.js @@ -12,7 +12,7 @@ import { } from 'src/components/fake-table/Table' import { Switch } from 'src/components/inputs' import { fromNamespace, toNamespace } from 'src/utils/config' -import { startCase } from 'src/utils/string' +import { sentenceCase } from 'src/utils/string' import NotificationsCtx from '../NotificationsContext' @@ -62,7 +62,7 @@ const Row = ({ return ( - {shouldUpperCase ? R.toUpper(namespace) : startCase(namespace)} + {shouldUpperCase ? R.toUpper(namespace) : sentenceCase(namespace)} @@ -127,7 +127,7 @@ const Setup = ({ wizard, forceDisable }) => { Channel {Object.keys(sizes).map(it => ( - {startCase(it)} + {sentenceCase(it)} ))} diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js b/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js index e1b68f21..bb3f9bb8 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ContactInfo.js @@ -136,7 +136,7 @@ const ContactInfo = ({ wizard }) => { const fields = [ { name: 'name', - label: 'Full name', + label: 'Company name', value: info.name ?? '', component: TextInput }, @@ -160,7 +160,7 @@ const ContactInfo = ({ wizard }) => { }, { name: 'companyNumber', - label: 'Company number', + label: 'Company registration number', value: info.companyNumber ?? '', component: TextInput } diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js index dd3f9d19..9b90c14a 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js @@ -109,7 +109,7 @@ const ReceiptPrinting = memo(({ wizard }) => { }, { name: 'companyNumber', - display: 'Company number' + display: 'Company registration number' }, { name: 'machineLocation', diff --git a/new-lamassu-admin/src/pages/Services/Services.js b/new-lamassu-admin/src/pages/Services/Services.js index 966038c9..6a2e08d8 100644 --- a/new-lamassu-admin/src/pages/Services/Services.js +++ b/new-lamassu-admin/src/pages/Services/Services.js @@ -103,7 +103,7 @@ const Services = () => { return (
- + {R.values(schemas).map(schema => ( diff --git a/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js b/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js index 83457474..bc7fbe02 100644 --- a/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js +++ b/new-lamassu-admin/src/pages/SessionManagement/SessionManagement.js @@ -108,7 +108,7 @@ const SessionManagement = () => { return ( <> - + { return ( <> - + { <>
{ }, { name: 'allowTransactionBatching', - header: `Allow BTC Transaction Batching`, + header: `Allow BTC transaction batching`, size: 'sm', stripe: true, width: 260, @@ -119,7 +119,7 @@ const getAdvancedWalletElements = () => { }, { name: 'feeMultiplier', - header: `BTC Miner's Fee`, + header: `BTC Miner's fee`, size: 'sm', stripe: true, width: 250, @@ -179,7 +179,7 @@ const getAdvancedWalletElementsOverrides = ( }, { name: 'feeMultiplier', - header: `Miner's Fee`, + header: `Miner's fee`, size: 'sm', stripe: true, width: 250, @@ -280,7 +280,7 @@ const getElements = (cryptoCurrencies, accounts, onChange, wizard = false) => { }, { name: 'zeroConf', - header: 'Confidence Checking', + header: 'Confidence checking', size: 'sm', stripe: true, view: (it, row) => { @@ -304,7 +304,7 @@ const getElements = (cryptoCurrencies, accounts, onChange, wizard = false) => { }, { name: 'zeroConfLimit', - header: '0-conf Limit', + header: '0-conf limit', size: 'sm', stripe: true, view: (it, row) => diff --git a/new-lamassu-admin/src/routing/lamassu.routes.js b/new-lamassu-admin/src/routing/lamassu.routes.js index 4b2ca01f..873fc0fb 100644 --- a/new-lamassu-admin/src/routing/lamassu.routes.js +++ b/new-lamassu-admin/src/routing/lamassu.routes.js @@ -49,7 +49,7 @@ const getLamassuRoutes = () => [ children: [ { key: 'cash_units', - label: 'Cash Units', + label: 'Cash units', route: '/maintenance/cash-units', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: CashUnits @@ -63,14 +63,14 @@ const getLamassuRoutes = () => [ }, { key: 'logs', - label: 'Machine Logs', + label: 'Machine logs', route: '/maintenance/logs', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineLogs }, { key: 'machine-status', - label: 'Machine Status', + label: 'Machine status', route: '/maintenance/machine-status', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineStatus @@ -130,7 +130,7 @@ const getLamassuRoutes = () => [ }, { key: 'services', - label: '3rd Party Services', + label: '3rd Party services', route: '/settings/3rd-party-services', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: Services @@ -144,9 +144,9 @@ const getLamassuRoutes = () => [ }, { key: namespaces.OPERATOR_INFO, - label: 'Operator Info', + label: 'Operator info', route: '/settings/operator-info', - title: 'Operator Information', + title: 'Operator information', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], get component() { return () => ( @@ -232,7 +232,7 @@ const getLamassuRoutes = () => [ key: 'loyalty', label: 'Loyalty', route: '/compliance/loyalty', - title: 'Loyalty Panel', + title: 'Loyalty panel', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], get component() { return () => ( @@ -247,14 +247,14 @@ const getLamassuRoutes = () => [ children: [ { key: 'individual-discounts', - label: 'Individual Discounts', + label: 'Individual discounts', route: '/compliance/loyalty/individual-discounts', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: IndividualDiscounts }, { key: 'promo-codes', - label: 'Promo Codes', + label: 'Promo codes', route: '/compliance/loyalty/codes', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: PromoCodes @@ -280,14 +280,14 @@ const getLamassuRoutes = () => [ children: [ { key: 'user-management', - label: 'User Management', + label: 'User management', route: '/system/user-management', allowedRoles: [ROLES.SUPERUSER], component: UserManagement }, { key: 'session-management', - label: 'Session Management', + label: 'Session management', route: '/system/session-management', allowedRoles: [ROLES.SUPERUSER], component: SessionManagement diff --git a/new-lamassu-admin/src/routing/pazuz.routes.js b/new-lamassu-admin/src/routing/pazuz.routes.js index e0a9be94..f6ad9d21 100644 --- a/new-lamassu-admin/src/routing/pazuz.routes.js +++ b/new-lamassu-admin/src/routing/pazuz.routes.js @@ -56,14 +56,14 @@ const getPazuzRoutes = () => [ }, { key: 'logs', - label: 'Machine Logs', + label: 'Machine logs', route: '/maintenance/logs', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineLogs }, { key: 'machine-status', - label: 'Machine Status', + label: 'Machine status', route: '/maintenance/machine-status', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: MachineStatus @@ -123,9 +123,9 @@ const getPazuzRoutes = () => [ }, { key: namespaces.OPERATOR_INFO, - label: 'Operator Info', + label: 'Operator info', route: '/settings/operator-info', - title: 'Operator Information', + title: 'Operator information', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], get component() { return () => ( @@ -232,7 +232,7 @@ const getPazuzRoutes = () => [ }, { key: 'promo-codes', - label: 'Promo Codes', + label: 'Promo codes', route: '/compliance/loyalty/codes', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: PromoCodes @@ -290,14 +290,14 @@ const getPazuzRoutes = () => [ children: [ { key: 'user-management', - label: 'User Management', + label: 'User management', route: '/system/user-management', allowedRoles: [ROLES.SUPERUSER], component: UserManagement }, { key: 'session-management', - label: 'Session Management', + label: 'Session management', route: '/system/session-management', allowedRoles: [ROLES.SUPERUSER], component: SessionManagement diff --git a/new-lamassu-admin/src/utils/string.js b/new-lamassu-admin/src/utils/string.js index 837369c8..d210cfba 100644 --- a/new-lamassu-admin/src/utils/string.js +++ b/new-lamassu-admin/src/utils/string.js @@ -26,7 +26,15 @@ const startCase = R.compose( splitOnUpper ) +const sentenceCase = R.compose(onlyFirstToUpper, S.joinWith(' '), splitOnUpper) + const singularOrPlural = (amount, singularStr, pluralStr) => parseInt(amount) === 1 ? singularStr : pluralStr -export { startCase, onlyFirstToUpper, formatLong, singularOrPlural } +export { + startCase, + onlyFirstToUpper, + formatLong, + singularOrPlural, + sentenceCase +} From 644a6b32bd12630182299c4f283896be21c81c5b Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Tue, 13 Dec 2022 11:34:19 +0100 Subject: [PATCH 029/119] fix: standardize caps --- .../src/pages/Analytics/Analytics.js | 2 +- .../src/pages/Commissions/helper.js | 10 ++++----- .../pages/Customers/components/IdDataCard.js | 4 ++-- .../src/pages/Customers/helper.js | 2 +- new-lamassu-admin/src/pages/Locales/helper.js | 6 ++--- .../sections/CryptoBalanceOverrides.js | 4 ++-- .../src/pages/Services/Services.js | 2 +- .../src/pages/Services/schemas/binance.js | 4 ++-- .../src/pages/Services/schemas/binanceus.js | 4 ++-- .../src/pages/Services/schemas/bitgo.js | 22 +++++++++---------- .../src/pages/Services/schemas/bitstamp.js | 4 ++-- .../src/pages/Services/schemas/blockcypher.js | 4 ++-- .../src/pages/Services/schemas/cex.js | 4 ++-- .../src/pages/Services/schemas/itbit.js | 4 ++-- .../src/pages/Services/schemas/kraken.js | 4 ++-- .../src/pages/Services/schemas/mailgun.js | 6 ++--- .../src/pages/Services/schemas/singlebitgo.js | 6 ++--- .../src/pages/Services/schemas/twilio.js | 6 ++--- .../src/pages/Transactions/Transactions.js | 2 +- new-lamassu-admin/src/pages/Wallet/helper.js | 2 +- .../src/routing/lamassu.routes.js | 2 +- new-lamassu-admin/src/routing/pazuz.routes.js | 2 +- 22 files changed, 53 insertions(+), 53 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index b7eed8fa..46d85572 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -29,7 +29,7 @@ const useStyles = makeStyles(styles) const MACHINE_OPTIONS = [{ code: 'all', display: 'All machines' }] const REPRESENTING_OPTIONS = [ { code: 'overTime', display: 'Over time' }, - { code: 'topMachines', display: 'Top Machines' }, + { code: 'topMachines', display: 'Top machines' }, { code: 'hourOfTheDay', display: 'Hour of the day' } ] const PERIOD_OPTIONS = [ diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index f93e6789..6418afa4 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -245,7 +245,7 @@ const getSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed Fee') + .label('Fixed fee') .min(0) .max(highestBill) .required(), @@ -326,7 +326,7 @@ const getOverridesSchema = (values, rawData, locale) => { return true } }) - .label('Crypto Currencies') + .label('Crypto currencies') .required() .min(1), cashIn: Yup.number() @@ -340,7 +340,7 @@ const getOverridesSchema = (values, rawData, locale) => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed Fee') + .label('Fixed fee') .min(0) .max(highestBill) .required(), @@ -437,7 +437,7 @@ const getListCommissionsSchema = locale => { .label('Machine') .required(), cryptoCurrencies: Yup.array() - .label('Crypto Currency') + .label('Crypto currency') .required() .min(1), cashIn: Yup.number() @@ -451,7 +451,7 @@ const getListCommissionsSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed Fee') + .label('Fixed fee') .min(0) .max(highestBill) .required(), diff --git a/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js b/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js index 3083283f..12a838db 100644 --- a/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/IdDataCard.js @@ -32,7 +32,7 @@ const IdDataCard = memo(({ customerData, updateCustomer }) => { size: 160 }, { - header: 'Birth Date', + header: 'Birth date', display: (rawDob && format('yyyy-MM-dd')(parse(new Date(), 'yyyyMMdd', rawDob))) ?? @@ -61,7 +61,7 @@ const IdDataCard = memo(({ customerData, updateCustomer }) => { size: 120 }, { - header: 'Expiration Date', + header: 'Expiration date', display: ifNotNull( rawExpirationDate, format('yyyy-MM-dd', rawExpirationDate) diff --git a/new-lamassu-admin/src/pages/Customers/helper.js b/new-lamassu-admin/src/pages/Customers/helper.js index 42e38317..84954b99 100644 --- a/new-lamassu-admin/src/pages/Customers/helper.js +++ b/new-lamassu-admin/src/pages/Customers/helper.js @@ -411,7 +411,7 @@ const customerDataElements = { }, { name: 'expirationDate', - label: 'Expiration Date', + label: 'Expiration date', component: TextInput, editable: true }, diff --git a/new-lamassu-admin/src/pages/Locales/helper.js b/new-lamassu-admin/src/pages/Locales/helper.js index 32b14e4e..2c050694 100644 --- a/new-lamassu-admin/src/pages/Locales/helper.js +++ b/new-lamassu-admin/src/pages/Locales/helper.js @@ -157,7 +157,7 @@ const LocaleSchema = Yup.object().shape({ .label('Country') .required(), fiatCurrency: Yup.string() - .label('Fiat Currency') + .label('Fiat currency') .required(), languages: Yup.array() .label('Languages') @@ -165,7 +165,7 @@ const LocaleSchema = Yup.object().shape({ .min(1) .max(4), cryptoCurrencies: Yup.array() - .label('Crypto Currencies') + .label('Crypto currencies') .required() .min(1), timezone: Yup.string() @@ -186,7 +186,7 @@ const OverridesSchema = Yup.object().shape({ .min(1) .max(4), cryptoCurrencies: Yup.array() - .label('Crypto Currencies') + .label('Crypto currencies') .required() .min(1) }) diff --git a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js index dcd2fb4e..c4957965 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/CryptoBalanceOverrides.js @@ -62,7 +62,7 @@ const CryptoBalanceOverrides = ({ section }) => { .nullable() .required(), [LOW_BALANCE_KEY]: Yup.number() - .label('Low Balance') + .label('Low balance') .when(HIGH_BALANCE_KEY, { is: HIGH_BALANCE_KEY => !HIGH_BALANCE_KEY, then: Yup.number().required() @@ -73,7 +73,7 @@ const CryptoBalanceOverrides = ({ section }) => { .max(CURRENCY_MAX) .nullable(), [HIGH_BALANCE_KEY]: Yup.number() - .label('High Balance') + .label('High balance') .when(LOW_BALANCE_KEY, { is: LOW_BALANCE_KEY => !LOW_BALANCE_KEY, then: Yup.number().required() diff --git a/new-lamassu-admin/src/pages/Services/Services.js b/new-lamassu-admin/src/pages/Services/Services.js index 6a2e08d8..72eab97b 100644 --- a/new-lamassu-admin/src/pages/Services/Services.js +++ b/new-lamassu-admin/src/pages/Services/Services.js @@ -103,7 +103,7 @@ const Services = () => { return (
- + {R.values(schemas).map(schema => ( diff --git a/new-lamassu-admin/src/pages/Services/schemas/binance.js b/new-lamassu-admin/src/pages/Services/schemas/binance.js index 8e4e9bd4..6be4be26 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/binance.js +++ b/new-lamassu-admin/src/pages/Services/schemas/binance.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/binanceus.js b/new-lamassu-admin/src/pages/Services/schemas/binanceus.js index eee1ece7..7afd724b 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/binanceus.js +++ b/new-lamassu-admin/src/pages/Services/schemas/binanceus.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/bitgo.js b/new-lamassu-admin/src/pages/Services/schemas/bitgo.js index f810a728..2e57b9a0 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/bitgo.js +++ b/new-lamassu-admin/src/pages/Services/schemas/bitgo.js @@ -26,7 +26,7 @@ export default { elements: [ { code: 'token', - display: 'API Token', + display: 'API token', component: TextInput, face: true, long: true @@ -47,52 +47,52 @@ export default { }, { code: 'BTCWalletId', - display: 'BTC Wallet ID', + display: 'BTC wallet ID', component: TextInput }, { code: 'BTCWalletPassphrase', - display: 'BTC Wallet Passphrase', + display: 'BTC wallet passphrase', component: SecretInput }, { code: 'LTCWalletId', - display: 'LTC Wallet ID', + display: 'LTC wallet ID', component: TextInput }, { code: 'LTCWalletPassphrase', - display: 'LTC Wallet Passphrase', + display: 'LTC wallet passphrase', component: SecretInput }, { code: 'ZECWalletId', - display: 'ZEC Wallet ID', + display: 'ZEC wallet ID', component: TextInput }, { code: 'ZECWalletPassphrase', - display: 'ZEC Wallet Passphrase', + display: 'ZEC wallet passphrase', component: SecretInput }, { code: 'BCHWalletId', - display: 'BCH Wallet ID', + display: 'BCH wallet ID', component: TextInput }, { code: 'BCHWalletPassphrase', - display: 'BCH Wallet Passphrase', + display: 'BCH wallet passphrase', component: SecretInput }, { code: 'DASHWalletId', - display: 'DASH Wallet ID', + display: 'DASH wallet ID', component: TextInput }, { code: 'DASHWalletPassphrase', - display: 'DASH Wallet Passphrase', + display: 'DASH wallet passphrase', component: SecretInput } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js b/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js index df8e8105..431fcfb5 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js +++ b/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js @@ -19,14 +19,14 @@ export default { }, { code: 'key', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'secret', - display: 'API Secret', + display: 'API secret', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js b/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js index 3515eb1e..d0875577 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js +++ b/new-lamassu-admin/src/pages/Services/schemas/blockcypher.js @@ -9,14 +9,14 @@ export default { elements: [ { code: 'token', - display: 'API Token', + display: 'API token', component: TextInput, face: true, long: true }, { code: 'confidenceFactor', - display: 'Confidence Factor', + display: 'Confidence factor', component: NumberInput, face: true }, diff --git a/new-lamassu-admin/src/pages/Services/schemas/cex.js b/new-lamassu-admin/src/pages/Services/schemas/cex.js index 2c67aa1c..c43b6bda 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/cex.js +++ b/new-lamassu-admin/src/pages/Services/schemas/cex.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/itbit.js b/new-lamassu-admin/src/pages/Services/schemas/itbit.js index 702ca29e..949ba692 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/itbit.js +++ b/new-lamassu-admin/src/pages/Services/schemas/itbit.js @@ -26,12 +26,12 @@ export default { }, { code: 'clientKey', - display: 'Client Key', + display: 'Client key', component: TextInputFormik }, { code: 'clientSecret', - display: 'Client Secret', + display: 'Client secret', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/kraken.js b/new-lamassu-admin/src/pages/Services/schemas/kraken.js index 752c3f7a..733cebe4 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/kraken.js +++ b/new-lamassu-admin/src/pages/Services/schemas/kraken.js @@ -12,14 +12,14 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik, face: true, long: true }, { code: 'privateKey', - display: 'Private Key', + display: 'Private key', component: SecretInputFormik } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/mailgun.js b/new-lamassu-admin/src/pages/Services/schemas/mailgun.js index 151344e9..80e1f615 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/mailgun.js +++ b/new-lamassu-admin/src/pages/Services/schemas/mailgun.js @@ -9,7 +9,7 @@ export default { elements: [ { code: 'apiKey', - display: 'API Key', + display: 'API key', component: TextInputFormik }, { @@ -19,13 +19,13 @@ export default { }, { code: 'fromEmail', - display: 'From Email', + display: 'From email', component: TextInputFormik, face: true }, { code: 'toEmail', - display: 'To Email', + display: 'To email', component: TextInputFormik, face: true } diff --git a/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js b/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js index 5af804ca..9e206632 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js +++ b/new-lamassu-admin/src/pages/Services/schemas/singlebitgo.js @@ -13,7 +13,7 @@ const singleBitgo = code => ({ elements: [ { code: 'token', - display: 'API Token', + display: 'API token', component: TextInput, face: true, long: true @@ -34,12 +34,12 @@ const singleBitgo = code => ({ }, { code: `${code}WalletId`, - display: `${code} Wallet ID`, + display: `${code} wallet ID`, component: TextInput }, { code: `${code}WalletPassphrase`, - display: `${code} Wallet Passphrase`, + display: `${code} wallet passphrase`, component: SecretInput } ], diff --git a/new-lamassu-admin/src/pages/Services/schemas/twilio.js b/new-lamassu-admin/src/pages/Services/schemas/twilio.js index 1ed2228f..4628edb3 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/twilio.js +++ b/new-lamassu-admin/src/pages/Services/schemas/twilio.js @@ -17,18 +17,18 @@ export default { }, { code: 'authToken', - display: 'Auth Token', + display: 'Auth token', component: SecretInputFormik }, { code: 'fromNumber', - display: 'Twilio Number (international format)', + display: 'Twilio number (international format)', component: TextInputFormik, face: true }, { code: 'toNumber', - display: 'Notifications Number (international format)', + display: 'Notifications number (international format)', component: TextInputFormik, face: true } diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index 2559dfbf..cd49ca34 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -323,7 +323,7 @@ const Transactions = () => { loading={filtersLoading} filters={filters} options={filterOptions} - inputPlaceholder={'Search Transactions'} + inputPlaceholder={'Search transactions'} onChange={onFilterChange} />
diff --git a/new-lamassu-admin/src/pages/Wallet/helper.js b/new-lamassu-admin/src/pages/Wallet/helper.js index 1f6d6c61..7747292f 100644 --- a/new-lamassu-admin/src/pages/Wallet/helper.js +++ b/new-lamassu-admin/src/pages/Wallet/helper.js @@ -119,7 +119,7 @@ const getAdvancedWalletElements = () => { }, { name: 'feeMultiplier', - header: `BTC Miner's fee`, + header: `BTC miner's fee`, size: 'sm', stripe: true, width: 250, diff --git a/new-lamassu-admin/src/routing/lamassu.routes.js b/new-lamassu-admin/src/routing/lamassu.routes.js index 873fc0fb..ec5d5325 100644 --- a/new-lamassu-admin/src/routing/lamassu.routes.js +++ b/new-lamassu-admin/src/routing/lamassu.routes.js @@ -130,7 +130,7 @@ const getLamassuRoutes = () => [ }, { key: 'services', - label: '3rd Party services', + label: 'Third-party services', route: '/settings/3rd-party-services', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: Services diff --git a/new-lamassu-admin/src/routing/pazuz.routes.js b/new-lamassu-admin/src/routing/pazuz.routes.js index f6ad9d21..8551c123 100644 --- a/new-lamassu-admin/src/routing/pazuz.routes.js +++ b/new-lamassu-admin/src/routing/pazuz.routes.js @@ -225,7 +225,7 @@ const getPazuzRoutes = () => [ children: [ { key: 'individual-discounts', - label: 'Individual Discounts', + label: 'Individual discounts', route: '/compliance/loyalty/individual-discounts', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: IndividualDiscounts From 0db359afa39f926ae93642062bf6600cf6b84793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Wed, 30 Nov 2022 15:47:17 +0000 Subject: [PATCH 030/119] fix: add 2 decimal places to commission --- new-lamassu-admin/src/pages/Transactions/DetailsCard.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index cd40af4b..936c6ced 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -131,8 +131,9 @@ const DetailsRow = ({ it: tx, timezone }) => { ) const commission = BigNumber(tx.profit).toFixed(2, 1) // ROUND_DOWN - const commissionPercentage = + const commissionPercentage = BigNumber( Number.parseFloat(tx.commissionPercentage, 2) * 100 + ).toFixed(2, 1) // ROUND_DOWN const cashInFee = isCashIn ? Number.parseFloat(tx.cashInFee) : 0 const fiat = BigNumber(tx.fiat) .minus(cashInFee) From 9f84ae97f2f0320eca5a6160f6e9548e1db71b33 Mon Sep 17 00:00:00 2001 From: siiky Date: Wed, 27 Nov 2024 10:24:08 +0000 Subject: [PATCH 031/119] chore: fix functions' docs --- lib/customers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/customers.js b/lib/customers.js index d7975972..96e36bd8 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -80,7 +80,7 @@ function getWithEmail (email) { * * @param {string} id Customer's id * @param {object} data Fields to update - * @param {string} Acting user's token + * @param {string} userToken Acting user's token * * @returns {Promise} Newly updated Customer */ @@ -229,7 +229,7 @@ function enhanceEditedPhotos (fields) { /** * Remove the edited data from the db record * - * @name enhanceOverrideFields + * @name deleteEditedData * @function * * @param {string} id Customer's id From b86bcf63ffe0f1ead05212399a91f8efdac03388 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 6 Feb 2023 13:29:08 +0100 Subject: [PATCH 032/119] fix: cash boxes table height --- new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js b/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js index 5d793293..389968bc 100644 --- a/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js +++ b/new-lamassu-admin/src/pages/Maintenance/CashUnits.styles.js @@ -5,7 +5,7 @@ export default { height: 36 }, tBody: { - maxHeight: '65vh', + maxHeight: 'calc(100vh - 350px)', overflow: 'auto' }, tableWidth: { From ac35e5c006060576b8f3c5cef3d204e4d0ab99e7 Mon Sep 17 00:00:00 2001 From: siiky Date: Wed, 27 Nov 2024 10:24:44 +0000 Subject: [PATCH 033/119] refactor: remove unused argument --- lib/routes/customerRoutes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/routes/customerRoutes.js b/lib/routes/customerRoutes.js index f9120b84..1b51b872 100644 --- a/lib/routes/customerRoutes.js +++ b/lib/routes/customerRoutes.js @@ -108,7 +108,7 @@ function updateCustomer (req, res, next) { .then(_.merge(patch)) .then(newPatch => customers.updatePhotoCard(id, newPatch)) .then(newPatch => customers.updateFrontCamera(id, newPatch)) - .then(newPatch => customers.update(id, newPatch, null, txId)) + .then(newPatch => customers.update(id, newPatch, null)) .then(customer => { createPendingManualComplianceNotifs(settings, customer, deviceId) respond(req, res, { customer }) From ac7bcac53f2f4211634a523c0b01c65b781cab97 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 6 Feb 2023 13:33:36 +0100 Subject: [PATCH 034/119] fix: cashbox history table height --- .../src/pages/Maintenance/CashboxHistory.js | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js b/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js index 139899d1..080868cb 100644 --- a/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js +++ b/new-lamassu-admin/src/pages/Maintenance/CashboxHistory.js @@ -51,6 +51,12 @@ const styles = { display: 'flex', flexDirection: 'row', justifyContent: 'space-between' + }, + tableWrapper: { + display: 'flex', + flexDirection: 'column', + flex: 1, + marginBottom: 80 } } @@ -243,13 +249,15 @@ const CashboxHistory = ({ machines, currency, timezone }) => { ] return ( - +
+ +
) } From b44a7e2d750f137b0380522a3f1e78d6139604b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1?= Date: Wed, 9 Mar 2022 17:51:24 +0000 Subject: [PATCH 035/119] fix: correctly hide secret fields from GQL results --- lib/new-settings-loader.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/new-settings-loader.js b/lib/new-settings-loader.js index 76cd120c..e571d1e2 100644 --- a/lib/new-settings-loader.js +++ b/lib/new-settings-loader.js @@ -100,16 +100,19 @@ function loadAccounts (schemaVersion) { .then(_.compose(_.defaultTo({}), _.get('data.accounts'))) } +function hideSecretFields (accounts) { + return _.flow( + _.filter(path => !_.isEmpty(_.get(path, accounts))), + _.reduce( + (accounts, path) => _.assoc(path, PASSWORD_FILLED, accounts), + accounts + ) + )(SECRET_FIELDS) +} + function showAccounts (schemaVersion) { return loadAccounts(schemaVersion) - .then(accounts => { - const filledSecretPaths = _.compact(_.map(path => { - if (!_.isEmpty(_.get(path, accounts))) { - return path - } - }, SECRET_FIELDS)) - return _.compose(_.map(path => _.assoc(path, PASSWORD_FILLED), filledSecretPaths))(accounts) - }) + .then(hideSecretFields) } const insertConfigRow = (dbOrTx, data) => From b9fb15fa79d75a134e1d607a929329bdaba17d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Fri, 19 Aug 2022 17:29:35 +0100 Subject: [PATCH 036/119] feat: check package hash upon install and update --- lib/blockchain/bitcoin.js | 6 ++++++ lib/blockchain/bitcoincash.js | 4 ++++ lib/blockchain/common.js | 15 +++++++++++++++ lib/blockchain/dash.js | 4 ++++ lib/blockchain/ethereum.js | 4 ++++ lib/blockchain/litecoin.js | 4 ++++ lib/blockchain/monero.js | 4 ++++ lib/blockchain/zcash.js | 4 ++++ 8 files changed, 45 insertions(+) diff --git a/lib/blockchain/bitcoin.js b/lib/blockchain/bitcoin.js index 12c96815..fd0dfbeb 100644 --- a/lib/blockchain/bitcoin.js +++ b/lib/blockchain/bitcoin.js @@ -27,6 +27,10 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Bitcoin Core. This may take a minute...') !isDevMode() && common.es(`sudo supervisorctl stop bitcoin`) common.es(`curl -#o /tmp/bitcoin.tar.gz ${coinRec.url}`) + if (common.es(`sha256 /tmp/bitcoin.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + common.logger.info('Failed to update Bitcoin Core: Package signature do not match!') + return + } common.es(`tar -xzf /tmp/bitcoin.tar.gz -C /tmp/`) common.logger.info('Updating wallet...') @@ -63,6 +67,8 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Bitcoin Core is updated!') } +console.log(typeof common.es(`sha256sum ../../../../../Downloads/monero-linux-x64-v0.18.0.0.tar.bz2 | awk '{print $1}'`).trim()) + function buildConfig () { return `rpcuser=lamassuserver rpcpassword=${common.randomPass()} diff --git a/lib/blockchain/bitcoincash.js b/lib/blockchain/bitcoincash.js index d8ac0efe..88c1865f 100644 --- a/lib/blockchain/bitcoincash.js +++ b/lib/blockchain/bitcoincash.js @@ -20,6 +20,10 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Bitcoin Cash. This may take a minute...') common.es(`sudo supervisorctl stop bitcoincash`) common.es(`curl -#Lo /tmp/bitcoincash.tar.gz ${coinRec.url}`) + if (common.es(`sha256 /tmp/bitcoincash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + common.logger.info('Failed to update Bitcoin Cash: Package signature do not match!') + return + } common.es(`tar -xzf /tmp/bitcoincash.tar.gz -C /tmp/`) common.logger.info('Updating wallet...') diff --git a/lib/blockchain/common.js b/lib/blockchain/common.js index 8db73a72..1a32e092 100644 --- a/lib/blockchain/common.js +++ b/lib/blockchain/common.js @@ -29,37 +29,47 @@ module.exports = { const BINARIES = { BTC: { defaultUrl: 'https://bitcoincore.org/bin/bitcoin-core-0.20.1/bitcoin-0.20.1-x86_64-linux-gnu.tar.gz', + defaultUrlHash: '376194f06596ecfa40331167c39bc70c355f960280bd2a645fdbf18f66527397', defaultDir: 'bitcoin-0.20.1/bin', url: 'https://bitcoincore.org/bin/bitcoin-core-27.1/bitcoin-27.1-x86_64-linux-gnu.tar.gz', + UrlHash: 'c9840607d230d65f6938b81deaec0b98fe9cb14c3a41a5b13b2c05d044a48422', dir: 'bitcoin-27.1/bin' }, ETH: { url: 'https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.14.8-a9523b64.tar.gz', + urlHash: 'fff507c90c180443456950e4fc0bf224d26ce5ea6896194ff864c3c3754c136b', dir: 'geth-linux-amd64-1.14.8-a9523b64' }, ZEC: { url: 'https://github.com/zcash/artifacts/raw/master/v5.9.0/bullseye/zcash-5.9.0-linux64-debian-bullseye.tar.gz', + urlHash: 'd385b9fbeeb145f60b0b339d256cabb342713ed3014cd634cf2d68078365abd2', dir: 'zcash-5.9.0/bin' }, DASH: { defaultUrl: 'https://github.com/dashpay/dash/releases/download/v18.1.0/dashcore-18.1.0-x86_64-linux-gnu.tar.gz', + defaultUrlHash: 'd89c2afd78183f3ee815adcccdff02098be0c982633889e7b1e9c9656fbef219', defaultDir: 'dashcore-18.1.0/bin', url: 'https://github.com/dashpay/dash/releases/download/v21.1.0/dashcore-21.1.0-x86_64-linux-gnu.tar.gz', + urlHash: 'a7d0c1b04d53a9b1b3499eb82182c0fa57f4c8768c16163e5d05971bf45d7928', dir: 'dashcore-21.1.0/bin' }, LTC: { defaultUrl: 'https://download.litecoin.org/litecoin-0.18.1/linux/litecoin-0.18.1-x86_64-linux-gnu.tar.gz', + defaultUrlHash: 'ca50936299e2c5a66b954c266dcaaeef9e91b2f5307069b9894048acf3eb5751', defaultDir: 'litecoin-0.18.1/bin', url: 'https://download.litecoin.org/litecoin-0.21.3/linux/litecoin-0.21.3-x86_64-linux-gnu.tar.gz', + urlHash: 'ea231c630e2a243cb01affd4c2b95a2be71560f80b64b9f4bceaa13d736aa7cb', dir: 'litecoin-0.21.3/bin' }, BCH: { url: 'https://github.com/bitcoin-cash-node/bitcoin-cash-node/releases/download/v27.1.0/bitcoin-cash-node-27.1.0-x86_64-linux-gnu.tar.gz', + urlHash: '0dcc387cbaa3a039c97ddc8fb99c1fa7bff5dc6e4bd3a01d3c3095f595ad2dce', dir: 'bitcoin-cash-node-27.1.0/bin', files: [['bitcoind', 'bitcoincashd'], ['bitcoin-cli', 'bitcoincash-cli']] }, XMR: { url: 'https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.3.3.tar.bz2', + urlHash: '47c7e6b4b88a57205800a2538065a7874174cd087eedc2526bee1ebcce0cc5e3', dir: 'monero-x86_64-linux-gnu-v0.18.3.3', files: [['monerod', 'monerod'], ['monero-wallet-rpc', 'monero-wallet-rpc']] } @@ -133,10 +143,15 @@ function fetchAndInstall (coinRec) { if (!binaries) throw new Error(`No such coin: ${coinRec.code}`) const url = requiresUpdate ? binaries.defaultUrl : binaries.url + const hash = requiresUpdate ? binaries.defaultUrlHash : binaries.urlHash const downloadFile = path.basename(url) const binDir = requiresUpdate ? binaries.defaultDir : binaries.dir es(`wget -q ${url}`) + if (es(`sha256 ${downloadFile} | awk '{print $1}'`).trim() !== hash) { + logger.info(`Failed to install ${coinRec.code}: Package signature do not match!`) + return + } es(`tar -xf ${downloadFile}`) const usrBinDir = isDevMode() ? path.resolve(BLOCKCHAIN_DIR, 'bin') : '/usr/local/bin' diff --git a/lib/blockchain/dash.js b/lib/blockchain/dash.js index 05ace3a7..af225729 100644 --- a/lib/blockchain/dash.js +++ b/lib/blockchain/dash.js @@ -20,6 +20,10 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Dash Core. This may take a minute...') common.es(`sudo supervisorctl stop dash`) common.es(`curl -#Lo /tmp/dash.tar.gz ${coinRec.url}`) + if (common.es(`sha256 /tmp/dash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + common.logger.info('Failed to update Dash Core: Package signature do not match!') + return + } common.es(`tar -xzf /tmp/dash.tar.gz -C /tmp/`) common.logger.info('Updating wallet...') diff --git a/lib/blockchain/ethereum.js b/lib/blockchain/ethereum.js index dd39468a..ab7d2985 100644 --- a/lib/blockchain/ethereum.js +++ b/lib/blockchain/ethereum.js @@ -8,6 +8,10 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating the Geth Ethereum wallet. This may take a minute...') common.es(`sudo supervisorctl stop ethereum`) common.es(`curl -#o /tmp/ethereum.tar.gz ${coinRec.url}`) + if (common.es(`sha256 /tmp/ethereum.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + common.logger.info('Failed to update Geth: Package signature do not match!') + return + } common.es(`tar -xzf /tmp/ethereum.tar.gz -C /tmp/`) common.logger.info('Updating wallet...') diff --git a/lib/blockchain/litecoin.js b/lib/blockchain/litecoin.js index cd02a77f..e488c171 100644 --- a/lib/blockchain/litecoin.js +++ b/lib/blockchain/litecoin.js @@ -20,6 +20,10 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Litecoin Core. This may take a minute...') common.es(`sudo supervisorctl stop litecoin`) common.es(`curl -#o /tmp/litecoin.tar.gz ${coinRec.url}`) + if (common.es(`sha256 /tmp/litecoin.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + common.logger.info('Failed to update Litecoin Core: Package signature do not match!') + return + } common.es(`tar -xzf /tmp/litecoin.tar.gz -C /tmp/`) common.logger.info('Updating wallet...') diff --git a/lib/blockchain/monero.js b/lib/blockchain/monero.js index 447b2722..4bf64983 100644 --- a/lib/blockchain/monero.js +++ b/lib/blockchain/monero.js @@ -22,6 +22,10 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Monero. This may take a minute...') common.es(`sudo supervisorctl stop monero monero-wallet`) common.es(`curl -#o /tmp/monero.tar.gz ${coinRec.url}`) + if (common.es(`sha256 /tmp/monero.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + common.logger.info('Failed to update Monero: Package signature do not match!') + return + } common.es(`tar -xf /tmp/monero.tar.gz -C /tmp/`) common.logger.info('Updating wallet...') diff --git a/lib/blockchain/zcash.js b/lib/blockchain/zcash.js index 51430969..59749f2d 100644 --- a/lib/blockchain/zcash.js +++ b/lib/blockchain/zcash.js @@ -13,6 +13,10 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating your Zcash wallet. This may take a minute...') common.es(`sudo supervisorctl stop zcash`) common.es(`curl -#Lo /tmp/zcash.tar.gz ${coinRec.url}`) + if (common.es(`sha256 /tmp/zcash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + common.logger.info('Failed to update Zcash: Package signature do not match!') + return + } common.es(`tar -xzf /tmp/zcash.tar.gz -C /tmp/`) common.logger.info('Updating wallet...') From f81b254d5ace6e4bdf3c858930ceed90d01fff5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Fri, 19 Aug 2022 17:30:47 +0100 Subject: [PATCH 037/119] fix: remove debug log --- lib/blockchain/bitcoin.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/blockchain/bitcoin.js b/lib/blockchain/bitcoin.js index fd0dfbeb..e3f5a57c 100644 --- a/lib/blockchain/bitcoin.js +++ b/lib/blockchain/bitcoin.js @@ -67,8 +67,6 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Bitcoin Core is updated!') } -console.log(typeof common.es(`sha256sum ../../../../../Downloads/monero-linux-x64-v0.18.0.0.tar.bz2 | awk '{print $1}'`).trim()) - function buildConfig () { return `rpcuser=lamassuserver rpcpassword=${common.randomPass()} From 06961c29723ad8be8b62bc1a85b22aae2845220e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Oliveira?= Date: Tue, 23 Aug 2022 11:47:54 +0100 Subject: [PATCH 038/119] fix: sha256sum command syntax --- lib/blockchain/bitcoin.js | 2 +- lib/blockchain/bitcoincash.js | 2 +- lib/blockchain/common.js | 2 +- lib/blockchain/dash.js | 2 +- lib/blockchain/ethereum.js | 2 +- lib/blockchain/litecoin.js | 2 +- lib/blockchain/monero.js | 2 +- lib/blockchain/zcash.js | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/blockchain/bitcoin.js b/lib/blockchain/bitcoin.js index e3f5a57c..e5a1a7d6 100644 --- a/lib/blockchain/bitcoin.js +++ b/lib/blockchain/bitcoin.js @@ -27,7 +27,7 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Bitcoin Core. This may take a minute...') !isDevMode() && common.es(`sudo supervisorctl stop bitcoin`) common.es(`curl -#o /tmp/bitcoin.tar.gz ${coinRec.url}`) - if (common.es(`sha256 /tmp/bitcoin.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + if (common.es(`sha256sum /tmp/bitcoin.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { common.logger.info('Failed to update Bitcoin Core: Package signature do not match!') return } diff --git a/lib/blockchain/bitcoincash.js b/lib/blockchain/bitcoincash.js index 88c1865f..53e4ab8e 100644 --- a/lib/blockchain/bitcoincash.js +++ b/lib/blockchain/bitcoincash.js @@ -20,7 +20,7 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Bitcoin Cash. This may take a minute...') common.es(`sudo supervisorctl stop bitcoincash`) common.es(`curl -#Lo /tmp/bitcoincash.tar.gz ${coinRec.url}`) - if (common.es(`sha256 /tmp/bitcoincash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + if (common.es(`sha256sum /tmp/bitcoincash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { common.logger.info('Failed to update Bitcoin Cash: Package signature do not match!') return } diff --git a/lib/blockchain/common.js b/lib/blockchain/common.js index 1a32e092..3e844f6c 100644 --- a/lib/blockchain/common.js +++ b/lib/blockchain/common.js @@ -148,7 +148,7 @@ function fetchAndInstall (coinRec) { const binDir = requiresUpdate ? binaries.defaultDir : binaries.dir es(`wget -q ${url}`) - if (es(`sha256 ${downloadFile} | awk '{print $1}'`).trim() !== hash) { + if (es(`sha256sum ${downloadFile} | awk '{print $1}'`).trim() !== hash) { logger.info(`Failed to install ${coinRec.code}: Package signature do not match!`) return } diff --git a/lib/blockchain/dash.js b/lib/blockchain/dash.js index af225729..51ed159f 100644 --- a/lib/blockchain/dash.js +++ b/lib/blockchain/dash.js @@ -20,7 +20,7 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Dash Core. This may take a minute...') common.es(`sudo supervisorctl stop dash`) common.es(`curl -#Lo /tmp/dash.tar.gz ${coinRec.url}`) - if (common.es(`sha256 /tmp/dash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + if (common.es(`sha256sum /tmp/dash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { common.logger.info('Failed to update Dash Core: Package signature do not match!') return } diff --git a/lib/blockchain/ethereum.js b/lib/blockchain/ethereum.js index ab7d2985..9434ebdc 100644 --- a/lib/blockchain/ethereum.js +++ b/lib/blockchain/ethereum.js @@ -8,7 +8,7 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating the Geth Ethereum wallet. This may take a minute...') common.es(`sudo supervisorctl stop ethereum`) common.es(`curl -#o /tmp/ethereum.tar.gz ${coinRec.url}`) - if (common.es(`sha256 /tmp/ethereum.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + if (common.es(`sha256sum /tmp/ethereum.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { common.logger.info('Failed to update Geth: Package signature do not match!') return } diff --git a/lib/blockchain/litecoin.js b/lib/blockchain/litecoin.js index e488c171..ce128dd0 100644 --- a/lib/blockchain/litecoin.js +++ b/lib/blockchain/litecoin.js @@ -20,7 +20,7 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Litecoin Core. This may take a minute...') common.es(`sudo supervisorctl stop litecoin`) common.es(`curl -#o /tmp/litecoin.tar.gz ${coinRec.url}`) - if (common.es(`sha256 /tmp/litecoin.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + if (common.es(`sha256sum /tmp/litecoin.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { common.logger.info('Failed to update Litecoin Core: Package signature do not match!') return } diff --git a/lib/blockchain/monero.js b/lib/blockchain/monero.js index 4bf64983..870f3920 100644 --- a/lib/blockchain/monero.js +++ b/lib/blockchain/monero.js @@ -22,7 +22,7 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating Monero. This may take a minute...') common.es(`sudo supervisorctl stop monero monero-wallet`) common.es(`curl -#o /tmp/monero.tar.gz ${coinRec.url}`) - if (common.es(`sha256 /tmp/monero.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + if (common.es(`sha256sum /tmp/monero.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { common.logger.info('Failed to update Monero: Package signature do not match!') return } diff --git a/lib/blockchain/zcash.js b/lib/blockchain/zcash.js index 59749f2d..a6baed51 100644 --- a/lib/blockchain/zcash.js +++ b/lib/blockchain/zcash.js @@ -13,7 +13,7 @@ function updateCore (coinRec, isCurrentlyRunning) { common.logger.info('Updating your Zcash wallet. This may take a minute...') common.es(`sudo supervisorctl stop zcash`) common.es(`curl -#Lo /tmp/zcash.tar.gz ${coinRec.url}`) - if (common.es(`sha256 /tmp/zcash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { + if (common.es(`sha256sum /tmp/zcash.tar.gz | awk '{print $1}'`).trim() !== coinRec.urlHash) { common.logger.info('Failed to update Zcash: Package signature do not match!') return } From c5e781883698bee23a586b27a42736d9951dd0c7 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:12 +0100 Subject: [PATCH 039/119] feat: add cash-out fixed fee columns to DB --- .../1732790112740-add-cashout-fee-to-cash_out_txs.js | 7 +++++++ migrations/1732790112741-add-cashout-fee-to-user_config.js | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js create mode 100644 migrations/1732790112741-add-cashout-fee-to-user_config.js diff --git a/migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js b/migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js new file mode 100644 index 00000000..ad5df91b --- /dev/null +++ b/migrations/1732790112740-add-cashout-fee-to-cash_out_txs.js @@ -0,0 +1,7 @@ +const db = require('./db') + +exports.up = next => db.multi([ + 'ALTER TABLE cash_out_txs ADD COLUMN fixed_fee numeric(14, 5) NOT NULL DEFAULT 0;' +], next) + +exports.down = next => next() diff --git a/migrations/1732790112741-add-cashout-fee-to-user_config.js b/migrations/1732790112741-add-cashout-fee-to-user_config.js new file mode 100644 index 00000000..92296e38 --- /dev/null +++ b/migrations/1732790112741-add-cashout-fee-to-user_config.js @@ -0,0 +1,7 @@ +const { saveConfig } = require('../lib/new-settings-loader') + +exports.up = next => saveConfig({ 'commissions_cashOutFixedFee': 0 }) + .then(next) + .catch(next) + +exports.down = next => next() From 5b55ce89d8f673f7845e20b246ac41424dcf8065 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:14 +0100 Subject: [PATCH 040/119] feat: add support for multiple double-headers to `EditableTable` --- .../src/components/editableTable/Header.js | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/new-lamassu-admin/src/components/editableTable/Header.js b/new-lamassu-admin/src/components/editableTable/Header.js index b6ca9b2c..2c422e43 100644 --- a/new-lamassu-admin/src/components/editableTable/Header.js +++ b/new-lamassu-admin/src/components/editableTable/Header.js @@ -22,22 +22,27 @@ const styles = { const useStyles = makeStyles(styles) const groupSecondHeader = elements => { - const [toSHeader, noSHeader] = R.partition(R.has('doubleHeader'))(elements) - - if (!toSHeader.length) { - return [elements, THead] - } - - const index = R.indexOf(toSHeader[0], elements) - const width = R.compose(R.sum, R.map(R.path(['width'])))(toSHeader) - - const innerElements = R.insert( - index, - { width, elements: toSHeader, name: toSHeader[0].doubleHeader }, - noSHeader + const doubleHeader = R.prop('doubleHeader') + const sameDoubleHeader = (a, b) => doubleHeader(a) === doubleHeader(b) + const group = R.pipe( + R.groupWith(sameDoubleHeader), + R.map(group => + R.isNil(doubleHeader(group[0])) // No doubleHeader + ? group + : [ + { + width: R.sum(R.map(R.prop('width'), group)), + elements: group, + name: doubleHeader(group[0]) + } + ] + ), + R.reduce(R.concat, []) ) - return [innerElements, TDoubleLevelHead] + return R.all(R.pipe(doubleHeader, R.isNil), elements) + ? [elements, THead] + : [group(elements), TDoubleLevelHead] } const Header = () => { From d6d7753e076d12ba38b44e30ac23b96fbc0823f8 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:16 +0100 Subject: [PATCH 041/119] feat: add cash-out fixed fee to Admin UI --- .../src/pages/Commissions/helper.js | 70 +++++++++++++++++-- .../Commissions/Commissions.js | 5 +- .../MachineComponents/Commissions/helper.js | 8 +++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index 6418afa4..c7f098a6 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -156,6 +156,20 @@ const getOverridesFields = (getData, currency, auxElements) => { inputProps: { decimalPlaces: 2 } + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 144, + doubleHeader: 'Cash-out only', + textAlign: 'center', + editingAlign: 'right', + input: NumberInput, + suffix: currency, + bold: bold, + inputProps: { + decimalPlaces: 2 + } } ] } @@ -218,6 +232,20 @@ const mainFields = currency => [ inputProps: { decimalPlaces: 2 } + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 169, + doubleHeader: 'Cash-out only', + textAlign: 'center', + editingAlign: 'right', + input: NumberInput, + suffix: currency, + bold: bold, + inputProps: { + decimalPlaces: 2 + } } ] @@ -245,7 +273,7 @@ const getSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed fee') + .label('Cash-in fixed fee') .min(0) .max(highestBill) .required(), @@ -253,6 +281,11 @@ const getSchema = locale => { .label('Minimum Tx') .min(0) .max(highestBill) + .required(), + cashOutFixedFee: Yup.number() + .label('Cash-out fixed fee') + .min(0) + .max(highestBill) .required() }) } @@ -340,7 +373,7 @@ const getOverridesSchema = (values, rawData, locale) => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed fee') + .label('Cash-in fixed fee') .min(0) .max(highestBill) .required(), @@ -348,6 +381,11 @@ const getOverridesSchema = (values, rawData, locale) => { .label('Minimum Tx') .min(0) .max(highestBill) + .required(), + cashOutFixedFee: Yup.number() + .label('Cash-out fixed fee') + .min(0) + .max(highestBill) .required() }) } @@ -356,7 +394,8 @@ const defaults = { cashIn: '', cashOut: '', fixedFee: '', - minimumTx: '' + minimumTx: '', + cashOutFixedFee: '' } const overridesDefaults = { @@ -365,7 +404,8 @@ const overridesDefaults = { cashIn: '', cashOut: '', fixedFee: '', - minimumTx: '' + minimumTx: '', + cashOutFixedFee: '' } const getOrder = ({ machine, cryptoCurrencies }) => { @@ -385,6 +425,7 @@ const createCommissions = (cryptoCode, deviceId, isDefault, config) => { fixedFee: config.fixedFee, cashOut: config.cashOut, cashIn: config.cashIn, + cashOutFixedFee: config.cashOutFixedFee, machine: deviceId, cryptoCurrencies: [cryptoCode], default: isDefault, @@ -451,7 +492,7 @@ const getListCommissionsSchema = locale => { .max(percentMax) .required(), fixedFee: Yup.number() - .label('Fixed fee') + .label('Cash-in fixed fee') .min(0) .max(highestBill) .required(), @@ -459,6 +500,11 @@ const getListCommissionsSchema = locale => { .label('Minimum Tx') .min(0) .max(highestBill) + .required(), + cashOutFixedFee: Yup.number() + .label('Cash-out fixed fee') + .min(0) + .max(highestBill) .required() }) } @@ -544,6 +590,20 @@ const getListCommissionsFields = (getData, currency, defaults) => { inputProps: { decimalPlaces: 2 } + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 144, + doubleHeader: 'Cash-out only', + textAlign: 'center', + editingAlign: 'right', + input: NumberInput, + suffix: currency, + bold: bold, + inputProps: { + decimalPlaces: 2 + } } ] } diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js index caf876e9..a9f8766b 100644 --- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js +++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/Commissions.js @@ -64,10 +64,11 @@ const Commissions = ({ name: SCREEN_KEY, id: deviceId }) => { cashIn: config.cashIn, cashOut: config.cashOut, fixedFee: config.fixedFee, - minimumTx: config.minimumTx + minimumTx: config.minimumTx, + cashOutFixedFee: config.cashOutFixedFee }, R.project( - ['cashIn', 'cashOut', 'fixedFee', 'minimumTx'], + ['cashIn', 'cashOut', 'fixedFee', 'minimumTx', 'cashOutFixedFee'], R.filter( o => R.includes(coin.code, o.cryptoCurrencies) || diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js index 649979db..cbc47265 100644 --- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Commissions/helper.js @@ -61,6 +61,14 @@ const getOverridesFields = currency => { doubleHeader: 'Cash-in only', textAlign: 'right', suffix: currency + }, + { + name: 'cashOutFixedFee', + display: 'Fixed fee', + width: 155, + doubleHeader: 'Cash-out only', + textAlign: 'right', + suffix: currency } ] } From 83595efd8e07045e5887a858ec566ee5c8691506 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:19 +0100 Subject: [PATCH 042/119] feat: send cash-out fixed fee to Coin ATM Radar --- lib/coinatmradar/coinatmradar.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index f6ead34a..88b9eaf4 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -29,6 +29,7 @@ function mapCoin (rates, deviceId, settings, cryptoCode) { const cashInFee = showCommissions ? commissions.cashIn / 100 : null const cashOutFee = showCommissions ? commissions.cashOut / 100 : null const cashInFixedFee = showCommissions ? commissions.fixedFee : null + const cashOutFixedFee = showCommissions ? commissions.cashOutFixedFee : null const cashInRate = showCommissions ? _.invoke('cashIn.toNumber', buildedRates) : null const cashOutRate = showCommissions ? _.invoke('cashOut.toNumber', buildedRates) : null @@ -37,6 +38,7 @@ function mapCoin (rates, deviceId, settings, cryptoCode) { cashInFee, cashOutFee, cashInFixedFee, + cashOutFixedFee, cashInRate, cashOutRate } From 35b1a69434f9a3a19b686d755fa480a72b8ac2db Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:21 +0100 Subject: [PATCH 043/119] feat: add cash-out fixed fee to Server-Machine GraphQL API --- lib/graphql/resolvers.js | 1 + lib/graphql/types.js | 1 + lib/plugins.js | 2 ++ 3 files changed, 4 insertions(+) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index cf4f4da0..1270f1f3 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -89,6 +89,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings 'cashInCommission', 'cashInFee', 'cashOutCommission', + 'cashOutFee', 'cryptoCode', 'cryptoCodeDisplay', 'cryptoNetwork', diff --git a/lib/graphql/types.js b/lib/graphql/types.js index 466391f9..89296c6c 100644 --- a/lib/graphql/types.js +++ b/lib/graphql/types.js @@ -6,6 +6,7 @@ type Coin { display: String! minimumTx: String! cashInFee: String! + cashOutFee: String! cashInCommission: String! cashOutCommission: String! cryptoNetwork: String! diff --git a/lib/plugins.js b/lib/plugins.js index f1587f07..d5bfcb4f 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -249,6 +249,7 @@ function plugins (settings, deviceId) { const commissions = configManager.getCommissions(cryptoCode, deviceId, settings.config) const minimumTx = new BN(commissions.minimumTx) const cashInFee = new BN(commissions.fixedFee) + const cashOutFee = new BN(commissions.cashOutFixedFee) const cashInCommission = new BN(commissions.cashIn) const cashOutCommission = _.isNumber(commissions.cashOut) ? new BN(commissions.cashOut) : null const cryptoRec = coinUtils.getCryptoCurrency(cryptoCode) @@ -261,6 +262,7 @@ function plugins (settings, deviceId) { isCashInOnly: Boolean(cryptoRec.isCashinOnly), minimumTx: BN.max(minimumTx, cashInFee), cashInFee, + cashOutFee, cashInCommission, cashOutCommission, cryptoNetwork, From 8fc3d7d81927389ec88bc7bdb2ad73cd56bd50d9 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:23 +0100 Subject: [PATCH 044/119] refactor: rename `cashInFee` to `fixedFee` --- lib/new-admin/graphql/types/transaction.type.js | 2 +- lib/new-admin/services/transactions.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/new-admin/graphql/types/transaction.type.js b/lib/new-admin/graphql/types/transaction.type.js index 8c43f49e..ae57a365 100644 --- a/lib/new-admin/graphql/types/transaction.type.js +++ b/lib/new-admin/graphql/types/transaction.type.js @@ -23,7 +23,7 @@ const typeDef = gql` errorCode: String operatorCompleted: Boolean sendPending: Boolean - cashInFee: String + fixedFee: String minimumTx: Float customerId: ID isAnonymous: Boolean diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index 733fcad9..67972c19 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -50,7 +50,19 @@ function batch ( excludeTestingCustomers = false, simplified ) { - const packager = _.flow(_.flatten, _.orderBy(_.property('created'), ['desc']), _.map(camelize), addProfits, addNames) + const packager = _.flow( + _.flatten, + _.orderBy(_.property('created'), ['desc']), + _.map(_.flow( + camelize, + _.mapKeys(k => + k == 'cashInFee' ? 'fixedFee' : + k + ) + )), + addProfits, + addNames + ) const cashInSql = `SELECT 'cashIn' AS tx_class, txs.*, c.phone AS customer_phone, From dc9ca619bd483424735f771836e5313474309fae Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:25 +0100 Subject: [PATCH 045/119] feat: include cash-out fee in transaction updates --- lib/tx.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tx.js b/lib/tx.js index 92e1dea6..3e3dc27e 100644 --- a/lib/tx.js +++ b/lib/tx.js @@ -40,6 +40,7 @@ function massage (tx, pi) { : { cryptoAtoms: new BN(r.cryptoAtoms), fiat: new BN(r.fiat), + cashOutFee: new BN(r.cashOutFee), rawTickerPrice: r.rawTickerPrice ? new BN(r.rawTickerPrice) : null, commissionPercentage: new BN(r.commissionPercentage) } From e7ca33c8a4f40515ea97a5db39b989bb42091f60 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:28 +0100 Subject: [PATCH 046/119] refactor: use the common `fixedFee` field --- new-lamassu-admin/src/pages/Analytics/Analytics.js | 2 +- .../Dashboard/SystemPerformance/Graphs/RefLineChart.js | 4 ++-- .../pages/Dashboard/SystemPerformance/SystemPerformance.js | 2 +- .../Machines/MachineComponents/Transactions/Transactions.js | 2 +- new-lamassu-admin/src/pages/Transactions/DetailsCard.js | 6 +++--- new-lamassu-admin/src/pages/Transactions/Transactions.js | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/new-lamassu-admin/src/pages/Analytics/Analytics.js b/new-lamassu-admin/src/pages/Analytics/Analytics.js index 46d85572..34711b36 100644 --- a/new-lamassu-admin/src/pages/Analytics/Analytics.js +++ b/new-lamassu-admin/src/pages/Analytics/Analytics.js @@ -77,7 +77,7 @@ const GET_TRANSACTIONS = gql` hasError: error deviceId fiat - cashInFee + fixedFee fiatCode cryptoAtoms cryptoCode diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js index b9f82f44..4c3ea952 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js @@ -5,10 +5,10 @@ import React, { useEffect, useRef, useCallback } from 'react' import { backgroundColor, zircon, primaryColor } from 'src/styling/variables' const transactionProfit = tx => { - const cashInFee = tx.cashInFee ? Number.parseFloat(tx.cashInFee) : 0 + const fixedFee = tx.fixedFee ? Number.parseFloat(tx.fixedFee) : 0 const commission = Number.parseFloat(tx.commissionPercentage) * Number.parseFloat(tx.fiat) - return commission + cashInFee + return commission + fixedFee } const mockPoint = (tx, offsetMs, profit) => { diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js index 457869ce..4ae6ec87 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/SystemPerformance.js @@ -36,7 +36,7 @@ const GET_DATA = gql` transactions(excludeTestingCustomers: $excludeTestingCustomers) { fiatCode fiat - cashInFee + fixedFee commissionPercentage created txClass diff --git a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js index bb360152..7c13ffa6 100644 --- a/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Machines/MachineComponents/Transactions/Transactions.js @@ -40,7 +40,7 @@ const GET_TRANSACTIONS = gql` hasError: error deviceId fiat - cashInFee + fixedFee fiatCode cryptoAtoms cryptoCode diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index cd40af4b..27cf2c5b 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -133,9 +133,9 @@ const DetailsRow = ({ it: tx, timezone }) => { const commission = BigNumber(tx.profit).toFixed(2, 1) // ROUND_DOWN const commissionPercentage = Number.parseFloat(tx.commissionPercentage, 2) * 100 - const cashInFee = isCashIn ? Number.parseFloat(tx.cashInFee) : 0 + const fixedFee = Number.parseFloat(tx.fixedFee) || 0 const fiat = BigNumber(tx.fiat) - .minus(cashInFee) + .minus(fixedFee) .toFixed(2, 1) // ROUND_DOWN const crypto = getCryptoAmount(tx) const cryptoFee = tx.fee ? `${getCryptoFeeAmount(tx)} ${tx.fiatCode}` : 'N/A' @@ -350,7 +350,7 @@ const DetailsRow = ({ it: tx, timezone }) => {
-
{isCashIn ? `${cashInFee} ${tx.fiatCode}` : 'N/A'}
+
{`${fixedFee} ${tx.fiatCode}`}
diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index cd49ca34..55666384 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -105,7 +105,7 @@ const GET_TRANSACTIONS = gql` deviceId fiat fee - cashInFee + fixedFee fiatCode cryptoAtoms cryptoCode From ce8295e54a21d7460c257ea32d395c1217fba1f3 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:34 +0100 Subject: [PATCH 047/119] refactor: use proft calculated in GraphQL resolver --- .../Dashboard/SystemPerformance/Graphs/RefLineChart.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js index 4c3ea952..8fafd220 100644 --- a/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js +++ b/new-lamassu-admin/src/pages/Dashboard/SystemPerformance/Graphs/RefLineChart.js @@ -4,12 +4,7 @@ import React, { useEffect, useRef, useCallback } from 'react' import { backgroundColor, zircon, primaryColor } from 'src/styling/variables' -const transactionProfit = tx => { - const fixedFee = tx.fixedFee ? Number.parseFloat(tx.fixedFee) : 0 - const commission = - Number.parseFloat(tx.commissionPercentage) * Number.parseFloat(tx.fiat) - return commission + fixedFee -} +const transactionProfit = R.prop('profit') const mockPoint = (tx, offsetMs, profit) => { const date = new Date(new Date(tx.created).getTime() + offsetMs).toISOString() From e0d8f7c24d0c836ea99229239f351dfc3810966b Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:37 +0100 Subject: [PATCH 048/119] fix: DB doesn't like bn.js numbers --- lib/cash-out/cash-out-helper.js | 2 +- lib/tx.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cash-out/cash-out-helper.js b/lib/cash-out/cash-out-helper.js index a98f7a31..cae14a0d 100644 --- a/lib/cash-out/cash-out-helper.js +++ b/lib/cash-out/cash-out-helper.js @@ -51,7 +51,7 @@ const mapValuesWithKey = _.mapValues.convert({cap: false}) function convertBigNumFields (obj) { const convert = (value, key) => { - if (_.includes(key, [ 'cryptoAtoms', 'receivedCryptoAtoms', 'fiat' ])) { + if (_.includes(key, [ 'cryptoAtoms', 'receivedCryptoAtoms', 'fiat', 'fixedFee', 'fixedFeeCrypto' ])) { return value.toString() } diff --git a/lib/tx.js b/lib/tx.js index 3e3dc27e..2e777c51 100644 --- a/lib/tx.js +++ b/lib/tx.js @@ -40,7 +40,7 @@ function massage (tx, pi) { : { cryptoAtoms: new BN(r.cryptoAtoms), fiat: new BN(r.fiat), - cashOutFee: new BN(r.cashOutFee), + fixedFee: new BN(r.fixedFee), rawTickerPrice: r.rawTickerPrice ? new BN(r.rawTickerPrice) : null, commissionPercentage: new BN(r.commissionPercentage) } From 599dbf86799d72ee10af62b5aa0cb3a1cd883e47 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:39 +0100 Subject: [PATCH 049/119] fix: make commission details list fit --- new-lamassu-admin/src/pages/Commissions/helper.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index c7f098a6..7cbdc868 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -533,7 +533,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'cryptoCurrencies', display: 'Crypto Currency', - width: 255, + width: 150, view: R.prop(0), size: 'sm', editable: false @@ -542,7 +542,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { header: cashInHeader, name: 'cashIn', display: 'Cash-in', - width: 130, + width: 120, input: NumberInput, textAlign: 'right', suffix: '%', @@ -555,7 +555,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { header: cashOutHeader, name: 'cashOut', display: 'Cash-out', - width: 140, + width: 126, input: NumberInput, textAlign: 'right', greenText: true, @@ -568,7 +568,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'fixedFee', display: 'Fixed fee', - width: 144, + width: 140, input: NumberInput, doubleHeader: 'Cash-in only', textAlign: 'right', @@ -581,7 +581,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'minimumTx', display: 'Minimum Tx', - width: 144, + width: 140, input: NumberInput, doubleHeader: 'Cash-in only', textAlign: 'right', @@ -594,7 +594,7 @@ const getListCommissionsFields = (getData, currency, defaults) => { { name: 'cashOutFixedFee', display: 'Fixed fee', - width: 144, + width: 140, doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', From 6d141f816dc474ed77fe448e6582ed38cff1631a Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:41 +0100 Subject: [PATCH 050/119] fix: make cash-out fixed fee overrides green --- new-lamassu-admin/src/pages/Commissions/helper.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index 7cbdc868..9b91e943 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -237,6 +237,7 @@ const mainFields = currency => [ name: 'cashOutFixedFee', display: 'Fixed fee', width: 169, + size: 'lg', doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', @@ -595,12 +596,12 @@ const getListCommissionsFields = (getData, currency, defaults) => { name: 'cashOutFixedFee', display: 'Fixed fee', width: 140, + input: NumberInput, doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', - input: NumberInput, suffix: currency, - bold: bold, + textStyle: obj => getTextStyle(obj), inputProps: { decimalPlaces: 2 } From 328257432e1023a77ebf3ffb92fda63608309b54 Mon Sep 17 00:00:00 2001 From: siiky Date: Mon, 10 Oct 2022 16:05:43 +0100 Subject: [PATCH 051/119] fix: make the non-list view overrides narrower --- new-lamassu-admin/src/pages/Commissions/helper.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/new-lamassu-admin/src/pages/Commissions/helper.js b/new-lamassu-admin/src/pages/Commissions/helper.js index 9b91e943..5447d2c7 100644 --- a/new-lamassu-admin/src/pages/Commissions/helper.js +++ b/new-lamassu-admin/src/pages/Commissions/helper.js @@ -91,7 +91,7 @@ const getOverridesFields = (getData, currency, auxElements) => { }, { name: 'cryptoCurrencies', - width: 280, + width: 145, size: 'sm', view: displayCodeArray(cryptoData), input: Autocomplete, @@ -108,7 +108,7 @@ const getOverridesFields = (getData, currency, auxElements) => { header: cashInHeader, name: 'cashIn', display: 'Cash-in', - width: 130, + width: 123, input: NumberInput, textAlign: 'right', suffix: '%', @@ -121,7 +121,7 @@ const getOverridesFields = (getData, currency, auxElements) => { header: cashOutHeader, name: 'cashOut', display: 'Cash-out', - width: 130, + width: 127, input: NumberInput, textAlign: 'right', suffix: '%', @@ -133,7 +133,7 @@ const getOverridesFields = (getData, currency, auxElements) => { { name: 'fixedFee', display: 'Fixed fee', - width: 144, + width: 126, input: NumberInput, doubleHeader: 'Cash-in only', textAlign: 'right', @@ -146,7 +146,7 @@ const getOverridesFields = (getData, currency, auxElements) => { { name: 'minimumTx', display: 'Minimum Tx', - width: 169, + width: 140, doubleHeader: 'Cash-in only', textAlign: 'center', editingAlign: 'right', @@ -160,7 +160,7 @@ const getOverridesFields = (getData, currency, auxElements) => { { name: 'cashOutFixedFee', display: 'Fixed fee', - width: 144, + width: 134, doubleHeader: 'Cash-out only', textAlign: 'center', editingAlign: 'right', From 0c1fd7ce87dd6f67a2bb06d7103838b58a4f82f6 Mon Sep 17 00:00:00 2001 From: siiky Date: Tue, 18 Oct 2022 17:00:29 +0100 Subject: [PATCH 052/119] fix: export fixed fee and transaction fee --- lib/new-admin/services/transactions.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/new-admin/services/transactions.js b/lib/new-admin/services/transactions.js index 67972c19..546ef0b3 100644 --- a/lib/new-admin/services/transactions.js +++ b/lib/new-admin/services/transactions.js @@ -165,7 +165,7 @@ function batch ( function advancedBatch (data) { const fields = ['txClass', 'id', 'deviceId', 'toAddress', 'cryptoAtoms', 'cryptoCode', 'fiat', 'fiatCode', 'fee', 'status', 'fiatProfit', 'cryptoAmount', - 'dispense', 'notified', 'redeem', 'phone', 'error', + 'dispense', 'notified', 'redeem', 'phone', 'error', 'fixedFee', 'created', 'confirmedAt', 'hdIndex', 'swept', 'timedout', 'dispenseConfirmed', 'provisioned1', 'provisioned2', 'provisioned3', 'provisioned4', 'provisionedRecycler1', 'provisionedRecycler2', 'provisionedRecycler3', 'provisionedRecycler4', 'provisionedRecycler5', 'provisionedRecycler6', @@ -181,7 +181,9 @@ function advancedBatch (data) { ...it, status: getStatus(it), fiatProfit: getProfit(it).toString(), - cryptoAmount: getCryptoAmount(it).toString() + cryptoAmount: getCryptoAmount(it).toString(), + fixedFee: it.fixedFee ?? null, + fee: it.fee ?? null, })) return _.compose(_.map(_.pick(fields)), addAdvancedFields)(data) From 52a3d4cf81785401a8583ede5f79f541dc0b7fd1 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Mon, 24 Oct 2022 18:10:24 +0200 Subject: [PATCH 053/119] fix: tooltip doesn't stay open --- new-lamassu-admin/src/components/Tooltip.js | 31 ++++++++++++++++--- .../src/pages/Accounting/Accounting.js | 6 ++-- .../src/pages/Blacklist/Blacklist.js | 25 +++++++++++---- .../src/pages/Cashout/Cashout.js | 29 ++++++++++++++--- .../src/pages/Commissions/Commissions.js | 22 +++++++++++++ .../Customers/components/EditableCard.js | 3 +- .../src/pages/Locales/Locales.js | 20 ++++++++++-- .../LoyaltyPanel/IndividualDiscountModal.js | 6 ++-- .../src/pages/LoyaltyPanel/PromoCodesModal.js | 6 ++-- .../src/pages/Maintenance/CashUnits.js | 18 +++++++++-- .../pages/Maintenance/Wizard/WizardStep.js | 6 ++-- .../src/pages/Notifications/Notifications.js | 21 ++++++++++++- .../src/pages/OperatorInfo/CoinATMRadar.js | 13 ++++++-- .../src/pages/OperatorInfo/ContactInfo.js | 14 ++++++++- .../src/pages/OperatorInfo/ReceiptPrinting.js | 14 +++++++++ .../OperatorInfo/SMSNotices/SMSNotices.js | 19 +++++++++--- .../src/pages/OperatorInfo/TermsConditions.js | 14 ++++++++- .../src/pages/Transactions/DetailsCard.js | 6 ++-- .../src/pages/Transactions/Transactions.js | 19 +++++++++++- .../src/pages/Triggers/Triggers.js | 6 ++-- new-lamassu-admin/src/pages/Wallet/Wallet.js | 17 ++++++++++ .../src/pages/Wizard/components/Twilio.js | 6 ++-- 22 files changed, 269 insertions(+), 52 deletions(-) diff --git a/new-lamassu-admin/src/components/Tooltip.js b/new-lamassu-admin/src/components/Tooltip.js index 2fa5b7f9..40c85c36 100644 --- a/new-lamassu-admin/src/components/Tooltip.js +++ b/new-lamassu-admin/src/components/Tooltip.js @@ -13,6 +13,16 @@ const useStyles = makeStyles({ cursor: 'pointer', marginTop: 4 }, + relativelyPositioned: { + position: 'relative' + }, + safeSpace: { + position: 'absolute', + backgroundColor: '#0000', + height: 40, + left: '-50%', + width: '200%' + }, popoverContent: ({ width }) => ({ width, padding: [[10, 15]] @@ -27,6 +37,10 @@ const usePopperHandler = width => { setHelpPopperAnchorEl(helpPopperAnchorEl ? null : event.currentTarget) } + const openHelpPopper = event => { + setHelpPopperAnchorEl(event.currentTarget) + } + const handleCloseHelpPopper = () => { setHelpPopperAnchorEl(null) } @@ -38,25 +52,32 @@ const usePopperHandler = width => { helpPopperAnchorEl, helpPopperOpen, handleOpenHelpPopper, + openHelpPopper, handleCloseHelpPopper } } -const Tooltip = memo(({ children, width, Icon = HelpIcon }) => { +const HelpTooltip = memo(({ children, width }) => { const handler = usePopperHandler(width) return ( -
+
+ {handler.helpPopperOpen && ( +
+ )}
{children}
@@ -96,4 +117,4 @@ const HoverableTooltip = memo(({ parentElements, children, width }) => { ) }) -export { Tooltip, HoverableTooltip } +export { HoverableTooltip, HelpTooltip } diff --git a/new-lamassu-admin/src/pages/Accounting/Accounting.js b/new-lamassu-admin/src/pages/Accounting/Accounting.js index 09b38d0b..dcc6b18d 100644 --- a/new-lamassu-admin/src/pages/Accounting/Accounting.js +++ b/new-lamassu-admin/src/pages/Accounting/Accounting.js @@ -6,7 +6,7 @@ import * as R from 'ramda' import React, { useContext } from 'react' import AppContext from 'src/AppContext' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import TitleSection from 'src/components/layout/TitleSection' import DataTable from 'src/components/tables/DataTable' import { H4, Info2, P } from 'src/components/typography' @@ -128,9 +128,9 @@ const Accounting = () => { {it.description} {!!it.extraInfo && ( - +

{it.extraInfo}

-
+ )}
) diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index b4918993..dec75592 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -7,8 +7,13 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' -import { HoverableTooltip } from 'src/components/Tooltip' -import { Link, Button, IconButton } from 'src/components/buttons' +import { HelpTooltip } from 'src/components/Tooltip' +import { + Link, + Button, + IconButton, + SupportLinkButton +} from 'src/components/buttons' import { Switch } from 'src/components/inputs' import Sidebar from 'src/components/layout/Sidebar' import TitleSection from 'src/components/layout/TitleSection' @@ -251,13 +256,13 @@ const Blacklist = () => { value={enablePaperWalletOnly} /> {enablePaperWalletOnly ? 'On' : 'Off'} - +

The "Enable paper wallet (only)" option means that only paper wallets will be printed for users, and they won't be permitted to scan an address from their own wallet.

-
+ { value={rejectAddressReuse} /> {rejectAddressReuse ? 'On' : 'Off'} - +

The "Reject reused addresses" option means that all addresses that are used once will be automatically rejected if there's an attempt to use them again on a new transaction.

-
+

+ For details please read the relevant knowledgebase article: +

+ +
{ return ( !loading && ( <> - + +

+ For details on configuring cash-out, please read the relevant + knowledgebase article: +

+ + + }>

Transaction fudge factor

{ {fudgeFactorActive ? 'On' : 'Off'} - +

Automatically accept customer deposits as complete if their received amount is 100 crypto atoms or less. @@ -114,7 +129,13 @@ const CashOut = ({ name: SCREEN_KEY }) => { (Crypto atoms are the smallest unit in each cryptocurrency. E.g., satoshis in Bitcoin, or wei in Ethereum.)

-
+

For details please read the relevant knowledgebase article:

+ +
{ } ]} iconClassName={classes.listViewButton} + appendix={ + +

+ For details about commissions, please read the relevant + knowledgebase articles: +

+ + +
+ } /> {!showMachines && !loading && ( diff --git a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js index 0eb0be28..89479a02 100644 --- a/new-lamassu-admin/src/pages/Customers/components/EditableCard.js +++ b/new-lamassu-admin/src/pages/Customers/components/EditableCard.js @@ -8,6 +8,7 @@ import { useState, React, useRef } from 'react' import ErrorMessage from 'src/components/ErrorMessage' import PromptWhenDirty from 'src/components/PromptWhenDirty' import { MainStatus } from 'src/components/Status' +// import { HelpTooltip } from 'src/components/Tooltip' import { ActionButton } from 'src/components/buttons' import { Label1, P, H3 } from 'src/components/typography' import { @@ -182,7 +183,7 @@ const EditableCard = ({

{title}

{ // TODO: Enable for next release - /* */ + /* */ }
{state && authorize && ( diff --git a/new-lamassu-admin/src/pages/Locales/Locales.js b/new-lamassu-admin/src/pages/Locales/Locales.js index 3a820c8a..7956121a 100644 --- a/new-lamassu-admin/src/pages/Locales/Locales.js +++ b/new-lamassu-admin/src/pages/Locales/Locales.js @@ -5,7 +5,8 @@ import * as R from 'ramda' import React, { useState } from 'react' import Modal from 'src/components/Modal' -import { Link } from 'src/components/buttons' +import { HelpTooltip } from 'src/components/Tooltip' +import { Link, SupportLinkButton } from 'src/components/buttons' import { Table as EditableTable } from 'src/components/editableTable' import Section from 'src/components/layout/Section' import TitleSection from 'src/components/layout/TitleSection' @@ -176,7 +177,22 @@ const Locales = ({ name: SCREEN_KEY }) => { close={() => setDataToSave(null)} save={() => dataToSave && save(dataToSave)} /> - + +

+ For details on configuring languages, please read the relevant + knowledgebase article: +

+ + + } + />

Define discount rate

- +

This is a percentage discount off of your existing commission rates for a customer entering this code at @@ -110,7 +110,7 @@ const IndividualDiscountModal = ({ code is set for 50%, then you'll instead be charging 4% on transactions using the code.

-
+
{ />

Define discount rate

- +

This is a percentage discount off of your existing commission rates for a customer entering this code at the @@ -80,7 +80,7 @@ const PromoCodesModal = ({ showModal, onClose, errorMsg, addCode }) => { set for 50%, then you'll instead be charging 4% on transactions using the code.

-
+
{ } ]} iconClassName={classes.listViewButton} - className={classes.tableWidth}> + className={classes.tableWidth} + appendix={ + +

+ For details on configuring cash boxes and cassettes, please read + the relevant knowledgebase article: +

+ +
+ }> {!showHistory && ( Cash box resets diff --git a/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js b/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js index 04595563..b8468472 100644 --- a/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js +++ b/new-lamassu-admin/src/pages/Maintenance/Wizard/WizardStep.js @@ -6,7 +6,7 @@ import React from 'react' import ErrorMessage from 'src/components/ErrorMessage' import Stepper from 'src/components/Stepper' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { Button } from 'src/components/buttons' import { Cashbox } from 'src/components/inputs/cashbox/Cashbox' import { NumberInput, RadioGroup } from 'src/components/inputs/formik' @@ -245,12 +245,12 @@ const WizardStep = ({ classes.centerAlignment )}>

Since previous update

- +

Number of bills inside the cash box, since the last cash box changes.

-
+
- {displayTitle && } + {displayTitle && ( + +

+ For details on configuring notifications, please read the + relevant knowledgebase article: +

+ + + } + /> + )} {displayThirdPartyProvider && (
{

Coin ATM Radar share settings

- +

For details on configuring this panel, please read the relevant knowledgebase article{' '} @@ -78,7 +80,12 @@ const CoinATMRadar = memo(({ wizard }) => { .

-
+ +
{ <>

Contact information

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +

Info card enabled?

diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js index 9b90c14a..2c59c3ce 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js @@ -4,11 +4,14 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { memo } from 'react' +import { HelpTooltip } from 'src/components/Tooltip' import { BooleanPropertiesTable } from 'src/components/booleanPropertiesTable' import { Switch } from 'src/components/inputs' import { H4, P, Label2 } from 'src/components/typography' import { fromNamespace, toNamespace, namespaces } from 'src/utils/config' +import { SupportLinkButton } from '../../components/buttons' + import { global } from './OperatorInfo.styles' const useStyles = makeStyles(global) @@ -47,6 +50,17 @@ const ReceiptPrinting = memo(({ wizard }) => { <>

Receipt options

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +

Enable receipt printing

diff --git a/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js index 232ad92d..3cd29f10 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js @@ -4,8 +4,8 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' -import { HoverableTooltip } from 'src/components/Tooltip' -import { IconButton } from 'src/components/buttons' +import { HelpTooltip } from 'src/components/Tooltip' +import { IconButton, SupportLinkButton } from 'src/components/buttons' import { Switch } from 'src/components/inputs' import DataTable from 'src/components/tables/DataTable' import { H4, P, Label3 } from 'src/components/typography' @@ -162,9 +162,9 @@ const SMSNotices = () => { !R.isEmpty(TOOLTIPS[it.event]) ? (
{R.prop('messageName', it)} - +

{TOOLTIPS[it.event]}

-
+
) : ( R.prop('messageName', it) @@ -237,6 +237,17 @@ const SMSNotices = () => { <>

SMS notices

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +
{showModal && ( { <>

Terms & Conditions

+ +

+ For details on configuring this panel, please read the relevant + knowledgebase article: +

+ +

Show on screen

diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index cd40af4b..1bdb5ed3 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -11,7 +11,7 @@ import * as R from 'ramda' import React, { memo, useState } from 'react' import { ConfirmDialog } from 'src/components/ConfirmDialog' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip, HoverableTooltip } from 'src/components/Tooltip' import { IDButton, ActionButton } from 'src/components/buttons' import { P, Label1 } from 'src/components/typography' import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg' @@ -358,9 +358,9 @@ const DetailsRow = ({ it: tx, timezone }) => {
{!R.isNil(tx.walletScore) && ( - + {`Chain analysis score: ${tx.walletScore}/10`} - + )}
diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index cd49ca34..4b3b9326 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -11,6 +11,8 @@ import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper' import SearchBox from 'src/components/SearchBox' import SearchFilter from 'src/components/SearchFilter' import Title from 'src/components/Title' +import { HelpTooltip } from 'src/components/Tooltip' +import { SupportLinkButton } from 'src/components/buttons' import DataTable from 'src/components/tables/DataTable' import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg' import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg' @@ -233,7 +235,22 @@ const Transactions = () => { }, { header: 'Status', - view: it => getStatus(it), + view: it => { + if (getStatus(it) === 'Pending') + return ( +
+ {'Pending'} + + + +
+ ) + else return getStatus(it) + }, textAlign: 'left', size: 'sm', width: 80 diff --git a/new-lamassu-admin/src/pages/Triggers/Triggers.js b/new-lamassu-admin/src/pages/Triggers/Triggers.js index 07629699..02a9fc49 100644 --- a/new-lamassu-admin/src/pages/Triggers/Triggers.js +++ b/new-lamassu-admin/src/pages/Triggers/Triggers.js @@ -6,7 +6,7 @@ import * as R from 'ramda' import React, { useState } from 'react' import Modal from 'src/components/Modal' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { Link, SupportLinkButton } from 'src/components/buttons' import { Switch } from 'src/components/inputs' import TitleSection from 'src/components/layout/TitleSection' @@ -187,13 +187,13 @@ const Triggers = () => { {rejectAddressReuse ? 'On' : 'Off'} - +

This option requires a user to scan a different cryptocurrency address if they attempt to scan one that had been previously used for a transaction in your network

-
+ )} diff --git a/new-lamassu-admin/src/pages/Wallet/Wallet.js b/new-lamassu-admin/src/pages/Wallet/Wallet.js index e2d74ec0..eaf1148e 100644 --- a/new-lamassu-admin/src/pages/Wallet/Wallet.js +++ b/new-lamassu-admin/src/pages/Wallet/Wallet.js @@ -5,6 +5,8 @@ import * as R from 'ramda' import React, { useState } from 'react' import Modal from 'src/components/Modal' +import { HelpTooltip } from 'src/components/Tooltip' +import { SupportLinkButton } from 'src/components/buttons' import { NamespacedTable as EditableTable } from 'src/components/editableTable' import TitleSection from 'src/components/layout/TitleSection' import FormRenderer from 'src/pages/Services/FormRenderer' @@ -13,6 +15,8 @@ import { ReactComponent as ReverseSettingsIcon } from 'src/styling/icons/circle import { ReactComponent as SettingsIcon } from 'src/styling/icons/circle buttons/settings/zodiac.svg' import { fromNamespace, toNamespace } from 'src/utils/config' +import { P } from '../../components/typography' + import AdvancedWallet from './AdvancedWallet' import styles from './Wallet.styles.js' import Wizard from './Wizard' @@ -124,6 +128,19 @@ const Wallet = ({ name: SCREEN_KEY }) => { toggle: setAdvancedSettings } ]} + appendix={ + +

+ For details on configuring wallets, please read the relevant + knowledgebase article: +

+ +
+ } />
{!advancedSettings && ( diff --git a/new-lamassu-admin/src/pages/Wizard/components/Twilio.js b/new-lamassu-admin/src/pages/Wizard/components/Twilio.js index a8a55bed..e553290c 100644 --- a/new-lamassu-admin/src/pages/Wizard/components/Twilio.js +++ b/new-lamassu-admin/src/pages/Wizard/components/Twilio.js @@ -5,7 +5,7 @@ import gql from 'graphql-tag' import React, { useState } from 'react' import InfoMessage from 'src/components/InfoMessage' -import { HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { Button, SupportLinkButton } from 'src/components/buttons' import { RadioGroup } from 'src/components/inputs' import { H1, H4, P } from 'src/components/typography' @@ -102,7 +102,7 @@ function Twilio({ doContinue }) {

Will you setup a two way machine or compliance?

- +

Two-way machines allow your customers not only to buy (cash-in) but also sell cryptocurrencies (cash-out). @@ -111,7 +111,7 @@ function Twilio({ doContinue }) { You’ll need an SMS service for cash-out transactions and for any compliance triggers

-
+ Date: Thu, 28 Nov 2024 11:30:35 +0000 Subject: [PATCH 054/119] refactor: don't send transactions' `expired` field --- lib/tx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tx.js b/lib/tx.js index 92e1dea6..4a1d9b3c 100644 --- a/lib/tx.js +++ b/lib/tx.js @@ -69,7 +69,7 @@ function cancel (txId) { } function customerHistory (customerId, thresholdDays) { - const sql = `SELECT * FROM ( + const sql = `SELECT ch.id, ch.created, ch.fiat, ch.direction FROM ( SELECT txIn.id, txIn.created, txIn.fiat, 'cashIn' AS direction, ((NOT txIn.send_confirmed) AND (txIn.created <= now() - interval $3)) AS expired FROM cash_in_txs txIn From d64c4a4df6a83359da30eb54e2b94260f341d568 Mon Sep 17 00:00:00 2001 From: siiky Date: Thu, 28 Nov 2024 13:01:09 +0000 Subject: [PATCH 055/119] feat: add read/written bytes from/to request/response Based on `count-response-size-middleware`. --- lib/middlewares/addRWBytes.js | 15 +++++++++++++++ lib/routes.js | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 lib/middlewares/addRWBytes.js diff --git a/lib/middlewares/addRWBytes.js b/lib/middlewares/addRWBytes.js new file mode 100644 index 00000000..46a79275 --- /dev/null +++ b/lib/middlewares/addRWBytes.js @@ -0,0 +1,15 @@ +const addRWBytes = () => (req, res, next) => { + const handle = () => { + res.removeListener('finish', handle) + res.removeListener('close', handle) + res.bytesRead = req.connection.bytesRead + res.bytesWritten = req.connection.bytesWritten + } + + res.on('finish', handle) + res.on('close', handle) + + next() +} + +module.exports = addRWBytes diff --git a/lib/routes.js b/lib/routes.js index 6248fc8e..0d0cb5d0 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -7,10 +7,11 @@ const nocache = require('nocache') const logger = require('./logger') +const addRWBytes = require('./middlewares/addRWBytes') const authorize = require('./middlewares/authorize') +const computeSchema = require('./middlewares/compute-schema') const errorHandler = require('./middlewares/errorHandler') const filterOldRequests = require('./middlewares/filterOldRequests') -const computeSchema = require('./middlewares/compute-schema') const findOperatorId = require('./middlewares/operatorId') const populateDeviceId = require('./middlewares/populateDeviceId') const populateSettings = require('./middlewares/populateSettings') @@ -50,6 +51,7 @@ const configRequiredRoutes = [ ] // middleware setup +app.use(addRWBytes()) app.use(compression({ threshold: 500 })) app.use(helmet()) app.use(nocache()) From 2e4eb9a2e7801d4e9c2d65cd23b2c52acc925823 Mon Sep 17 00:00:00 2001 From: siiky Date: Thu, 28 Nov 2024 13:01:54 +0000 Subject: [PATCH 056/119] feat: add read/written bytes to logs --- lib/routes.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/routes.js b/lib/routes.js index 0d0cb5d0..e6654121 100644 --- a/lib/routes.js +++ b/lib/routes.js @@ -56,7 +56,10 @@ app.use(compression({ threshold: 500 })) app.use(helmet()) app.use(nocache()) app.use(express.json({ limit: '2mb' })) -app.use(morgan(':method :url :status :response-time ms -- :req[content-length]/:res[content-length] b', { stream: logger.stream })) + +morgan.token('bytesRead', (_req, res) => res.bytesRead) +morgan.token('bytesWritten', (_req, res) => res.bytesWritten) +app.use(morgan(':method :url :status :response-time ms -- :bytesRead/:bytesWritten B', { stream: logger.stream })) // app /pair and /ca routes app.use('/', pairingRoutes) From d0573daa74e416a894c6ad20d6746b059446b9e9 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 08:36:48 +0000 Subject: [PATCH 057/119] build: fix eslint error --- new-lamassu-admin/src/pages/Transactions/DetailsCard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index 9bb4c96a..364a56b5 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -11,7 +11,7 @@ import * as R from 'ramda' import React, { memo, useState } from 'react' import { ConfirmDialog } from 'src/components/ConfirmDialog' -import { HelpTooltip, HoverableTooltip } from 'src/components/Tooltip' +import { HelpTooltip } from 'src/components/Tooltip' import { IDButton, ActionButton } from 'src/components/buttons' import { P, Label1 } from 'src/components/typography' import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg' From eac9f2cf69ee0be4b882e85010f874fab92dd5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 14 Jul 2022 22:11:15 +0100 Subject: [PATCH 058/119] feat: add cash collection receipts --- lib/cashbox-batches.js | 64 +++++++++++++++++++++++++++++++------ lib/routes/cashboxRoutes.js | 35 ++++++++++---------- 2 files changed, 72 insertions(+), 27 deletions(-) diff --git a/lib/cashbox-batches.js b/lib/cashbox-batches.js index 52f41dc6..35a03d9e 100644 --- a/lib/cashbox-batches.js +++ b/lib/cashbox-batches.js @@ -6,7 +6,7 @@ const camelize = require('./utils') function createCashboxBatch (deviceId, cashboxCount) { if (_.isEqual(0, cashboxCount)) throw new Error('Cash box is empty. Cash box batch could not be created.') - const sql = `INSERT INTO cash_unit_operation (id, device_id, created, operation_type) VALUES ($1, $2, now(), 'cash-box-empty')` + const sql = `INSERT INTO cash_unit_operation (id, device_id, created, operation_type) VALUES ($1, $2, now(), 'cash-box-empty') RETURNING *` const sql2 = ` UPDATE bills SET cashbox_batch_id=$1 FROM cash_in_txs @@ -25,6 +25,7 @@ function createCashboxBatch (deviceId, cashboxCount) { const q2 = t.none(sql2, [batchId, deviceId]) const q3 = t.none(sql3, [batchId, deviceId]) return t.batch([q1, q2, q3]) + .then(([it]) => it) }) } @@ -100,14 +101,6 @@ function editBatchById (id, performedBy) { return db.none(sql, [performedBy, id]) } -function getBillsByBatchId (id) { - const sql = `SELECT bi.* FROM ( - SELECT b.id, b.fiat, b.fiat_code, b.created, b.cashbox_batch_id, cit.device_id AS device_id FROM bills b LEFT OUTER JOIN (SELECT id, device_id FROM cash_in_txs) AS cit ON cit.id = b.cash_in_txs_id UNION - SELECT id, fiat, fiat_code, created, cashbox_batch_id, device_id FROM empty_unit_bills - ) AS bi WHERE bi.cashbox_batch_id=$1` - return db.any(sql, [id]) -} - function logFormatter (data) { return _.map( it => { @@ -124,11 +117,62 @@ function logFormatter (data) { ) } +function getMachineUnbatchedBills (deviceId) { + const sql = ` + SELECT now() AS created, cash_in_txs.device_id, json_agg(b.*) AS bills FROM bills b LEFT OUTER JOIN cash_in_txs + ON b.cash_in_txs_id = cash_in_txs.id + WHERE b.cashbox_batch_id IS NULL AND cash_in_txs.device_id = $1 + GROUP BY cash_in_txs.device_id + ` + + return db.oneOrNone(sql, [deviceId]) + .then(res => _.mapKeys(it => _.camelCase(it), res)) + .then(logFormatterSingle) +} + +function getBatchById (id) { + const sql = ` + SELECT cb.id, cb.device_id, cb.created, cb.operation_type, cb.bill_count_override, cb.performed_by, json_agg(b.*) AS bills + FROM cashbox_batches AS cb + LEFT JOIN bills AS b ON cb.id = b.cashbox_batch_id + WHERE cb.id = $1 + GROUP BY cb.id + ` + + return db.oneOrNone(sql, [id]).then(res => _.mapKeys(it => _.camelCase(it), res)) + .then(logFormatterSingle) +} + +function logFormatterSingle (data) { + const bills = _.filter( + it => !(_.isNil(it) || _.isNil(it.fiat_code) || _.isNil(it.fiat) || _.isNaN(it.fiat)), + data.bills + ) + + return { + id: data.id, + deviceId: data.deviceId, + created: data.created, + operationType: data.operationType, + billCount: _.size(bills), + fiatTotals: _.reduce( + (acc, value) => { + acc[value.fiat_code] = (acc[value.fiat_code] || 0) + value.fiat + return acc + }, + {}, + bills + ), + billsByDenomination: _.countBy(it => `${it.fiat} ${it.fiat_code}`, bills) + } +} + module.exports = { createCashboxBatch, updateMachineWithBatch, getBatches, - getBillsByBatchId, editBatchById, + getBatchById, + getMachineUnbatchedBills, logFormatter } diff --git a/lib/routes/cashboxRoutes.js b/lib/routes/cashboxRoutes.js index cec84416..6fcc88bf 100644 --- a/lib/routes/cashboxRoutes.js +++ b/lib/routes/cashboxRoutes.js @@ -1,40 +1,41 @@ const express = require('express') +const _ = require('lodash/fp') const router = express.Router() const cashbox = require('../cashbox-batches') const notifier = require('../notifier') -const { getMachine, setMachine } = require('../machine-loader') +const { getMachine, setMachine, getMachineName } = require('../machine-loader') const { loadLatestConfig } = require('../new-settings-loader') const { getCashInSettings } = require('../new-config-manager') const { AUTOMATIC } = require('../constants') const logger = require('../logger') -function notifyCashboxRemoval (req, res, next) { + +function cashboxRemoval (req, res, next) { const operatorId = res.locals.operatorId - logger.info(`** DEBUG ** - Cashbox removal - Received a cashbox opening request from device ${req.deviceId}`) + notifier.cashboxNotify(req.deviceId).catch(logger.error) - return notifier.cashboxNotify(req.deviceId) - .then(() => Promise.all([getMachine(req.deviceId), loadLatestConfig()])) + return Promise.all([getMachine(req.deviceId), loadLatestConfig()]) .then(([machine, config]) => { - logger.info('** DEBUG ** - Cashbox removal - Retrieving system options for cash-in') const cashInSettings = getCashInSettings(config) if (cashInSettings.cashboxReset !== AUTOMATIC) { - logger.info('** DEBUG ** - Cashbox removal - Cashbox reset is set to manual. A cashbox batch will NOT be created') - logger.info(`** DEBUG ** - Cashbox removal - Process finished`) - return res.status(200).send({ status: 'OK' }) + return Promise.all([ + cashbox.getMachineUnbatchedBills(req.deviceId), + getMachineName(req.deviceId) + ]) } - logger.info('** DEBUG ** - Cashbox removal - Cashbox reset is set to automatic. A cashbox batch WILL be created') - logger.info('** DEBUG ** - Cashbox removal - Creating new batch...') - return cashbox.createCashboxBatch(req.deviceId, machine.cashUnits.cashbox) - .then(() => { - logger.info(`** DEBUG ** - Cashbox removal - Process finished`) - return res.status(200).send({ status: 'OK' }) - }) + return cashbox.createCashboxBatch(req.deviceId, machine.cashbox) + .then(batch => Promise.all([ + cashbox.getBatchById(batch.id), + getMachineName(batch.device_id), + setMachine({ deviceId: req.deviceId, action: 'emptyCashInBills' }, operatorId) + ])) }) + .then(([batch, machineName]) => res.status(200).send({ batch: _.merge(batch, { machineName }), status: 'OK' })) .catch(next) } -router.post('/removal', notifyCashboxRemoval) +router.post('/removal', cashboxRemoval) module.exports = router From 4427258dd58414793effd36f7d3a1e486c8c4cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Wed, 13 Jul 2022 15:55:45 +0100 Subject: [PATCH 059/119] fix: improve HoverableTooltip behavior and UX feat: add market currency selector for exchange 3rd party services --- lib/exchange.js | 23 +++- lib/new-admin/graphql/resolvers/index.js | 2 + .../graphql/resolvers/market.resolver.js | 9 ++ lib/new-admin/graphql/types/index.js | 2 + lib/new-admin/graphql/types/market.type.js | 9 ++ lib/plugins/common/ccxt.js | 10 +- lib/plugins/exchange/binance.js | 2 +- lib/plugins/exchange/binanceus.js | 2 +- lib/plugins/exchange/bitstamp.js | 2 +- lib/plugins/exchange/ccxt.js | 38 +++++- lib/plugins/exchange/cex.js | 2 +- lib/plugins/exchange/itbit.js | 2 +- lib/plugins/exchange/kraken.js | 2 +- .../components/inputs/base/Autocomplete.js | 38 ++++++ .../src/pages/Services/Services.js | 83 +++++++------ .../src/pages/Services/schemas/binance.js | 79 +++++++----- .../src/pages/Services/schemas/binanceus.js | 79 +++++++----- .../src/pages/Services/schemas/bitfinex.js | 79 +++++++----- .../src/pages/Services/schemas/bitstamp.js | 99 +++++++++------ .../src/pages/Services/schemas/cex.js | 99 +++++++++------ .../src/pages/Services/schemas/helper.js | 31 ++++- .../src/pages/Services/schemas/index.js | 68 ++++++----- .../src/pages/Services/schemas/itbit.js | 115 +++++++++++------- .../src/pages/Services/schemas/kraken.js | 79 +++++++----- new-lamassu-admin/src/styling/variables.js | 4 + new-lamassu-admin/src/utils/constants.js | 8 +- 26 files changed, 646 insertions(+), 320 deletions(-) create mode 100644 lib/new-admin/graphql/resolvers/market.resolver.js create mode 100644 lib/new-admin/graphql/types/market.type.js diff --git a/lib/exchange.js b/lib/exchange.js index 0431a7d5..94083882 100644 --- a/lib/exchange.js +++ b/lib/exchange.js @@ -1,6 +1,10 @@ +const _ = require('lodash/fp') +const { ALL_CRYPTOS } = require('@lamassu/coins') + const configManager = require('./new-config-manager') const ccxt = require('./plugins/exchange/ccxt') const mockExchange = require('./plugins/exchange/mock-exchange') +const accounts = require('./new-admin/config/accounts') function lookupExchange (settings, cryptoCode) { const exchange = configManager.getWalletSettings(cryptoCode, settings.config).exchange @@ -45,8 +49,25 @@ function active (settings, cryptoCode) { return !!lookupExchange(settings, cryptoCode) } +function getMarkets () { + const filterExchanges = _.filter(it => it.class === 'exchange') + const availableExchanges = _.map(it => it.code, filterExchanges(accounts.ACCOUNT_LIST)) + + return _.reduce( + (acc, value) => + Promise.all([acc, ccxt.getMarkets(value, ALL_CRYPTOS)]) + .then(([a, markets]) => Promise.resolve({ + ...a, + [value]: markets + })), + Promise.resolve({}), + availableExchanges + ) +} + module.exports = { buy, sell, - active + active, + getMarkets } diff --git a/lib/new-admin/graphql/resolvers/index.js b/lib/new-admin/graphql/resolvers/index.js index a20d9216..ea3cb3fa 100644 --- a/lib/new-admin/graphql/resolvers/index.js +++ b/lib/new-admin/graphql/resolvers/index.js @@ -11,6 +11,7 @@ const funding = require('./funding.resolver') const log = require('./log.resolver') const loyalty = require('./loyalty.resolver') const machine = require('./machine.resolver') +const market = require('./market.resolver') const notification = require('./notification.resolver') const pairing = require('./pairing.resolver') const rates = require('./rates.resolver') @@ -35,6 +36,7 @@ const resolvers = [ log, loyalty, machine, + market, notification, pairing, rates, diff --git a/lib/new-admin/graphql/resolvers/market.resolver.js b/lib/new-admin/graphql/resolvers/market.resolver.js new file mode 100644 index 00000000..49864417 --- /dev/null +++ b/lib/new-admin/graphql/resolvers/market.resolver.js @@ -0,0 +1,9 @@ +const exchange = require('../../../exchange') + +const resolvers = { + Query: { + getMarkets: () => exchange.getMarkets() + } +} + +module.exports = resolvers diff --git a/lib/new-admin/graphql/types/index.js b/lib/new-admin/graphql/types/index.js index f4794b67..e33c50b5 100644 --- a/lib/new-admin/graphql/types/index.js +++ b/lib/new-admin/graphql/types/index.js @@ -11,6 +11,7 @@ const funding = require('./funding.type') const log = require('./log.type') const loyalty = require('./loyalty.type') const machine = require('./machine.type') +const market = require('./market.type') const notification = require('./notification.type') const pairing = require('./pairing.type') const rates = require('./rates.type') @@ -35,6 +36,7 @@ const types = [ log, loyalty, machine, + market, notification, pairing, rates, diff --git a/lib/new-admin/graphql/types/market.type.js b/lib/new-admin/graphql/types/market.type.js new file mode 100644 index 00000000..2413a9fe --- /dev/null +++ b/lib/new-admin/graphql/types/market.type.js @@ -0,0 +1,9 @@ +const { gql } = require('apollo-server-express') + +const typeDef = gql` + type Query { + getMarkets: JSONObject @auth + } +` + +module.exports = typeDef diff --git a/lib/plugins/common/ccxt.js b/lib/plugins/common/ccxt.js index db98b460..b822bb70 100644 --- a/lib/plugins/common/ccxt.js +++ b/lib/plugins/common/ccxt.js @@ -29,15 +29,13 @@ const ALL = { bitfinex: bitfinex } -function buildMarket (fiatCode, cryptoCode, serviceName) { +function buildMarket (_fiatCode, cryptoCode, serviceName) { if (!_.includes(cryptoCode, ALL[serviceName].CRYPTO)) { throw new Error('Unsupported crypto: ' + cryptoCode) } - const fiatSupported = ALL[serviceName].FIAT - if (fiatSupported !== 'ALL_CURRENCIES' && !_.includes(fiatCode, fiatSupported)) { - logger.info('Building a market for an unsupported fiat. Defaulting to EUR market') - return cryptoCode + '/' + 'EUR' - } + + if (_.isNil(_fiatCode)) logger.debug('Missing fiat code information, defaulting to EUR markets') + const fiatCode = _fiatCode ?? 'EUR' return cryptoCode + '/' + fiatCode } diff --git a/lib/plugins/exchange/binance.js b/lib/plugins/exchange/binance.js index 8a45723c..97c90c26 100644 --- a/lib/plugins/exchange/binance.js +++ b/lib/plugins/exchange/binance.js @@ -7,7 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, XMR, ETH, LTC, ZEC, LN } = COINS const CRYPTO = [BTC, ETH, LTC, ZEC, BCH, XMR, LN] const FIAT = ['USD', 'EUR'] -const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] +const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const loadConfig = (account) => { const mapper = { diff --git a/lib/plugins/exchange/binanceus.js b/lib/plugins/exchange/binanceus.js index ecf058b6..59290fc6 100644 --- a/lib/plugins/exchange/binanceus.js +++ b/lib/plugins/exchange/binanceus.js @@ -7,7 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT, USDT_TRON, LN } = COINS const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON, LN] const FIAT = ['USD'] -const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] +const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const loadConfig = (account) => { const mapper = { diff --git a/lib/plugins/exchange/bitstamp.js b/lib/plugins/exchange/bitstamp.js index 5494ff1c..859ca743 100644 --- a/lib/plugins/exchange/bitstamp.js +++ b/lib/plugins/exchange/bitstamp.js @@ -8,7 +8,7 @@ const { BTC, ETH, LTC, BCH, USDT, LN } = COINS const CRYPTO = [BTC, ETH, LTC, BCH, USDT, LN] const FIAT = ['USD', 'EUR'] const AMOUNT_PRECISION = 8 -const REQUIRED_CONFIG_FIELDS = ['key', 'secret', 'clientId'] +const REQUIRED_CONFIG_FIELDS = ['key', 'secret', 'clientId', 'currencyMarket'] const loadConfig = (account) => { const mapper = { diff --git a/lib/plugins/exchange/ccxt.js b/lib/plugins/exchange/ccxt.js index 5de324f5..85e353cf 100644 --- a/lib/plugins/exchange/ccxt.js +++ b/lib/plugins/exchange/ccxt.js @@ -1,9 +1,13 @@ const { utils: coinUtils } = require('@lamassu/coins') const _ = require('lodash/fp') const ccxt = require('ccxt') +const mem = require('mem') const { buildMarket, ALL, isConfigValid } = require('../common/ccxt') const { ORDER_TYPES } = require('./consts') +const logger = require('../../logger') +const { currencies } = require('../../new-admin/config') +const T = require('../../time') const DEFAULT_PRICE_PRECISION = 2 const DEFAULT_AMOUNT_PRECISION = 8 @@ -18,7 +22,8 @@ function trade (side, account, tradeEntry, exchangeName) { const { USER_REF, loadOptions, loadConfig = _.noop, REQUIRED_CONFIG_FIELDS, ORDER_TYPE, AMOUNT_PRECISION } = exchangeConfig if (!isConfigValid(account, REQUIRED_CONFIG_FIELDS)) throw Error('Invalid config') - const symbol = buildMarket(fiatCode, cryptoCode, exchangeName) + const selectedFiatMarket = account.currencyMarket + const symbol = buildMarket(selectedFiatMarket, cryptoCode, exchangeName) const precision = _.defaultTo(DEFAULT_AMOUNT_PRECISION, AMOUNT_PRECISION) const amount = coinUtils.toUnit(cryptoAtoms, cryptoCode).toFixed(precision) const accountOptions = _.isFunction(loadOptions) ? loadOptions(account) : {} @@ -50,4 +55,33 @@ function calculatePrice (side, amount, orderBook) { throw new Error('Insufficient market depth') } -module.exports = { trade } +function _getMarkets (exchangeName, availableCryptos) { + try { + const exchange = new ccxt[exchangeName]() + const currencyCodes = _.map(it => it.code, currencies) + + return exchange.fetchMarkets() + .then(_.filter(it => (it.type === 'spot' || it.spot))) + .then(res => + _.reduce((acc, value) => { + if (_.includes(value.base, availableCryptos) && _.includes(value.quote, currencyCodes)) { + if (_.isNil(acc[value.quote])) { + return { ...acc, [value.quote]: [value.base] } + } + + acc[value.quote].push(value.base) + } + return acc + }, {}, res) + ) + } catch (e) { + logger.debug(`No CCXT exchange found for ${exchangeName}`) + } +} + +const getMarkets = mem(_getMarkets, { + maxAge: T.week, + cacheKey: (exchangeName, availableCryptos) => exchangeName +}) + +module.exports = { trade, getMarkets } diff --git a/lib/plugins/exchange/cex.js b/lib/plugins/exchange/cex.js index 525eb427..94a17811 100644 --- a/lib/plugins/exchange/cex.js +++ b/lib/plugins/exchange/cex.js @@ -7,7 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, DASH, ETH, LTC, USDT, TRX, USDT_TRON, LN } = COINS const CRYPTO = [BTC, ETH, LTC, DASH, BCH, USDT, TRX, USDT_TRON, LN] const FIAT = ['USD', 'EUR'] -const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] +const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const loadConfig = (account) => { const mapper = { diff --git a/lib/plugins/exchange/itbit.js b/lib/plugins/exchange/itbit.js index 02572335..8bf4ada5 100644 --- a/lib/plugins/exchange/itbit.js +++ b/lib/plugins/exchange/itbit.js @@ -8,7 +8,7 @@ const { BTC, ETH, USDT, LN } = COINS const CRYPTO = [BTC, ETH, USDT, LN] const FIAT = ['USD'] const AMOUNT_PRECISION = 4 -const REQUIRED_CONFIG_FIELDS = ['clientKey', 'clientSecret', 'userId', 'walletId'] +const REQUIRED_CONFIG_FIELDS = ['clientKey', 'clientSecret', 'userId', 'walletId', 'currencyMarket'] const loadConfig = (account) => { const mapper = { diff --git a/lib/plugins/exchange/kraken.js b/lib/plugins/exchange/kraken.js index 849af0e5..f14408bb 100644 --- a/lib/plugins/exchange/kraken.js +++ b/lib/plugins/exchange/kraken.js @@ -8,7 +8,7 @@ const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR, USDT, TRX, USDT_TRON, LN } = COINS const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, XMR, USDT, TRX, USDT_TRON, LN] const FIAT = ['USD', 'EUR'] const AMOUNT_PRECISION = 6 -const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] +const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const USER_REF = 'userref' const loadConfig = (account) => { diff --git a/new-lamassu-admin/src/components/inputs/base/Autocomplete.js b/new-lamassu-admin/src/components/inputs/base/Autocomplete.js index 996fb909..e5f9b941 100644 --- a/new-lamassu-admin/src/components/inputs/base/Autocomplete.js +++ b/new-lamassu-admin/src/components/inputs/base/Autocomplete.js @@ -1,8 +1,13 @@ +import { Box } from '@material-ui/core' import MAutocomplete from '@material-ui/lab/Autocomplete' import sort from 'match-sorter' import * as R from 'ramda' import React from 'react' +import { HoverableTooltip } from 'src/components/Tooltip' +import { P } from 'src/components/typography' +import { errorColor, orangeYellow, spring4 } from 'src/styling/variables' + import TextInput from './TextInput' const Autocomplete = ({ @@ -95,6 +100,39 @@ const Autocomplete = ({ /> ) }} + renderOption={props => { + if (!props.warning && !props.warningMessage) + return R.path([labelProp])(props) + + const warningColors = { + clean: spring4, + partial: orangeYellow, + important: errorColor + } + + const hoverableElement = ( + + ) + + return ( + + {R.path([labelProp])(props)} + +

{props.warningMessage}

+
+
+ ) + }} /> ) } diff --git a/new-lamassu-admin/src/pages/Services/Services.js b/new-lamassu-admin/src/pages/Services/Services.js index 72eab97b..c1d5b408 100644 --- a/new-lamassu-admin/src/pages/Services/Services.js +++ b/new-lamassu-admin/src/pages/Services/Services.js @@ -12,7 +12,7 @@ import SingleRowTable from 'src/components/single-row-table/SingleRowTable' import { formatLong } from 'src/utils/string' import FormRenderer from './FormRenderer' -import schemas from './schemas' +import _schemas from './schemas' const GET_INFO = gql` query getData { @@ -21,6 +21,12 @@ const GET_INFO = gql` } ` +const GET_MARKETS = gql` + query getMarkets { + getMarkets + } +` + const SAVE_ACCOUNT = gql` mutation Save($accounts: JSONObject) { saveAccounts(accounts: $accounts) @@ -40,12 +46,17 @@ const useStyles = makeStyles(styles) const Services = () => { const [editingSchema, setEditingSchema] = useState(null) - const { data } = useQuery(GET_INFO) + const { data, loading: configLoading } = useQuery(GET_INFO) + const { data: marketsData, loading: marketsLoading } = useQuery(GET_MARKETS) const [saveAccount] = useMutation(SAVE_ACCOUNT, { onCompleted: () => setEditingSchema(null), refetchQueries: ['getData'] }) + const markets = marketsData?.getMarkets + + const schemas = _schemas(markets) + const classes = useStyles() const accounts = data?.accounts ?? {} @@ -101,40 +112,44 @@ const Services = () => { const getValidationSchema = ({ code, getValidationSchema }) => getValidationSchema(accounts[code]) + const loading = marketsLoading || configLoading + return ( -
- - - {R.values(schemas).map(schema => ( - - setEditingSchema(schema)} - items={getItems(schema.code, schema.elements)} + !loading && ( +
+ + + {R.values(schemas).map(schema => ( + + setEditingSchema(schema)} + items={getItems(schema.code, schema.elements)} + /> + + ))} + + {editingSchema && ( + setEditingSchema(null)} + open={true}> + + saveAccount({ + variables: { accounts: { [editingSchema.code]: it } } + }) + } + elements={getElements(editingSchema)} + validationSchema={getValidationSchema(editingSchema)} + value={getAccounts(editingSchema)} /> - - ))} - - {editingSchema && ( - setEditingSchema(null)} - open={true}> - - saveAccount({ - variables: { accounts: { [editingSchema.code]: it } } - }) - } - elements={getElements(editingSchema)} - validationSchema={getValidationSchema(editingSchema)} - value={getAccounts(editingSchema)} - /> - - )} -
+ + )} +
+ ) ) } diff --git a/new-lamassu-admin/src/pages/Services/schemas/binance.js b/new-lamassu-admin/src/pages/Services/schemas/binance.js index 6be4be26..faec0e35 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/binance.js +++ b/new-lamassu-admin/src/pages/Services/schemas/binance.js @@ -1,36 +1,57 @@ import * as Yup from 'yup' -import SecretInputFormik from 'src/components/inputs/formik/SecretInput' -import TextInputFormik from 'src/components/inputs/formik/TextInput' +import { + SecretInput, + TextInput, + Autocomplete +} from 'src/components/inputs/formik' -import { secretTest } from './helper' +import { secretTest, buildCurrencyOptions } from './helper' -export default { - code: 'binance', - name: 'Binance', - title: 'Binance (Exchange)', - elements: [ - { - code: 'apiKey', - display: 'API key', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'privateKey', - display: 'Private key', - component: SecretInputFormik +const schema = markets => { + return { + code: 'binance', + name: 'Binance', + title: 'Binance (Exchange)', + elements: [ + { + code: 'apiKey', + display: 'API key', + component: TextInput, + face: true, + long: true + }, + { + code: 'privateKey', + display: 'Private key', + component: SecretInput + }, + { + code: 'currencyMarket', + display: 'Currency market', + component: Autocomplete, + inputProps: { + options: buildCurrencyOptions(markets), + labelProp: 'display', + valueProp: 'code' + }, + face: true + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + apiKey: Yup.string('The API key must be a string') + .max(100, 'The API key is too long') + .required('The API key is required'), + privateKey: Yup.string('The private key must be a string') + .max(100, 'The private key is too long') + .test(secretTest(account?.privateKey, 'private key')), + currencyMarket: Yup.string( + 'The currency market must be a string' + ).required('The currency market is required') + }) } - ], - getValidationSchema: account => { - return Yup.object().shape({ - apiKey: Yup.string('The API key must be a string') - .max(100, 'The API key is too long') - .required('The API key is required'), - privateKey: Yup.string('The private key must be a string') - .max(100, 'The private key is too long') - .test(secretTest(account?.privateKey, 'private key')) - }) } } + +export default schema diff --git a/new-lamassu-admin/src/pages/Services/schemas/binanceus.js b/new-lamassu-admin/src/pages/Services/schemas/binanceus.js index 7afd724b..74795e24 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/binanceus.js +++ b/new-lamassu-admin/src/pages/Services/schemas/binanceus.js @@ -1,36 +1,57 @@ import * as Yup from 'yup' -import SecretInputFormik from 'src/components/inputs/formik/SecretInput' -import TextInputFormik from 'src/components/inputs/formik/TextInput' +import { + SecretInput, + TextInput, + Autocomplete +} from 'src/components/inputs/formik' -import { secretTest } from './helper' +import { secretTest, buildCurrencyOptions } from './helper' -export default { - code: 'binanceus', - name: 'Binance.us', - title: 'Binance.us (Exchange)', - elements: [ - { - code: 'apiKey', - display: 'API key', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'privateKey', - display: 'Private key', - component: SecretInputFormik +const schema = markets => { + return { + code: 'binanceus', + name: 'Binance.us', + title: 'Binance.us (Exchange)', + elements: [ + { + code: 'apiKey', + display: 'API key', + component: TextInput, + face: true, + long: true + }, + { + code: 'privateKey', + display: 'Private key', + component: SecretInput + }, + { + code: 'currencyMarket', + display: 'Currency market', + component: Autocomplete, + inputProps: { + options: buildCurrencyOptions(markets), + labelProp: 'display', + valueProp: 'code' + }, + face: true + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + apiKey: Yup.string('The API key must be a string') + .max(100, 'The API key is too long') + .required('The API key is required'), + privateKey: Yup.string('The private key must be a string') + .max(100, 'The private key is too long') + .test(secretTest(account?.privateKey, 'private key')), + currencyMarket: Yup.string( + 'The currency market must be a string' + ).required('The currency market is required') + }) } - ], - getValidationSchema: account => { - return Yup.object().shape({ - apiKey: Yup.string('The API key must be a string') - .max(100, 'The API key is too long') - .required('The API key is required'), - privateKey: Yup.string('The private key must be a string') - .max(100, 'The private key is too long') - .test(secretTest(account?.privateKey, 'private key')) - }) } } + +export default schema diff --git a/new-lamassu-admin/src/pages/Services/schemas/bitfinex.js b/new-lamassu-admin/src/pages/Services/schemas/bitfinex.js index 0609807a..c0485af1 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/bitfinex.js +++ b/new-lamassu-admin/src/pages/Services/schemas/bitfinex.js @@ -1,36 +1,57 @@ import * as Yup from 'yup' -import SecretInputFormik from 'src/components/inputs/formik/SecretInput' -import TextInputFormik from 'src/components/inputs/formik/TextInput' +import { + SecretInput, + TextInput, + Autocomplete +} from 'src/components/inputs/formik' -import { secretTest } from './helper' +import { secretTest, buildCurrencyOptions } from './helper' -export default { - code: 'bitfinex', - name: 'Bitfinex', - title: 'Bitfinex (Exchange)', - elements: [ - { - code: 'key', - display: 'API Key', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'secret', - display: 'API Secret', - component: SecretInputFormik +const schema = markets => { + return { + code: 'bitfinex', + name: 'Bitfinex', + title: 'Bitfinex (Exchange)', + elements: [ + { + code: 'key', + display: 'API key', + component: TextInput, + face: true, + long: true + }, + { + code: 'secret', + display: 'API secret', + component: SecretInput + }, + { + code: 'currencyMarket', + display: 'Currency Market', + component: Autocomplete, + inputProps: { + options: buildCurrencyOptions(markets), + labelProp: 'display', + valueProp: 'code' + }, + face: true + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + key: Yup.string('The API key must be a string') + .max(100, 'The API key is too long') + .required('The API key is required'), + secret: Yup.string('The API secret must be a string') + .max(100, 'The API secret is too long') + .test(secretTest(account?.secret, 'API secret')), + currencyMarket: Yup.string( + 'The currency market must be a string' + ).required('The currency market is required') + }) } - ], - getValidationSchema: account => { - return Yup.object().shape({ - key: Yup.string('The API key must be a string') - .max(100, 'The API key is too long') - .required('The API key is required'), - secret: Yup.string('The API secret must be a string') - .max(100, 'The API secret is too long') - .test(secretTest(account?.secret, 'API secret')) - }) } } + +export default schema diff --git a/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js b/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js index 431fcfb5..e9061e9e 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js +++ b/new-lamassu-admin/src/pages/Services/schemas/bitstamp.js @@ -1,46 +1,67 @@ import * as Yup from 'yup' -import SecretInputFormik from 'src/components/inputs/formik/SecretInput' -import TextInputFormik from 'src/components/inputs/formik/TextInput' +import { + SecretInput, + TextInput, + Autocomplete +} from 'src/components/inputs/formik' -import { secretTest } from './helper' +import { secretTest, buildCurrencyOptions } from './helper' -export default { - code: 'bitstamp', - name: 'Bitstamp', - title: 'Bitstamp (Exchange)', - elements: [ - { - code: 'clientId', - display: 'Client ID', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'key', - display: 'API key', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'secret', - display: 'API secret', - component: SecretInputFormik +const schema = markets => { + return { + code: 'bitstamp', + name: 'Bitstamp', + title: 'Bitstamp (Exchange)', + elements: [ + { + code: 'clientId', + display: 'Client ID', + component: TextInput, + face: true, + long: true + }, + { + code: 'key', + display: 'API key', + component: TextInput, + face: true, + long: true + }, + { + code: 'secret', + display: 'API secret', + component: SecretInput + }, + { + code: 'currencyMarket', + display: 'Currency market', + component: Autocomplete, + inputProps: { + options: buildCurrencyOptions(markets), + labelProp: 'display', + valueProp: 'code' + }, + face: true + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + clientId: Yup.string('The client ID must be a string') + .max(100, 'The client ID is too long') + .required('The client ID is required'), + key: Yup.string('The API key must be a string') + .max(100, 'The API key is too long') + .required('The API key is required'), + secret: Yup.string('The API secret must be a string') + .max(100, 'The API secret is too long') + .test(secretTest(account?.secret, 'API secret')), + currencyMarket: Yup.string( + 'The currency market must be a string' + ).required('The currency market is required') + }) } - ], - getValidationSchema: account => { - return Yup.object().shape({ - clientId: Yup.string('The client ID must be a string') - .max(100, 'The client ID is too long') - .required('The client ID is required'), - key: Yup.string('The API key must be a string') - .max(100, 'The API key is too long') - .required('The API key is required'), - secret: Yup.string('The API secret must be a string') - .max(100, 'The API secret is too long') - .test(secretTest(account?.secret, 'API secret')) - }) } } + +export default schema diff --git a/new-lamassu-admin/src/pages/Services/schemas/cex.js b/new-lamassu-admin/src/pages/Services/schemas/cex.js index f8374c6f..b887db93 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/cex.js +++ b/new-lamassu-admin/src/pages/Services/schemas/cex.js @@ -1,46 +1,67 @@ import * as Yup from 'yup' -import SecretInputFormik from 'src/components/inputs/formik/SecretInput' -import TextInputFormik from 'src/components/inputs/formik/TextInput' +import { + SecretInput, + TextInput, + Autocomplete +} from 'src/components/inputs/formik' -import { secretTest } from './helper' +import { secretTest, buildCurrencyOptions } from './helper' -export default { - code: 'cex', - name: 'CEX.IO', - title: 'CEX.IO (Exchange)', - elements: [ - { - code: 'apiKey', - display: 'API key', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'uid', - display: 'User ID', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'privateKey', - display: 'Private key', - component: SecretInputFormik +const schema = markets => { + return { + code: 'cex', + name: 'CEX.IO', + title: 'CEX.IO (Exchange)', + elements: [ + { + code: 'apiKey', + display: 'API key', + component: TextInput, + face: true, + long: true + }, + { + code: 'uid', + display: 'User ID', + component: TextInput, + face: true, + long: true + }, + { + code: 'privateKey', + display: 'Private key', + component: SecretInput + }, + { + code: 'currencyMarket', + display: 'Currency Market', + component: Autocomplete, + inputProps: { + options: buildCurrencyOptions(markets), + labelProp: 'display', + valueProp: 'code' + }, + face: true + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + apiKey: Yup.string('The API key must be a string') + .max(100, 'The API key is too long') + .required('The API key is required'), + uid: Yup.string('The User ID must be a string') + .max(100, 'The User ID is too long') + .required('The User ID is required'), + privateKey: Yup.string('The private key must be a string') + .max(100, 'The private key is too long') + .test(secretTest(account?.privateKey, 'private key')), + currencyMarket: Yup.string( + 'The currency market must be a string' + ).required('The currency market is required') + }) } - ], - getValidationSchema: account => { - return Yup.object().shape({ - apiKey: Yup.string('The API key must be a string') - .max(100, 'The API key is too long') - .required('The API key is required'), - uid: Yup.string('The User ID must be a string') - .max(100, 'The User ID is too long') - .required('The User ID is required'), - privateKey: Yup.string('The private key must be a string') - .max(100, 'The private key is too long') - .test(secretTest(account?.privateKey, 'private key')) - }) } } + +export default schema diff --git a/new-lamassu-admin/src/pages/Services/schemas/helper.js b/new-lamassu-admin/src/pages/Services/schemas/helper.js index ccb49a79..a82c2821 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/helper.js +++ b/new-lamassu-admin/src/pages/Services/schemas/helper.js @@ -1,5 +1,8 @@ +import { ALL_CRYPTOS } from '@lamassu/coins' import * as R from 'ramda' +import { WARNING_LEVELS } from 'src/utils/constants' + const secretTest = (secret, message) => ({ name: 'secret-test', message: message ? `The ${message} is invalid` : 'Invalid field', @@ -21,4 +24,30 @@ const leadingZerosTest = (value, context) => { return true } -export { secretTest, leadingZerosTest } +const buildCurrencyOptions = markets => { + return R.map(it => { + const unavailableCryptos = R.difference(ALL_CRYPTOS, markets[it]) + const unavailableMarkets = R.join( + ', ', + R.map(ite => `${ite}/${it}`, unavailableCryptos) + ) + + const warningLevel = R.isEmpty(unavailableCryptos) + ? WARNING_LEVELS.CLEAN + : !R.isEmpty(unavailableCryptos) && + R.length(unavailableCryptos) < R.length(ALL_CRYPTOS) + ? WARNING_LEVELS.PARTIAL + : WARNING_LEVELS.IMPORTANT + + return { + code: R.toUpper(it), + display: R.toUpper(it), + warning: warningLevel, + warningMessage: !R.isEmpty(unavailableMarkets) + ? `No market pairs available for ${unavailableMarkets}` + : `All market pairs are available` + } + }, R.keys(markets)) +} + +export { secretTest, leadingZerosTest, buildCurrencyOptions } diff --git a/new-lamassu-admin/src/pages/Services/schemas/index.js b/new-lamassu-admin/src/pages/Services/schemas/index.js index 22368537..e952771b 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/index.js +++ b/new-lamassu-admin/src/pages/Services/schemas/index.js @@ -1,16 +1,16 @@ -import binance from './binance' -import binanceus from './binanceus' -import bitfinex from './bitfinex' +import _binance from './binance' +import _binanceus from './binanceus' +import _bitfinex from './bitfinex' import bitgo from './bitgo' -import bitstamp from './bitstamp' +import _bitstamp from './bitstamp' import blockcypher from './blockcypher' -import cex from './cex' +import _cex from './cex' import elliptic from './elliptic' import galoy from './galoy' import inforu from './inforu' import infura from './infura' -import itbit from './itbit' -import kraken from './kraken' +import _itbit from './itbit' +import _kraken from './kraken' import mailgun from './mailgun' import scorechain from './scorechain' import sumsub from './sumsub' @@ -19,25 +19,37 @@ import trongrid from './trongrid' import twilio from './twilio' import vonage from './vonage' -export default { - [bitgo.code]: bitgo, - [galoy.code]: galoy, - [bitstamp.code]: bitstamp, - [blockcypher.code]: blockcypher, - [elliptic.code]: elliptic, - [inforu.code]: inforu, - [infura.code]: infura, - [itbit.code]: itbit, - [kraken.code]: kraken, - [mailgun.code]: mailgun, - [telnyx.code]: telnyx, - [vonage.code]: vonage, - [twilio.code]: twilio, - [binanceus.code]: binanceus, - [cex.code]: cex, - [scorechain.code]: scorechain, - [trongrid.code]: trongrid, - [binance.code]: binance, - [bitfinex.code]: bitfinex, - [sumsub.code]: sumsub +const schemas = (markets = {}) => { + const binance = _binance(markets?.binance) + const bitfinex = _bitfinex(markets?.bitfinex) + const binanceus = _binanceus(markets?.binanceus) + const bitstamp = _bitstamp(markets?.bitstamp) + const cex = _cex(markets?.cex) + const itbit = _itbit(markets?.itbit) + const kraken = _kraken(markets?.kraken) + + return { + [bitgo.code]: bitgo, + [galoy.code]: galoy, + [bitstamp.code]: bitstamp, + [blockcypher.code]: blockcypher, + [elliptic.code]: elliptic, + [inforu.code]: inforu, + [infura.code]: infura, + [itbit.code]: itbit, + [kraken.code]: kraken, + [mailgun.code]: mailgun, + [telnyx.code]: telnyx, + [vonage.code]: vonage, + [twilio.code]: twilio, + [binanceus.code]: binanceus, + [cex.code]: cex, + [scorechain.code]: scorechain, + [trongrid.code]: trongrid, + [binance.code]: binance, + [bitfinex.code]: bitfinex, + [sumsub.code]: sumsub + } } + +export default schemas diff --git a/new-lamassu-admin/src/pages/Services/schemas/itbit.js b/new-lamassu-admin/src/pages/Services/schemas/itbit.js index 949ba692..d6607461 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/itbit.js +++ b/new-lamassu-admin/src/pages/Services/schemas/itbit.js @@ -1,54 +1,75 @@ import * as Yup from 'yup' -import SecretInputFormik from 'src/components/inputs/formik/SecretInput' -import TextInputFormik from 'src/components/inputs/formik/TextInput' +import { + SecretInput, + TextInput, + Autocomplete +} from 'src/components/inputs/formik' -import { secretTest } from './helper' +import { buildCurrencyOptions, secretTest } from './helper' -export default { - code: 'itbit', - name: 'itBit', - title: 'itBit (Exchange)', - elements: [ - { - code: 'userId', - display: 'User ID', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'walletId', - display: 'Wallet ID', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'clientKey', - display: 'Client key', - component: TextInputFormik - }, - { - code: 'clientSecret', - display: 'Client secret', - component: SecretInputFormik +const schema = markets => { + return { + code: 'itbit', + name: 'itBit', + title: 'itBit (Exchange)', + elements: [ + { + code: 'userId', + display: 'User ID', + component: TextInput, + face: true, + long: true + }, + { + code: 'walletId', + display: 'Wallet ID', + component: TextInput, + face: true, + long: true + }, + { + code: 'clientKey', + display: 'Client key', + component: TextInput + }, + { + code: 'clientSecret', + display: 'Client secret', + component: SecretInput + }, + { + code: 'currencyMarket', + display: 'Currency market', + component: Autocomplete, + inputProps: { + options: buildCurrencyOptions(markets), + labelProp: 'display', + valueProp: 'code' + }, + face: true + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + userId: Yup.string('The user ID must be a string') + .max(100, 'The user ID is too long') + .required('The user ID is required'), + walletId: Yup.string('The wallet ID must be a string') + .max(100, 'The wallet ID is too long') + .required('The wallet ID is required'), + clientKey: Yup.string('The client key must be a string') + .max(100, 'The client key is too long') + .required('The client key is required'), + clientSecret: Yup.string('The client secret must be a string') + .max(100, 'The client secret is too long') + .test(secretTest(account?.clientSecret, 'client secret')), + currencyMarket: Yup.string( + 'The currency market must be a string' + ).required('The currency market is required') + }) } - ], - getValidationSchema: account => { - return Yup.object().shape({ - userId: Yup.string('The user ID must be a string') - .max(100, 'The user ID is too long') - .required('The user ID is required'), - walletId: Yup.string('The wallet ID must be a string') - .max(100, 'The wallet ID is too long') - .required('The wallet ID is required'), - clientKey: Yup.string('The client key must be a string') - .max(100, 'The client key is too long') - .required('The client key is required'), - clientSecret: Yup.string('The client secret must be a string') - .max(100, 'The client secret is too long') - .test(secretTest(account?.clientSecret, 'client secret')) - }) } } + +export default schema diff --git a/new-lamassu-admin/src/pages/Services/schemas/kraken.js b/new-lamassu-admin/src/pages/Services/schemas/kraken.js index 733cebe4..2c0ee271 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/kraken.js +++ b/new-lamassu-admin/src/pages/Services/schemas/kraken.js @@ -1,36 +1,57 @@ import * as Yup from 'yup' -import SecretInputFormik from 'src/components/inputs/formik/SecretInput' -import TextInputFormik from 'src/components/inputs/formik/TextInput' +import { + SecretInput, + TextInput, + Autocomplete +} from 'src/components/inputs/formik' -import { secretTest } from './helper' +import { secretTest, buildCurrencyOptions } from './helper' -export default { - code: 'kraken', - name: 'Kraken', - title: 'Kraken (Exchange)', - elements: [ - { - code: 'apiKey', - display: 'API key', - component: TextInputFormik, - face: true, - long: true - }, - { - code: 'privateKey', - display: 'Private key', - component: SecretInputFormik +const schema = markets => { + return { + code: 'kraken', + name: 'Kraken', + title: 'Kraken (Exchange)', + elements: [ + { + code: 'apiKey', + display: 'API key', + component: TextInput, + face: true, + long: true + }, + { + code: 'privateKey', + display: 'Private key', + component: SecretInput + }, + { + code: 'currencyMarket', + display: 'Currency market', + component: Autocomplete, + inputProps: { + options: buildCurrencyOptions(markets), + labelProp: 'display', + valueProp: 'code' + }, + face: true + } + ], + getValidationSchema: account => { + return Yup.object().shape({ + apiKey: Yup.string('The API key must be a string') + .max(100, 'The API key is too long') + .required('The API key is required'), + privateKey: Yup.string('The private key must be a string') + .max(100, 'The private key is too long') + .test(secretTest(account?.privateKey, 'private key')), + currencyMarket: Yup.string( + 'The currency market must be a string' + ).required('The currency market is required') + }) } - ], - getValidationSchema: account => { - return Yup.object().shape({ - apiKey: Yup.string('The API key must be a string') - .max(100, 'The API key is too long') - .required('The API key is required'), - privateKey: Yup.string('The private key must be a string') - .max(100, 'The private key is too long') - .test(secretTest(account?.privateKey, 'private key')) - }) } } + +export default schema diff --git a/new-lamassu-admin/src/styling/variables.js b/new-lamassu-admin/src/styling/variables.js index 2cb84f7f..63289223 100644 --- a/new-lamassu-admin/src/styling/variables.js +++ b/new-lamassu-admin/src/styling/variables.js @@ -32,6 +32,9 @@ const mistyRose = '#ffeceb' const pumpkin = '#ff7311' const linen = '#fbf3ec' +// Warning +const orangeYellow = '#ffcc00' + // Color Variables const primaryColor = zodiac @@ -136,6 +139,7 @@ export { java, neon, linen, + orangeYellow, // named colors primaryColor, secondaryColor, diff --git a/new-lamassu-admin/src/utils/constants.js b/new-lamassu-admin/src/utils/constants.js index 9d829d3c..f5516b99 100644 --- a/new-lamassu-admin/src/utils/constants.js +++ b/new-lamassu-admin/src/utils/constants.js @@ -9,6 +9,11 @@ const MANUAL = 'manual' const IP_CHECK_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ const SWEEPABLE_CRYPTOS = ['ETH'] +const WARNING_LEVELS = { + CLEAN: 'clean', + PARTIAL: 'partial', + IMPORTANT: 'important' +} export { CURRENCY_MAX, @@ -18,5 +23,6 @@ export { MANUAL, WALLET_SCORING_DEFAULT_THRESHOLD, IP_CHECK_REGEX, - SWEEPABLE_CRYPTOS + SWEEPABLE_CRYPTOS, + WARNING_LEVELS } From 653c78313e4d85a6563eb2b259211925ac52bcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 14 Jul 2022 15:43:27 +0100 Subject: [PATCH 060/119] feat: add currency market migration --- migrations/1732874039534-market-currency.js | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 migrations/1732874039534-market-currency.js diff --git a/migrations/1732874039534-market-currency.js b/migrations/1732874039534-market-currency.js new file mode 100644 index 00000000..5f0b7135 --- /dev/null +++ b/migrations/1732874039534-market-currency.js @@ -0,0 +1,31 @@ +const _ = require('lodash/fp') +const { loadLatest, saveAccounts } = require('../lib/new-settings-loader') +const { ACCOUNT_LIST } = require('../lib/new-admin/config/accounts') +const { ALL } = require('../lib/plugins/common/ccxt') + +exports.up = function (next) { + return loadLatest() + .then(({ config, accounts }) => { + const allExchanges = _.map(it => it.code)(_.filter(it => it.class === 'exchange', ACCOUNT_LIST)) + const configuredExchanges = _.intersection(allExchanges, _.keys(accounts)) + const localeCurrency = config.locale_fiatCurrency + + const newAccounts = _.reduce( + (acc, value) => { + if (!_.isNil(accounts[value].currencyMarket)) return acc + if (_.includes(localeCurrency, ALL[value].FIAT)) return { ...acc, [value]: { currencyMarket: localeCurrency } } + return { ...acc, [value]: { currencyMarket: _.head(ALL[value].FIAT) } } + }, + {}, + configuredExchanges + ) + + return saveAccounts(newAccounts) + }) + .then(next) + .catch(next) +} + +module.exports.down = function (next) { + next() +} From 7f168859d891e4837a36d69c1a98bcc64bef8e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 1 Sep 2022 17:03:28 +0100 Subject: [PATCH 061/119] feat: add USDT as a trading market --- lib/plugins/exchange/ccxt.js | 5 +++- .../src/pages/Services/schemas/helper.js | 23 +++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/plugins/exchange/ccxt.js b/lib/plugins/exchange/ccxt.js index 85e353cf..63b57fa9 100644 --- a/lib/plugins/exchange/ccxt.js +++ b/lib/plugins/exchange/ccxt.js @@ -58,13 +58,16 @@ function calculatePrice (side, amount, orderBook) { function _getMarkets (exchangeName, availableCryptos) { try { const exchange = new ccxt[exchangeName]() - const currencyCodes = _.map(it => it.code, currencies) + const cryptosToQuoteAgainst = ['USDT'] + const currencyCodes = _.concat(_.map(it => it.code, currencies), cryptosToQuoteAgainst) return exchange.fetchMarkets() .then(_.filter(it => (it.type === 'spot' || it.spot))) .then(res => _.reduce((acc, value) => { if (_.includes(value.base, availableCryptos) && _.includes(value.quote, currencyCodes)) { + if (value.quote === value.base) return acc + if (_.isNil(acc[value.quote])) { return { ...acc, [value.quote]: [value.base] } } diff --git a/new-lamassu-admin/src/pages/Services/schemas/helper.js b/new-lamassu-admin/src/pages/Services/schemas/helper.js index a82c2821..7d71e79f 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/helper.js +++ b/new-lamassu-admin/src/pages/Services/schemas/helper.js @@ -27,15 +27,20 @@ const leadingZerosTest = (value, context) => { const buildCurrencyOptions = markets => { return R.map(it => { const unavailableCryptos = R.difference(ALL_CRYPTOS, markets[it]) - const unavailableMarkets = R.join( - ', ', - R.map(ite => `${ite}/${it}`, unavailableCryptos) - ) + const unavailableCryptosFiltered = R.difference(unavailableCryptos, [it]) // As the markets can have stablecoins to trade against other crypto, filter them out, as there can't be pairs such as USDT/USDT - const warningLevel = R.isEmpty(unavailableCryptos) + const unavailableMarketsStr = + R.length(unavailableCryptosFiltered) > 1 + ? `${R.join( + ', ', + R.slice(0, -1, unavailableCryptosFiltered) + )} and ${R.last(unavailableCryptosFiltered)}` + : unavailableCryptosFiltered[0] + + const warningLevel = R.isEmpty(unavailableCryptosFiltered) ? WARNING_LEVELS.CLEAN - : !R.isEmpty(unavailableCryptos) && - R.length(unavailableCryptos) < R.length(ALL_CRYPTOS) + : !R.isEmpty(unavailableCryptosFiltered) && + R.length(unavailableCryptosFiltered) < R.length(ALL_CRYPTOS) ? WARNING_LEVELS.PARTIAL : WARNING_LEVELS.IMPORTANT @@ -43,8 +48,8 @@ const buildCurrencyOptions = markets => { code: R.toUpper(it), display: R.toUpper(it), warning: warningLevel, - warningMessage: !R.isEmpty(unavailableMarkets) - ? `No market pairs available for ${unavailableMarkets}` + warningMessage: !R.isEmpty(unavailableCryptosFiltered) + ? `No market pairs available for ${unavailableMarketsStr}` : `All market pairs are available` } }, R.keys(markets)) From 47c548c9563c1e0be7c795bbcf6093937a1e6656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Fri, 7 Oct 2022 02:02:11 +0100 Subject: [PATCH 062/119] fix: market currency migration --- lib/plugins/common/ccxt.js | 5 ++--- lib/plugins/exchange/binance.js | 3 ++- lib/plugins/exchange/binanceus.js | 3 ++- lib/plugins/exchange/bitfinex.js | 3 ++- lib/plugins/exchange/bitstamp.js | 3 ++- lib/plugins/exchange/cex.js | 3 ++- lib/plugins/exchange/itbit.js | 3 ++- lib/plugins/exchange/kraken.js | 3 ++- migrations/1732874039534-market-currency.js | 7 +++---- new-lamassu-admin/src/pages/Services/schemas/helper.js | 6 +++++- new-lamassu-admin/src/utils/constants.js | 8 +------- 11 files changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/plugins/common/ccxt.js b/lib/plugins/common/ccxt.js index b822bb70..1acdaa95 100644 --- a/lib/plugins/common/ccxt.js +++ b/lib/plugins/common/ccxt.js @@ -29,13 +29,12 @@ const ALL = { bitfinex: bitfinex } -function buildMarket (_fiatCode, cryptoCode, serviceName) { +function buildMarket (fiatCode, cryptoCode, serviceName) { if (!_.includes(cryptoCode, ALL[serviceName].CRYPTO)) { throw new Error('Unsupported crypto: ' + cryptoCode) } - if (_.isNil(_fiatCode)) logger.debug('Missing fiat code information, defaulting to EUR markets') - const fiatCode = _fiatCode ?? 'EUR' + if (_.isNil(fiatCode)) throw new Error('Market pair building failed: Missing fiat code') return cryptoCode + '/' + fiatCode } diff --git a/lib/plugins/exchange/binance.js b/lib/plugins/exchange/binance.js index 97c90c26..47c498e7 100644 --- a/lib/plugins/exchange/binance.js +++ b/lib/plugins/exchange/binance.js @@ -7,6 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, XMR, ETH, LTC, ZEC, LN } = COINS const CRYPTO = [BTC, ETH, LTC, ZEC, BCH, XMR, LN] const FIAT = ['USD', 'EUR'] +const DEFAULT_FIAT_MARKET = 'EUR' const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const loadConfig = (account) => { @@ -17,4 +18,4 @@ const loadConfig = (account) => { return { ...mapped, timeout: 3000 } } -module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } +module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } diff --git a/lib/plugins/exchange/binanceus.js b/lib/plugins/exchange/binanceus.js index 59290fc6..e8f0c371 100644 --- a/lib/plugins/exchange/binanceus.js +++ b/lib/plugins/exchange/binanceus.js @@ -7,6 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT, USDT_TRON, LN } = COINS const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON, LN] const FIAT = ['USD'] +const DEFAULT_FIAT_MARKET = 'USD' const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const loadConfig = (account) => { @@ -17,4 +18,4 @@ const loadConfig = (account) => { return { ...mapped, timeout: 3000 } } -module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } +module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } diff --git a/lib/plugins/exchange/bitfinex.js b/lib/plugins/exchange/bitfinex.js index 4feccb0c..4e4d85ce 100644 --- a/lib/plugins/exchange/bitfinex.js +++ b/lib/plugins/exchange/bitfinex.js @@ -7,6 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, ETH, LTC, BCH, USDT, LN } = COINS const CRYPTO = [BTC, ETH, LTC, BCH, USDT, LN] const FIAT = ['USD', 'EUR'] +const DEFAULT_FIAT_MARKET = 'EUR' const AMOUNT_PRECISION = 8 const REQUIRED_CONFIG_FIELDS = ['key', 'secret'] @@ -18,4 +19,4 @@ const loadConfig = (account) => { return { ...mapped, timeout: 3000 } } -module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } +module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, DEFAULT_FIAT_MARKET, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } diff --git a/lib/plugins/exchange/bitstamp.js b/lib/plugins/exchange/bitstamp.js index 859ca743..bd745d49 100644 --- a/lib/plugins/exchange/bitstamp.js +++ b/lib/plugins/exchange/bitstamp.js @@ -7,6 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, ETH, LTC, BCH, USDT, LN } = COINS const CRYPTO = [BTC, ETH, LTC, BCH, USDT, LN] const FIAT = ['USD', 'EUR'] +const DEFAULT_FIAT_MARKET = 'EUR' const AMOUNT_PRECISION = 8 const REQUIRED_CONFIG_FIELDS = ['key', 'secret', 'clientId', 'currencyMarket'] @@ -19,4 +20,4 @@ const loadConfig = (account) => { return { ...mapped, timeout: 3000 } } -module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } +module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } diff --git a/lib/plugins/exchange/cex.js b/lib/plugins/exchange/cex.js index 94a17811..b9687e15 100644 --- a/lib/plugins/exchange/cex.js +++ b/lib/plugins/exchange/cex.js @@ -7,6 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, DASH, ETH, LTC, USDT, TRX, USDT_TRON, LN } = COINS const CRYPTO = [BTC, ETH, LTC, DASH, BCH, USDT, TRX, USDT_TRON, LN] const FIAT = ['USD', 'EUR'] +const DEFAULT_FIAT_MARKET = 'EUR' const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const loadConfig = (account) => { @@ -17,4 +18,4 @@ const loadConfig = (account) => { return { ...mapped, timeout: 3000 } } -module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } +module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } diff --git a/lib/plugins/exchange/itbit.js b/lib/plugins/exchange/itbit.js index 8bf4ada5..d80268e1 100644 --- a/lib/plugins/exchange/itbit.js +++ b/lib/plugins/exchange/itbit.js @@ -7,6 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.LIMIT const { BTC, ETH, USDT, LN } = COINS const CRYPTO = [BTC, ETH, USDT, LN] const FIAT = ['USD'] +const DEFAULT_FIAT_MARKET = 'USD' const AMOUNT_PRECISION = 4 const REQUIRED_CONFIG_FIELDS = ['clientKey', 'clientSecret', 'userId', 'walletId', 'currencyMarket'] @@ -21,4 +22,4 @@ const loadConfig = (account) => { } const loadOptions = ({ walletId }) => ({ walletId }) -module.exports = { loadOptions, loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } +module.exports = { loadOptions, loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } diff --git a/lib/plugins/exchange/kraken.js b/lib/plugins/exchange/kraken.js index f14408bb..0f050ccf 100644 --- a/lib/plugins/exchange/kraken.js +++ b/lib/plugins/exchange/kraken.js @@ -7,6 +7,7 @@ const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR, USDT, TRX, USDT_TRON, LN } = COINS const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, XMR, USDT, TRX, USDT_TRON, LN] const FIAT = ['USD', 'EUR'] +const DEFAULT_FIAT_MARKET = 'EUR' const AMOUNT_PRECISION = 6 const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey', 'currencyMarket'] const USER_REF = 'userref' @@ -26,4 +27,4 @@ const loadConfig = (account) => { const loadOptions = () => ({ expiretm: '+60' }) -module.exports = { USER_REF, loadOptions, loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } +module.exports = { USER_REF, loadOptions, loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE, AMOUNT_PRECISION } diff --git a/migrations/1732874039534-market-currency.js b/migrations/1732874039534-market-currency.js index 5f0b7135..359db4bd 100644 --- a/migrations/1732874039534-market-currency.js +++ b/migrations/1732874039534-market-currency.js @@ -5,16 +5,15 @@ const { ALL } = require('../lib/plugins/common/ccxt') exports.up = function (next) { return loadLatest() - .then(({ config, accounts }) => { + .then(({ accounts }) => { const allExchanges = _.map(it => it.code)(_.filter(it => it.class === 'exchange', ACCOUNT_LIST)) const configuredExchanges = _.intersection(allExchanges, _.keys(accounts)) - const localeCurrency = config.locale_fiatCurrency const newAccounts = _.reduce( (acc, value) => { if (!_.isNil(accounts[value].currencyMarket)) return acc - if (_.includes(localeCurrency, ALL[value].FIAT)) return { ...acc, [value]: { currencyMarket: localeCurrency } } - return { ...acc, [value]: { currencyMarket: _.head(ALL[value].FIAT) } } + if (_.includes('EUR', ALL[value].FIAT)) return { ...acc, [value]: { currencyMarket: 'EUR' } } + return { ...acc, [value]: { currencyMarket: ALL[value].DEFAULT_FIAT_CURRENCY } } }, {}, configuredExchanges diff --git a/new-lamassu-admin/src/pages/Services/schemas/helper.js b/new-lamassu-admin/src/pages/Services/schemas/helper.js index 7d71e79f..c1c97870 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/helper.js +++ b/new-lamassu-admin/src/pages/Services/schemas/helper.js @@ -1,7 +1,11 @@ import { ALL_CRYPTOS } from '@lamassu/coins' import * as R from 'ramda' -import { WARNING_LEVELS } from 'src/utils/constants' +const WARNING_LEVELS = { + CLEAN: 'clean', + PARTIAL: 'partial', + IMPORTANT: 'important' +} const secretTest = (secret, message) => ({ name: 'secret-test', diff --git a/new-lamassu-admin/src/utils/constants.js b/new-lamassu-admin/src/utils/constants.js index f5516b99..9d829d3c 100644 --- a/new-lamassu-admin/src/utils/constants.js +++ b/new-lamassu-admin/src/utils/constants.js @@ -9,11 +9,6 @@ const MANUAL = 'manual' const IP_CHECK_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ const SWEEPABLE_CRYPTOS = ['ETH'] -const WARNING_LEVELS = { - CLEAN: 'clean', - PARTIAL: 'partial', - IMPORTANT: 'important' -} export { CURRENCY_MAX, @@ -23,6 +18,5 @@ export { MANUAL, WALLET_SCORING_DEFAULT_THRESHOLD, IP_CHECK_REGEX, - SWEEPABLE_CRYPTOS, - WARNING_LEVELS + SWEEPABLE_CRYPTOS } From 0b719be8eb909eb4a2b30054f3825bc168c043c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Mon, 31 Oct 2022 18:30:14 +0000 Subject: [PATCH 063/119] fix: use selected fiat currency on exchange to store queued trades on the database --- lib/exchange.js | 1 + lib/plugins.js | 56 +++++++++++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/lib/exchange.js b/lib/exchange.js index 94083882..f9811bb8 100644 --- a/lib/exchange.js +++ b/lib/exchange.js @@ -66,6 +66,7 @@ function getMarkets () { } module.exports = { + fetchExchange, buy, sell, active, diff --git a/lib/plugins.js b/lib/plugins.js index d5bfcb4f..157c67ed 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -475,25 +475,28 @@ function plugins (settings, deviceId) { function buyAndSell (rec, doBuy, tx) { const cryptoCode = rec.cryptoCode - const fiatCode = rec.fiatCode - const cryptoAtoms = doBuy ? commissionMath.fiatToCrypto(tx, rec, deviceId, settings.config) : rec.cryptoAtoms.negated() + return exchange.fetchExchange(settings, cryptoCode) + .then(_exchange => { + const fiatCode = _exchange.account.currencyMarket + const cryptoAtoms = doBuy ? commissionMath.fiatToCrypto(tx, rec, deviceId, settings.config) : rec.cryptoAtoms.negated() - const market = [fiatCode, cryptoCode].join('') + const market = [fiatCode, cryptoCode].join('') - if (!exchange.active(settings, cryptoCode)) return + if (!exchange.active(settings, cryptoCode)) return - const direction = doBuy ? 'cashIn' : 'cashOut' - const internalTxId = tx ? tx.id : rec.id - logger.debug('[%s] Pushing trade: %d', market, cryptoAtoms) - if (!tradesQueues[market]) tradesQueues[market] = [] - tradesQueues[market].push({ - direction, - internalTxId, - fiatCode, - cryptoAtoms, - cryptoCode, - timestamp: Date.now() - }) + const direction = doBuy ? 'cashIn' : 'cashOut' + const internalTxId = tx ? tx.id : rec.id + logger.debug('[%s] Pushing trade: %d', market, cryptoAtoms) + if (!tradesQueues[market]) tradesQueues[market] = [] + tradesQueues[market].push({ + direction, + internalTxId, + fiatCode, + cryptoAtoms, + cryptoCode, + timestamp: Date.now() + }) + }) } function consolidateTrades (cryptoCode, fiatCode) { @@ -550,19 +553,22 @@ function plugins (settings, deviceId) { const deviceIds = devices.map(device => device.deviceId) const lists = deviceIds.map(deviceId => { const localeConfig = configManager.getLocale(deviceId, settings.config) - const fiatCode = localeConfig.fiatCurrency const cryptoCodes = localeConfig.cryptoCurrencies - return cryptoCodes.map(cryptoCode => ({ - fiatCode, - cryptoCode + return Promise.all(cryptoCodes.map(cryptoCode => { + return exchange.fetchExchange(settings, cryptoCode) + .then(exchange => ({ + fiatCode: exchange.account.currencyMarket, + cryptoCode + })) })) }) - - const tradesPromises = _.uniq(_.flatten(lists)) - .map(r => executeTradesForMarket(settings, r.fiatCode, r.cryptoCode)) - - return Promise.all(tradesPromises) + + return Promise.all(lists) + }) + .then(lists => { + return Promise.all(_.uniq(_.flatten(lists)) + .map(r => executeTradesForMarket(settings, r.fiatCode, r.cryptoCode))) }) .catch(logger.error) } From 3b12dd56085d356e968b38ada3165675dadaa2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Fri, 15 Jul 2022 19:59:41 +0100 Subject: [PATCH 064/119] feat: add machine rates screen toggle --- lib/graphql/resolvers.js | 12 ++- lib/graphql/types.js | 9 +++ lib/new-config-manager.js | 11 ++- lib/plugins.js | 4 +- migrations/1657909035091-rates-screen.js | 20 +++++ .../src/pages/OperatorInfo/MachineScreens.js | 80 +++++++++++++++++++ .../src/routing/lamassu.routes.js | 8 ++ new-lamassu-admin/src/routing/pazuz.routes.js | 8 ++ new-lamassu-admin/src/utils/config.js | 3 +- 9 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 migrations/1657909035091-rates-screen.js create mode 100644 new-lamassu-admin/src/pages/OperatorInfo/MachineScreens.js diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index 1270f1f3..29101102 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -61,6 +61,13 @@ const addReceiptInfo = receiptInfo => ret => { } +const addMachineScreenOpts = addSmthInfo( + 'screenOptions', + [ + 'rates.active' + ] +) + /* TODO: Simplify this. */ const buildTriggers = allTriggers => { const normalTriggers = [] @@ -117,6 +124,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings configManager.getLocale(deviceId, settings.config), configManager.getOperatorInfo(settings.config), configManager.getReceipt(settings.config), + configManager.getAllMachineScreenOpts(settings.config), !!configManager.getCashOut(deviceId, settings.config).active, getMachine(deviceId, currentConfigVersion), configManager.getCustomerAuthenticationMethod(settings.config) @@ -129,6 +137,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings localeInfo, operatorInfo, receiptInfo, + machineScreenOpts, twoWayMode, { numberOfCassettes, numberOfRecyclers }, customerAuthentication, @@ -153,7 +162,8 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings urlsToPing, }), addOperatorInfo(operatorInfo), - addReceiptInfo(receiptInfo) + addReceiptInfo(receiptInfo), + addMachineScreenOpts(machineScreenOpts) )(staticConf)) } diff --git a/lib/graphql/types.js b/lib/graphql/types.js index 89296c6c..c0c72b1e 100644 --- a/lib/graphql/types.js +++ b/lib/graphql/types.js @@ -49,6 +49,14 @@ type ReceiptInfo { addressQRCode: Boolean! } +type MachineScreenOptions { + rates: RateScreenOptions! +} + +type RateScreenOptions { + active: Boolean! +} + type SpeedtestFile { url: String! size: Int! @@ -147,6 +155,7 @@ type StaticConfig { operatorInfo: OperatorInfo machineInfo: MachineInfo! receiptInfo: ReceiptInfo + screenOptions: MachineScreenOptions speedtestFiles: [SpeedtestFile!]! urlsToPing: [String!]! diff --git a/lib/new-config-manager.js b/lib/new-config-manager.js index 680b57a9..239bfa20 100644 --- a/lib/new-config-manager.js +++ b/lib/new-config-manager.js @@ -13,7 +13,12 @@ const namespaces = { TERMS_CONDITIONS: 'termsConditions', CASH_OUT: 'cashOut', CASH_IN: 'cashIn', - COMPLIANCE: 'compliance' + COMPLIANCE: 'compliance', + MACHINE_SCREENS: 'machineScreens' +} + +const machineScreens = { + RATES: 'rates' } const stripl = _.curry((q, str) => _.startsWith(q, str) ? str.slice(q.length) : str) @@ -72,6 +77,8 @@ const getCoinAtmRadar = fromNamespace(namespaces.COIN_ATM_RADAR) const getTermsConditions = fromNamespace(namespaces.TERMS_CONDITIONS) const getReceipt = fromNamespace(namespaces.RECEIPT) const getCompliance = fromNamespace(namespaces.COMPLIANCE) +const getMachineScreenOpts = (screenName, config) => _.compose(fromNamespace(screenName), fromNamespace(namespaces.MACHINE_SCREENS))(config) +const getAllMachineScreenOpts = config => _.reduce((acc, value) => ({ ...acc, [value]: getMachineScreenOpts(value, config) }), {}, _.values(machineScreens)) const getAllCryptoCurrencies = (config) => { const locale = fromNamespace(namespaces.LOCALE)(config) @@ -180,6 +187,8 @@ module.exports = { getWalletSettings, getCashInSettings, getOperatorInfo, + getMachineScreenOpts, + getAllMachineScreenOpts, getNotifications, getGlobalNotifications, getLocale, diff --git a/lib/plugins.js b/lib/plugins.js index d5bfcb4f..0d374672 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -278,6 +278,7 @@ function plugins (settings, deviceId) { const localeConfig = configManager.getLocale(deviceId, settings.config) const fiatCode = localeConfig.fiatCurrency const cryptoCodes = localeConfig.cryptoCurrencies + const machineScreenOpts = configManager.getAllMachineScreenOpts(settings.config) const tickerPromises = cryptoCodes.map(c => getTickerRates(fiatCode, c)) const balancePromises = cryptoCodes.map(c => fiatBalance(fiatCode, c)) @@ -327,7 +328,8 @@ function plugins (settings, deviceId) { coins, configVersion, areThereAvailablePromoCodes: numberOfAvailablePromoCodes > 0, - timezone + timezone, + screenOptions: machineScreenOpts } }) } diff --git a/migrations/1657909035091-rates-screen.js b/migrations/1657909035091-rates-screen.js new file mode 100644 index 00000000..94db1542 --- /dev/null +++ b/migrations/1657909035091-rates-screen.js @@ -0,0 +1,20 @@ +const _ = require('lodash/fp') +const { saveConfig, loadLatest } = require('../lib/new-settings-loader') + +exports.up = function (next) { + const newConfig = {} + return loadLatest() + .then(({ config }) => { + if (!_.isNil(config.machineScreens_rates_active)) return + newConfig[`machineScreens_rates_active`] = true + return saveConfig(newConfig) + }) + .then(next) + .catch(err => { + return next(err) + }) +} + +module.exports.down = function (next) { + next() +} diff --git a/new-lamassu-admin/src/pages/OperatorInfo/MachineScreens.js b/new-lamassu-admin/src/pages/OperatorInfo/MachineScreens.js new file mode 100644 index 00000000..c3ca3b53 --- /dev/null +++ b/new-lamassu-admin/src/pages/OperatorInfo/MachineScreens.js @@ -0,0 +1,80 @@ +import { useQuery, useMutation } from '@apollo/react-hooks' +import { makeStyles } from '@material-ui/core/styles' +import gql from 'graphql-tag' +import * as R from 'ramda' +import React, { memo } from 'react' + +import { Switch } from 'src/components/inputs' +import { H4, P, Label2 } from 'src/components/typography' +import { fromNamespace, toNamespace, namespaces } from 'src/utils/config' + +import { global } from './OperatorInfo.styles' + +const useStyles = makeStyles(global) + +const GET_CONFIG = gql` + query getData { + config + } +` + +const SAVE_CONFIG = gql` + mutation Save($config: JSONObject) { + saveConfig(config: $config) + } +` + +const MachineScreens = memo(({ wizard }) => { + const classes = useStyles() + + const { data } = useQuery(GET_CONFIG) + + const [saveConfig] = useMutation(SAVE_CONFIG, { + refetchQueries: () => ['getData'] + }) + + const machineScreensConfig = + data?.config && fromNamespace(namespaces.MACHINE_SCREENS, data.config) + + const ratesScreenConfig = + data?.config && + R.compose( + fromNamespace('rates'), + fromNamespace(namespaces.MACHINE_SCREENS) + )(data.config) + + if (!machineScreensConfig) return null + + return ( + <> +
+

Rates screen

+
+
+

Enable rates screen

+
+ + saveConfig({ + variables: { + config: R.compose( + toNamespace(namespaces.MACHINE_SCREENS), + toNamespace('rates') + )( + R.merge(ratesScreenConfig, { + active: event.target.checked + }) + ) + } + }) + } + /> + {ratesScreenConfig.active ? 'Yes' : 'No'} +
+
+ + ) +}) + +export default MachineScreens diff --git a/new-lamassu-admin/src/routing/lamassu.routes.js b/new-lamassu-admin/src/routing/lamassu.routes.js index ec5d5325..59049b60 100644 --- a/new-lamassu-admin/src/routing/lamassu.routes.js +++ b/new-lamassu-admin/src/routing/lamassu.routes.js @@ -16,6 +16,7 @@ import MachineStatus from 'src/pages/Maintenance/MachineStatus' import Notifications from 'src/pages/Notifications/Notifications' import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar' import ContactInfo from 'src/pages/OperatorInfo/ContactInfo' +import MachineScreens from 'src/pages/OperatorInfo/MachineScreens' import ReceiptPrinting from 'src/pages/OperatorInfo/ReceiptPrinting' import SMSNotices from 'src/pages/OperatorInfo/SMSNotices/SMSNotices' import TermsConditions from 'src/pages/OperatorInfo/TermsConditions' @@ -193,6 +194,13 @@ const getLamassuRoutes = () => [ route: '/settings/operator-info/terms-conditions', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: TermsConditions + }, + { + key: 'machine-screens', + label: 'Machine screens', + route: '/settings/operator-info/machine-screens', + allowedRoles: [ROLES.USER, ROLES.SUPERUSER], + component: MachineScreens } ] } diff --git a/new-lamassu-admin/src/routing/pazuz.routes.js b/new-lamassu-admin/src/routing/pazuz.routes.js index 8551c123..53d22d9d 100644 --- a/new-lamassu-admin/src/routing/pazuz.routes.js +++ b/new-lamassu-admin/src/routing/pazuz.routes.js @@ -18,6 +18,7 @@ import MachineStatus from 'src/pages/Maintenance/MachineStatus' import Notifications from 'src/pages/Notifications/Notifications' import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar' import ContactInfo from 'src/pages/OperatorInfo/ContactInfo' +import MachineScreens from 'src/pages/OperatorInfo/MachineScreens' import ReceiptPrinting from 'src/pages/OperatorInfo/ReceiptPrinting' import SMSNotices from 'src/pages/OperatorInfo/SMSNotices/SMSNotices' import TermsConditions from 'src/pages/OperatorInfo/TermsConditions' @@ -172,6 +173,13 @@ const getPazuzRoutes = () => [ route: '/settings/operator-info/terms-conditions', allowedRoles: [ROLES.USER, ROLES.SUPERUSER], component: TermsConditions + }, + { + key: 'machine-screens', + label: 'Machine screens', + route: '/settings/operator-info/machine-screens', + allowedRoles: [ROLES.USER, ROLES.SUPERUSER], + component: MachineScreens } ] } diff --git a/new-lamassu-admin/src/utils/config.js b/new-lamassu-admin/src/utils/config.js index a2f78582..0c282719 100644 --- a/new-lamassu-admin/src/utils/config.js +++ b/new-lamassu-admin/src/utils/config.js @@ -12,7 +12,8 @@ const namespaces = { RECEIPT: 'receipt', COIN_ATM_RADAR: 'coinAtmRadar', TERMS_CONDITIONS: 'termsConditions', - TRIGGERS: 'triggersConfig' + TRIGGERS: 'triggersConfig', + MACHINE_SCREENS: 'machineScreens' } const mapKeys = R.curry((fn, obj) => From aef84142c7f1bb76d946fc51344ef1e7c494f663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Mon, 18 Jul 2022 17:41:17 +0100 Subject: [PATCH 065/119] fix: variable depth issue on machineScreenOpts --- lib/graphql/resolvers.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index 29101102..070b0a04 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -61,11 +61,16 @@ const addReceiptInfo = receiptInfo => ret => { } -const addMachineScreenOpts = addSmthInfo( +const addMachineScreenOpts = smth => _.update( 'screenOptions', - [ - 'rates.active' - ] + _.flow( + addSmthInfo( + 'rates', + [ + 'active' + ] + )(smth.rates) + ) ) /* TODO: Simplify this. */ @@ -163,7 +168,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings }), addOperatorInfo(operatorInfo), addReceiptInfo(receiptInfo), - addMachineScreenOpts(machineScreenOpts) + _.update('screenOptions', addMachineScreenOpts(machineScreenOpts)) )(staticConf)) } From 2e4b1ea4635ed688ec78e510e02587dc18335eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 19 Jul 2022 13:07:03 +0100 Subject: [PATCH 066/119] fix: remove unnecessary _.update() call --- lib/graphql/resolvers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index 070b0a04..270882f2 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -168,7 +168,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings }), addOperatorInfo(operatorInfo), addReceiptInfo(receiptInfo), - _.update('screenOptions', addMachineScreenOpts(machineScreenOpts)) + addMachineScreenOpts(machineScreenOpts) )(staticConf)) } From 4074636663b48272537c33b9a6f73a080e935260 Mon Sep 17 00:00:00 2001 From: josepfo Date: Thu, 8 Dec 2022 16:29:01 +0000 Subject: [PATCH 067/119] fix: add screen options missing field --- lib/graphql/resolvers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index 1270f1f3..da4759e3 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -103,7 +103,8 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings _.pick([ 'coins', 'configVersion', - 'timezone' + 'timezone', + 'screenOptions' ]), _.update('coins', massageCoins), _.set('serverVersion', VERSION), From c5f3caab2f9418d0d191c902eda7f5373f31ce82 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 10:19:24 +0000 Subject: [PATCH 068/119] Revert "fix: add screen options missing field" This reverts commit 4074636663b48272537c33b9a6f73a080e935260. --- lib/graphql/resolvers.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index da4759e3..1270f1f3 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -103,8 +103,7 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings _.pick([ 'coins', 'configVersion', - 'timezone', - 'screenOptions' + 'timezone' ]), _.update('coins', massageCoins), _.set('serverVersion', VERSION), From 171b353d9711f5e98f66779418a54a8ddb01e630 Mon Sep 17 00:00:00 2001 From: josepfo Date: Thu, 8 Dec 2022 16:29:01 +0000 Subject: [PATCH 069/119] fix: add screen options missing field --- lib/graphql/resolvers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index 270882f2..5d1f6323 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -115,7 +115,8 @@ const staticConfig = ({ currentConfigVersion, deviceId, deviceName, pq, settings _.pick([ 'coins', 'configVersion', - 'timezone' + 'timezone', + 'screenOptions' ]), _.update('coins', massageCoins), _.set('serverVersion', VERSION), From 2048b1921cf72d60d1d83268e65b159ea1d0f440 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Thu, 26 Jan 2023 13:04:16 +0100 Subject: [PATCH 070/119] fix: wording --- new-lamassu-admin/src/pages/Blacklist/Blacklist.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index dec75592..94dde70f 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -280,9 +280,9 @@ const Blacklist = () => { {rejectAddressReuse ? 'On' : 'Off'}

- The "Reject reused addresses" option means that all addresses - that are used once will be automatically rejected if there's - an attempt to use them again on a new transaction. + This option requires a user to scan a fresh wallet address if + they attempt to scan one that had been previously used for a + transaction in your network.

For details please read the relevant knowledgebase article: From f41415b00c362d1ffb8c4a9daa72c9c9c2bde9a2 Mon Sep 17 00:00:00 2001 From: josepfo Date: Fri, 21 Oct 2022 11:44:18 +0100 Subject: [PATCH 071/119] fix: load schemas --- new-lamassu-admin/src/pages/Wallet/Wallet.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Wallet/Wallet.js b/new-lamassu-admin/src/pages/Wallet/Wallet.js index eaf1148e..67b02bba 100644 --- a/new-lamassu-admin/src/pages/Wallet/Wallet.js +++ b/new-lamassu-admin/src/pages/Wallet/Wallet.js @@ -10,7 +10,7 @@ import { SupportLinkButton } from 'src/components/buttons' import { NamespacedTable as EditableTable } from 'src/components/editableTable' import TitleSection from 'src/components/layout/TitleSection' import FormRenderer from 'src/pages/Services/FormRenderer' -import schemas from 'src/pages/Services/schemas' +import _schemas from 'src/pages/Services/schemas' import { ReactComponent as ReverseSettingsIcon } from 'src/styling/icons/circle buttons/settings/white.svg' import { ReactComponent as SettingsIcon } from 'src/styling/icons/circle buttons/settings/zodiac.svg' import { fromNamespace, toNamespace } from 'src/utils/config' @@ -54,6 +54,12 @@ const GET_INFO = gql` } ` +const GET_MARKETS = gql` + query getMarkets { + getMarkets + } +` + const LOCALE = 'locale' const useStyles = makeStyles(styles) @@ -71,6 +77,8 @@ const Wallet = ({ name: SCREEN_KEY }) => { refetchQueries: () => ['getData'] }) + const { data: marketsData } = useQuery(GET_MARKETS) + const [saveAccount] = useMutation(SAVE_ACCOUNT, { onCompleted: () => setEditingSchema(null), refetchQueries: () => ['getData'] @@ -89,6 +97,10 @@ const Wallet = ({ name: SCREEN_KEY }) => { const cryptoCurrencies = data?.cryptoCurrencies ?? [] const accounts = data?.accounts ?? [] + const markets = marketsData?.getMarkets + + const schemas = _schemas(markets) + const onChange = (previous, current, setValue) => { if (!current) return setValue(current) From 473bb15c24f4250937959d8287a2a199150f4159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Tue, 4 Oct 2022 19:28:18 +0100 Subject: [PATCH 072/119] feat: turn address into a coin-agnostic solution --- lib/blacklist.js | 29 ++- lib/cash-in/cash-in-tx.js | 2 +- .../graphql/resolvers/blacklist.resolver.js | 8 +- lib/new-admin/graphql/types/blacklist.type.js | 5 +- .../1664907000312-coin-agnostic-blacklist.js | 18 ++ .../src/pages/Blacklist/Blacklist.js | 175 +++++++----------- .../src/pages/Blacklist/Blacklist.styles.js | 10 +- .../src/pages/Blacklist/BlacklistModal.js | 39 +--- .../src/pages/Blacklist/BlacklistTable.js | 13 +- 9 files changed, 122 insertions(+), 177 deletions(-) create mode 100644 migrations/1664907000312-coin-agnostic-blacklist.js diff --git a/lib/blacklist.js b/lib/blacklist.js index 4c3d8595..15bd7b12 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -5,38 +5,37 @@ const notifierQueries = require('./notifier/queries') const getBlacklist = () => { return db.any(`SELECT * FROM blacklist`).then(res => res.map(item => ({ - cryptoCode: item.crypto_code, address: item.address })) ) } // Delete row from blacklist table by crypto code and address -const deleteFromBlacklist = (cryptoCode, address) => { - const sql = `DELETE FROM blacklist WHERE crypto_code = $1 AND address = $2` - notifierQueries.clearBlacklistNotification(cryptoCode, address) - return db.none(sql, [cryptoCode, address]) +const deleteFromBlacklist = address => { + const sql = `DELETE FROM blacklist WHERE address = $1` + notifierQueries.clearBlacklistNotification(address) + return db.none(sql, [address]) } -const insertIntoBlacklist = (cryptoCode, address) => { +const insertIntoBlacklist = address => { return db .none( - 'INSERT INTO blacklist (crypto_code, address) VALUES ($1, $2);', - [cryptoCode, address] + 'INSERT INTO blacklist (address) VALUES ($1);', + [address] ) } -function blocked (address, cryptoCode) { - const sql = `SELECT * FROM blacklist WHERE address = $1 AND crypto_code = $2` - return db.any(sql, [address, cryptoCode]) +function blocked (address) { + const sql = `SELECT * FROM blacklist WHERE address = $1` + return db.any(sql, [address]) } -function addToUsedAddresses (address, cryptoCode) { +function addToUsedAddresses (address) { // ETH reuses addresses - if (cryptoCode === 'ETH') return Promise.resolve() + // if (cryptoCode === 'ETH') return Promise.resolve() - const sql = `INSERT INTO blacklist (crypto_code, address) VALUES ($1, $2)` - return db.oneOrNone(sql, [cryptoCode, address]) + const sql = `INSERT INTO blacklist (address) VALUES ($1)` + return db.oneOrNone(sql, [address]) } module.exports = { diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index cc676554..5123eeb6 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -94,7 +94,7 @@ function logActionById (action, _rec, txId) { } function checkForBlacklisted (tx) { - return blacklist.blocked(tx.toAddress, tx.cryptoCode) + return blacklist.blocked(tx.toAddress) } function postProcess (r, pi, isBlacklisted, addressReuse, walletScore) { diff --git a/lib/new-admin/graphql/resolvers/blacklist.resolver.js b/lib/new-admin/graphql/resolvers/blacklist.resolver.js index 8c15e43f..7cb825cc 100644 --- a/lib/new-admin/graphql/resolvers/blacklist.resolver.js +++ b/lib/new-admin/graphql/resolvers/blacklist.resolver.js @@ -5,10 +5,10 @@ const resolvers = { blacklist: () => blacklist.getBlacklist() }, Mutation: { - deleteBlacklistRow: (...[, { cryptoCode, address }]) => - blacklist.deleteFromBlacklist(cryptoCode, address), - insertBlacklistRow: (...[, { cryptoCode, address }]) => - blacklist.insertIntoBlacklist(cryptoCode, address) + deleteBlacklistRow: (...[, { address }]) => + blacklist.deleteFromBlacklist(address), + insertBlacklistRow: (...[, { address }]) => + blacklist.insertIntoBlacklist(address) } } diff --git a/lib/new-admin/graphql/types/blacklist.type.js b/lib/new-admin/graphql/types/blacklist.type.js index 3cd1bfa1..ee9ee149 100644 --- a/lib/new-admin/graphql/types/blacklist.type.js +++ b/lib/new-admin/graphql/types/blacklist.type.js @@ -2,7 +2,6 @@ const { gql } = require('apollo-server-express') const typeDef = gql` type Blacklist { - cryptoCode: String! address: String! } @@ -11,8 +10,8 @@ const typeDef = gql` } type Mutation { - deleteBlacklistRow(cryptoCode: String!, address: String!): Blacklist @auth - insertBlacklistRow(cryptoCode: String!, address: String!): Blacklist @auth + deleteBlacklistRow(address: String!): Blacklist @auth + insertBlacklistRow(address: String!): Blacklist @auth } ` diff --git a/migrations/1664907000312-coin-agnostic-blacklist.js b/migrations/1664907000312-coin-agnostic-blacklist.js new file mode 100644 index 00000000..9cd78a5f --- /dev/null +++ b/migrations/1664907000312-coin-agnostic-blacklist.js @@ -0,0 +1,18 @@ +var db = require('./db') + +exports.up = function (next) { + var sql = [ + `CREATE TABLE blacklist_temp ( + address TEXT NOT NULL UNIQUE + )` + `INSERT INTO blacklist_temp (address) SELECT DISTINCT address FROM blacklist`, + `DROP TABLE blacklist`, + `ALTER TABLE blacklist_temp RENAME TO blacklist` + ] + + db.multi(sql, next) +} + +exports.down = function (next) { + next() +} diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index dec75592..7726ddba 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -1,5 +1,5 @@ import { useQuery, useMutation } from '@apollo/react-hooks' -import { utils as coinUtils } from '@lamassu/coins' +import { addressDetector } from '@lamassu/coins' import { Box, Dialog, DialogContent, DialogActions } from '@material-ui/core' import Grid from '@material-ui/core/Grid' import { makeStyles } from '@material-ui/core/styles' @@ -8,16 +8,10 @@ import * as R from 'ramda' import React, { useState } from 'react' import { HelpTooltip } from 'src/components/Tooltip' -import { - Link, - Button, - IconButton, - SupportLinkButton -} from 'src/components/buttons' +import { Link, Button, IconButton } from 'src/components/buttons' import { Switch } from 'src/components/inputs' -import Sidebar from 'src/components/layout/Sidebar' import TitleSection from 'src/components/layout/TitleSection' -import { H4, H2, Label2, P, Info3, Info2 } from 'src/components/typography' +import { H2, Label2, P, Info3, Info2 } from 'src/components/typography' import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg' import { fromNamespace, toNamespace } from 'src/utils/config' @@ -27,12 +21,9 @@ import BlacklistTable from './BlacklistTable' const useStyles = makeStyles(styles) -const groupByCode = R.groupBy(obj => obj.cryptoCode) - const DELETE_ROW = gql` - mutation DeleteBlacklistRow($cryptoCode: String!, $address: String!) { - deleteBlacklistRow(cryptoCode: $cryptoCode, address: $address) { - cryptoCode + mutation DeleteBlacklistRow($address: String!) { + deleteBlacklistRow(address: $address) { address } } @@ -41,7 +32,6 @@ const DELETE_ROW = gql` const GET_BLACKLIST = gql` query getBlacklistData { blacklist { - cryptoCode address } cryptoCurrencies { @@ -64,9 +54,8 @@ const GET_INFO = gql` ` const ADD_ROW = gql` - mutation InsertBlacklistRow($cryptoCode: String!, $address: String!) { - insertBlacklistRow(cryptoCode: $cryptoCode, address: $address) { - cryptoCode + mutation InsertBlacklistRow($address: String!) { + insertBlacklistRow(address: $address) { address } } @@ -118,10 +107,6 @@ const Blacklist = () => { const { data: blacklistResponse } = useQuery(GET_BLACKLIST) const { data: configData } = useQuery(GET_INFO) const [showModal, setShowModal] = useState(false) - const [clickedItem, setClickedItem] = useState({ - code: 'BTC', - display: 'Bitcoin' - }) const [errorMsg, setErrorMsg] = useState(null) const [deleteDialog, setDeleteDialog] = useState(false) const [confirmDialog, setConfirmDialog] = useState(false) @@ -147,11 +132,6 @@ const Blacklist = () => { const classes = useStyles() const blacklistData = R.path(['blacklist'])(blacklistResponse) ?? [] - const availableCurrencies = R.filter( - coin => coinUtils.getEquivalentCode(coin.code) === coin.code - )(R.path(['cryptoCurrencies'], blacklistResponse) ?? []) - - const formattedData = groupByCode(blacklistData) const complianceConfig = configData?.config && fromNamespace('compliance')(configData.config) @@ -165,12 +145,8 @@ const Blacklist = () => { return saveConfig({ variables: { config } }) } - const onClickSidebarItem = e => { - setClickedItem({ code: e.code, display: e.display }) - } - - const handleDeleteEntry = (cryptoCode, address) => { - deleteEntry({ variables: { cryptoCode, address } }) + const handleDeleteEntry = address => { + deleteEntry({ variables: { address } }) } const handleConfirmDialog = confirm => { @@ -180,21 +156,21 @@ const Blacklist = () => { setConfirmDialog(false) } - const validateAddress = (cryptoCode, address) => { + const validateAddress = address => { try { - return !R.isNil(coinUtils.parseUrl(cryptoCode, 'main', address)) + return !R.isEmpty(addressDetector.detectAddress(address).matches) } catch { return false } } - const addToBlacklist = async (cryptoCode, address) => { + const addToBlacklist = async address => { setErrorMsg(null) - if (!validateAddress(cryptoCode, address)) { + if (!validateAddress(address)) { setErrorMsg('Invalid address') return } - const res = await addEntry({ variables: { cryptoCode, address } }) + const res = await addEntry({ variables: { address } }) if (!res.errors) { return setShowModal(false) } @@ -218,86 +194,64 @@ const Blacklist = () => { }} /> - + + +

Enable paper wallet (only)

+ + enablePaperWalletOnly + ? addressReuseSave({ + enablePaperWalletOnly: e.target.checked + }) + : setConfirmDialog(true) + } + value={enablePaperWalletOnly} + /> + {enablePaperWalletOnly ? 'On' : 'Off'} + +

+ The "Enable paper wallet (only)" option means that only paper + wallets will be printed for users, and they won't be permitted + to scan an address from their own wallet. +

+
+
+ +

Reject reused addresses

+ { + addressReuseSave({ rejectAddressReuse: event.target.checked }) + }} + value={rejectAddressReuse} + /> + {rejectAddressReuse ? 'On' : 'Off'} + +

+ The "Reject reused addresses" option means that all addresses + that are used once will be automatically rejected if there's an + attempt to use them again on a new transaction. +

+
+
setShowModal(true)}> Blacklist new addresses - it.display} - onClick={onClickSidebarItem} - />
- -

- {clickedItem.display - ? `${clickedItem.display} blacklisted addresses` - : ''}{' '} -

- -

Enable paper wallet (only)

- - enablePaperWalletOnly - ? addressReuseSave({ - enablePaperWalletOnly: e.target.checked - }) - : setConfirmDialog(true) - } - value={enablePaperWalletOnly} - /> - {enablePaperWalletOnly ? 'On' : 'Off'} - -

- The "Enable paper wallet (only)" option means that only paper - wallets will be printed for users, and they won't be permitted - to scan an address from their own wallet. -

-
-
- -

Reject reused addresses

- { - addressReuseSave({ rejectAddressReuse: event.target.checked }) - }} - value={rejectAddressReuse} - /> - {rejectAddressReuse ? 'On' : 'Off'} - -

- The "Reject reused addresses" option means that all addresses - that are used once will be automatically rejected if there's - an attempt to use them again on a new transaction. -

-

- For details please read the relevant knowledgebase article: -

- -
-
-
{ setShowModal(false) }} errorMsg={errorMsg} - selectedCoin={clickedItem} addToBlacklist={addToBlacklist} /> )} diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js index 9c44bb1d..6e4a09e4 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js @@ -7,11 +7,15 @@ const styles = { content: { display: 'flex', flexDirection: 'column', - flex: 1, - marginLeft: spacer * 6 + flex: 1 }, footer: { - margin: [['auto', 0, spacer * 3, 'auto']] + display: 'flex', + flexDirection: 'row', + margin: [['auto', 0, spacer * 3, 0]] + }, + submit: { + margin: [['auto', 0, 0, 'auto']] }, modalTitle: { margin: [['auto', 0, 8.5, 'auto']] diff --git a/new-lamassu-admin/src/pages/Blacklist/BlacklistModal.js b/new-lamassu-admin/src/pages/Blacklist/BlacklistModal.js index 4c13881b..5e9eb95a 100644 --- a/new-lamassu-admin/src/pages/Blacklist/BlacklistModal.js +++ b/new-lamassu-admin/src/pages/Blacklist/BlacklistModal.js @@ -14,31 +14,14 @@ import { H3 } from 'src/components/typography' import styles from './Blacklist.styles' const useStyles = makeStyles(styles) -const BlackListModal = ({ - onClose, - selectedCoin, - addToBlacklist, - errorMsg -}) => { +const BlackListModal = ({ onClose, addToBlacklist, errorMsg }) => { const classes = useStyles() const handleAddToBlacklist = address => { - if (selectedCoin.code === 'BCH' && !address.startsWith('bitcoincash:')) { - address = 'bitcoincash:' + address - } - addToBlacklist(selectedCoin.code, address) - } - const placeholderAddress = { - BTC: '1ADwinnimZKGgQ3dpyfoUZvJh4p1UWSSpD', - ETH: '0x71C7656EC7ab88b098defB751B7401B5f6d8976F', - LTC: 'LPKvbjwV1Kaksktzkr7TMK3FQtQEEe6Wqa', - DASH: 'XqQ7gU8eM76rEfey726cJpT2RGKyJyBrcn', - ZEC: 't1KGyyv24eL354C9gjveBGEe8Xz9UoPKvHR', - BCH: 'qrd6za97wm03lfyg82w0c9vqgc727rhemg5yd9k3dm', - USDT: '0x5754284f345afc66a98fbb0a0afe71e0f007b949', - XMR: - '888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H' + addToBlacklist(address) } + const placeholderAddress = '1ADwinnimZKGgQ3dpyfoUZvJh4p1UWSSpD' + return (
-

- {selectedCoin.display - ? `Blacklist ${R.toLower(selectedCoin.display)} address` - : ''} -

+

Blacklist new address

- {!R.isNil(errorMsg) && ( - {errorMsg} - )}
- + {!R.isNil(errorMsg) && {errorMsg}} + Blacklist address diff --git a/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js b/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js index 9ce480a3..39bcb1ab 100644 --- a/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js +++ b/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js @@ -5,7 +5,6 @@ import React, { useState } from 'react' import { DeleteDialog } from 'src/components/DeleteDialog' import { IconButton } from 'src/components/buttons' import DataTable from 'src/components/tables/DataTable' -import { Label1 } from 'src/components/typography' import CopyToClipboard from 'src/pages/Transactions/CopyToClipboard' import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg' @@ -15,7 +14,6 @@ const useStyles = makeStyles(styles) const BlacklistTable = ({ data, - selectedCoin, handleDeleteEntry, errorMessage, setErrorMessage, @@ -29,8 +27,8 @@ const BlacklistTable = ({ const elements = [ { name: 'address', - header: {'Addresses'}, - width: 800, + header: 'Address', + width: 1070, textAlign: 'left', size: 'sm', view: it => ( @@ -41,7 +39,7 @@ const BlacklistTable = ({ }, { name: 'deleteButton', - header: {'Delete'}, + header: 'Delete', width: 130, textAlign: 'center', size: 'sm', @@ -57,14 +55,11 @@ const BlacklistTable = ({ ) } ] - const dataToShow = selectedCoin - ? data[selectedCoin.code] - : data[R.keys(data)[0]] return ( <> Date: Thu, 6 Oct 2022 17:18:12 +0100 Subject: [PATCH 073/119] feat: add advanced address blacklisting --- lib/blacklist.js | 28 ++- .../graphql/resolvers/blacklist.resolver.js | 7 +- lib/new-admin/graphql/types/blacklist.type.js | 10 + .../1664916753772-advanced-blacklisting.js | 26 +++ .../src/pages/Blacklist/Blacklist.js | 174 +++++++++++------ .../src/pages/Blacklist/Blacklist.styles.js | 11 ++ .../src/pages/Blacklist/BlacklistAdvanced.js | 177 ++++++++++++++++++ 7 files changed, 367 insertions(+), 66 deletions(-) create mode 100644 migrations/1664916753772-advanced-blacklisting.js create mode 100644 new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js diff --git a/lib/blacklist.js b/lib/blacklist.js index 15bd7b12..89a9037f 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -1,16 +1,16 @@ +const _ = require('lodash/fp') + const db = require('./db') const notifierQueries = require('./notifier/queries') -// Get all blacklist rows from the DB "blacklist" table that were manually inserted by the operator const getBlacklist = () => { - return db.any(`SELECT * FROM blacklist`).then(res => - res.map(item => ({ - address: item.address - })) - ) + const blacklistSql = `SELECT * FROM blacklist` + const messagesSql = `SELECT * FROM blacklist_messages` + return Promise.all([db.any(blacklistSql), db.any(messagesSql)]) + .then(([blacklist, messages]) => Promise.all([_.map(_.mapKeys(_.camelCase), blacklist), _.map(_.mapKeys(_.camelCase), messages)])) + .then(([blacklist, messages]) => _.map(it => ({ ...it, blacklistMessage: _.find(ite => it.blacklistMessageId === ite.id, messages) }), blacklist)) } -// Delete row from blacklist table by crypto code and address const deleteFromBlacklist = address => { const sql = `DELETE FROM blacklist WHERE address = $1` notifierQueries.clearBlacklistNotification(address) @@ -38,10 +38,22 @@ function addToUsedAddresses (address) { return db.oneOrNone(sql, [address]) } +function getMessages () { + const sql = `SELECT * FROM blacklist_messages` + return db.any(sql) +} + +function editBlacklistMessage (id, content) { + const sql = `UPDATE blacklist_messages SET content = $1 WHERE id = $2 RETURNING id` + return db.oneOrNone(sql, [content, id]) +} + module.exports = { blocked, addToUsedAddresses, getBlacklist, deleteFromBlacklist, - insertIntoBlacklist + insertIntoBlacklist, + getMessages, + editBlacklistMessage } diff --git a/lib/new-admin/graphql/resolvers/blacklist.resolver.js b/lib/new-admin/graphql/resolvers/blacklist.resolver.js index 7cb825cc..e0b63d53 100644 --- a/lib/new-admin/graphql/resolvers/blacklist.resolver.js +++ b/lib/new-admin/graphql/resolvers/blacklist.resolver.js @@ -2,13 +2,16 @@ const blacklist = require('../../../blacklist') const resolvers = { Query: { - blacklist: () => blacklist.getBlacklist() + blacklist: () => blacklist.getBlacklist(), + blacklistMessages: () => blacklist.getMessages() }, Mutation: { deleteBlacklistRow: (...[, { address }]) => blacklist.deleteFromBlacklist(address), insertBlacklistRow: (...[, { address }]) => - blacklist.insertIntoBlacklist(address) + blacklist.insertIntoBlacklist(address), + editBlacklistMessage: (...[, { id, content }]) => + blacklist.editBlacklistMessage(id, content) } } diff --git a/lib/new-admin/graphql/types/blacklist.type.js b/lib/new-admin/graphql/types/blacklist.type.js index ee9ee149..7cc34721 100644 --- a/lib/new-admin/graphql/types/blacklist.type.js +++ b/lib/new-admin/graphql/types/blacklist.type.js @@ -3,15 +3,25 @@ const { gql } = require('apollo-server-express') const typeDef = gql` type Blacklist { address: String! + blacklistMessage: BlacklistMessage! + } + + type BlacklistMessage { + id: ID + label: String + content: String + allowToggle: Boolean } type Query { blacklist: [Blacklist] @auth + blacklistMessages: [BlacklistMessage] @auth } type Mutation { deleteBlacklistRow(address: String!): Blacklist @auth insertBlacklistRow(address: String!): Blacklist @auth + editBlacklistMessage(id: ID, content: String): BlacklistMessage @auth } ` diff --git a/migrations/1664916753772-advanced-blacklisting.js b/migrations/1664916753772-advanced-blacklisting.js new file mode 100644 index 00000000..915c1f33 --- /dev/null +++ b/migrations/1664916753772-advanced-blacklisting.js @@ -0,0 +1,26 @@ +const uuid = require('uuid') + +var db = require('./db') + +exports.up = function (next) { + const defaultMessageId = uuid.v4() + + var sql = [ + `CREATE TABLE blacklist_messages ( + id UUID PRIMARY KEY, + label TEXT NOT NULL, + content TEXT NOT NULL, + allow_toggle BOOLEAN NOT NULL DEFAULT true + )`, + `INSERT INTO blacklist_messages (id, label, content, allow_toggle) VALUES ('${defaultMessageId}', 'Suspicious address', 'This address may be associated with a deceptive offer or a prohibited group. Please make sure you''re using an address from your own wallet.', false)`, + `ALTER TABLE blacklist ADD COLUMN blacklist_message_id UUID REFERENCES blacklist_messages(id)`, + `UPDATE blacklist SET blacklist_message_id = '${defaultMessageId}'`, + `ALTER TABLE blacklist ALTER COLUMN blacklist_message_id SET NOT NULL` + ] + + db.multi(sql, next) +} + +exports.down = function (next) { + next() +} diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index 7726ddba..59c97e64 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -1,7 +1,6 @@ import { useQuery, useMutation } from '@apollo/react-hooks' import { addressDetector } from '@lamassu/coins' import { Box, Dialog, DialogContent, DialogActions } from '@material-ui/core' -import Grid from '@material-ui/core/Grid' import { makeStyles } from '@material-ui/core/styles' import gql from 'graphql-tag' import * as R from 'ramda' @@ -13,9 +12,12 @@ import { Switch } from 'src/components/inputs' import TitleSection from 'src/components/layout/TitleSection' import { H2, Label2, P, Info3, Info2 } from 'src/components/typography' import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg' +import { ReactComponent as ReverseSettingsIcon } from 'src/styling/icons/circle buttons/settings/white.svg' +import { ReactComponent as SettingsIcon } from 'src/styling/icons/circle buttons/settings/zodiac.svg' import { fromNamespace, toNamespace } from 'src/utils/config' import styles from './Blacklist.styles' +import BlackListAdvanced from './BlacklistAdvanced' import BlackListModal from './BlacklistModal' import BlacklistTable from './BlacklistTable' @@ -33,6 +35,11 @@ const GET_BLACKLIST = gql` query getBlacklistData { blacklist { address + blacklistMessage { + id + label + content + } } cryptoCurrencies { display @@ -61,6 +68,25 @@ const ADD_ROW = gql` } ` +const GET_BLACKLIST_MESSAGES = gql` + query getBlacklistMessages { + blacklistMessages { + id + label + content + allowToggle + } + } +` + +const EDIT_BLACKLIST_MESSAGE = gql` + mutation editBlacklistMessage($id: ID, $content: String) { + editBlacklistMessage(id: $id, content: $content) { + id + } + } +` + const PaperWalletDialog = ({ onConfirmed, onDissmised, open, props }) => { const classes = useStyles() @@ -106,10 +132,13 @@ const PaperWalletDialog = ({ onConfirmed, onDissmised, open, props }) => { const Blacklist = () => { const { data: blacklistResponse } = useQuery(GET_BLACKLIST) const { data: configData } = useQuery(GET_INFO) + const { data: messagesResponse, refetch } = useQuery(GET_BLACKLIST_MESSAGES) const [showModal, setShowModal] = useState(false) const [errorMsg, setErrorMsg] = useState(null) + const [editMessageError, setEditMessageError] = useState(null) const [deleteDialog, setDeleteDialog] = useState(false) const [confirmDialog, setConfirmDialog] = useState(false) + const [advancedSettings, setAdvancedSettings] = useState(false) const [deleteEntry] = useMutation(DELETE_ROW, { onError: ({ message }) => { @@ -129,6 +158,11 @@ const Blacklist = () => { refetchQueries: () => ['getData'] }) + const [editMessage] = useMutation(EDIT_BLACKLIST_MESSAGE, { + onError: e => setEditMessageError(e), + refetchQueries: () => ['getBlacklistData'] + }) + const classes = useStyles() const blacklistData = R.path(['blacklist'])(blacklistResponse) ?? [] @@ -184,6 +218,15 @@ const Blacklist = () => { } } + const editBlacklistMessage = r => { + editMessage({ + variables: { + id: r.id, + content: r.content + } + }) + } + return ( <> { setConfirmDialog(false) }} /> - - - -

Enable paper wallet (only)

- - enablePaperWalletOnly - ? addressReuseSave({ - enablePaperWalletOnly: e.target.checked - }) - : setConfirmDialog(true) - } - value={enablePaperWalletOnly} - /> - {enablePaperWalletOnly ? 'On' : 'Off'} - -

- The "Enable paper wallet (only)" option means that only paper - wallets will be printed for users, and they won't be permitted - to scan an address from their own wallet. -

-
+ + {!advancedSettings && ( + + +

Enable paper wallet (only)

+ + enablePaperWalletOnly + ? addressReuseSave({ + enablePaperWalletOnly: e.target.checked + }) + : setConfirmDialog(true) + } + value={enablePaperWalletOnly} + /> + {enablePaperWalletOnly ? 'On' : 'Off'} + +

+ The "Enable paper wallet (only)" option means that only paper + wallets will be printed for users, and they won't be permitted + to scan an address from their own wallet. +

+
+
+ +

Reject reused addresses

+ { + addressReuseSave({ rejectAddressReuse: event.target.checked }) + }} + value={rejectAddressReuse} + /> + {rejectAddressReuse ? 'On' : 'Off'} + +

+ The "Reject reused addresses" option means that all addresses + that are used once will be automatically rejected if there's + an attempt to use them again on a new transaction. +

+
+
+ setShowModal(true)}> + Blacklist new addresses +
- -

Reject reused addresses

- { - addressReuseSave({ rejectAddressReuse: event.target.checked }) - }} - value={rejectAddressReuse} - /> - {rejectAddressReuse ? 'On' : 'Off'} - -

- The "Reject reused addresses" option means that all addresses - that are used once will be automatically rejected if there's an - attempt to use them again on a new transaction. -

-
-
- setShowModal(true)}> - Blacklist new addresses - -
+ )}
- + {!advancedSettings && (
{ setDeleteDialog={setDeleteDialog} />
-
+ )} + {advancedSettings && ( + refetch()} + /> + )} {showModal && ( { diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js index 6e4a09e4..3cfc09ec 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.styles.js @@ -9,6 +9,14 @@ const styles = { flexDirection: 'column', flex: 1 }, + advancedForm: { + '& > *': { + marginTop: 20 + }, + display: 'flex', + flexDirection: 'column', + height: '100%' + }, footer: { display: 'flex', flexDirection: 'row', @@ -58,6 +66,9 @@ const styles = { cancelButton: { marginRight: 8, padding: 0 + }, + resetToDefault: { + width: 145 } } diff --git a/new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js b/new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js new file mode 100644 index 00000000..4c764b46 --- /dev/null +++ b/new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js @@ -0,0 +1,177 @@ +import { makeStyles } from '@material-ui/core/styles' +import { Form, Formik, Field } from 'formik' +import * as R from 'ramda' +import React, { useState } from 'react' +import * as Yup from 'yup' + +import ErrorMessage from 'src/components/ErrorMessage' +import Modal from 'src/components/Modal' +import { ActionButton, IconButton, Button } from 'src/components/buttons' +import { TextInput } from 'src/components/inputs/formik' +import DataTable from 'src/components/tables/DataTable' +import { ReactComponent as DisabledDeleteIcon } from 'src/styling/icons/action/delete/disabled.svg' +import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg' +import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg' +import { ReactComponent as DefaultIconReverse } from 'src/styling/icons/button/retry/white.svg' +import { ReactComponent as DefaultIcon } from 'src/styling/icons/button/retry/zodiac.svg' + +import styles from './Blacklist.styles' + +const useStyles = makeStyles(styles) + +const DEFAULT_MESSAGE = `This address may be associated with a deceptive offer or a prohibited group. Please make sure you're using an address from your own wallet.` + +const getErrorMsg = (formikErrors, formikTouched, mutationError) => { + if (!formikErrors || !formikTouched) return null + if (mutationError) return 'Internal server error' + if (formikErrors.event && formikTouched.event) return formikErrors.event + if (formikErrors.message && formikTouched.message) return formikErrors.message + return null +} + +const BlacklistAdvanced = ({ + data, + editBlacklistMessage, + onClose, + mutationError +}) => { + const classes = useStyles() + const [selectedMessage, setSelectedMessage] = useState(null) + + const elements = [ + { + name: 'label', + header: 'Label', + width: 250, + textAlign: 'left', + size: 'sm', + view: it => R.path(['label'], it) + }, + { + name: 'content', + header: 'Content', + width: 690, + textAlign: 'left', + size: 'sm', + view: it => R.path(['content'], it) + }, + { + name: 'edit', + header: 'Edit', + width: 130, + textAlign: 'center', + size: 'sm', + view: it => ( + setSelectedMessage(it)}> + + + ) + }, + { + name: 'deleteButton', + header: 'Delete', + width: 130, + textAlign: 'center', + size: 'sm', + view: it => ( + + {R.path(['allowToggle'], it) ? ( + + ) : ( + + )} + + ) + } + ] + + const handleModalClose = () => { + setSelectedMessage(null) + } + + const handleSubmit = values => { + editBlacklistMessage(values) + handleModalClose() + !R.isNil(onClose) && onClose() + } + + const initialValues = { + label: !R.isNil(selectedMessage) ? selectedMessage.label : '', + content: !R.isNil(selectedMessage) ? selectedMessage.content : '' + } + + const validationSchema = Yup.object().shape({ + label: Yup.string().required('A label is required!'), + content: Yup.string() + .required('The message content is required!') + .trim() + }) + + return ( + <> + + {selectedMessage && ( + + + handleSubmit({ id: selectedMessage.id, ...values }) + }> + {({ errors, touched, setFieldValue }) => ( +
+ setFieldValue('content', DEFAULT_MESSAGE)}> + Reset to default + + +
+ {getErrorMsg(errors, touched, mutationError) && ( + + {getErrorMsg(errors, touched, mutationError)} + + )} + +
+ + )} +
+
+ )} + + ) +} + +export default BlacklistAdvanced From 677cb39f0c4433630adc34096a7d59255a293ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Thu, 6 Oct 2022 19:03:00 +0100 Subject: [PATCH 074/119] feat: add blacklist message to machine communication --- lib/blacklist.js | 2 +- lib/cash-in/cash-in-low.js | 2 +- lib/cash-in/cash-in-tx.js | 7 ++++--- migrations/1664916753772-advanced-blacklisting.js | 4 +--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/blacklist.js b/lib/blacklist.js index 89a9037f..79835f10 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -26,7 +26,7 @@ const insertIntoBlacklist = address => { } function blocked (address) { - const sql = `SELECT * FROM blacklist WHERE address = $1` + const sql = `SELECT address, content FROM blacklist b LEFT OUTER JOIN blacklist_messages bm ON bm.id = b.blacklist_message_id WHERE address = $1` return db.any(sql, [address]) } diff --git a/lib/cash-in/cash-in-low.js b/lib/cash-in/cash-in-low.js index 5b8066a0..0f2942df 100644 --- a/lib/cash-in/cash-in-low.js +++ b/lib/cash-in/cash-in-low.js @@ -8,7 +8,7 @@ const E = require('../error') const PENDING_INTERVAL_MS = 60 * T.minutes -const massageFields = ['direction', 'cryptoNetwork', 'bills', 'blacklisted', 'addressReuse', 'promoCodeApplied', 'validWalletScore', 'cashInFeeCrypto'] +const massageFields = ['direction', 'cryptoNetwork', 'bills', 'blacklisted', 'blacklistMessage', 'addressReuse', 'promoCodeApplied', 'validWalletScore', 'cashInFeeCrypto'] const massageUpdateFields = _.concat(massageFields, 'cryptoAtoms') const massage = _.flow(_.omit(massageFields), diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 5123eeb6..2f301cc5 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -32,7 +32,7 @@ function post (machineTx, pi) { return cashInAtomic.atomic(machineTx, pi) .then(r => { const updatedTx = r.tx - let blacklisted = false + let blacklisted = null let addressReuse = false let walletScore = {} @@ -50,7 +50,7 @@ function post (machineTx, pi) { walletScore = fetchedWalletScore if (_.some(it => it.address === updatedTx.toAddress)(blacklistItems)) { - blacklisted = true + blacklisted = _.find(it => it.address === updatedTx.toAddress)(blacklistItems) notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, false) } else if (isReusedAddress && rejectAddressReuse) { notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, true) @@ -61,7 +61,8 @@ function post (machineTx, pi) { .then(changes => _.set('walletScore', _.isNil(walletScore) ? null : walletScore.score, changes)) .then(changes => cashInLow.update(db, updatedTx, changes)) .then(tx => _.set('bills', machineTx.bills, tx)) - .then(tx => _.set('blacklisted', blacklisted, tx)) + .then(tx => _.set('blacklisted', Boolean(blacklisted), tx)) + .then(tx => _.set('blacklistMessage', blacklisted?.content, tx)) .then(tx => _.set('addressReuse', addressReuse, tx)) .then(tx => _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid, tx)) }) diff --git a/migrations/1664916753772-advanced-blacklisting.js b/migrations/1664916753772-advanced-blacklisting.js index 915c1f33..4648f182 100644 --- a/migrations/1664916753772-advanced-blacklisting.js +++ b/migrations/1664916753772-advanced-blacklisting.js @@ -13,9 +13,7 @@ exports.up = function (next) { allow_toggle BOOLEAN NOT NULL DEFAULT true )`, `INSERT INTO blacklist_messages (id, label, content, allow_toggle) VALUES ('${defaultMessageId}', 'Suspicious address', 'This address may be associated with a deceptive offer or a prohibited group. Please make sure you''re using an address from your own wallet.', false)`, - `ALTER TABLE blacklist ADD COLUMN blacklist_message_id UUID REFERENCES blacklist_messages(id)`, - `UPDATE blacklist SET blacklist_message_id = '${defaultMessageId}'`, - `ALTER TABLE blacklist ALTER COLUMN blacklist_message_id SET NOT NULL` + `ALTER TABLE blacklist ADD COLUMN blacklist_message_id UUID REFERENCES blacklist_messages(id) NOT NULL DEFAULT '${defaultMessageId}'` ] db.multi(sql, next) From 01303d6454e7a98c3d4ef5e702c8eec93183ed8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Sat, 15 Oct 2022 04:07:30 +0100 Subject: [PATCH 075/119] fix: clean up code --- lib/blacklist.js | 10 +--------- lib/cash-in/cash-in-tx.js | 15 +++++++++------ .../src/pages/Blacklist/Blacklist.js | 5 ----- .../src/pages/Blacklist/BlacklistAdvanced.js | 5 +++-- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/lib/blacklist.js b/lib/blacklist.js index 79835f10..63a7fb13 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -27,15 +27,8 @@ const insertIntoBlacklist = address => { function blocked (address) { const sql = `SELECT address, content FROM blacklist b LEFT OUTER JOIN blacklist_messages bm ON bm.id = b.blacklist_message_id WHERE address = $1` - return db.any(sql, [address]) -} - -function addToUsedAddresses (address) { - // ETH reuses addresses - // if (cryptoCode === 'ETH') return Promise.resolve() - - const sql = `INSERT INTO blacklist (address) VALUES ($1)` return db.oneOrNone(sql, [address]) + .then(r => !_.isNil(r)) } function getMessages () { @@ -50,7 +43,6 @@ function editBlacklistMessage (id, content) { module.exports = { blocked, - addToUsedAddresses, getBlacklist, deleteFromBlacklist, insertIntoBlacklist, diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 2f301cc5..f321e8fe 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -40,28 +40,31 @@ function post (machineTx, pi) { const isFirstPost = !r.tx.fiat || r.tx.fiat.isZero() if (isFirstPost) { - promises.push(checkForBlacklisted(updatedTx), doesTxReuseAddress(updatedTx), getWalletScore(updatedTx, pi)) + promises.push( + checkForBlacklisted(updatedTx), + doesTxReuseAddress(updatedTx), + getWalletScore(updatedTx, pi) + ) } return Promise.all(promises) - .then(([config, blacklistItems = false, isReusedAddress = false, fetchedWalletScore = null]) => { + .then(([config, isBlacklisted = false, isReusedAddress = false, fetchedWalletScore = null]) => { const rejectAddressReuse = configManager.getCompliance(config).rejectAddressReuse walletScore = fetchedWalletScore - if (_.some(it => it.address === updatedTx.toAddress)(blacklistItems)) { - blacklisted = _.find(it => it.address === updatedTx.toAddress)(blacklistItems) + if (isBlacklisted) { notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, false) } else if (isReusedAddress && rejectAddressReuse) { notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, true) addressReuse = true } - return postProcess(r, pi, blacklisted, addressReuse, walletScore) + return postProcess(r, pi, isBlacklisted, addressReuse, walletScore) }) .then(changes => _.set('walletScore', _.isNil(walletScore) ? null : walletScore.score, changes)) .then(changes => cashInLow.update(db, updatedTx, changes)) .then(tx => _.set('bills', machineTx.bills, tx)) - .then(tx => _.set('blacklisted', Boolean(blacklisted), tx)) + .then(tx => _.set('blacklisted', isBlacklisted, tx)) .then(tx => _.set('blacklistMessage', blacklisted?.content, tx)) .then(tx => _.set('addressReuse', addressReuse, tx)) .then(tx => _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid, tx)) diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index 59c97e64..0ca8c509 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -35,11 +35,6 @@ const GET_BLACKLIST = gql` query getBlacklistData { blacklist { address - blacklistMessage { - id - label - content - } } cryptoCurrencies { display diff --git a/new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js b/new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js index 4c764b46..f3790959 100644 --- a/new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js +++ b/new-lamassu-admin/src/pages/Blacklist/BlacklistAdvanced.js @@ -22,8 +22,8 @@ const useStyles = makeStyles(styles) const DEFAULT_MESSAGE = `This address may be associated with a deceptive offer or a prohibited group. Please make sure you're using an address from your own wallet.` const getErrorMsg = (formikErrors, formikTouched, mutationError) => { - if (!formikErrors || !formikTouched) return null if (mutationError) return 'Internal server error' + if (!formikErrors || !formikTouched) return null if (formikErrors.event && formikTouched.event) return formikErrors.event if (formikErrors.message && formikTouched.message) return formikErrors.message return null @@ -79,7 +79,8 @@ const BlacklistAdvanced = ({ {R.path(['allowToggle'], it) ? ( From a6078689421786f06e1b5f3c29532fa32ea315d4 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 12:32:38 +0000 Subject: [PATCH 076/119] fix: syntax error in migration file --- migrations/1664907000312-coin-agnostic-blacklist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/1664907000312-coin-agnostic-blacklist.js b/migrations/1664907000312-coin-agnostic-blacklist.js index 9cd78a5f..9a227308 100644 --- a/migrations/1664907000312-coin-agnostic-blacklist.js +++ b/migrations/1664907000312-coin-agnostic-blacklist.js @@ -4,7 +4,7 @@ exports.up = function (next) { var sql = [ `CREATE TABLE blacklist_temp ( address TEXT NOT NULL UNIQUE - )` + )`, `INSERT INTO blacklist_temp (address) SELECT DISTINCT address FROM blacklist`, `DROP TABLE blacklist`, `ALTER TABLE blacklist_temp RENAME TO blacklist` From 4793b2a415053528b4a364b17282c9829dd17af7 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 12:41:14 +0000 Subject: [PATCH 077/119] refactor: join in the DB --- lib/blacklist.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/blacklist.js b/lib/blacklist.js index 63a7fb13..2a34a1f2 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -3,13 +3,12 @@ const _ = require('lodash/fp') const db = require('./db') const notifierQueries = require('./notifier/queries') -const getBlacklist = () => { - const blacklistSql = `SELECT * FROM blacklist` - const messagesSql = `SELECT * FROM blacklist_messages` - return Promise.all([db.any(blacklistSql), db.any(messagesSql)]) - .then(([blacklist, messages]) => Promise.all([_.map(_.mapKeys(_.camelCase), blacklist), _.map(_.mapKeys(_.camelCase), messages)])) - .then(([blacklist, messages]) => _.map(it => ({ ...it, blacklistMessage: _.find(ite => it.blacklistMessageId === ite.id, messages) }), blacklist)) -} +const getBlacklist = () => + db.any( + `SELECT blacklist.address AS address, blacklist_messages.content AS blacklistMessage + FROM blacklist JOIN blacklist_messages + ON blacklist.blacklist_message_id = blacklist_messages.id` + ) const deleteFromBlacklist = address => { const sql = `DELETE FROM blacklist WHERE address = $1` From 7f2651fa9ec53c70d451044cf0fca1ee0b1211b8 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 16:58:33 +0000 Subject: [PATCH 078/119] fix: undefined variable --- lib/cash-in/cash-in-tx.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index f321e8fe..8ebdcf20 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -60,14 +60,14 @@ function post (machineTx, pi) { addressReuse = true } return postProcess(r, pi, isBlacklisted, addressReuse, walletScore) + .then(changes => _.set('walletScore', _.isNil(walletScore) ? null : walletScore.score, changes)) + .then(changes => cashInLow.update(db, updatedTx, changes)) + .then(tx => _.set('bills', machineTx.bills, tx)) + .then(tx => _.set('blacklisted', isBlacklisted, tx)) + .then(tx => _.set('blacklistMessage', blacklisted?.content, tx)) + .then(tx => _.set('addressReuse', addressReuse, tx)) + .then(tx => _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid, tx)) }) - .then(changes => _.set('walletScore', _.isNil(walletScore) ? null : walletScore.score, changes)) - .then(changes => cashInLow.update(db, updatedTx, changes)) - .then(tx => _.set('bills', machineTx.bills, tx)) - .then(tx => _.set('blacklisted', isBlacklisted, tx)) - .then(tx => _.set('blacklistMessage', blacklisted?.content, tx)) - .then(tx => _.set('addressReuse', addressReuse, tx)) - .then(tx => _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid, tx)) }) } From f010398ebf34b4cb99f1bc31131c9036e7a92790 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 17:00:28 +0000 Subject: [PATCH 079/119] refactor: replace `then` chain with `flow` --- lib/cash-in/cash-in-tx.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 8ebdcf20..8d046834 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -62,11 +62,13 @@ function post (machineTx, pi) { return postProcess(r, pi, isBlacklisted, addressReuse, walletScore) .then(changes => _.set('walletScore', _.isNil(walletScore) ? null : walletScore.score, changes)) .then(changes => cashInLow.update(db, updatedTx, changes)) - .then(tx => _.set('bills', machineTx.bills, tx)) - .then(tx => _.set('blacklisted', isBlacklisted, tx)) - .then(tx => _.set('blacklistMessage', blacklisted?.content, tx)) - .then(tx => _.set('addressReuse', addressReuse, tx)) - .then(tx => _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid, tx)) + .then(_.flow( + _.set('bills', machineTx.bills), + _.set('blacklisted', isBlacklisted), + _.set('blacklistMessage', blacklisted?.content), + _.set('addressReuse', addressReuse), + _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid), + )) }) }) } From 944ef60121323e41d74e11e08276fb3cb7a55330 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 17:03:26 +0000 Subject: [PATCH 080/119] refactor: remove unnecessary variable --- lib/cash-in/cash-in-tx.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 8d046834..64afaa7f 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -34,7 +34,6 @@ function post (machineTx, pi) { const updatedTx = r.tx let blacklisted = null let addressReuse = false - let walletScore = {} const promises = [settingsLoader.loadLatestConfig()] @@ -48,11 +47,9 @@ function post (machineTx, pi) { } return Promise.all(promises) - .then(([config, isBlacklisted = false, isReusedAddress = false, fetchedWalletScore = null]) => { + .then(([config, isBlacklisted = false, isReusedAddress = false, walletScore = null]) => { const rejectAddressReuse = configManager.getCompliance(config).rejectAddressReuse - walletScore = fetchedWalletScore - if (isBlacklisted) { notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, false) } else if (isReusedAddress && rejectAddressReuse) { From e1811daf24ffe7701f47da9f8947adfa6b68d38f Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 17:03:45 +0000 Subject: [PATCH 081/119] refactor: use restructuring --- lib/cash-in/cash-in-tx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 64afaa7f..03235176 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -48,7 +48,7 @@ function post (machineTx, pi) { return Promise.all(promises) .then(([config, isBlacklisted = false, isReusedAddress = false, walletScore = null]) => { - const rejectAddressReuse = configManager.getCompliance(config).rejectAddressReuse + const { rejectAddressReuse } = configManager.getCompliance(config) if (isBlacklisted) { notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, false) From a56336282f2faee8c795dee8f81b8d14efd252b1 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 17:24:13 +0000 Subject: [PATCH 082/119] fix: get blacklist message associated with address --- lib/blacklist.js | 1 - lib/cash-in/cash-in-tx.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/blacklist.js b/lib/blacklist.js index 2a34a1f2..8324fc20 100644 --- a/lib/blacklist.js +++ b/lib/blacklist.js @@ -27,7 +27,6 @@ const insertIntoBlacklist = address => { function blocked (address) { const sql = `SELECT address, content FROM blacklist b LEFT OUTER JOIN blacklist_messages bm ON bm.id = b.blacklist_message_id WHERE address = $1` return db.oneOrNone(sql, [address]) - .then(r => !_.isNil(r)) } function getMessages () { diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 03235176..09d0a235 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -32,7 +32,6 @@ function post (machineTx, pi) { return cashInAtomic.atomic(machineTx, pi) .then(r => { const updatedTx = r.tx - let blacklisted = null let addressReuse = false const promises = [settingsLoader.loadLatestConfig()] @@ -47,8 +46,9 @@ function post (machineTx, pi) { } return Promise.all(promises) - .then(([config, isBlacklisted = false, isReusedAddress = false, walletScore = null]) => { + .then(([config, blacklisted = false, isReusedAddress = false, walletScore = null]) => { const { rejectAddressReuse } = configManager.getCompliance(config) + const isBlacklisted = !!blacklisted if (isBlacklisted) { notifier.notifyIfActive('compliance', 'blacklistNotify', r.tx, false) From 63bb2c791d95fe2dce83c9433728678f779be256 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 16 Dec 2022 17:35:19 +0000 Subject: [PATCH 083/119] refactor: replace ternary operator with binary OR operator --- lib/cash-in/cash-in-tx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cash-in/cash-in-tx.js b/lib/cash-in/cash-in-tx.js index 09d0a235..a4e8c228 100644 --- a/lib/cash-in/cash-in-tx.js +++ b/lib/cash-in/cash-in-tx.js @@ -64,7 +64,7 @@ function post (machineTx, pi) { _.set('blacklisted', isBlacklisted), _.set('blacklistMessage', blacklisted?.content), _.set('addressReuse', addressReuse), - _.set('validWalletScore', _.isNil(walletScore) ? true : walletScore.isValid), + _.set('validWalletScore', _.isNil(walletScore) || walletScore.isValid), )) }) }) From b52ad6c8da41a64fef593ed2db6c06adc1296584 Mon Sep 17 00:00:00 2001 From: josepfo Date: Tue, 20 Dec 2022 11:49:47 +0000 Subject: [PATCH 084/119] fix: binance ticker default market fiat --- lib/plugins/common/ccxt.js | 9 +++++++-- lib/plugins/exchange/binance.js | 5 +++-- lib/plugins/ticker/ccxt.js | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/plugins/common/ccxt.js b/lib/plugins/common/ccxt.js index db98b460..5312b35c 100644 --- a/lib/plugins/common/ccxt.js +++ b/lib/plugins/common/ccxt.js @@ -23,7 +23,8 @@ const ALL = { bitpay: bitpay, coinbase: { CRYPTO: [BTC, ETH, LTC, DASH, ZEC, BCH, USDT, USDT_TRON, TRX, LN], - FIAT: 'ALL_CURRENCIES' + FIAT: 'ALL_CURRENCIES', + DEFAULT_FIAT_MARKET: 'EUR' }, binance: binance, bitfinex: bitfinex @@ -51,4 +52,8 @@ function isConfigValid (config, fields) { return _.every(it => it || it === 0)(values) } -module.exports = { buildMarket, ALL, verifyFiatSupport, isConfigValid } +function defaultFiatMarket (serviceName) { + return ALL[serviceName].DEFAULT_FIAT_MARKET +} + +module.exports = { buildMarket, ALL, verifyFiatSupport, isConfigValid, defaultFiatMarket } diff --git a/lib/plugins/exchange/binance.js b/lib/plugins/exchange/binance.js index 8a45723c..e1b4a4c4 100644 --- a/lib/plugins/exchange/binance.js +++ b/lib/plugins/exchange/binance.js @@ -6,7 +6,8 @@ const { ORDER_TYPES } = require('./consts') const ORDER_TYPE = ORDER_TYPES.MARKET const { BTC, BCH, XMR, ETH, LTC, ZEC, LN } = COINS const CRYPTO = [BTC, ETH, LTC, ZEC, BCH, XMR, LN] -const FIAT = ['USD', 'EUR'] +const FIAT = ['EUR'] +const DEFAULT_FIAT_MARKET = 'EUR' const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey'] const loadConfig = (account) => { @@ -17,4 +18,4 @@ const loadConfig = (account) => { return { ...mapped, timeout: 3000 } } -module.exports = { loadConfig, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } +module.exports = { loadConfig, DEFAULT_FIAT_MARKET, REQUIRED_CONFIG_FIELDS, CRYPTO, FIAT, ORDER_TYPE } diff --git a/lib/plugins/ticker/ccxt.js b/lib/plugins/ticker/ccxt.js index 336ef8a3..1f63ff3d 100644 --- a/lib/plugins/ticker/ccxt.js +++ b/lib/plugins/ticker/ccxt.js @@ -1,7 +1,7 @@ const ccxt = require('ccxt') const BN = require('../../bn') -const { buildMarket, verifyFiatSupport } = require('../common/ccxt') +const { buildMarket, verifyFiatSupport, defaultFiatMarket } = require('../common/ccxt') const { getRate } = require('../../../lib/forex') const RETRIES = 2 @@ -33,7 +33,7 @@ function ticker (fiatCode, cryptoCode, tickerName) { return getRate(RETRIES, fiatCode) .then(({ fxRate }) => { try { - return getCurrencyRates(ticker, 'USD', cryptoCode) + return getCurrencyRates(ticker, defaultFiatMarket(tickerName), cryptoCode) .then(res => ({ rates: { ask: res.rates.ask.times(fxRate), From bcfa108f0d0b17d17f62f64b0954ba5841cf8942 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 11:58:40 +0000 Subject: [PATCH 085/119] chore: update time of migration --- ...stic-blacklist.js => 1732881489395-coin-agnostic-blacklist.js} | 0 ...ced-blacklisting.js => 1732881489396-advanced-blacklisting.js} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename migrations/{1664907000312-coin-agnostic-blacklist.js => 1732881489395-coin-agnostic-blacklist.js} (100%) rename migrations/{1664916753772-advanced-blacklisting.js => 1732881489396-advanced-blacklisting.js} (100%) diff --git a/migrations/1664907000312-coin-agnostic-blacklist.js b/migrations/1732881489395-coin-agnostic-blacklist.js similarity index 100% rename from migrations/1664907000312-coin-agnostic-blacklist.js rename to migrations/1732881489395-coin-agnostic-blacklist.js diff --git a/migrations/1664916753772-advanced-blacklisting.js b/migrations/1732881489396-advanced-blacklisting.js similarity index 100% rename from migrations/1664916753772-advanced-blacklisting.js rename to migrations/1732881489396-advanced-blacklisting.js From 5956268a37c324574cb2230d596532efa7b1f39f Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 12:01:12 +0000 Subject: [PATCH 086/119] chore: update migration date --- ...657909035091-rates-screen.js => 1732881659436-rates-screen.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename migrations/{1657909035091-rates-screen.js => 1732881659436-rates-screen.js} (100%) diff --git a/migrations/1657909035091-rates-screen.js b/migrations/1732881659436-rates-screen.js similarity index 100% rename from migrations/1657909035091-rates-screen.js rename to migrations/1732881659436-rates-screen.js From 5881fe5d9c99f047bb03a9d9a9a60ed09c7804c1 Mon Sep 17 00:00:00 2001 From: Nikola Ubavic <53820106+ubavic@users.noreply.github.com> Date: Thu, 26 Jan 2023 14:47:06 +0100 Subject: [PATCH 087/119] fix: undefined address --- new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js b/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js index 39bcb1ab..9e929a0c 100644 --- a/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js +++ b/new-lamassu-admin/src/pages/Blacklist/BlacklistTable.js @@ -72,10 +72,7 @@ const BlacklistTable = ({ }} onConfirmed={() => { setErrorMessage(null) - handleDeleteEntry( - R.path(['cryptoCode'], toBeDeleted), - R.path(['address'], toBeDeleted) - ) + handleDeleteEntry(R.path(['address'], toBeDeleted)) }} errorMessage={errorMessage} /> From 818813718e856918ce85514dcf22e8d7394122f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Mon, 4 Jul 2022 18:27:04 +0100 Subject: [PATCH 088/119] feat: add automatic receipt printing toggle --- lib/graphql/resolvers.js | 1 + lib/graphql/types.js | 1 + lib/routes/pollingRoutes.js | 1 + .../src/pages/OperatorInfo/ReceiptPrinting.js | 22 +++++++++++++++++++ 4 files changed, 25 insertions(+) diff --git a/lib/graphql/resolvers.js b/lib/graphql/resolvers.js index 1270f1f3..b9c50cd3 100644 --- a/lib/graphql/resolvers.js +++ b/lib/graphql/resolvers.js @@ -36,6 +36,7 @@ const addReceiptInfo = receiptInfo => ret => { if (!receiptInfo) return ret const fields = [ + 'automaticPrint', 'paper', 'sms', 'operatorWebsite', diff --git a/lib/graphql/types.js b/lib/graphql/types.js index 89296c6c..15e42227 100644 --- a/lib/graphql/types.js +++ b/lib/graphql/types.js @@ -38,6 +38,7 @@ type MachineInfo { type ReceiptInfo { paper: Boolean! + automaticPrint: Boolean! sms: Boolean! operatorWebsite: Boolean! operatorEmail: Boolean! diff --git a/lib/routes/pollingRoutes.js b/lib/routes/pollingRoutes.js index f5bad40e..96ce9135 100644 --- a/lib/routes/pollingRoutes.js +++ b/lib/routes/pollingRoutes.js @@ -114,6 +114,7 @@ function poll (req, res, next) { locale, version, receiptPrintingActive: receipt.active, + automaticReceiptPrint: receipt.automaticPrint, smsReceiptActive: receipt.sms, enablePaperWalletOnly, twoWayMode: cashOutConfig.active, diff --git a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js index 2c59c3ce..f3c797f7 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/ReceiptPrinting.js @@ -83,6 +83,28 @@ const ReceiptPrinting = memo(({ wizard }) => { {receiptPrintingConfig.active ? 'Yes' : 'No'}
+
+

Automatic receipt printing

+
+ + saveConfig({ + variables: { + config: toNamespace( + namespaces.RECEIPT, + R.merge(receiptPrintingConfig, { + automaticPrint: event.target.checked + }) + ) + } + }) + } + /> + {receiptPrintingConfig.automaticPrint ? 'Yes' : 'No'} +
+

Offer SMS receipt

From 677d94487359a7cb9478baf2fe756a21da90e9e3 Mon Sep 17 00:00:00 2001 From: Neal Date: Tue, 17 Jan 2023 08:40:51 -0500 Subject: [PATCH 089/119] chore: add TRY for cash-out --- new-lamassu-admin/src/utils/bill-denominations.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/new-lamassu-admin/src/utils/bill-denominations.js b/new-lamassu-admin/src/utils/bill-denominations.js index 508a26fd..b6b9dbac 100644 --- a/new-lamassu-admin/src/utils/bill-denominations.js +++ b/new-lamassu-admin/src/utils/bill-denominations.js @@ -371,6 +371,18 @@ export default { }, polymer: false }, + TRY: { + thickness: 0x0d, + lengths: { + 5: [0x87, 0x7d], + 10: [0x8d, 0x83], + 20: [0x93, 0x89], + 50: [0x99, 0x8f], + 100: [0x9f, 0x95], + 200: [0xa5, 0x9b] + }, + polymer: false + }, TWD: { thickness: 0x0d, lengths: { From d917268d644bd87b21bc9f2915c34e402bf592c8 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 14:11:17 +0000 Subject: [PATCH 090/119] Revert "chore: add TRY for cash-out" This reverts commit 677d94487359a7cb9478baf2fe756a21da90e9e3. --- new-lamassu-admin/src/utils/bill-denominations.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/new-lamassu-admin/src/utils/bill-denominations.js b/new-lamassu-admin/src/utils/bill-denominations.js index b6b9dbac..508a26fd 100644 --- a/new-lamassu-admin/src/utils/bill-denominations.js +++ b/new-lamassu-admin/src/utils/bill-denominations.js @@ -371,18 +371,6 @@ export default { }, polymer: false }, - TRY: { - thickness: 0x0d, - lengths: { - 5: [0x87, 0x7d], - 10: [0x8d, 0x83], - 20: [0x93, 0x89], - 50: [0x99, 0x8f], - 100: [0x9f, 0x95], - 200: [0xa5, 0x9b] - }, - polymer: false - }, TWD: { thickness: 0x0d, lengths: { From 35e9c754e016fe7e541761cf25b2410b67557750 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 15:07:35 +0000 Subject: [PATCH 091/119] fix: correct function call on blacklist --- new-lamassu-admin/src/pages/Blacklist/Blacklist.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js index ebfea5c0..5e0e0ab0 100644 --- a/new-lamassu-admin/src/pages/Blacklist/Blacklist.js +++ b/new-lamassu-admin/src/pages/Blacklist/Blacklist.js @@ -187,7 +187,9 @@ const Blacklist = () => { const validateAddress = address => { try { - return !R.isEmpty(addressDetector.detectAddress(address).matches) + return !R.isEmpty( + addressDetector.getSupportedCoinsForAddress(address).matches + ) } catch { return false } From 277297c2e3f89c45b60214d264008017339b8d0d Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 15:08:00 +0000 Subject: [PATCH 092/119] chore: correct support page on wallet --- new-lamassu-admin/src/pages/Wallet/Wallet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/pages/Wallet/Wallet.js b/new-lamassu-admin/src/pages/Wallet/Wallet.js index 67b02bba..d79dda3f 100644 --- a/new-lamassu-admin/src/pages/Wallet/Wallet.js +++ b/new-lamassu-admin/src/pages/Wallet/Wallet.js @@ -147,7 +147,7 @@ const Wallet = ({ name: SCREEN_KEY }) => { knowledgebase article:

From 2e94d84c1911752016647cf14bfe71c706561b80 Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 15:08:25 +0000 Subject: [PATCH 093/119] fix: regular hoverable link --- new-lamassu-admin/src/components/Tooltip.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/new-lamassu-admin/src/components/Tooltip.js b/new-lamassu-admin/src/components/Tooltip.js index 8b56d6ff..c067c37b 100644 --- a/new-lamassu-admin/src/components/Tooltip.js +++ b/new-lamassu-admin/src/components/Tooltip.js @@ -93,7 +93,9 @@ const HoverableTooltip = memo(({ parentElements, children, width }) => {
{!R.isNil(parentElements) && ( -
+
{parentElements}
)} @@ -101,6 +103,7 @@ const HoverableTooltip = memo(({ parentElements, children, width }) => { From 21925ae145dfc41ca75f07b86da9215290877a83 Mon Sep 17 00:00:00 2001 From: Rafael Date: Mon, 2 Dec 2024 08:31:48 +0000 Subject: [PATCH 094/119] fix: build markets requests and caching --- lib/exchange.js | 29 ++++++++++++------- lib/new-admin/admin-server.js | 4 +++ lib/plugins/exchange/ccxt.js | 6 ++-- .../src/pages/Services/schemas/helper.js | 10 +++++-- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/lib/exchange.js b/lib/exchange.js index f9811bb8..ee325b2f 100644 --- a/lib/exchange.js +++ b/lib/exchange.js @@ -50,19 +50,26 @@ function active (settings, cryptoCode) { } function getMarkets () { - const filterExchanges = _.filter(it => it.class === 'exchange') + const filterExchanges = _.filter(it => it.class === 'exchange' && !it.dev && it.code !== 'no-exchange') const availableExchanges = _.map(it => it.code, filterExchanges(accounts.ACCOUNT_LIST)) - return _.reduce( - (acc, value) => - Promise.all([acc, ccxt.getMarkets(value, ALL_CRYPTOS)]) - .then(([a, markets]) => Promise.resolve({ - ...a, - [value]: markets - })), - Promise.resolve({}), - availableExchanges - ) + const fetchMarketForExchange = exchange => + ccxt.getMarkets(exchange, ALL_CRYPTOS) + .then(markets => ({ exchange, markets })) + .catch(error => ({ + exchange, + markets: [], + error: error.message + })) + + const transformToObject = _.reduce((acc, { exchange, markets }) => ({ + ...acc, + [exchange]: markets + }), {}) + + const promises = _.map(fetchMarketForExchange, availableExchanges) + return Promise.all(promises) + .then(transformToObject) } module.exports = { diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index 3b13daf8..24ac2424 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -14,6 +14,7 @@ const { ApolloServer } = require('apollo-server-express') require('../environment-helper') const { asyncLocalStorage, defaultStore } = require('../async-storage') const logger = require('../logger') +const exchange = require('../exchange') const { AuthDirective } = require('./graphql/directives') const { typeDefs, resolvers } = require('./graphql/schema') @@ -98,6 +99,9 @@ function run () { const serverLog = `lamassu-admin-server listening on port ${serverPort}` + // cache markets on startup + exchange.getMarkets().catch(console.error) + const webServer = https.createServer(certOptions, app) webServer.listen(serverPort, () => logger.info(serverLog)) }) diff --git a/lib/plugins/exchange/ccxt.js b/lib/plugins/exchange/ccxt.js index 63b57fa9..a69021ba 100644 --- a/lib/plugins/exchange/ccxt.js +++ b/lib/plugins/exchange/ccxt.js @@ -56,6 +56,8 @@ function calculatePrice (side, amount, orderBook) { } function _getMarkets (exchangeName, availableCryptos) { + const prunedCryptos = _.compose(_.uniq, _.map(coinUtils.getEquivalentCode))(availableCryptos) + try { const exchange = new ccxt[exchangeName]() const cryptosToQuoteAgainst = ['USDT'] @@ -65,13 +67,13 @@ function _getMarkets (exchangeName, availableCryptos) { .then(_.filter(it => (it.type === 'spot' || it.spot))) .then(res => _.reduce((acc, value) => { - if (_.includes(value.base, availableCryptos) && _.includes(value.quote, currencyCodes)) { + if (_.includes(value.base, prunedCryptos) && _.includes(value.quote, currencyCodes)) { if (value.quote === value.base) return acc if (_.isNil(acc[value.quote])) { return { ...acc, [value.quote]: [value.base] } } - + acc[value.quote].push(value.base) } return acc diff --git a/new-lamassu-admin/src/pages/Services/schemas/helper.js b/new-lamassu-admin/src/pages/Services/schemas/helper.js index c1c97870..58d97339 100644 --- a/new-lamassu-admin/src/pages/Services/schemas/helper.js +++ b/new-lamassu-admin/src/pages/Services/schemas/helper.js @@ -1,4 +1,4 @@ -import { ALL_CRYPTOS } from '@lamassu/coins' +import { ALL_CRYPTOS, utils as coinUtils } from '@lamassu/coins' import * as R from 'ramda' const WARNING_LEVELS = { @@ -29,8 +29,12 @@ const leadingZerosTest = (value, context) => { } const buildCurrencyOptions = markets => { + const prunedCoins = R.compose( + R.uniq, + R.map(coinUtils.getEquivalentCode) + )(ALL_CRYPTOS) return R.map(it => { - const unavailableCryptos = R.difference(ALL_CRYPTOS, markets[it]) + const unavailableCryptos = R.difference(prunedCoins, markets[it]) const unavailableCryptosFiltered = R.difference(unavailableCryptos, [it]) // As the markets can have stablecoins to trade against other crypto, filter them out, as there can't be pairs such as USDT/USDT const unavailableMarketsStr = @@ -44,7 +48,7 @@ const buildCurrencyOptions = markets => { const warningLevel = R.isEmpty(unavailableCryptosFiltered) ? WARNING_LEVELS.CLEAN : !R.isEmpty(unavailableCryptosFiltered) && - R.length(unavailableCryptosFiltered) < R.length(ALL_CRYPTOS) + R.length(unavailableCryptosFiltered) < R.length(prunedCoins) ? WARNING_LEVELS.PARTIAL : WARNING_LEVELS.IMPORTANT From 770fa13ea039e02ff4e4080796fd584b593bcd2b Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 18:57:19 +0000 Subject: [PATCH 095/119] chore: remove unused storybook code --- new-lamassu-admin/.storybook/main.js | 10 - new-lamassu-admin/README.md | 4 - new-lamassu-admin/package-lock.json | 4551 +----------------------- new-lamassu-admin/package.json | 9 - new-lamassu-admin/src/stories/index.js | 210 -- 5 files changed, 5 insertions(+), 4779 deletions(-) delete mode 100644 new-lamassu-admin/.storybook/main.js delete mode 100644 new-lamassu-admin/src/stories/index.js diff --git a/new-lamassu-admin/.storybook/main.js b/new-lamassu-admin/.storybook/main.js deleted file mode 100644 index c40a8faa..00000000 --- a/new-lamassu-admin/.storybook/main.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - stories: ['../src/stories/index.js'], - addons: [ - '@storybook/addon-actions', - '@storybook/addon-links', - '@storybook/addon-knobs', - '@storybook/addon-backgrounds', - '@storybook/preset-create-react-app' - ] -} diff --git a/new-lamassu-admin/README.md b/new-lamassu-admin/README.md index f5c1776e..e44a779e 100644 --- a/new-lamassu-admin/README.md +++ b/new-lamassu-admin/README.md @@ -36,10 +36,6 @@ You will also see any lint errors in the console. Runs eslint --fix on the src folder -### `npm storybook` - -Runs the storybook server - ### `npm test` Launches the test runner in the interactive watch mode.
diff --git a/new-lamassu-admin/package-lock.json b/new-lamassu-admin/package-lock.json index 6bc175d0..0dc0163d 100644 --- a/new-lamassu-admin/package-lock.json +++ b/new-lamassu-admin/package-lock.json @@ -1130,25 +1130,6 @@ } } }, - "@babel/plugin-proposal-decorators": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.12.13.tgz", - "integrity": "sha512-x2aOr5w4ARJoYHFKoG2iEUL/Xe99JAJXjAasHijXp3/KgaetJXGE62SmHgsW3Tia/XUT5AxF2YC0F+JyhPY/0Q==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-syntax-decorators": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", - "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", - "dev": true - } - } - }, "@babel/plugin-proposal-dynamic-import": { "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", @@ -1159,24 +1140,6 @@ "@babel/plugin-syntax-dynamic-import": "^7.8.0" } }, - "@babel/plugin-proposal-export-default-from": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.12.13.tgz", - "integrity": "sha512-idIsBT+DGXdOHL82U+8bwX4goHm/z10g8sGGrQroh+HCRcm7mDv/luaGdWJQMTuCX2FsdXS7X0Nyyzp4znAPJA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-syntax-export-default-from": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", - "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", - "dev": true - } - } - }, "@babel/plugin-proposal-export-namespace-from": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", @@ -1412,23 +1375,6 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, - "@babel/plugin-syntax-export-default-from": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.12.13.tgz", - "integrity": "sha512-gVry0zqoums0hA+EniCYK3gABhjYSLX1dVuwYpPw9DrLNA4/GovXySHVg4FGRsZht09ON/5C2NVx3keq+qqVGQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", - "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", - "dev": true - } - } - }, "@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", @@ -1896,24 +1842,6 @@ } } }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.13.tgz", - "integrity": "sha512-39/t9HtN+Jlc7EEY6oCSCf3kRrKIl2JULOGPnHZiaRjoYZEFaDXDZI32uE2NosQRh8o6N9B+8iGvDK7ToJhJaw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-syntax-flow": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", - "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", - "dev": true - } - } - }, "@babel/plugin-transform-for-of": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.13.tgz", @@ -3401,24 +3329,6 @@ } } }, - "@babel/preset-flow": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.12.13.tgz", - "integrity": "sha512-gcEjiwcGHa3bo9idURBp5fmJPcyFPOszPQjztXrOjUE2wWVqc6fIVJPgWPIQksaQ5XZ2HWiRsf2s1fRGVjUtVw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-transform-flow-strip-types": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", - "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", - "dev": true - } - } - }, "@babel/preset-modules": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", @@ -3453,62 +3363,6 @@ } } }, - "@babel/preset-typescript": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.12.13.tgz", - "integrity": "sha512-gYry7CeXwD2wtw5qHzrtzKaShEhOfTmKb4i0ZxeYBcBosN5VuAudsNbjX7Oj5EAfQ3K4s4HsVMQRRcqGsPvs2A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/helper-validator-option": "^7.12.11", - "@babel/plugin-transform-typescript": "^7.12.13" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz", - "integrity": "sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA==", - "dev": true - } - } - }, - "@babel/register": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.12.13.tgz", - "integrity": "sha512-fnCeRXj970S9seY+973oPALQg61TRvAaW0nRDe1f4ytKqM3fZgsNXewTZWmqZedg74LFIRpg/11dsrPZZvYs2g==", - "dev": true, - "requires": { - "find-cache-dir": "^2.0.0", - "lodash": "^4.17.19", - "make-dir": "^2.1.0", - "pirates": "^4.0.0", - "source-map-support": "^0.5.16" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "@babel/runtime": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.13.tgz", @@ -3643,128 +3497,11 @@ "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==", "dev": true }, - "@emotion/cache": { - "version": "10.0.29", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", - "dev": true, - "requires": { - "@emotion/sheet": "0.9.4", - "@emotion/stylis": "0.8.5", - "@emotion/utils": "0.11.3", - "@emotion/weak-memoize": "0.2.5" - } - }, - "@emotion/core": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.1.1.tgz", - "integrity": "sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.5", - "@emotion/cache": "^10.0.27", - "@emotion/css": "^10.0.27", - "@emotion/serialize": "^0.11.15", - "@emotion/sheet": "0.9.4", - "@emotion/utils": "0.11.3" - } - }, - "@emotion/css": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", - "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", - "dev": true, - "requires": { - "@emotion/serialize": "^0.11.15", - "@emotion/utils": "0.11.3", - "babel-plugin-emotion": "^10.0.27" - } - }, "@emotion/hash": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, - "@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "dev": true, - "requires": { - "@emotion/memoize": "0.7.4" - } - }, - "@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "dev": true - }, - "@emotion/serialize": { - "version": "0.11.16", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", - "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", - "dev": true, - "requires": { - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/unitless": "0.7.5", - "@emotion/utils": "0.11.3", - "csstype": "^2.5.7" - } - }, - "@emotion/sheet": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", - "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", - "dev": true - }, - "@emotion/styled": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz", - "integrity": "sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==", - "dev": true, - "requires": { - "@emotion/styled-base": "^10.0.27", - "babel-plugin-emotion": "^10.0.27" - } - }, - "@emotion/styled-base": { - "version": "10.0.31", - "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.0.31.tgz", - "integrity": "sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.5", - "@emotion/is-prop-valid": "0.8.8", - "@emotion/serialize": "^0.11.15", - "@emotion/utils": "0.11.3" - } - }, - "@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", - "dev": true - }, - "@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", - "dev": true - }, - "@emotion/utils": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", - "dev": true - }, - "@emotion/weak-memoize": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", - "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==", - "dev": true - }, "@eslint/eslintrc": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", @@ -3868,12 +3605,6 @@ "@hapi/hoek": "^8.3.0" } }, - "@icons/material": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", - "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", - "dev": true - }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -4521,16 +4252,6 @@ "react-is": "^16.8.0 || ^17.0.0" } }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", @@ -4611,18 +4332,6 @@ "resolved": "https://registry.npmjs.org/@reach/auto-id/-/auto-id-0.2.0.tgz", "integrity": "sha512-lVK/svL2HuQdp7jgvlrLkFsUx50Az9chAhxpiPwBqcS83I2pVWvXp98FOcSCCJCV++l115QmzHhFd+ycw1zLBg==" }, - "@reach/router": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.4.tgz", - "integrity": "sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA==", - "dev": true, - "requires": { - "create-react-context": "0.3.0", - "invariant": "^2.2.3", - "prop-types": "^15.6.1", - "react-lifecycles-compat": "^3.0.4" - } - }, "@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -4674,12 +4383,6 @@ "any-observable": "^0.3.0" } }, - "@scarf/scarf": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.1.0.tgz", - "integrity": "sha512-b2iE8kjjzzUo2WZ0xuE2N77kfnTds7ClrDxcz3Atz7h2XrNVoAPUoT75i7CY0st5x++70V91Y+c6RpBX9MX7Jg==", - "dev": true - }, "@simplewebauthn/browser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-3.1.0.tgz", @@ -4703,877 +4406,6 @@ "@sinonjs/commons": "^1.7.0" } }, - "@storybook/addon-actions": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.0.26.tgz", - "integrity": "sha512-9tWbAqSwzWWVz8zwAndZFusZYjIcRYgZUC0LqC8QlH79DgF3ASjw9y97+w1VTTAzdb6LYnsMuSpX6+8m5hrR4g==", - "dev": true, - "requires": { - "@storybook/addons": "6.0.26", - "@storybook/api": "6.0.26", - "@storybook/client-api": "6.0.26", - "@storybook/components": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/theming": "6.0.26", - "core-js": "^3.0.1", - "fast-deep-equal": "^3.1.1", - "global": "^4.3.2", - "lodash": "^4.17.15", - "polished": "^3.4.4", - "prop-types": "^15.7.2", - "react": "^16.8.3", - "react-inspector": "^5.0.1", - "regenerator-runtime": "^0.13.3", - "ts-dedent": "^1.1.1", - "util-deprecate": "^1.0.2", - "uuid": "^8.0.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } - } - }, - "@storybook/addon-backgrounds": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-6.0.26.tgz", - "integrity": "sha512-Y9t1s4N2PgTxLhO85w+WFnnclZNRdxGpsoiLDPkb63HajZvUa5/ogmIOrfFl5DX2zCpkgNLlskmDcEP6n835cA==", - "dev": true, - "requires": { - "@storybook/addons": "6.0.26", - "@storybook/api": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/components": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/theming": "6.0.26", - "core-js": "^3.0.1", - "memoizerific": "^1.11.3", - "react": "^16.8.3", - "regenerator-runtime": "^0.13.3" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - } - } - }, - "@storybook/addon-knobs": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-6.0.26.tgz", - "integrity": "sha512-a25hOepctnsqX1nym80HLKrn8fvXFqsbcL3ZkAZWAIXZhf+zPYTJFrw25FxvbyhktmjQv6l89jteAfGfC0g8DA==", - "dev": true, - "requires": { - "@storybook/addons": "6.0.26", - "@storybook/api": "6.0.26", - "@storybook/channels": "6.0.26", - "@storybook/client-api": "6.0.26", - "@storybook/components": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/theming": "6.0.26", - "copy-to-clipboard": "^3.0.8", - "core-js": "^3.0.1", - "escape-html": "^1.0.3", - "fast-deep-equal": "^3.1.1", - "global": "^4.3.2", - "lodash": "^4.17.15", - "prop-types": "^15.7.2", - "qs": "^6.6.0", - "react-color": "^2.17.0", - "react-lifecycles-compat": "^3.0.4", - "react-select": "^3.0.8", - "regenerator-runtime": "^0.13.3" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - } - } - }, - "@storybook/addon-links": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.0.26.tgz", - "integrity": "sha512-yHC6gSMW6qLqikf9yF62tXvykwCDLZy/7SRW9PEAsQcz27bilTh5swoV4HK24Gb6d+TAR+8sJK+BXuFlKFJE+Q==", - "dev": true, - "requires": { - "@storybook/addons": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/csf": "0.0.1", - "@storybook/router": "6.0.26", - "@types/qs": "^6.9.0", - "core-js": "^3.0.1", - "global": "^4.3.2", - "prop-types": "^15.7.2", - "qs": "^6.6.0", - "regenerator-runtime": "^0.13.3", - "ts-dedent": "^1.1.1" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - } - } - }, - "@storybook/addons": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.0.26.tgz", - "integrity": "sha512-OhAApFKgsj9an7FLYfHI4cJQuZ4Zm6yoGOpaxhOvKQMw7dXUPsLvbCyw/6dZOLvaFhjJjQiXtbxtZG+UjR8nvA==", - "dev": true, - "requires": { - "@storybook/api": "6.0.26", - "@storybook/channels": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/router": "6.0.26", - "@storybook/theming": "6.0.26", - "core-js": "^3.0.1", - "global": "^4.3.2", - "regenerator-runtime": "^0.13.3" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - } - } - }, - "@storybook/api": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.0.26.tgz", - "integrity": "sha512-aszDoz1c6T+eRtTUwWvySoyd3gRXmQxsingD084NnEp4VfFLA5H7VS/0sre0ZvU5GWh8d9COxY0DS2Ry/QSKvw==", - "dev": true, - "requires": { - "@reach/router": "^1.3.3", - "@storybook/channels": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/csf": "0.0.1", - "@storybook/router": "6.0.26", - "@storybook/semver": "^7.3.2", - "@storybook/theming": "6.0.26", - "@types/reach__router": "^1.3.5", - "core-js": "^3.0.1", - "fast-deep-equal": "^3.1.1", - "global": "^4.3.2", - "lodash": "^4.17.15", - "memoizerific": "^1.11.3", - "react": "^16.8.3", - "regenerator-runtime": "^0.13.3", - "store2": "^2.7.1", - "telejson": "^5.0.2", - "ts-dedent": "^1.1.1", - "util-deprecate": "^1.0.2" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - } - } - }, - "@storybook/channel-postmessage": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.0.26.tgz", - "integrity": "sha512-FT6lC8M5JlNBxPT0rYfmF1yl9mBv04nfYs82TZpp1CzpLxf7wxdCBZ8SSRmvWIVBoNwGZPDhIk5+6JWyDEISBg==", - "dev": true, - "requires": { - "@storybook/channels": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/core-events": "6.0.26", - "core-js": "^3.0.1", - "global": "^4.3.2", - "qs": "^6.6.0", - "telejson": "^5.0.2" - } - }, - "@storybook/channels": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.0.26.tgz", - "integrity": "sha512-H0iUorayYqS+zfhbjd+cYRzAdRLGLWUeWFu2Aa+oJ4/zeAQNL+DafWboHc567RQ4Vb5KqE5QZoCFskWUUYqJYA==", - "dev": true, - "requires": { - "core-js": "^3.0.1", - "ts-dedent": "^1.1.1", - "util-deprecate": "^1.0.2" - } - }, - "@storybook/client-api": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.0.26.tgz", - "integrity": "sha512-Qd5wR5b5lio/EchuJMhAmmJAE1pfvnEyu+JnyFGwMZLV9mN9NSspz+YsqbSCCDZsYcP5ewvPEnumIWqmj/wagQ==", - "dev": true, - "requires": { - "@storybook/addons": "6.0.26", - "@storybook/channel-postmessage": "6.0.26", - "@storybook/channels": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/csf": "0.0.1", - "@types/qs": "^6.9.0", - "@types/webpack-env": "^1.15.2", - "core-js": "^3.0.1", - "global": "^4.3.2", - "lodash": "^4.17.15", - "memoizerific": "^1.11.3", - "qs": "^6.6.0", - "stable": "^0.1.8", - "store2": "^2.7.1", - "ts-dedent": "^1.1.1", - "util-deprecate": "^1.0.2" - } - }, - "@storybook/client-logger": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.0.26.tgz", - "integrity": "sha512-VNoL6/oehVhn3hZi9vrTNT+C/3oAZKV+smfZFnPtsCR/Fq7CKbmsBd0pGPL57f81RU8e8WygwrIlAGJTDSNIjw==", - "dev": true, - "requires": { - "core-js": "^3.0.1", - "global": "^4.3.2" - } - }, - "@storybook/components": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.0.26.tgz", - "integrity": "sha512-8wigI1pDFJO1m1IQWPguOK+nOsaAVRWkVdu+2te/rDcIR9QNvMzzou0+Lhfp3zKSVT4E6mEoGB/TWXXF5Iq0sQ==", - "dev": true, - "requires": { - "@storybook/client-logger": "6.0.26", - "@storybook/csf": "0.0.1", - "@storybook/theming": "6.0.26", - "@types/overlayscrollbars": "^1.9.0", - "@types/react-color": "^3.0.1", - "@types/react-syntax-highlighter": "11.0.4", - "core-js": "^3.0.1", - "fast-deep-equal": "^3.1.1", - "global": "^4.3.2", - "lodash": "^4.17.15", - "markdown-to-jsx": "^6.11.4", - "memoizerific": "^1.11.3", - "overlayscrollbars": "^1.10.2", - "polished": "^3.4.4", - "popper.js": "^1.14.7", - "react": "^16.8.3", - "react-color": "^2.17.0", - "react-dom": "^16.8.3", - "react-popper-tooltip": "^2.11.0", - "react-syntax-highlighter": "^12.2.1", - "react-textarea-autosize": "^8.1.1", - "ts-dedent": "^1.1.1" - }, - "dependencies": { - "popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", - "dev": true - } - } - }, - "@storybook/core": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/core/-/core-6.0.26.tgz", - "integrity": "sha512-2kmkxbzDJVrjzCjlseffoQJwZRH9bHZUumo5m8gpbN9kVnADER7yd6RUf2Zle5BK3ExC+0PPI1Whfg0qkiXvqw==", - "dev": true, - "requires": { - "@babel/plugin-proposal-class-properties": "^7.8.3", - "@babel/plugin-proposal-decorators": "^7.8.3", - "@babel/plugin-proposal-export-default-from": "^7.8.3", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.1", - "@babel/plugin-proposal-object-rest-spread": "^7.9.6", - "@babel/plugin-proposal-optional-chaining": "^7.10.1", - "@babel/plugin-proposal-private-methods": "^7.8.3", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-arrow-functions": "^7.8.3", - "@babel/plugin-transform-block-scoping": "^7.8.3", - "@babel/plugin-transform-classes": "^7.9.5", - "@babel/plugin-transform-destructuring": "^7.9.5", - "@babel/plugin-transform-for-of": "^7.9.0", - "@babel/plugin-transform-parameters": "^7.9.5", - "@babel/plugin-transform-shorthand-properties": "^7.8.3", - "@babel/plugin-transform-spread": "^7.8.3", - "@babel/plugin-transform-template-literals": "^7.8.3", - "@babel/preset-env": "^7.9.6", - "@babel/preset-react": "^7.8.3", - "@babel/preset-typescript": "^7.9.0", - "@babel/register": "^7.10.5", - "@storybook/addons": "6.0.26", - "@storybook/api": "6.0.26", - "@storybook/channel-postmessage": "6.0.26", - "@storybook/channels": "6.0.26", - "@storybook/client-api": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/components": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/csf": "0.0.1", - "@storybook/node-logger": "6.0.26", - "@storybook/router": "6.0.26", - "@storybook/semver": "^7.3.2", - "@storybook/theming": "6.0.26", - "@storybook/ui": "6.0.26", - "@types/glob-base": "^0.3.0", - "@types/micromatch": "^4.0.1", - "@types/node-fetch": "^2.5.4", - "airbnb-js-shims": "^2.2.1", - "ansi-to-html": "^0.6.11", - "autoprefixer": "^9.7.2", - "babel-loader": "^8.0.6", - "babel-plugin-emotion": "^10.0.20", - "babel-plugin-macros": "^2.8.0", - "babel-preset-minify": "^0.5.0 || 0.6.0-alpha.5", - "better-opn": "^2.0.0", - "boxen": "^4.1.0", - "case-sensitive-paths-webpack-plugin": "^2.2.0", - "chalk": "^4.0.0", - "cli-table3": "0.6.0", - "commander": "^5.0.0", - "core-js": "^3.0.1", - "css-loader": "^3.5.3", - "detect-port": "^1.3.0", - "dotenv-webpack": "^1.7.0", - "ejs": "^3.1.2", - "express": "^4.17.0", - "file-loader": "^6.0.0", - "file-system-cache": "^1.0.5", - "find-up": "^4.1.0", - "fork-ts-checker-webpack-plugin": "^4.1.4", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "glob-base": "^0.3.0", - "glob-promise": "^3.4.0", - "global": "^4.3.2", - "html-webpack-plugin": "^4.2.1", - "inquirer": "^7.0.0", - "interpret": "^2.0.0", - "ip": "^1.1.5", - "json5": "^2.1.1", - "lazy-universal-dotenv": "^3.0.1", - "micromatch": "^4.0.2", - "node-fetch": "^2.6.0", - "pkg-dir": "^4.2.0", - "pnp-webpack-plugin": "1.6.4", - "postcss-flexbugs-fixes": "^4.1.0", - "postcss-loader": "^3.0.0", - "pretty-hrtime": "^1.0.3", - "qs": "^6.6.0", - "raw-loader": "^4.0.1", - "react-dev-utils": "^10.0.0", - "regenerator-runtime": "^0.13.3", - "resolve-from": "^5.0.0", - "serve-favicon": "^2.5.0", - "shelljs": "^0.8.3", - "stable": "^0.1.8", - "style-loader": "^1.2.1", - "terser-webpack-plugin": "^3.0.0", - "ts-dedent": "^1.1.1", - "unfetch": "^4.1.0", - "url-loader": "^4.0.0", - "util-deprecate": "^1.0.2", - "webpack": "^4.43.0", - "webpack-dev-middleware": "^3.7.0", - "webpack-hot-middleware": "^2.25.0", - "webpack-virtual-modules": "^0.2.2" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } - } - }, - "@storybook/core-events": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.0.26.tgz", - "integrity": "sha512-nWjS/+kMiw31OPgeJQaiFsJk9ZJJo3/d4c+kc6GOl2iC1H3Q4/5cm3NvJBn/7bUtKHmSFwfbDouj+XjUk5rZbQ==", - "dev": true, - "requires": { - "core-js": "^3.0.1" - } - }, - "@storybook/csf": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", - "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "@storybook/node-logger": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.0.26.tgz", - "integrity": "sha512-mdILu91d/2ZgYfICoAMBjwBAYOgjk2URsPudrs5+23lFoPPIwf4CPWcfgs0f4GdfoICk3kV0W7+8bIARhRKp3g==", - "dev": true, - "requires": { - "@types/npmlog": "^4.1.2", - "chalk": "^4.0.0", - "core-js": "^3.0.1", - "npmlog": "^4.1.2", - "pretty-hrtime": "^1.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@storybook/preset-create-react-app": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@storybook/preset-create-react-app/-/preset-create-react-app-3.1.5.tgz", - "integrity": "sha512-tzYcCRD5j22/HoDZ1tvsKaVnzyd4qqTE9sn3cx56Reb0XHcm4XkvG87jx0NvBGPCZrsThyBAtB3+XNxoFbI+9Q==", - "dev": true, - "requires": { - "@types/babel__core": "^7.1.7", - "@types/webpack": "^4.41.13", - "babel-plugin-react-docgen": "^4.1.0", - "pnp-webpack-plugin": "^1.6.4", - "react-docgen-typescript-plugin": "^0.6.2", - "semver": "^7.3.2" - } - }, - "@storybook/react": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-6.0.26.tgz", - "integrity": "sha512-X02VpIEhpVc4avYiff861c015++tvMVSXJSrDP5J1xTAglVEiRFcU0Kn5h96o9N8FTup2n2xyj6Y7e8oC9yLXQ==", - "dev": true, - "requires": { - "@babel/preset-flow": "^7.0.0", - "@babel/preset-react": "^7.0.0", - "@storybook/addons": "6.0.26", - "@storybook/core": "6.0.26", - "@storybook/node-logger": "6.0.26", - "@storybook/semver": "^7.3.2", - "@svgr/webpack": "^5.4.0", - "@types/webpack-env": "^1.15.2", - "babel-plugin-add-react-displayname": "^0.0.5", - "babel-plugin-named-asset-import": "^0.3.1", - "babel-plugin-react-docgen": "^4.1.0", - "core-js": "^3.0.1", - "global": "^4.3.2", - "lodash": "^4.17.15", - "prop-types": "^15.7.2", - "react-dev-utils": "^10.0.0", - "react-docgen-typescript-plugin": "^0.5.2", - "regenerator-runtime": "^0.13.3", - "ts-dedent": "^1.1.1", - "webpack": "^4.43.0" - }, - "dependencies": { - "react-docgen-typescript-plugin": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.5.2.tgz", - "integrity": "sha512-NQfWyWLmzUnedkiN2nPDb6Nkm68ik6fqbC3UvgjqYSeZsbKijXUA4bmV6aU7qICOXdop9PevPdjEgJuAN0nNVQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "endent": "^2.0.1", - "micromatch": "^4.0.2", - "react-docgen-typescript": "^1.20.1", - "react-docgen-typescript-loader": "^3.7.2", - "tslib": "^2.0.0" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true - } - } - }, - "@storybook/router": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.0.26.tgz", - "integrity": "sha512-kQ1LF/2gX3IkjS1wX7CsoeBc9ptHQzOsyax16rUyJa769DT5vMNtFtQxjNXMqSiSapPg2yrXJFKQNaoWvKgQEQ==", - "dev": true, - "requires": { - "@reach/router": "^1.3.3", - "@types/reach__router": "^1.3.5", - "core-js": "^3.0.1", - "global": "^4.3.2", - "memoizerific": "^1.11.3", - "qs": "^6.6.0" - } - }, - "@storybook/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", - "dev": true, - "requires": { - "core-js": "^3.6.5", - "find-up": "^4.1.0" - } - }, - "@storybook/theming": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.0.26.tgz", - "integrity": "sha512-9yon2ofb9a+RT1pdvn8Njydy7XRw0qXcIsMqGsJRKoZecmRRozqB6DxH9Gbdf1vRSbM9gYUUDjbiMDFz7+4RiQ==", - "dev": true, - "requires": { - "@emotion/core": "^10.0.20", - "@emotion/is-prop-valid": "^0.8.6", - "@emotion/styled": "^10.0.17", - "@storybook/client-logger": "6.0.26", - "core-js": "^3.0.1", - "deep-object-diff": "^1.1.0", - "emotion-theming": "^10.0.19", - "global": "^4.3.2", - "memoizerific": "^1.11.3", - "polished": "^3.4.4", - "resolve-from": "^5.0.0", - "ts-dedent": "^1.1.1" - } - }, - "@storybook/ui": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-6.0.26.tgz", - "integrity": "sha512-Jb7oUJs6uyW+rM4zA8xDn9T0/0XtUAOC/zBl6ofdhYU9rVjYKAQUJqmYgUHNOggq1NGS7BVp1RJIzDWGYEagsA==", - "dev": true, - "requires": { - "@emotion/core": "^10.0.20", - "@storybook/addons": "6.0.26", - "@storybook/api": "6.0.26", - "@storybook/channels": "6.0.26", - "@storybook/client-logger": "6.0.26", - "@storybook/components": "6.0.26", - "@storybook/core-events": "6.0.26", - "@storybook/router": "6.0.26", - "@storybook/semver": "^7.3.2", - "@storybook/theming": "6.0.26", - "@types/markdown-to-jsx": "^6.11.0", - "copy-to-clipboard": "^3.0.8", - "core-js": "^3.0.1", - "core-js-pure": "^3.0.1", - "emotion-theming": "^10.0.19", - "fuse.js": "^3.6.1", - "global": "^4.3.2", - "lodash": "^4.17.15", - "markdown-to-jsx": "^6.11.4", - "memoizerific": "^1.11.3", - "polished": "^3.4.4", - "qs": "^6.6.0", - "react": "^16.8.3", - "react-dom": "^16.8.3", - "react-draggable": "^4.0.3", - "react-helmet-async": "^1.0.2", - "react-hotkeys": "2.0.0", - "react-sizeme": "^2.6.7", - "regenerator-runtime": "^0.13.3", - "resolve-from": "^5.0.0", - "store2": "^2.7.1" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - } - } - }, "@surma/rollup-plugin-off-main-thread": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz", @@ -5759,41 +4591,6 @@ } } }, - "@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" - }, - "dependencies": { - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - } - } - }, "@types/anymatch": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", @@ -5841,12 +4638,6 @@ "@babel/types": "^7.3.0" } }, - "@types/braces": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.0.tgz", - "integrity": "sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==", - "dev": true - }, "@types/eslint": { "version": "7.2.6", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", @@ -5873,12 +4664,6 @@ "@types/node": "*" } }, - "@types/glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@types/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-pYHWiDR+EOUN18F9byiAoQNUMZ0=", - "dev": true - }, "@types/graceful-fs": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", @@ -5894,12 +4679,6 @@ "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", "dev": true }, - "@types/is-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.0.tgz", - "integrity": "sha512-iTs9HReBu7evG77Q4EC8hZnqRt57irBDkK9nvmHroiOIVwYMQc4IvYvdRgwKfYepunIY7Oh/dBuuld+Gj9uo6w==", - "dev": true - }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -5946,24 +4725,6 @@ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.170.tgz", "integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q==" }, - "@types/markdown-to-jsx": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz", - "integrity": "sha512-30nFYpceM/ZEvhGiqWjm5quLUxNeld0HCzJEXMZZDpq53FPkS85mTwkWtCXzCqq8s5JYLgM5W392a02xn8Bdaw==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, - "@types/micromatch": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.1.tgz", - "integrity": "sha512-my6fLBvpY70KattTNzYOK6KU1oR1+UCz9ug/JbcF5UrEmeCt9P7DV2t7L8+t18mMPINqGQCE4O8PLOPbI84gxw==", - "dev": true, - "requires": { - "@types/braces": "*" - } - }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -5975,34 +4736,12 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.8.tgz", "integrity": "sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==" }, - "@types/node-fetch": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", - "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", - "dev": true, - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, "@types/normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, - "@types/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-4QQmOF5KlwfxJ5IGXFIudkeLCdMABz03RcUXu+LCb24zmln8QW6aDjuGl4d4XPVLf2j+FnjelHTP7dvceAFbhA==", - "dev": true - }, - "@types/overlayscrollbars": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@types/overlayscrollbars/-/overlayscrollbars-1.12.0.tgz", - "integrity": "sha512-h/pScHNKi4mb+TrJGDon8Yb06ujFG0mSg12wIO0sWMUF3dQIe2ExRRdNRviaNt9IjxIiOfnRr7FsQAdHwK4sMg==", - "dev": true - }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -6026,21 +4765,6 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", "dev": true }, - "@types/qs": { - "version": "6.9.5", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", - "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==", - "dev": true - }, - "@types/reach__router": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.3.7.tgz", - "integrity": "sha512-cyBEb8Ef3SJNH5NYEIDGPoMMmYUxROatuxbICusVRQIqZUB85UCt6R2Ok60tKS/TABJsJYaHyNTW3kqbpxlMjg==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/react": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.1.tgz", @@ -6057,25 +4781,6 @@ } } }, - "@types/react-color": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.4.tgz", - "integrity": "sha512-EswbYJDF1kkrx93/YU+BbBtb46CCtDMvTiGmcOa/c5PETnwTiSWoseJ1oSWeRl/4rUXkhME9bVURvvPg0W5YQw==", - "dev": true, - "requires": { - "@types/react": "*", - "@types/reactcss": "*" - } - }, - "@types/react-syntax-highlighter": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz", - "integrity": "sha512-9GfTo3a0PHwQeTVoqs0g5bS28KkSY48pp5659wA+Dp4MqceDEa8EHBqrllJvvtyusszyJhViUEap0FDvlk/9Zg==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/react-transition-group": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", @@ -6084,15 +4789,6 @@ "@types/react": "*" } }, - "@types/reactcss": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.3.tgz", - "integrity": "sha512-d2gQQ0IL6hXLnoRfVYZukQNWHuVsE75DzFTLPUuyyEhJS8G2VvlE+qfQQ91SJjaMqlURRCNIsX7Jcsw6cEuJlA==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", @@ -6148,12 +4844,6 @@ "source-map": "^0.6.0" } }, - "@types/webpack-env": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.0.tgz", - "integrity": "sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw==", - "dev": true - }, "@types/webpack-sources": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", @@ -6508,55 +5198,6 @@ "@xtuc/long": "4.2.2" } }, - "@webpack-contrib/schema-utils": { - "version": "1.0.0-beta.0", - "resolved": "https://registry.npmjs.org/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz", - "integrity": "sha512-LonryJP+FxQQHsjGBi6W786TQB1Oym+agTpY0c+Kj8alnIw+DLUJb6SI8Y1GHGhLCH1yPRrucjObUmxNICQ1pg==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chalk": "^2.3.2", - "strip-ansi": "^4.0.0", - "text-table": "^0.2.0", - "webpack-log": "^1.1.2" - }, - "dependencies": { - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "webpack-log": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz", - "integrity": "sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA==", - "dev": true, - "requires": { - "chalk": "^2.1.0", - "log-symbols": "^2.1.0", - "loglevelnext": "^1.0.1", - "uuid": "^3.1.0" - } - } - } - }, "@welldone-software/why-did-you-render": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-3.6.0.tgz", @@ -6701,31 +5342,6 @@ "indent-string": "^4.0.0" } }, - "airbnb-js-shims": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz", - "integrity": "sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==", - "dev": true, - "requires": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "array.prototype.flatmap": "^1.2.1", - "es5-shim": "^4.5.13", - "es6-shim": "^0.35.5", - "function.prototype.name": "^1.1.0", - "globalthis": "^1.0.0", - "object.entries": "^1.1.0", - "object.fromentries": "^2.0.0 || ^1.0.0", - "object.getownpropertydescriptors": "^2.0.3", - "object.values": "^1.1.0", - "promise.allsettled": "^1.0.0", - "promise.prototype.finally": "^3.1.0", - "string.prototype.matchall": "^4.0.0 || ^3.0.1", - "string.prototype.padend": "^3.0.0", - "string.prototype.padstart": "^3.0.0", - "symbol.prototype.description": "^1.0.0" - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -6750,49 +5366,6 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, - "ansi-align": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", - "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", - "dev": true, - "requires": { - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, "ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", @@ -6826,15 +5399,6 @@ "color-convert": "^1.9.0" } }, - "ansi-to-html": { - "version": "0.6.14", - "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.14.tgz", - "integrity": "sha512-7ZslfB1+EnFSDO5Ju+ue5Y6It19DRnZXWv8jrGHgIlPna5Mh4jz7BV5jCbQneXNFurQcKoolaaAjHtgSBfOIuA==", - "dev": true, - "requires": { - "entities": "^1.1.2" - } - }, "any-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", @@ -6950,12 +5514,6 @@ "tslib": "^1.10.0" } }, - "app-root-dir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", - "integrity": "sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg=", - "dev": true - }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -6968,56 +5526,6 @@ "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "arg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz", @@ -7127,19 +5635,6 @@ "function-bind": "^1.1.1" } }, - "array.prototype.map": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.3.tgz", - "integrity": "sha512-nNcb30v0wfDyIe26Yif3PcV1JXQp4zEeEfupG7L4SRjnD6HLbO5b2a7eVSba53bOx4YCHYMBHt+Fp4vYstneRA==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.5" - } - }, "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -7185,23 +5680,6 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, - "ast-types": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", - "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", - "dev": true, - "requires": { - "tslib": "^2.0.1" - }, - "dependencies": { - "tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", - "dev": true - } - } - }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -7337,65 +5815,6 @@ "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", "dev": true }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -7419,48 +5838,6 @@ "babylon": "^6.18.0" } }, - "babel-helper-evaluate-path": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", - "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", - "dev": true - }, - "babel-helper-flip-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", - "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", - "dev": true - }, - "babel-helper-is-nodes-equiv": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", - "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", - "dev": true - }, - "babel-helper-is-void-0": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", - "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", - "dev": true - }, - "babel-helper-mark-eval-scopes": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", - "dev": true - }, - "babel-helper-remove-or-void": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", - "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", - "dev": true - }, - "babel-helper-to-multiple-sequence-expressions": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz", - "integrity": "sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==", - "dev": true - }, "babel-jest": { "version": "26.6.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", @@ -7528,52 +5905,6 @@ } } }, - "babel-loader": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz", - "integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==", - "dev": true, - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "babel-plugin-add-react-displayname": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", - "integrity": "sha1-M51M3be2X9YtHfnbn+BN4TQSK9U=", - "dev": true - }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", @@ -7583,32 +5914,6 @@ "object.assign": "^4.1.0" } }, - "babel-plugin-emotion": { - "version": "10.0.33", - "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz", - "integrity": "sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/serialize": "^0.11.16", - "babel-plugin-macros": "^2.0.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^1.0.5", - "find-root": "^1.1.0", - "source-map": "^0.5.7" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, "babel-plugin-istanbul": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", @@ -7645,153 +5950,18 @@ "resolve": "^1.12.0" } }, - "babel-plugin-minify-builtins": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz", - "integrity": "sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==", - "dev": true - }, - "babel-plugin-minify-constant-folding": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz", - "integrity": "sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0" - } - }, - "babel-plugin-minify-dead-code-elimination": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz", - "integrity": "sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-mark-eval-scopes": "^0.4.3", - "babel-helper-remove-or-void": "^0.4.3", - "lodash": "^4.17.11" - } - }, - "babel-plugin-minify-flip-comparisons": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", - "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", - "dev": true, - "requires": { - "babel-helper-is-void-0": "^0.4.3" - } - }, - "babel-plugin-minify-guarded-expressions": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", - "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-flip-expressions": "^0.4.3" - } - }, - "babel-plugin-minify-infinity": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", - "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", - "dev": true - }, - "babel-plugin-minify-mangle-names": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz", - "integrity": "sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==", - "dev": true, - "requires": { - "babel-helper-mark-eval-scopes": "^0.4.3" - } - }, - "babel-plugin-minify-numeric-literals": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", - "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", - "dev": true - }, - "babel-plugin-minify-replace": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz", - "integrity": "sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==", - "dev": true - }, - "babel-plugin-minify-simplify": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz", - "integrity": "sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-flip-expressions": "^0.4.3", - "babel-helper-is-nodes-equiv": "^0.0.1", - "babel-helper-to-multiple-sequence-expressions": "^0.5.0" - } - }, - "babel-plugin-minify-type-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", - "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", - "dev": true, - "requires": { - "babel-helper-is-void-0": "^0.4.3" - } - }, "babel-plugin-named-asset-import": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz", "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw==", "dev": true }, - "babel-plugin-react-docgen": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz", - "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==", - "dev": true, - "requires": { - "ast-types": "^0.14.2", - "lodash": "^4.17.15", - "react-docgen": "^5.0.0" - } - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", - "dev": true - }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "dev": true }, - "babel-plugin-transform-inline-consecutive-adds": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", - "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", - "dev": true - }, - "babel-plugin-transform-member-expression-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", - "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", - "dev": true - }, - "babel-plugin-transform-merge-sibling-variables": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", - "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", - "dev": true - }, - "babel-plugin-transform-minify-booleans": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", - "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", - "dev": true - }, "babel-plugin-transform-object-rest-spread": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", @@ -7802,60 +5972,12 @@ "babel-runtime": "^6.26.0" } }, - "babel-plugin-transform-property-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", - "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, "babel-plugin-transform-react-remove-prop-types": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", "dev": true }, - "babel-plugin-transform-regexp-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", - "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", - "dev": true - }, - "babel-plugin-transform-remove-console": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", - "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", - "dev": true - }, - "babel-plugin-transform-remove-debugger": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", - "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", - "dev": true - }, - "babel-plugin-transform-remove-undefined": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz", - "integrity": "sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==", - "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0" - } - }, - "babel-plugin-transform-simplify-comparison-operators": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", - "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", - "dev": true - }, - "babel-plugin-transform-undefined-to-void": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", - "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", - "dev": true - }, "babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -7886,37 +6008,6 @@ "babel-preset-current-node-syntax": "^1.0.0" } }, - "babel-preset-minify": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz", - "integrity": "sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==", - "dev": true, - "requires": { - "babel-plugin-minify-builtins": "^0.5.0", - "babel-plugin-minify-constant-folding": "^0.5.0", - "babel-plugin-minify-dead-code-elimination": "^0.5.1", - "babel-plugin-minify-flip-comparisons": "^0.4.3", - "babel-plugin-minify-guarded-expressions": "^0.4.4", - "babel-plugin-minify-infinity": "^0.4.3", - "babel-plugin-minify-mangle-names": "^0.5.0", - "babel-plugin-minify-numeric-literals": "^0.4.3", - "babel-plugin-minify-replace": "^0.5.0", - "babel-plugin-minify-simplify": "^0.5.1", - "babel-plugin-minify-type-constructors": "^0.4.3", - "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", - "babel-plugin-transform-member-expression-literals": "^6.9.4", - "babel-plugin-transform-merge-sibling-variables": "^6.9.4", - "babel-plugin-transform-minify-booleans": "^6.9.4", - "babel-plugin-transform-property-literals": "^6.9.4", - "babel-plugin-transform-regexp-constructors": "^0.4.3", - "babel-plugin-transform-remove-console": "^6.9.4", - "babel-plugin-transform-remove-debugger": "^6.9.4", - "babel-plugin-transform-remove-undefined": "^0.5.0", - "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", - "babel-plugin-transform-undefined-to-void": "^6.9.4", - "lodash": "^4.17.11" - } - }, "babel-preset-react-app": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.0.tgz", @@ -8272,12 +6363,6 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, - "batch-processor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz", - "integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=", - "dev": true - }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -8292,15 +6377,6 @@ "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" }, - "better-opn": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz", - "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==", - "dev": true, - "requires": { - "open": "^7.0.3" - } - }, "bfj": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", @@ -8340,7 +6416,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "dev": true + "dev": true, + "optional": true }, "bindings": { "version": "1.5.0", @@ -8465,12 +6542,6 @@ "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" }, - "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", - "dev": true - }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", @@ -8558,117 +6629,6 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, - "boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -9049,12 +7009,6 @@ "get-intrinsic": "^1.0.2" } }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, "caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", @@ -9160,24 +7114,6 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, - "character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "dev": true - }, - "character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "dev": true - }, - "character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "dev": true - }, "check-types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", @@ -9189,6 +7125,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", "dev": true, + "optional": true, "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -9279,12 +7216,6 @@ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -9294,76 +7225,6 @@ "restore-cursor": "^2.0.0" } }, - "cli-table3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", - "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", - "dev": true, - "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "clipboard": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", - "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", - "dev": true, - "optional": true, - "requires": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, "clipboardy": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.2.3.tgz", @@ -9515,12 +7376,6 @@ "delayed-stream": "~1.0.0" } }, - "comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", - "dev": true - }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -9681,12 +7536,6 @@ "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", "dev": true }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -9906,16 +7755,6 @@ "sha.js": "^2.4.8" } }, - "create-react-context": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", - "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", - "dev": true, - "requires": { - "gud": "^1.0.0", - "warning": "^4.0.3" - } - }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -10044,41 +7883,6 @@ "isobject": "^3.0.1" } }, - "css-loader": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", - "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "cssesc": "^3.0.0", - "icss-utils": "^4.1.1", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.32", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.2.0", - "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^2.7.0", - "semver": "^6.3.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "css-prefers-color-scheme": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz", @@ -10668,12 +8472,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "deep-object-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz", - "integrity": "sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==", - "dev": true - }, "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", @@ -10803,19 +8601,6 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -10850,27 +8635,6 @@ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", "dev": true }, - "detect-port": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", - "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", - "dev": true, - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, "diff-sequences": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", @@ -10995,12 +8759,6 @@ } } }, - "dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", - "dev": true - }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -11076,36 +8834,12 @@ "is-obj": "^2.0.0" } }, - "dotenv": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", - "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", - "dev": true - }, - "dotenv-defaults": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-1.1.1.tgz", - "integrity": "sha512-6fPRo9o/3MxKvmRZBD3oNFdxODdhJtIy1zcJeUSCs6HCy4tarUpd+G67UTU9tF6OWXeSPqsm4fPAB+2eY9Rt9Q==", - "dev": true, - "requires": { - "dotenv": "^6.2.0" - } - }, "dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, - "dotenv-webpack": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-1.8.0.tgz", - "integrity": "sha512-o8pq6NLBehtrqA8Jv8jFQNtG9nhRtVqmoD4yWbgUyoU3+9WBlPe+c2EAiaJok9RB28QvrWvdWLZGeTT5aATDMg==", - "dev": true, - "requires": { - "dotenv-defaults": "^1.0.2" - } - }, "downshift": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/downshift/-/downshift-3.3.4.tgz", @@ -11220,15 +8954,6 @@ "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", "dev": true }, - "element-resize-detector": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.1.tgz", - "integrity": "sha512-BdFsPepnQr9fznNPF9nF4vQ457U/ZJXQDSNF1zBe7yaga8v9AdZf3/NElYxFdUh7SitSGt040QygiTo6dtatIw==", - "dev": true, - "requires": { - "batch-processor": "1.0.0" - } - }, "elliptic": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", @@ -11262,17 +8987,6 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, - "emotion-theming": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/emotion-theming/-/emotion-theming-10.0.27.tgz", - "integrity": "sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.5", - "@emotion/weak-memoize": "0.2.5", - "hoist-non-react-statics": "^3.3.0" - } - }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -11288,17 +9002,6 @@ "once": "^1.4.0" } }, - "endent": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/endent/-/endent-2.0.1.tgz", - "integrity": "sha512-mADztvcC+vCk4XEZaCz6xIPO2NHQuprv5CAEjuVAu6aZwqAj7nVNlMyl1goPFYqCCpS2OJV9jwpumJLkotZrNw==", - "dev": true, - "requires": { - "dedent": "^0.7.0", - "fast-json-parse": "^1.0.3", - "objectorarray": "^1.0.4" - } - }, "enhanced-resolve": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", @@ -11428,39 +9131,6 @@ "string.prototype.trimstart": "^1.0.3" } }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "dependencies": { - "is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0" - } - } - } - }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -11483,12 +9153,6 @@ "next-tick": "~1.0.0" } }, - "es5-shim": { - "version": "4.5.15", - "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.15.tgz", - "integrity": "sha512-FYpuxEjMeDvU4rulKqFdukQyZSTpzhg4ScQHrAosrlVpR6GFyaw14f74yn2+4BugniIS0Frpg7TvwZocU4ZMTw==", - "dev": true - }, "es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", @@ -11500,12 +9164,6 @@ "es6-symbol": "^3.1.1" } }, - "es6-shim": { - "version": "0.35.6", - "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz", - "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==", - "dev": true - }, "es6-symbol": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", @@ -12780,12 +10438,6 @@ "picomatch": "^2.2.1" } }, - "fast-json-parse": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", - "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", - "dev": true - }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -12833,15 +10485,6 @@ "reusify": "^1.0.4" } }, - "fault": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", - "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", - "dev": true, - "requires": { - "format": "^0.2.0" - } - }, "faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", @@ -12884,52 +10527,6 @@ "flat-cache": "^3.0.4" } }, - "file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, "file-saver": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz", @@ -12950,38 +10547,6 @@ } } }, - "file-system-cache": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-1.0.5.tgz", - "integrity": "sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08=", - "dev": true, - "requires": { - "bluebird": "^3.3.5", - "fs-extra": "^0.30.0", - "ramda": "^0.21.0" - }, - "dependencies": { - "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "ramda": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz", - "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=", - "dev": true - } - } - }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -12996,12 +10561,6 @@ "minimatch": "^3.0.4" } }, - "filesize": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", - "integrity": "sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg==", - "dev": true - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -13115,12 +10674,6 @@ } } }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -13521,23 +11074,6 @@ } } }, - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=", - "dev": true - }, "formik": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/formik/-/formik-2.2.0.tgz", @@ -13707,89 +11243,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "function.prototype.name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.3.tgz", - "integrity": "sha512-H51qkbNSp8mtkJt+nyW1gyStBiKZxfRqySNUR99ylq6BPXHKI4SEvIlTKp4odLfjRKJV04DFWMU3G/YRlQOsag==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "functions-have-names": "^1.2.1" - } - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "functions-have-names": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", - "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", - "dev": true - }, - "fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -13866,42 +11325,6 @@ "path-is-absolute": "^1.0.0" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, "glob-parent": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", @@ -13911,31 +11334,6 @@ "is-glob": "^4.0.1" } }, - "glob-promise": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz", - "integrity": "sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==", - "dev": true, - "requires": { - "@types/glob": "*" - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dev": true, - "requires": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, "global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -13962,15 +11360,6 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, - "globalthis": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz", - "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, "globby": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", @@ -13985,16 +11374,6 @@ "slash": "^3.0.0" } }, - "good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "dev": true, - "optional": true, - "requires": { - "delegate": "^3.1.2" - } - }, "google-libphonenumber": { "version": "3.2.22", "resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.22.tgz", @@ -14026,12 +11405,6 @@ "dev": true, "optional": true }, - "gud": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", - "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==", - "dev": true - }, "gzip-size": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", @@ -14116,12 +11489,6 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -14209,36 +11576,12 @@ "minimalistic-assert": "^1.0.1" } }, - "hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", - "dev": true - }, - "hastscript": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz", - "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==", - "dev": true, - "requires": { - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - } - }, "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", "dev": true }, - "highlight.js": { - "version": "9.15.10", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz", - "integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==", - "dev": true - }, "history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -14400,35 +11743,6 @@ } } }, - "html-webpack-plugin": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.1.tgz", - "integrity": "sha512-yzK7RQZwv9xB+pcdHNTjcqbaaDZ+5L0zJHXfi89iWIZmb/FtzxhLk0635rmJihcQbs3ZUF27Xp4oWGx6EK56zg==", - "dev": true, - "requires": { - "@types/html-minifier-terser": "^5.0.0", - "@types/tapable": "^1.0.5", - "@types/webpack": "^4.41.8", - "html-minifier-terser": "^5.0.1", - "loader-utils": "^1.2.3", - "lodash": "^4.17.20", - "pretty-error": "^2.1.1", - "tapable": "^1.1.3", - "util.promisify": "1.0.0" - }, - "dependencies": { - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - } - } - }, "htmlparser2": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", @@ -14735,12 +12049,6 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, - "immer": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz", - "integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==", - "dev": true - }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -14890,21 +12198,6 @@ "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.0.tgz", "integrity": "sha512-SdoDWwNOTE2n4JWUsLn4KXZGuZPjPF9yyOGc8bnfWnBQh7BD/l80rzSznKc/r4Y0aQ7z3RTk9X+tV4tHBpu+dA==" }, - "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -14957,22 +12250,6 @@ } } }, - "is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true - }, - "is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", @@ -14989,6 +12266,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "optional": true, "requires": { "binary-extensions": "^2.0.0" } @@ -15065,12 +12343,6 @@ "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, - "is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true - }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -15102,16 +12374,6 @@ "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", "dev": true }, - "is-dom": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz", - "integrity": "sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==", - "dev": true, - "requires": { - "is-object": "^1.0.1", - "is-window": "^1.0.2" - } - }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -15135,12 +12397,6 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", - "dev": true - }, "is-generator-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", @@ -15156,23 +12412,11 @@ "is-extglob": "^2.1.1" } }, - "is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "dev": true - }, "is-in-browser": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -15197,12 +12441,6 @@ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, - "is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true - }, "is-observable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", @@ -15290,12 +12528,6 @@ "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", "dev": true }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -15332,12 +12564,6 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "is-window": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-window/-/is-window-1.0.2.tgz", - "integrity": "sha1-LIlspT25feRdPDMTOmXYyfVjSA0=", - "dev": true - }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -15353,12 +12579,6 @@ "is-docker": "^2.0.0" } }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -15487,22 +12707,6 @@ "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" }, - "iterate-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", - "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", - "dev": true - }, - "iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, - "requires": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - } - }, "jake": { "version": "10.8.2", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", @@ -17165,15 +14369,6 @@ "minimist": "^1.2.5" } }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -17385,15 +14580,6 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, "klaw-sync": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", @@ -17434,27 +14620,6 @@ "webpack-sources": "^1.1.0" } }, - "lazy-universal-dotenv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", - "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.0", - "app-root-dir": "^1.0.2", - "core-js": "^3.0.4", - "dotenv": "^8.0.0", - "dotenv-expand": "^5.1.0" - }, - "dependencies": { - "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", - "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", - "dev": true - } - } - }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -17985,16 +15150,6 @@ "integrity": "sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ==", "dev": true }, - "loglevelnext": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz", - "integrity": "sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A==", - "dev": true, - "requires": { - "es6-symbol": "^3.1.1", - "object.assign": "^4.1.0" - } - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -18020,16 +15175,6 @@ } } }, - "lowlight": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.12.1.tgz", - "integrity": "sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w==", - "dev": true, - "requires": { - "fault": "^1.0.2", - "highlight.js": "~9.15.0" - } - }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -18063,12 +15208,6 @@ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, - "map-or-similar": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", - "integrity": "sha1-beJlMXSt+12e3DPGnT6Sobdvrwg=", - "dev": true - }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -18078,16 +15217,6 @@ "object-visit": "^1.0.0" } }, - "markdown-to-jsx": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz", - "integrity": "sha512-3lRCD5Sh+tfA52iGgfs/XZiw33f7fFX9Bn55aNnVNUd2GzLDkOWyKYYD8Yju2B1Vn+feiEdgJs8T6Tg0xNokPw==", - "dev": true, - "requires": { - "prop-types": "^15.6.2", - "unquote": "^1.1.0" - } - }, "match-sorter": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-4.2.1.tgz", @@ -18097,12 +15226,6 @@ "remove-accents": "0.4.2" } }, - "material-colors": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", - "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==", - "dev": true - }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -18124,21 +15247,6 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, - "memoize-one": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", - "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==", - "dev": true - }, - "memoizerific": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz", - "integrity": "sha1-fIekZGREwy11Q4VwkF8tvRsagFo=", - "dev": true, - "requires": { - "map-or-similar": "^1.5.0" - } - }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -18269,21 +15377,6 @@ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dev": true, - "requires": { - "dom-walk": "^0.1.0" - } - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true - }, "mini-create-react-context": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.3.tgz", @@ -18643,21 +15736,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" }, - "node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", - "dev": true, - "requires": { - "minimatch": "^3.0.2" - } - }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true - }, "node-forge": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", @@ -18889,18 +15967,6 @@ "path-key": "^2.0.0" } }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, "nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", @@ -19097,12 +16163,6 @@ "has": "^1.0.3" } }, - "objectorarray": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.4.tgz", - "integrity": "sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w==", - "dev": true - }, "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -19228,12 +16288,6 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "overlayscrollbars": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz", - "integrity": "sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==", - "dev": true - }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -19376,20 +16430,6 @@ "safe-buffer": "^5.1.1" } }, - "parse-entities": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz", - "integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==", - "dev": true, - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -19593,12 +16633,6 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", @@ -19700,16 +16734,6 @@ "ts-pnp": "^1.1.6" } }, - "polished": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/polished/-/polished-3.7.0.tgz", - "integrity": "sha512-1tnvQ2wsxfR/DyPE2Xu9sRbnLAwXAarCWiZJ8Hfirw59bTigqjbzEWSAmzYizT6ocQW995V8n7RP48jq50DjJA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.12.5", - "@scarf/scarf": "^1.1.0" - } - }, "popper.js": { "version": "1.16.1-lts", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", @@ -20926,12 +17950,6 @@ } } }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true - }, "pretty-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", @@ -20942,15 +17960,6 @@ "plur": "^1.0.0" } }, - "prismjs": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", - "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", - "dev": true, - "requires": { - "clipboard": "^2.0.0" - } - }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -20983,52 +17992,6 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, - "promise.allsettled": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.4.tgz", - "integrity": "sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag==", - "dev": true, - "requires": { - "array.prototype.map": "^1.0.3", - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.0.2", - "iterate-value": "^1.0.2" - } - }, - "promise.prototype.finally": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz", - "integrity": "sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.0", - "function-bind": "^1.1.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } - } - }, "prompts": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", @@ -21054,15 +18017,6 @@ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==" }, - "property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "dev": true, - "requires": { - "xtend": "^4.0.0" - } - }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -21277,52 +18231,6 @@ } } }, - "raw-loader": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", - "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "dependencies": { - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -21367,21 +18275,6 @@ } } }, - "react-color": { - "version": "2.19.3", - "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", - "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", - "dev": true, - "requires": { - "@icons/material": "^0.2.4", - "lodash": "^4.17.15", - "lodash-es": "^4.17.15", - "material-colors": "^1.2.1", - "prop-types": "^15.5.10", - "reactcss": "^1.2.0", - "tinycolor2": "^1.4.1" - } - }, "react-copy-to-clipboard": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.3.tgz", @@ -21391,621 +18284,6 @@ "prop-types": "^15.5.8" } }, - "react-dev-utils": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", - "integrity": "sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ==", - "dev": true, - "requires": { - "@babel/code-frame": "7.8.3", - "address": "1.1.2", - "browserslist": "4.10.0", - "chalk": "2.4.2", - "cross-spawn": "7.0.1", - "detect-port-alt": "1.1.6", - "escape-string-regexp": "2.0.0", - "filesize": "6.0.1", - "find-up": "4.1.0", - "fork-ts-checker-webpack-plugin": "3.1.1", - "global-modules": "2.0.0", - "globby": "8.0.2", - "gzip-size": "5.1.1", - "immer": "1.10.0", - "inquirer": "7.0.4", - "is-root": "2.1.0", - "loader-utils": "1.2.3", - "open": "^7.0.2", - "pkg-up": "3.1.0", - "react-error-overlay": "^6.0.7", - "recursive-readdir": "2.2.2", - "shell-quote": "1.7.2", - "strip-ansi": "6.0.0", - "text-table": "0.2.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browserslist": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.10.0.tgz", - "integrity": "sha512-TpfK0TDgv71dzuTsEAlQiHeWQ/tiPqgNZVdv046fvNtBZrjbv2O3TsWCDU0AWGJJKCF/KsjNdLzR9hXOsh/CfA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001035", - "electron-to-chromium": "^1.3.378", - "node-releases": "^1.1.52", - "pkg-up": "^3.1.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cross-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", - "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "dev": true, - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - } - }, - "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fork-ts-checker-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", - "dev": true, - "requires": { - "babel-code-frame": "^6.22.0", - "chalk": "^2.4.1", - "chokidar": "^3.3.0", - "micromatch": "^3.1.10", - "minimatch": "^3.0.4", - "semver": "^5.6.0", - "tapable": "^1.0.0", - "worker-rpc": "^0.1.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "globby": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - }, - "dependencies": { - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - } - } - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" - }, - "inquirer": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", - "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^2.4.2", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.2.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "react-docgen": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.3.1.tgz", - "integrity": "sha512-YG7YujVTwlLslr2Ny8nQiUfbBuEwKsLHJdQTSdEga1eY/nRFh/7LjCWUn6ogYhu2WDKg4z+6W/BJtUi+DPUIlA==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@babel/runtime": "^7.7.6", - "ast-types": "^0.14.2", - "commander": "^2.19.0", - "doctrine": "^3.0.0", - "neo-async": "^2.6.1", - "node-dir": "^0.1.10", - "strip-indent": "^3.0.0" - } - }, - "react-docgen-typescript": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-1.21.0.tgz", - "integrity": "sha512-E4y/OcXwHukgiVafCGlxwoNHr4BDmM70Ww7oimL/QkMo5dmGALhceewe/xmVjdMxxI7E5syOGOc9/tbHL742rg==", - "dev": true - }, - "react-docgen-typescript-loader": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/react-docgen-typescript-loader/-/react-docgen-typescript-loader-3.7.2.tgz", - "integrity": "sha512-fNzUayyUGzSyoOl7E89VaPKJk9dpvdSgyXg81cUkwy0u+NBvkzQG3FC5WBIlXda0k/iaxS+PWi+OC+tUiGxzPA==", - "dev": true, - "requires": { - "@webpack-contrib/schema-utils": "^1.0.0-beta.0", - "loader-utils": "^1.2.3", - "react-docgen-typescript": "^1.15.0" - } - }, - "react-docgen-typescript-plugin": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.6.3.tgz", - "integrity": "sha512-av1S/fmWBNFGgNa4qtkidFjjOz23eEi6EdCtwSWo9WNhGzUMyMygbD/DosMWoeFlZpk9R3MXPkRE7PDH6j5GMQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "endent": "^2.0.1", - "micromatch": "^4.0.2", - "react-docgen-typescript": "^1.20.5", - "tslib": "^2.0.0" - }, - "dependencies": { - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", - "dev": true - } - } - }, "react-dom": { "version": "16.14.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", @@ -22017,16 +18295,6 @@ "scheduler": "^0.19.1" } }, - "react-draggable": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", - "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", - "dev": true, - "requires": { - "classnames": "^2.2.5", - "prop-types": "^15.6.0" - } - }, "react-dropzone": { "version": "11.4.2", "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-11.4.2.tgz", @@ -22048,56 +18316,6 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" }, - "react-helmet-async": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.0.7.tgz", - "integrity": "sha512-By90p5uxAriGukbyejq2poK41DwTxpNWOpOjN8mIyX/BKrCd3+sXZ5pHUZXjHyjR5OYS7PGsOD9dbM61YxfFmA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.11.2", - "invariant": "^2.2.4", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.2.0", - "shallowequal": "^1.1.0" - }, - "dependencies": { - "react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==", - "dev": true - } - } - }, - "react-hotkeys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/react-hotkeys/-/react-hotkeys-2.0.0.tgz", - "integrity": "sha512-3n3OU8vLX/pfcJrR3xJ1zlww6KS1kEJt0Whxc4FiGV+MJrQ1mYSYI3qS/11d2MJDFm8IhOXMTFQirfu6AVOF6Q==", - "dev": true, - "requires": { - "prop-types": "^15.6.1" - } - }, - "react-input-autosize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", - "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", - "dev": true, - "requires": { - "prop-types": "^15.5.8" - } - }, - "react-inspector": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.0.tgz", - "integrity": "sha512-JAwswiengIcxi4X/Ssb8nf6suOuQsyit8Fxo04+iPKTnPNY3XIOuagjMZSzpJDDKkYcc/ARlySOYZZv626WUvA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.0.0", - "is-dom": "^1.0.0", - "prop-types": "^15.0.0" - } - }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -22130,39 +18348,6 @@ "resolved": "https://registry.npmjs.org/react-otp-input/-/react-otp-input-2.3.0.tgz", "integrity": "sha512-xzljlohVaPkUqO4H61x4r7KMRSq2ZPYFFZeSqqVXid+kJNL1UekSBP1xPafvI0eGNpus/PA1447jYZf2EJRY0A==" }, - "react-popper": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz", - "integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==", - "dev": true, - "requires": { - "@babel/runtime": "^7.1.2", - "create-react-context": "^0.3.0", - "deep-equal": "^1.1.1", - "popper.js": "^1.14.4", - "prop-types": "^15.6.1", - "typed-styles": "^0.0.7", - "warning": "^4.0.2" - }, - "dependencies": { - "popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", - "dev": true - } - } - }, - "react-popper-tooltip": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz", - "integrity": "sha512-04A2f24GhyyMicKvg/koIOQ5BzlrRbKiAgP6L+Pdj1MVX3yJ1NeZ8+EidndQsbejFT55oW1b++wg2Z8KlAyhfQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.9.2", - "react-popper": "^1.3.7" - } - }, "react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -23557,63 +19742,11 @@ } } }, - "react-select": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-3.2.0.tgz", - "integrity": "sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.4.4", - "@emotion/cache": "^10.0.9", - "@emotion/core": "^10.0.9", - "@emotion/css": "^10.0.9", - "memoize-one": "^5.0.0", - "prop-types": "^15.6.0", - "react-input-autosize": "^3.0.0", - "react-transition-group": "^4.3.0" - } - }, - "react-sizeme": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-2.6.12.tgz", - "integrity": "sha512-tL4sCgfmvapYRZ1FO2VmBmjPVzzqgHA7kI8lSJ6JS6L78jXFNRdOZFpXyK6P1NBZvKPPCZxReNgzZNUajAerZw==", - "dev": true, - "requires": { - "element-resize-detector": "^1.2.1", - "invariant": "^2.2.4", - "shallowequal": "^1.1.0", - "throttle-debounce": "^2.1.0" - } - }, "react-swipeable": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/react-swipeable/-/react-swipeable-6.1.2.tgz", "integrity": "sha512-vfZtOZNivwd/aI+ZZH1Grx0eQBdbV1UI3pB9p65jbW5guHHdSIPpKsND6XmaiZXP5REOOc9Ckfr36ChswPqwsA==" }, - "react-syntax-highlighter": { - "version": "12.2.1", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz", - "integrity": "sha512-CTsp0ZWijwKRYFg9xhkWD4DSpQqE4vb2NKVMdPAkomnILSmsNBHE0n5GuI5zB+PU3ySVvXvdt9jo+ViD9XibCA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "highlight.js": "~9.15.1", - "lowlight": "1.12.1", - "prismjs": "^1.8.4", - "refractor": "^2.4.1" - } - }, - "react-textarea-autosize": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.0.tgz", - "integrity": "sha512-3GLWFAan2pbwBeoeNDoqGmSbrShORtgWfaWX0RJDivsUrpShh01saRM5RU/i4Zmf+whpBVEY5cA90Eq8Ub1N3w==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "use-composed-ref": "^1.0.0", - "use-latest": "^1.0.0" - } - }, "react-transition-group": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", @@ -23671,15 +19804,6 @@ "react-lifecycles-compat": "^3.0.4" } }, - "reactcss": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", - "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", - "dev": true, - "requires": { - "lodash": "^4.0.1" - } - }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -23855,19 +19979,11 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "dev": true, + "optional": true, "requires": { "picomatch": "^2.2.1" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, "recursive-readdir": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", @@ -23877,28 +19993,6 @@ "minimatch": "3.0.4" } }, - "refractor": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-2.10.1.tgz", - "integrity": "sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw==", - "dev": true, - "requires": { - "hastscript": "^5.0.0", - "parse-entities": "^1.1.2", - "prismjs": "~1.17.0" - }, - "dependencies": { - "prismjs": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz", - "integrity": "sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==", - "dev": true, - "requires": { - "clipboard": "^2.0.0" - } - } - } - }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -24457,12 +20551,6 @@ "@babel/runtime": "^7.1.2" } }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, "run-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", @@ -24802,13 +20890,6 @@ "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.1.0.tgz", "integrity": "sha512-dYaNuOdzr+kc6J6CFcBrzkLCfyGcMg+gWkJ8us93IQ7y1cevhQAugFsaCdMHb6lw8KV3xPzSxzH7zM1dQap9mA==" }, - "select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", - "dev": true, - "optional": true - }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -25063,33 +21144,6 @@ } } }, - "serve-favicon": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", - "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", - "dev": true, - "requires": { - "etag": "~1.8.1", - "fresh": "0.5.2", - "ms": "2.1.1", - "parseurl": "~1.3.2", - "safe-buffer": "5.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - } - } - }, "serve-handler": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", @@ -25281,12 +21335,6 @@ "kind-of": "^6.0.2" } }, - "shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", - "dev": true - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -25308,25 +21356,6 @@ "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", "dev": true }, - "shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "dependencies": { - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - } - } - }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", @@ -25833,12 +21862,6 @@ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" }, - "space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "dev": true - }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -26051,12 +22074,6 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, - "store2": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/store2/-/store2-2.12.0.tgz", - "integrity": "sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw==", - "dev": true - }, "stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", @@ -26247,28 +22264,6 @@ "side-channel": "^1.0.3" } }, - "string.prototype.padend": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.1.tgz", - "integrity": "sha512-eCzTASPnoCr5Ht+Vn1YXgm8SB015hHKgEIMu9Nr9bQmLhRBxKRfmzSj/IQsxDFc8JInJDDFA0qXwK+xxI7wDkg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, - "string.prototype.padstart": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.padstart/-/string.prototype.padstart-3.1.1.tgz", - "integrity": "sha512-kcFjKhQYg40AK9MITCWYr/vIebruAD01sc/fxi8szHJaEG7Rke4XHw6LU9c1VWXh/+J/PxvWLLf/aIAGKhXkAQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, "string.prototype.trimend": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", @@ -26354,15 +22349,6 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "requires": { - "min-indent": "^1.0.0" - } - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -26519,18 +22505,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "symbol.prototype.description": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/symbol.prototype.description/-/symbol.prototype.description-1.0.3.tgz", - "integrity": "sha512-NvwWb5AdyTtmFNa1x0ksJakFUV/WJ+z7iRrYGU1xZew77Qd+kMrZKsk3uatCckk6yPNpbHhRcOO+JBU+ohcMBw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "es-abstract": "^1.18.0-next.1", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, "table": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", @@ -26603,30 +22577,6 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true }, - "telejson": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/telejson/-/telejson-5.1.0.tgz", - "integrity": "sha512-Yy0N2OV0mosmr1SCZEm3Ezhu/oi5Dbao5RqauZu4+VI5I/XtVBHXajRk0txuqbFYtKdzzWGDZFGSif9ovVLjEA==", - "dev": true, - "requires": { - "@types/is-function": "^1.0.0", - "global": "^4.4.0", - "is-function": "^1.0.2", - "is-regex": "^1.1.1", - "is-symbol": "^1.0.3", - "isobject": "^4.0.0", - "lodash": "^4.17.20", - "memoizerific": "^1.11.3" - }, - "dependencies": { - "isobject": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", - "dev": true - } - } - }, "temp": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", @@ -26682,12 +22632,6 @@ } } }, - "term-size": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", - "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", - "dev": true - }, "terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -26734,60 +22678,6 @@ "source-map-support": "~0.5.12" } }, - "terser-webpack-plugin": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-3.1.0.tgz", - "integrity": "sha512-cjdZte66fYkZ65rQ2oJfrdCAkkhJA7YLYk5eGOcGCSGlq0ieZupRdjedSQXYknMPo2IveQL+tPdrxUkERENCFA==", - "dev": true, - "requires": { - "cacache": "^15.0.5", - "find-cache-dir": "^3.3.1", - "jest-worker": "^26.2.1", - "p-limit": "^3.0.2", - "schema-utils": "^2.6.6", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.8.0", - "webpack-sources": "^1.4.3" - }, - "dependencies": { - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -26816,12 +22706,6 @@ "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==" }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -26893,13 +22777,6 @@ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", "dev": true }, - "tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "dev": true, - "optional": true - }, "tiny-invariant": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", @@ -26922,12 +22799,6 @@ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, - "tinycolor2": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", - "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", - "dev": true - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -27066,23 +22937,11 @@ "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", "dev": true }, - "ts-dedent": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-1.2.0.tgz", - "integrity": "sha512-6zSJp23uQI+Txyz5LlXMXAHpUhY4Hi0oluXny0OgIR7g/Cromq4vDBnhtbBdyIV34g0pgwxUvnvg+jLJe4c1NA==", - "dev": true - }, "ts-easing": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz", "integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==" }, - "ts-essentials": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", - "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==", - "dev": true - }, "ts-invariant": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz", @@ -27192,12 +23051,6 @@ "mime-types": "~2.1.24" } }, - "typed-styles": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", - "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==", - "dev": true - }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -27223,12 +23076,6 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz", "integrity": "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==" }, - "unfetch": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", - "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", - "dev": true - }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -27506,30 +23353,6 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "use-composed-ref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz", - "integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==", - "dev": true, - "requires": { - "ts-essentials": "^2.0.3" - } - }, - "use-isomorphic-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", - "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==", - "dev": true - }, - "use-latest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz", - "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", - "dev": true, - "requires": { - "use-isomorphic-layout-effect": "^1.0.0" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -27689,15 +23512,6 @@ "makeerror": "1.0.x" } }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, "watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", @@ -28002,248 +23816,6 @@ "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true }, - "webpack": { - "version": "4.46.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", - "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.5.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", - "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", - "dev": true, - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "dev": true - } - } - }, "webpack-dev-middleware": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", @@ -28869,35 +24441,6 @@ } } }, - "webpack-hot-middleware": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.25.0.tgz", - "integrity": "sha512-xs5dPOrGPCzuRXNi8F6rwhawWvQQkeli5Ro48PRuQh8pYPCPmNnltP9itiUPT4xI8oW+y0m59lyyeQk54s5VgA==", - "dev": true, - "requires": { - "ansi-html": "0.0.7", - "html-entities": "^1.2.0", - "querystring": "^0.2.0", - "strip-ansi": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, "webpack-log": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", @@ -28966,32 +24509,6 @@ "source-map": "~0.6.1" } }, - "webpack-virtual-modules": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz", - "integrity": "sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==", - "dev": true, - "requires": { - "debug": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, "websocket-driver": { "version": "0.6.5", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", @@ -29054,64 +24571,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, "wif": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", diff --git a/new-lamassu-admin/package.json b/new-lamassu-admin/package.json index f3341b34..bd8aaa49 100644 --- a/new-lamassu-admin/package.json +++ b/new-lamassu-admin/package.json @@ -53,13 +53,6 @@ "yup": "0.32.9" }, "devDependencies": { - "@storybook/addon-actions": "6.0.26", - "@storybook/addon-backgrounds": "6.0.26", - "@storybook/addon-knobs": "6.0.26", - "@storybook/addon-links": "6.0.26", - "@storybook/addons": "6.0.26", - "@storybook/preset-create-react-app": "^3.1.4", - "@storybook/react": "6.0.26", "@welldone-software/why-did-you-render": "^3.3.9", "eslint": "^7.19.0", "eslint-config-prettier": "^6.7.0", @@ -99,9 +92,7 @@ "analyze": "source-map-explorer 'build/static/js/*.js'", "test": "react-scripts test", "eject": "react-scripts eject", - "storybook": "start-storybook -p 9009 -s public", "postinstall": "patch-package", - "build-storybook": "build-storybook -s public", "lamassu": "REACT_APP_BUILD_TARGET=LAMASSU react-scripts start", "pazuz": "REACT_APP_BUILD_TARGET=PAZUZ react-scripts start" }, diff --git a/new-lamassu-admin/src/stories/index.js b/new-lamassu-admin/src/stories/index.js deleted file mode 100644 index 030c9e56..00000000 --- a/new-lamassu-admin/src/stories/index.js +++ /dev/null @@ -1,210 +0,0 @@ -import Checkbox from '@material-ui/core/Checkbox' -import FormControlLabel from '@material-ui/core/FormControlLabel' -import { - MuiThemeProvider, - createMuiTheme, - StylesProvider, - jssPreset -} from '@material-ui/core/styles' -import { withKnobs, text, boolean, select } from '@storybook/addon-knobs' -import { storiesOf } from '@storybook/react' -import { create } from 'jss' -import extendJss from 'jss-plugin-extend' -import React from 'react' - -import { ActionButton, Button, Link } from 'src/components/buttons' -import { TextInput, Switch, CashIn, CashOut } from 'src/components/inputs' -import { ReactComponent as AuthorizeIconReversed } from 'src/styling/icons/button/authorize/white.svg' -import { ReactComponent as AuthorizeIcon } from 'src/styling/icons/button/authorize/zodiac.svg' - -// import ConfirmDialog from '../components/ConfirmDialog' -import { - H1, - H2, - H3, - TL1, - TL2, - P, - Info1, - Info2, - Mono -} from '../components/typography' -import { - inputFontFamily, - secondaryColor, - fontColor -} from '../styling/variables' - -const jss = create({ - plugins: [extendJss(), ...jssPreset().plugins] -}) - -const Wrapper = ({ children }) => ( - - {children} - -) - -const story = storiesOf('Components', module) -story.addDecorator(withKnobs) - -const colors = { - Primary: 'primary', - Secondary: 'secondary' -} - -const linkColors = { - Primary: 'primary', - Secondary: 'secondary', - 'No Color': 'no-color' -} - -const sizes = { - Large: 'lg', - Small: 'sm' -} - -const theme = createMuiTheme({ - typography: { - fontFamily: inputFontFamily - }, - MuiButtonBase: { - disableRipple: true - }, - palette: { - primary: { - light: secondaryColor, - dark: secondaryColor, - main: secondaryColor - }, - secondary: { - light: secondaryColor, - dark: secondaryColor, - main: secondaryColor - } - }, - overrides: { - MuiInputLabel: { - paddingLeft: 4 - }, - MuiFormLabel: { - root: { - color: fontColor, - '&$focused': { - color: 'blue' - } - } - } - } -}) - -story.add('Button', () => ( - - - -)) - -story.add('Action Button', () => ( - - - {text('Label', 'Button')} - - -)) - -story.add('Text Button', () => ( - - - {text('Label', 'Text Button')} - - -)) - -story.add('Switch', () => ( - - } label="iOS style" /> - - -)) - -story.add('Text Input', () => ( - - - -)) - -story.add('Checkbox', () => ( - - - - - -)) - -story.add('Cashbox', () => ( - -
- -
- -
- -
- -
- -
-
- -
- -
- -
- -
- -
-
-)) - -const typographyStory = storiesOf('Typography', module) -typographyStory.add('H1', () =>

Hehehe

) - -typographyStory.add('H2', () =>

Hehehe

) - -typographyStory.add('H3', () =>

Hehehe

) - -typographyStory.add('TL1', () => Hehehe) - -typographyStory.add('TL2', () => Hehehe) - -typographyStory.add('P', () =>

Hehehe

) - -typographyStory.add('Info1', () => Hehehe) - -typographyStory.add('Info2', () => Hehehe) - -typographyStory.add('Mono', () => Hehehe) From f936386712b749dfb475756d2350e9e2c141021d Mon Sep 17 00:00:00 2001 From: Rafael Date: Fri, 29 Nov 2024 19:25:05 +0000 Subject: [PATCH 096/119] chore: pazuz removal --- lib/new-admin/middlewares/context.js | 1 - new-lamassu-admin/.env | 1 - new-lamassu-admin/package.json | 4 +- new-lamassu-admin/src/index.js | 30 +- .../src/pages/ATMWallet/ATMWallet.js | 258 -------------- .../src/pages/ATMWallet/ATMWallet.styles.js | 90 ----- .../src/pages/Accounting/Accounting.js | 203 ----------- .../src/pages/Accounting/Accounting.styles.js | 39 --- new-lamassu-admin/src/pages/Assets/Assets.js | 258 -------------- .../src/pages/Assets/Assets.styles.js | 45 --- .../src/pages/Authentication/Input2FAState.js | 15 +- .../src/pages/Authentication/LoginState.js | 6 - .../src/pages/Authentication/Register.js | 6 - .../src/pages/Authentication/Setup2FAState.js | 20 +- .../UserManagement/modals/CreateUserModal.js | 8 +- new-lamassu-admin/src/pages/Wizard/Wizard.js | 19 +- new-lamassu-admin/src/routing/pazuz.routes.js | 317 ------------------ new-lamassu-admin/src/routing/routes.js | 15 +- new-lamassu-admin/src/routing/utils.js | 5 - new-lamassu-admin/src/serviceWorker.js | 135 -------- new-lamassu-admin/src/utils/apollo.js | 16 +- 21 files changed, 14 insertions(+), 1477 deletions(-) delete mode 100644 new-lamassu-admin/src/pages/ATMWallet/ATMWallet.js delete mode 100644 new-lamassu-admin/src/pages/ATMWallet/ATMWallet.styles.js delete mode 100644 new-lamassu-admin/src/pages/Accounting/Accounting.js delete mode 100644 new-lamassu-admin/src/pages/Accounting/Accounting.styles.js delete mode 100644 new-lamassu-admin/src/pages/Assets/Assets.js delete mode 100644 new-lamassu-admin/src/pages/Assets/Assets.styles.js delete mode 100644 new-lamassu-admin/src/routing/pazuz.routes.js delete mode 100644 new-lamassu-admin/src/serviceWorker.js diff --git a/lib/new-admin/middlewares/context.js b/lib/new-admin/middlewares/context.js index 70e7d62f..c955bb49 100644 --- a/lib/new-admin/middlewares/context.js +++ b/lib/new-admin/middlewares/context.js @@ -20,7 +20,6 @@ const buildApolloContext = async ({ req, res }) => { req.session.user.role = user.role res.set('lamassu_role', user.role) - res.cookie('pazuz_operatoridentifier', base64.encode(user.username)) res.set('Access-Control-Expose-Headers', 'lamassu_role') return { req, res } diff --git a/new-lamassu-admin/.env b/new-lamassu-admin/.env index 153fab2c..e666d42d 100644 --- a/new-lamassu-admin/.env +++ b/new-lamassu-admin/.env @@ -2,4 +2,3 @@ SKIP_PREFLIGHT_CHECK=true HTTPS=true REACT_APP_TYPE_CHECK_SANCTUARY=false PORT=3001 -REACT_APP_BUILD_TARGET=LAMASSU diff --git a/new-lamassu-admin/package.json b/new-lamassu-admin/package.json index bd8aaa49..e6e554a7 100644 --- a/new-lamassu-admin/package.json +++ b/new-lamassu-admin/package.json @@ -92,9 +92,7 @@ "analyze": "source-map-explorer 'build/static/js/*.js'", "test": "react-scripts test", "eject": "react-scripts eject", - "postinstall": "patch-package", - "lamassu": "REACT_APP_BUILD_TARGET=LAMASSU react-scripts start", - "pazuz": "REACT_APP_BUILD_TARGET=PAZUZ react-scripts start" + "postinstall": "patch-package" }, "browserslist": { "production": [ diff --git a/new-lamassu-admin/src/index.js b/new-lamassu-admin/src/index.js index 8272c102..638af18d 100644 --- a/new-lamassu-admin/src/index.js +++ b/new-lamassu-admin/src/index.js @@ -2,30 +2,10 @@ import React from 'react' import ReactDOM from 'react-dom' import App from './App' -import * as serviceWorker from './serviceWorker' -function checkBuildTarget() { - const buildTarget = process.env.REACT_APP_BUILD_TARGET - - if (buildTarget !== 'LAMASSU' && buildTarget !== 'PAZUZ') { - return Promise.reject( - new Error('No such build target: ' + process.env.REACT_APP_BUILD_TARGET) - ) - } - - return Promise.resolve() -} - -checkBuildTarget().then(() => - ReactDOM.render( - - - , - document.getElementById('root') - ) +ReactDOM.render( + + + , + document.getElementById('root') ) - -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister() diff --git a/new-lamassu-admin/src/pages/ATMWallet/ATMWallet.js b/new-lamassu-admin/src/pages/ATMWallet/ATMWallet.js deleted file mode 100644 index b9601108..00000000 --- a/new-lamassu-admin/src/pages/ATMWallet/ATMWallet.js +++ /dev/null @@ -1,258 +0,0 @@ -import { useQuery } from '@apollo/react-hooks' -import { Paper } from '@material-ui/core' -import { makeStyles } from '@material-ui/core/styles' -import BigNumber from 'bignumber.js' -import classnames from 'classnames' -import gql from 'graphql-tag' -import * as R from 'ramda' -import React, { useContext } from 'react' - -import AppContext from 'src/AppContext' -import TitleSection from 'src/components/layout/TitleSection' -import { H3, Info2, Label2, Label3, P } from 'src/components/typography' -import { ReactComponent as BitcoinLogo } from 'src/styling/logos/icon-bitcoin-colour.svg' -import { ReactComponent as BitcoinCashLogo } from 'src/styling/logos/icon-bitcoincash-colour.svg' -import { ReactComponent as DashLogo } from 'src/styling/logos/icon-dash-colour.svg' -import { ReactComponent as EthereumLogo } from 'src/styling/logos/icon-ethereum-colour.svg' -import { ReactComponent as LitecoinLogo } from 'src/styling/logos/icon-litecoin-colour.svg' -import { ReactComponent as ZCashLogo } from 'src/styling/logos/icon-zcash-colour.svg' -import { numberToFiatAmount, numberToCryptoAmount } from 'src/utils/number' - -import styles from './ATMWallet.styles' - -const useStyles = makeStyles(styles) - -const GET_OPERATOR_BY_USERNAME = gql` - query operatorByUsername($username: String) { - operatorByUsername(username: $username) { - id - entityId - name - fiatBalances - cryptoBalances - machines - joined - assets - preferredFiatCurrency - contactInfo { - name - email - } - fundings { - id - origin - destination - fiatAmount - fiatBalanceAfter - fiatCurrency - created - status - description - } - } - } -` - -const CHIPS_PER_ROW = 6 - -const Assets = ({ balance, wallets, currency }) => { - const classes = useStyles({ numberOfChips: CHIPS_PER_ROW }) - - const walletFiatSum = R.sum(R.map(it => it.fiatValue, wallets)) - const totalValue = BigNumber(balance) - .plus(walletFiatSum) - .toNumber() - - return ( -
-
-

Available balance

-
- - {numberToFiatAmount(balance)} - - - {R.toUpper(currency)} - -
-
- + -
-

Total balance in wallets

-
- - {numberToFiatAmount(walletFiatSum)} - - - {R.toUpper(currency)} - -
-
- = -
-

Total assets

-
- - {numberToFiatAmount(totalValue)} - - - {R.toUpper(currency)} - -
-
-
- ) -} - -const WalletInfoChip = ({ wallet, currency }) => { - const classes = useStyles({ numberOfChips: CHIPS_PER_ROW }) - - const getLogo = cryptoCode => { - switch (cryptoCode) { - case 'BTC': - return - case 'ETH': - return - case 'LTC': - return - case 'ZEC': - return ( - - ) - case 'BCH': - return ( - - ) - case 'DASH': - return - default: - return - } - } - - return ( -
- -
- {getLogo(wallet.cryptoCode)} - - {wallet.isHedged ? 'Hedged' : 'Not hedged'} - -
-
- {wallet.name} value - - {numberToCryptoAmount(wallet.amount)} {wallet.cryptoCode} - - Hedged value - - {numberToFiatAmount(wallet.hedgedFiatValue)} {currency} - -
-
-
- ) -} - -const ATMWallet = () => { - const classes = useStyles({ numberOfChips: CHIPS_PER_ROW }) - const { userData } = useContext(AppContext) - - const { data, loading } = useQuery(GET_OPERATOR_BY_USERNAME, { - context: { clientName: 'pazuz' }, - variables: { username: userData?.username } - }) - - const operatorData = R.path(['operatorByUsername'], data) - - const wallets = [ - { - cryptoCode: 'BTC', - name: 'Bitcoin', - amount: operatorData?.cryptoBalances.xbt ?? 0, - fiatValue: operatorData?.assets.values.cryptoBalancesInFiat.xbt ?? 0, - hedgedFiatValue: operatorData?.assets.values.hedgedContracts.xbt ?? 0, - isHedged: BigNumber(operatorData?.assets.values.hedgedCrypto.xbt ?? 0).gt( - 0 - ) - }, - { - cryptoCode: 'ETH', - name: 'Ethereum', - amount: operatorData?.cryptoBalances.eth ?? 0, - fiatValue: operatorData?.assets.values.cryptoBalancesInFiat.eth ?? 0, - hedgedFiatValue: operatorData?.assets.values.hedgedContracts.eth ?? 0, - isHedged: BigNumber(operatorData?.assets.values.hedgedCrypto.eth ?? 0).gt( - 0 - ) - }, - { - cryptoCode: 'LTC', - name: 'Litecoin', - amount: operatorData?.cryptoBalances.ltc ?? 0, - fiatValue: operatorData?.assets.values.cryptoBalancesInFiat.ltc ?? 0, - hedgedFiatValue: operatorData?.assets.values.hedgedContracts.ltc ?? 0, - isHedged: BigNumber(operatorData?.assets.values.hedgedCrypto.ltc ?? 0).gt( - 0 - ) - }, - { - cryptoCode: 'ZEC', - name: 'Zcash', - amount: operatorData?.cryptoBalances.zec ?? 0, - fiatValue: operatorData?.assets.values.cryptoBalancesInFiat.zec ?? 0, - hedgedFiatValue: operatorData?.assets.values.hedgedContracts.zec ?? 0, - isHedged: BigNumber(operatorData?.assets.values.hedgedCrypto.zec ?? 0).gt( - 0 - ) - }, - { - cryptoCode: 'BCH', - name: 'Bitcoin Cash', - amount: operatorData?.cryptoBalances.bch ?? 0, - fiatValue: operatorData?.assets.values.cryptoBalancesInFiat.bch ?? 0, - hedgedFiatValue: operatorData?.assets.values.hedgedContracts.bch ?? 0, - isHedged: BigNumber(operatorData?.assets.values.hedgedCrypto.bch ?? 0).gt( - 0 - ) - }, - { - cryptoCode: 'DASH', - name: 'Dash', - amount: operatorData?.cryptoBalances.dash ?? 0, - fiatValue: operatorData?.assets.values.cryptoBalancesInFiat.dash ?? 0, - hedgedFiatValue: operatorData?.assets.values.hedgedContracts.dash ?? 0, - isHedged: BigNumber( - operatorData?.assets.values.hedgedCrypto.dash ?? 0 - ).gt(0) - } - ] - - return ( - !loading && ( - <> - - -

ATM Wallets

-
- {R.map( - it => ( - - ), - wallets - )} -
- - ) - ) -} - -export default ATMWallet diff --git a/new-lamassu-admin/src/pages/ATMWallet/ATMWallet.styles.js b/new-lamassu-admin/src/pages/ATMWallet/ATMWallet.styles.js deleted file mode 100644 index 8715a627..00000000 --- a/new-lamassu-admin/src/pages/ATMWallet/ATMWallet.styles.js +++ /dev/null @@ -1,90 +0,0 @@ -import { offColor } from 'src/styling/variables' - -const styles = ({ numberOfChips }) => ({ - totalAssetWrapper: { - display: 'flex', - flexDirection: 'row' - }, - totalAssetFieldWrapper: { - display: 'flex', - flexDirection: 'column' - }, - fieldHeader: { - color: offColor, - marginBottom: 5 - }, - fieldValue: { - fontSize: 36 - }, - fieldCurrency: { - fontSize: 20, - alignSelf: 'flex-end', - margin: [[0, 0, 5, 5]] - }, - separator: { - fontSize: 32, - alignSelf: 'center', - margin: [[25, 20, 0, 20]] - }, - walletChipList: { - display: 'flex', - flexDirection: 'row', - flexWrap: 'wrap' - }, - walletChipWrapper: { - flexGrow: 0, - flexShrink: 0, - flexBasis: `16.66667%`, - '&:nth-child(6n+1)': { - '& > div': { - margin: [[0, 10, 0, 0]] - } - }, - '&:nth-child(6n)': { - '& > div': { - margin: [[0, 0, 0, 10]] - } - }, - margin: [[10, 0]] - }, - walletChip: { - height: 200, - margin: [[0, 10]] - }, - walletHeader: { - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', - height: 50 - }, - logo: { - transform: `scale(0.4, 0.4)`, - height: 80, - maxWidth: 110, - margin: [[-14, 0, 0, -26]] - }, - zecLogo: { - margin: [[-15, 0, 0, -10]] - }, - bchLogo: { - margin: [[-12, 0, 0, -18]] - }, - hedgedText: { - color: offColor, - margin: [[13, 12, 0, 0]] - }, - walletValueWrapper: { - display: 'flex', - flexDirection: 'column', - margin: [[0, 0, 0, 15]] - }, - walletValue: { - fontSize: 18, - margin: [[0, 0, 10, 0]] - }, - walletChipTitle: { - marginTop: 50 - } -}) - -export default styles diff --git a/new-lamassu-admin/src/pages/Accounting/Accounting.js b/new-lamassu-admin/src/pages/Accounting/Accounting.js deleted file mode 100644 index dcc6b18d..00000000 --- a/new-lamassu-admin/src/pages/Accounting/Accounting.js +++ /dev/null @@ -1,203 +0,0 @@ -import { useQuery } from '@apollo/react-hooks' -import { makeStyles } from '@material-ui/core/styles' -import BigNumber from 'bignumber.js' -import gql from 'graphql-tag' -import * as R from 'ramda' -import React, { useContext } from 'react' - -import AppContext from 'src/AppContext' -import { HelpTooltip } from 'src/components/Tooltip' -import TitleSection from 'src/components/layout/TitleSection' -import DataTable from 'src/components/tables/DataTable' -import { H4, Info2, P } from 'src/components/typography' -import { numberToFiatAmount } from 'src/utils/number' -import { formatDate } from 'src/utils/timezones' - -import styles from './Accounting.styles' - -const useStyles = makeStyles(styles) - -const GET_OPERATOR_BY_USERNAME = gql` - query operatorByUsername($username: String) { - operatorByUsername(username: $username) { - id - entityId - name - fiatBalances - cryptoBalances - machines - joined - assets - preferredFiatCurrency - contactInfo { - name - email - } - fundings { - id - origin - destination - fiatAmount - fiatBalanceAfter - fiatCurrency - created - status - description - } - } - } -` - -const GET_DATA = gql` - query getData { - config - } -` - -const Assets = ({ balance, hedgingReserve, currency }) => { - const classes = useStyles() - - return ( -
-
-

Pazuz fiat balance

-
- - {numberToFiatAmount(balance)} - - - {R.toUpper(currency)} - -
-
- - -
-

Hedging reserve

-
- - {numberToFiatAmount(hedgingReserve)} - - - {R.toUpper(currency)} - -
-
- = -
-

Available balance

-
- - {numberToFiatAmount(balance - hedgingReserve)} - - - {R.toUpper(currency)} - -
-
-
- ) -} - -const Accounting = () => { - const classes = useStyles() - const { userData } = useContext(AppContext) - - const { data: opData, loading: operatorLoading } = useQuery( - GET_OPERATOR_BY_USERNAME, - { - context: { clientName: 'pazuz' }, - variables: { username: userData?.username } - } - ) - - const { data: configResponse, loading: configLoading } = useQuery(GET_DATA) - const timezone = R.path(['config', 'locale_timezone'], configResponse) - - const loading = operatorLoading || configLoading - - const operatorData = R.path(['operatorByUsername'], opData) - - const elements = [ - { - header: 'Operation', - width: 500, - size: 'sm', - textAlign: 'left', - view: it => { - return ( - - {it.description} - {!!it.extraInfo && ( - -

{it.extraInfo}

-
- )} -
- ) - } - }, - { - header: 'Amount', - width: 147, - size: 'sm', - textAlign: 'right', - view: it => - `${numberToFiatAmount(it.fiatAmount)} ${R.toUpper(it.fiatCurrency)}` - }, - { - header: 'Balance after operation', - width: 250, - size: 'sm', - textAlign: 'right', - view: it => - `${numberToFiatAmount(it.fiatBalanceAfter)} ${R.toUpper( - it.fiatCurrency - )}` - }, - { - header: 'Date', - width: 150, - size: 'sm', - textAlign: 'right', - view: it => formatDate(it.created, timezone, 'yyyy-MM-dd') - }, - { - header: 'Time', - width: 150, - size: 'sm', - textAlign: 'right', - view: it => formatDate(it.created, timezone, 'yyyy-MM-dd') - } - ] - - const hedgingReserve = BigNumber( - R.reduce( - (acc, value) => acc.plus(value), - BigNumber(0), - R.values(operatorData?.assets.values.hedgedContracts) ?? [] - ) ?? 0 - ).toNumber() - - return ( - !loading && ( - <> - - -

Fiat balance history

- - - ) - ) -} - -export default Accounting diff --git a/new-lamassu-admin/src/pages/Accounting/Accounting.styles.js b/new-lamassu-admin/src/pages/Accounting/Accounting.styles.js deleted file mode 100644 index e62a1c85..00000000 --- a/new-lamassu-admin/src/pages/Accounting/Accounting.styles.js +++ /dev/null @@ -1,39 +0,0 @@ -import { offColor } from 'src/styling/variables' - -const styles = () => ({ - totalAssetWrapper: { - display: 'flex', - flexDirection: 'row' - }, - totalAssetFieldWrapper: { - display: 'flex', - flexDirection: 'column' - }, - fieldHeader: { - color: offColor, - marginBottom: 5 - }, - fieldValue: { - fontSize: 36 - }, - fieldCurrency: { - fontSize: 20, - alignSelf: 'flex-end', - margin: [[0, 0, 5, 5]] - }, - separator: { - fontSize: 32, - alignSelf: 'center', - margin: [[25, 20, 0, 20]] - }, - tableTitle: { - marginTop: 35 - }, - operation: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center' - } -}) - -export default styles diff --git a/new-lamassu-admin/src/pages/Assets/Assets.js b/new-lamassu-admin/src/pages/Assets/Assets.js deleted file mode 100644 index 6a2f8e8c..00000000 --- a/new-lamassu-admin/src/pages/Assets/Assets.js +++ /dev/null @@ -1,258 +0,0 @@ -import { useQuery } from '@apollo/react-hooks' -import Grid from '@material-ui/core/Grid' -import Table from '@material-ui/core/Table' -import TableBody from '@material-ui/core/TableBody' -import TableCell from '@material-ui/core/TableCell' -import TableContainer from '@material-ui/core/TableContainer' -import TableHead from '@material-ui/core/TableHead' -import TableRow from '@material-ui/core/TableRow' -import { makeStyles, withStyles } from '@material-ui/core/styles' -import gql from 'graphql-tag' -import * as R from 'ramda' -import React, { useContext } from 'react' - -import AppContext from 'src/AppContext' -import TitleSection from 'src/components/layout/TitleSection' -import { H4, Label2, P, Info2 } from 'src/components/typography' -import { numberToFiatAmount } from 'src/utils/number' - -import styles from './Assets.styles' - -const useStyles = makeStyles(styles) - -const GET_OPERATOR_BY_USERNAME = gql` - query operatorByUsername($username: String) { - operatorByUsername(username: $username) { - id - entityId - name - fiatBalances - cryptoBalances - machines - joined - assets - preferredFiatCurrency - contactInfo { - name - email - } - fundings { - id - origin - destination - fiatAmount - fiatBalanceAfter - fiatCurrency - created - status - description - } - } - } -` - -const cellStyling = { - borderBottom: '4px solid white', - padding: 0, - paddingLeft: 20, - paddingRight: 20 -} - -const Cell = withStyles({ - root: cellStyling -})(TableCell) - -const HeaderCell = withStyles({ - root: { - ...cellStyling, - backgroundColor: 'white' - } -})(TableCell) - -const AssetsAmountTable = ({ title, data = [], numToRender }) => { - const classes = useStyles() - - const totalAmount = R.compose(R.sum, R.map(R.path(['amount'])))(data) ?? 0 - const currency = data[0]?.currency ?? '' - const selectAmountPrefix = it => - it.direction === 'in' ? '+' : R.isNil(it.direction) ? '' : '-' - - return ( - <> - -

{title}

- - - - - -
- Asset -
-
- -
- Amount -
-
-
-
- - {data?.map((asset, idx) => { - if (!(idx < numToRender)) return <> - return ( - - -

{asset.display}

-
- -

{`${selectAmountPrefix(asset)} - ${numberToFiatAmount(Math.abs(asset.amount))} ${ - asset.currency - }`}

-
-
- ) - })} - - - {`Total ${R.toLower(title)}`} - - - {`${numberToFiatAmount( - totalAmount - )} ${currency}`} - - -
-
-
-
- - ) -} - -const Assets = () => { - const classes = useStyles() - const { userData } = useContext(AppContext) - - const { data, loading } = useQuery(GET_OPERATOR_BY_USERNAME, { - context: { clientName: 'pazuz' }, - variables: { username: userData?.username } - }) - - const operatorData = R.path(['operatorByUsername'], data) - - const balanceData = [ - { - id: 'fiatBalance', - display: 'Fiat balance', - amount: operatorData?.assets.total ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? ''), - class: 'Available balance' - }, - { - id: 'hedgingReserve', - display: 'Hedging reserve', - amount: - -R.sum(R.values(operatorData?.assets.values.hedgedContracts)) ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? ''), - class: 'Available balance', - direction: 'out' - } - ] - - const walletData = [ - { - id: 'hedgedWalletAssets', - display: 'Hedged wallet assets', - amount: R.sum(R.values(operatorData?.assets.values.hedgedContracts)) ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? ''), - class: 'Wallet assets', - direction: 'in' - }, - { - id: 'unhedgedWalletAssets', - display: 'Unhedged wallet assets', - amount: R.sum(R.values(operatorData?.assets.values.unhedgedFiat)) ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? ''), - class: 'Wallet assets', - direction: 'in' - } - ] - - const totalData = [ - { - id: 'fiatBalance', - display: 'Fiat balance', - amount: - operatorData?.fiatBalances[operatorData?.preferredFiatCurrency] ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? '') - }, - { - id: 'hedgingReserve', - display: 'Hedging reserve', - amount: - -R.sum(R.values(operatorData?.assets.values.hedgedContracts)) ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? ''), - direction: 'out' - }, - { - id: 'hedgedWalletAssets', - display: 'Market value of hedged wallet assets', - amount: R.sum(R.values(operatorData?.assets.values.hedgedContracts)) ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? ''), - direction: 'in' - }, - { - id: 'unhedgedWalletAssets', - display: 'Unhedged wallet assets', - amount: R.sum(R.values(operatorData?.assets.values.unhedgedFiat)) ?? 0, - currency: R.toUpper(operatorData?.preferredFiatCurrency ?? ''), - direction: 'in' - } - ] - - return ( - !loading && ( - <> - -
- - - -
- -
-
- -
-
-
- - -
- -
-
-
-
-
- - ) - ) -} - -export default Assets diff --git a/new-lamassu-admin/src/pages/Assets/Assets.styles.js b/new-lamassu-admin/src/pages/Assets/Assets.styles.js deleted file mode 100644 index eea2e084..00000000 --- a/new-lamassu-admin/src/pages/Assets/Assets.styles.js +++ /dev/null @@ -1,45 +0,0 @@ -import { - white, - offColor, - backgroundColor, - subheaderColor -} from 'src/styling/variables' - -const styles = () => ({ - card: { - wordWrap: 'break-word', - boxShadow: '0 0 4px 0 rgba(0, 0, 0, 0.08)', - borderRadius: 12, - padding: 24, - backgroundColor: white - }, - h4: { - marginTop: 0 - }, - label: { - margin: 0, - color: offColor - }, - asset: { - float: 'left' - }, - amount: { - float: 'right' - }, - row: { - backgroundColor: backgroundColor, - borderBottom: 'none' - }, - totalRow: { - backgroundColor: subheaderColor, - borderBottom: 'none' - }, - leftSide: { - margin: [[0, 10, 20, 0]] - }, - rightSide: { - margin: [[0, 0, 0, 10]] - } -}) - -export default styles diff --git a/new-lamassu-admin/src/pages/Authentication/Input2FAState.js b/new-lamassu-admin/src/pages/Authentication/Input2FAState.js index 31deaf63..e1778b35 100644 --- a/new-lamassu-admin/src/pages/Authentication/Input2FAState.js +++ b/new-lamassu-admin/src/pages/Authentication/Input2FAState.js @@ -1,6 +1,5 @@ import { useMutation, useLazyQuery } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core/styles' -import base64 from 'base-64' import { Form, Formik } from 'formik' import gql from 'graphql-tag' import React, { useContext, useState } from 'react' @@ -59,14 +58,7 @@ const Input2FAState = ({ state, dispatch }) => { const [input2FA, { error: mutationError }] = useMutation(INPUT_2FA, { onCompleted: ({ input2FA: success }) => { if (success) { - const options = { - context: { - headers: { - 'Pazuz-Operator-Identifier': base64.encode(state.clientField) - } - } - } - return getUserData(options) + return getUserData() } return setInvalidToken(true) } @@ -94,11 +86,6 @@ const Input2FAState = ({ state, dispatch }) => { password: state.passwordField, code: state.twoFAField, rememberMe: state.rememberMeField - }, - context: { - headers: { - 'Pazuz-Operator-Identifier': base64.encode(state.clientField) - } } } diff --git a/new-lamassu-admin/src/pages/Authentication/LoginState.js b/new-lamassu-admin/src/pages/Authentication/LoginState.js index 1716919b..63272ba2 100644 --- a/new-lamassu-admin/src/pages/Authentication/LoginState.js +++ b/new-lamassu-admin/src/pages/Authentication/LoginState.js @@ -1,7 +1,6 @@ import { useMutation, useLazyQuery } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core/styles' import { startAssertion } from '@simplewebauthn/browser' -import base64 from 'base-64' import { Field, Form, Formik } from 'formik' import gql from 'graphql-tag' import React, { useContext } from 'react' @@ -84,11 +83,6 @@ const LoginState = ({ state, dispatch, strategy }) => { variables: { username, password - }, - context: { - headers: { - 'Pazuz-Operator-Identifier': base64.encode(username) - } } } const { data: loginResponse } = await login(options) diff --git a/new-lamassu-admin/src/pages/Authentication/Register.js b/new-lamassu-admin/src/pages/Authentication/Register.js index f9e24e5f..dcc6e64c 100644 --- a/new-lamassu-admin/src/pages/Authentication/Register.js +++ b/new-lamassu-admin/src/pages/Authentication/Register.js @@ -90,16 +90,10 @@ const Register = () => { const classes = useStyles() const history = useHistory() const token = QueryParams().get('t') - const identifier = QueryParams().get('id') ?? null const [state, dispatch] = useReducer(reducer, initialState) const queryOptions = { - context: { - headers: { - 'Pazuz-Operator-Identifier': identifier - } - }, variables: { token: token }, onCompleted: ({ validateRegisterLink: info }) => { if (!info) { diff --git a/new-lamassu-admin/src/pages/Authentication/Setup2FAState.js b/new-lamassu-admin/src/pages/Authentication/Setup2FAState.js index 618ed89e..68233c99 100644 --- a/new-lamassu-admin/src/pages/Authentication/Setup2FAState.js +++ b/new-lamassu-admin/src/pages/Authentication/Setup2FAState.js @@ -1,6 +1,5 @@ import { useMutation, useQuery, useLazyQuery } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core/styles' -import base64 from 'base-64' import { Form, Formik } from 'formik' import gql from 'graphql-tag' import QRCode from 'qrcode.react' @@ -71,11 +70,6 @@ const Setup2FAState = ({ state, dispatch }) => { const queryOptions = { variables: { username: state.clientField, password: state.passwordField }, - context: { - headers: { - 'Pazuz-Operator-Identifier': base64.encode(state.clientField) - } - }, onCompleted: ({ get2FASecret }) => { setSecret(get2FASecret.secret) setOtpauth(get2FASecret.otpauth) @@ -88,11 +82,6 @@ const Setup2FAState = ({ state, dispatch }) => { password: state.passwordField, rememberMe: state.rememberMeField, codeConfirmation: twoFAConfirmation - }, - context: { - headers: { - 'Pazuz-Operator-Identifier': base64.encode(state.clientField) - } } } @@ -107,14 +96,7 @@ const Setup2FAState = ({ state, dispatch }) => { const [setup2FA, { error: mutationError }] = useMutation(SETUP_2FA, { onCompleted: ({ setup2FA: success }) => { - const options = { - context: { - headers: { - 'Pazuz-Operator-Identifier': base64.encode(state.clientField) - } - } - } - success ? getUserData(options) : setInvalidToken(true) + success ? getUserData() : setInvalidToken(true) } }) diff --git a/new-lamassu-admin/src/pages/UserManagement/modals/CreateUserModal.js b/new-lamassu-admin/src/pages/UserManagement/modals/CreateUserModal.js index b6c21dc3..e4f5ea73 100644 --- a/new-lamassu-admin/src/pages/UserManagement/modals/CreateUserModal.js +++ b/new-lamassu-admin/src/pages/UserManagement/modals/CreateUserModal.js @@ -1,6 +1,5 @@ import { useMutation } from '@apollo/react-hooks' import { makeStyles } from '@material-ui/core/styles' -import base64 from 'base-64' import classnames from 'classnames' import { Field, Form, Formik } from 'formik' import gql from 'graphql-tag' @@ -75,12 +74,7 @@ const CreateUserModal = ({ state, dispatch }) => { const [createUser, { error }] = useMutation(CREATE_USER, { onCompleted: ({ createRegisterToken: token }) => { - const queryParams = - // Pazuz-created register tokens add a field to identify the creator - process.env.REACT_APP_BUILD_TARGET === 'LAMASSU' - ? `t=${token.token}` - : `t=${token.token}&id=${base64.encode(usernameField)}` - setCreateUserURL(urlResolver(`/register?${queryParams}`)) + setCreateUserURL(urlResolver(`/register?t${token.token}`)) } }) diff --git a/new-lamassu-admin/src/pages/Wizard/Wizard.js b/new-lamassu-admin/src/pages/Wizard/Wizard.js index fe68d1bf..b9ee1bb6 100644 --- a/new-lamassu-admin/src/pages/Wizard/Wizard.js +++ b/new-lamassu-admin/src/pages/Wizard/Wizard.js @@ -2,7 +2,6 @@ import { useQuery } from '@apollo/react-hooks' import { makeStyles, Dialog, DialogContent } from '@material-ui/core' import classnames from 'classnames' import gql from 'graphql-tag' -import * as R from 'ramda' import React, { useState, useContext } from 'react' import { useHistory } from 'react-router-dom' @@ -53,18 +52,6 @@ const Wizard = ({ fromAuthRegister }) => { const [footerExp, setFooterExp] = useState(false) - const getSteps = STEPS => { - const buildTarget = process.env.REACT_APP_BUILD_TARGET - if (buildTarget === 'PAZUZ') { - return R.filter(step => step.id !== 'wallet' && step.id !== 'twilio')( - STEPS - ) - } - return STEPS - } - - const steps = getSteps(STEPS) - if (loading) { return <> } @@ -91,7 +78,7 @@ const Wizard = ({ fromAuthRegister }) => { } const doContinue = () => { - if (step >= steps.length - 1) { + if (step >= STEPS.length - 1) { setOpen(false) history.push('/') } @@ -102,7 +89,7 @@ const Wizard = ({ fromAuthRegister }) => { setStep(nextStep) } - const current = steps[step] + const current = STEPS[step] return ( @@ -112,7 +99,7 @@ const Wizard = ({ fromAuthRegister }) => { {!isWelcome && (