From b9d2341cd1cb7c78ba1e5fb7db6311e135338ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20F=C3=A9lix?= <5789328+lcsfelix@users.noreply.github.com> Date: Fri, 10 Jan 2020 14:26:51 +0000 Subject: [PATCH] feat: add services page fix: change styles, fix hook trigger, add ux feat: setup custom error messages refactor: conform to new style guide refactor: migrate to graphql refactor: migrate to Ramda fix: update state on mutation refactor: migrate error ux to graphql fix: change structure of accounts config fix: use absolute imports fix: move makeStyles out of components fix: correct Strike behaviour --- bin/insecure-dev.sh | 0 lib/new-admin/accounts.js | 124 ++++ new-lamassu-admin/package-lock.json | 654 +++++++++++------- .../src/components/fake-table/Table.js | 4 +- .../inputs/formik/PhoneNumberInput.js | 42 ++ .../components/inputs/formik/SecretInput.js | 46 ++ .../inputs/formik/TextInput.styles.js | 28 + .../single-row-table/SingleRowTable.js | 160 +++++ new-lamassu-admin/src/pages/Services/Bitgo.js | 250 +++++++ .../src/pages/Services/Bitstamp.js | 116 ++++ .../src/pages/Services/Blockcypher.js | 101 +++ .../src/pages/Services/EditService.js | 94 +++ .../src/pages/Services/Infura.js | 117 ++++ new-lamassu-admin/src/pages/Services/Itbit.js | 126 ++++ .../src/pages/Services/Kraken.js | 101 +++ .../src/pages/Services/Mailgun.js | 132 ++++ .../src/pages/Services/Services.js | 242 +++++++ .../src/pages/Services/Services.styles.js | 177 +++++ .../src/pages/Services/Strike.js | 79 +++ .../src/pages/Services/Twilio.js | 131 ++++ new-lamassu-admin/src/pages/Services/aux.js | 44 ++ .../src/pages/Transactions/CopyToClipboard.js | 4 +- .../src/pages/Transactions/DetailsCard.js | 12 +- .../src/pages/Transactions/Transactions.js | 4 +- new-lamassu-admin/src/routing/routes.js | 9 +- .../src/styling/icons/action/close/zodiac.svg | 41 +- .../src/styling/icons/warning-icon/comet.svg | 12 + .../src/styling/icons/warning-icon/tomato.svg | 12 + new-lamassu-admin/src/styling/variables.js | 4 + package-lock.json | 19 +- 30 files changed, 2579 insertions(+), 306 deletions(-) mode change 100644 => 100755 bin/insecure-dev.sh create mode 100644 lib/new-admin/accounts.js create mode 100644 new-lamassu-admin/src/components/inputs/formik/PhoneNumberInput.js create mode 100644 new-lamassu-admin/src/components/inputs/formik/SecretInput.js create mode 100644 new-lamassu-admin/src/components/inputs/formik/TextInput.styles.js create mode 100644 new-lamassu-admin/src/components/single-row-table/SingleRowTable.js create mode 100644 new-lamassu-admin/src/pages/Services/Bitgo.js create mode 100644 new-lamassu-admin/src/pages/Services/Bitstamp.js create mode 100644 new-lamassu-admin/src/pages/Services/Blockcypher.js create mode 100644 new-lamassu-admin/src/pages/Services/EditService.js create mode 100644 new-lamassu-admin/src/pages/Services/Infura.js create mode 100644 new-lamassu-admin/src/pages/Services/Itbit.js create mode 100644 new-lamassu-admin/src/pages/Services/Kraken.js create mode 100644 new-lamassu-admin/src/pages/Services/Mailgun.js create mode 100644 new-lamassu-admin/src/pages/Services/Services.js create mode 100644 new-lamassu-admin/src/pages/Services/Services.styles.js create mode 100644 new-lamassu-admin/src/pages/Services/Strike.js create mode 100644 new-lamassu-admin/src/pages/Services/Twilio.js create mode 100644 new-lamassu-admin/src/pages/Services/aux.js create mode 100644 new-lamassu-admin/src/styling/icons/warning-icon/comet.svg create mode 100644 new-lamassu-admin/src/styling/icons/warning-icon/tomato.svg diff --git a/bin/insecure-dev.sh b/bin/insecure-dev.sh old mode 100644 new mode 100755 diff --git a/lib/new-admin/accounts.js b/lib/new-admin/accounts.js new file mode 100644 index 00000000..fd6624ef --- /dev/null +++ b/lib/new-admin/accounts.js @@ -0,0 +1,124 @@ +const _ = require('lodash/fp') + +const db = require('../db') +const config = require('./config') +const ph = require('../plugin-helper') + +const schemas = ph.loadSchemas() + +function fetchAccounts () { + return db.oneOrNone('select data from user_config where type=$1', ['accounts']) + .then(row => { + // Hard code this for now + const accounts = [{ + code: 'blockcypher', + display: 'Blockcypher', + fields: [ + { code: 'confidenceFactor', display: 'Confidence Factor', fieldType: 'integer', required: true, value: 40 } + ] + }] + + return row + ? Promise.resolve(row.data.accounts) + : db.none('insert into user_config (type, data, valid) values ($1, $2, $3)', ['accounts', { accounts }, true]) + .then(fetchAccounts) + }) +} + +function selectedAccounts () { + const mapAccount = v => v.fieldLocator.fieldType === 'account' && + v.fieldValue.value + + const mapSchema = code => schemas[code] + return config.fetchConfig() + .then(conf => { + const accountCodes = _.uniq(conf.map(mapAccount) + .filter(_.identity)) + + return _.sortBy(_.get('display'), accountCodes.map(mapSchema) + .filter(_.identity)) + }) +} + +function fetchAccountSchema (account) { + return schemas[account] +} + +function mergeAccount (oldAccount, newAccount) { + if (!newAccount) return oldAccount + + const newFields = newAccount.fields + + const updateWithData = oldField => { + const newField = _.find(r => r.code === oldField.code, newFields) + const newValue = _.isUndefined(newField) ? oldField.value : newField.value + return _.set('value', newValue, oldField) + } + + const updatedFields = oldAccount.fields.map(updateWithData) + + return _.set('fields', updatedFields, oldAccount) +} + +function getAccounts (accountCode) { + const schema = fetchAccountSchema(accountCode) + if (!schema) return Promise.reject(new Error('No schema for: ' + accountCode)) + + return fetchAccounts() + .then(accounts => { + if (_.isEmpty(accounts)) return [schema] + const account = _.find(r => r.code === accountCode, accounts) + const mergedAccount = mergeAccount(schema, account) + + return updateAccounts(mergedAccount, accounts) + }) +} + +function elideSecrets (account) { + const elideSecret = field => { + return field.fieldType === 'password' + ? _.set('value', !_.isEmpty(field.value), field) + : field + } + + return _.set('fields', account.fields.map(elideSecret), account) +} + +function getAccount (accountCode) { + return getAccounts(accountCode) + .then(accounts => _.find(r => r.code === accountCode, accounts)) + .then(elideSecrets) +} + +function save (accounts) { + return db.none('update user_config set data=$1 where type=$2', [{ accounts: accounts }, 'accounts']) +} + +function updateAccounts (newAccount, accounts) { + const accountCode = newAccount.code + const isPresent = _.some(_.matchesProperty('code', accountCode), accounts) + const updateAccount = r => r.code === accountCode + ? newAccount + : r + + return isPresent + ? _.map(updateAccount, accounts) + : _.concat(accounts, newAccount) +} + +function updateAccount (account) { + return getAccounts(account.code) + .then(accounts => { + const merged = mergeAccount(_.find(_.matchesProperty('code', account.code), accounts), account) + return save(updateAccounts(merged, accounts)) + }) + .then(() => getAccount(account.code)) + .catch((err) => console.log(err)) +} + +module.exports = { + selectedAccounts, + getAccount, + updateAccount, + fetchAccounts +} diff --git a/new-lamassu-admin/package-lock.json b/new-lamassu-admin/package-lock.json index e077372d..f53f38fd 100644 --- a/new-lamassu-admin/package-lock.json +++ b/new-lamassu-admin/package-lock.json @@ -1722,24 +1722,6 @@ } } }, - "@babel/runtime-corejs3": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.7.6.tgz", - "integrity": "sha512-NrRUehqG0sMSCaP+0XV/vOvvjNl4BQOWq3Qys1Q2KTEm5tGMo9h0dHnIzeKerj0a7SIB8LP5kYg/T1raE3FoKQ==", - "dev": true, - "requires": { - "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.2" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", - "dev": true - } - } - }, "@babel/template": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", @@ -1958,9 +1940,9 @@ "dev": true }, "@hapi/address": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", - "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.2.tgz", + "integrity": "sha512-O4QDrx+JoGKZc6aN64L04vqa7e41tIiLU+OvKdcYaEMP97UttL0f9GIi9/0A4WAMx0uBd6SidDIhktZhgOcN8Q==", "dev": true }, "@hapi/bourne": { @@ -1970,9 +1952,9 @@ "dev": true }, "@hapi/hoek": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.0.tgz", - "integrity": "sha512-7XYT10CZfPsH7j9F1Jmg1+d0ezOux2oM2GfArAzLwWe4mE2Dr3hVjsAL6+TFY49RRJlCdJDMw3nJsLFroTc8Kw==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.3.0.tgz", + "integrity": "sha512-C0QL9bmgUXTSuf8nDeGrpMjtJG7tPUr8wG6/wxPbP62tGwCwQtdMSJYfESowmY4P3Hn593f+8OzNY5bckcu/LQ==", "dev": true }, "@hapi/joi": { @@ -1988,12 +1970,12 @@ } }, "@hapi/topo": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", - "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.5.tgz", + "integrity": "sha512-bi9m1jrui9LlvtVdLaHv0DqeOoe+I8dep+nEcTgW6XxJHL3xArQcilYz3tIp0cRC4gWlsVtABK7vNKg4jzEmAA==", "dev": true, "requires": { - "@hapi/hoek": "^8.3.0" + "@hapi/hoek": "8.x.x" } }, "@icons/material": { @@ -3866,9 +3848,9 @@ } }, "@types/json-schema": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", - "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", "dev": true }, "@types/minimatch": { @@ -3983,43 +3965,26 @@ "integrity": "sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg==" }, "@typescript-eslint/eslint-plugin": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.11.0.tgz", - "integrity": "sha512-G2HHA1vpMN0EEbUuWubiCCfd0R3a30BB+UdvnFkxwZIxYEGOrWEXDv8tBFO9f44CWc47Xv9lLM3VSn4ORLI2bA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.14.0.tgz", + "integrity": "sha512-sneOJ3Hu0m5whJiVIxGBZZZMxMJ7c0LhAJzeMJgHo+n5wFs+/6rSR/gl7crkdR2kNwfOOSdzdc0gMvatG4dX2Q==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.11.0", + "@typescript-eslint/experimental-utils": "2.14.0", "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "tsutils": "^3.17.1" - }, - "dependencies": { - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "regexpp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", - "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", - "dev": true - } } }, "@typescript-eslint/experimental-utils": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.11.0.tgz", - "integrity": "sha512-YxcA/y0ZJaCc/fB/MClhcDxHI0nOBB7v2/WxBju2cOTanX7jO9ttQq6Fy4yW9UaY5bPd9xL3cun3lDVqk67sPQ==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.14.0.tgz", + "integrity": "sha512-KcyKS7G6IWnIgl3ZpyxyBCxhkBPV+0a5Jjy2g5HxlrbG2ZLQNFeneIBVXdaBCYOVjvGmGGFKom1kgiAY75SDeQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.11.0", + "@typescript-eslint/typescript-estree": "2.14.0", "eslint-scope": "^5.0.0" }, "dependencies": { @@ -4036,21 +4001,21 @@ } }, "@typescript-eslint/parser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.11.0.tgz", - "integrity": "sha512-DyGXeqhb3moMioEFZIHIp7oXBBh7dEfPTzGrlyP0Mi9ScCra4SWEGs3kPd18mG7Sy9Wy8z88zmrw5tSGL6r/6A==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.14.0.tgz", + "integrity": "sha512-haS+8D35fUydIs+zdSf4BxpOartb/DjrZ2IxQ5sR8zyGfd77uT9ZJZYF8+I0WPhzqHmfafUBx8MYpcp8pfaoSA==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.11.0", - "@typescript-eslint/typescript-estree": "2.11.0", + "@typescript-eslint/experimental-utils": "2.14.0", + "@typescript-eslint/typescript-estree": "2.14.0", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.11.0.tgz", - "integrity": "sha512-HGY4+d4MagO6cKMcKfIKaTMxcAv7dEVnji2Zi+vi5VV8uWAM631KjAB5GxFcexMYrwKT0EekRiiGK1/Sd7VFGA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.14.0.tgz", + "integrity": "sha512-pnLpUcMNG7GfFFfNQbEX6f1aPa5fMnH2G9By+A1yovYI4VIOK2DzkaRuUlIkbagpAcrxQHLqovI1YWqEcXyRnA==", "dev": true, "requires": { "debug": "^4.1.1", @@ -4371,6 +4336,12 @@ } } }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, "acorn-walk": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", @@ -5392,30 +5363,12 @@ } }, "axobject-query": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.1.tgz", - "integrity": "sha512-lF98xa/yvy6j3fBHAgQXIYl+J4eZadOSqsPojemUqClzNbBV38wWGpUbQbVEyf4eUF5yF7eHmGgGA2JiHyjeqw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", "dev": true, "requires": { - "@babel/runtime": "^7.7.4", - "@babel/runtime-corejs3": "^7.7.4" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.6.tgz", - "integrity": "sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", - "dev": true - } + "ast-types-flow": "0.0.7" } }, "babel-code-frame": { @@ -5477,9 +5430,9 @@ }, "dependencies": { "resolve": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", - "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -6605,14 +6558,14 @@ } }, "browserslist": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", - "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.2.tgz", + "integrity": "sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001015", - "electron-to-chromium": "^1.3.322", - "node-releases": "^1.1.42" + "caniuse-lite": "^1.0.30000939", + "electron-to-chromium": "^1.3.113", + "node-releases": "^1.1.8" } }, "bser": { @@ -6711,6 +6664,12 @@ "yallist": "^3.0.2" } }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -6801,9 +6760,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001015", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz", - "integrity": "sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ==", + "version": "1.0.30000943", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000943.tgz", + "integrity": "sha512-nJMjU4UaesbOHTcmz6VS+qaog++Fdepg4KAya5DL/AZrL/aaAZDGOOQ0AECtsJa09r4cJBdHZMive5mw8lnQ5A==", "dev": true }, "capture-exit": { @@ -8783,9 +8742,9 @@ "dev": true }, "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.0.tgz", + "integrity": "sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw==", "dev": true, "requires": { "is-arguments": "^1.0.4", @@ -9348,9 +9307,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.322", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", - "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==", + "version": "1.3.114", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.114.tgz", + "integrity": "sha512-EQEFDVId4dqTrV9wvDmu/Po8Re9nN1sJm9KZECKRf3HC39DUYAEHQ8s7s9HsnhO9iFwl/Gpke9dvm6VwQTss5w==", "dev": true }, "elegant-spinner": { @@ -9508,14 +9467,14 @@ } }, "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "version": "0.10.51", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", + "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", "dev": true, "requires": { "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" } }, "es5-shim": { @@ -9542,13 +9501,13 @@ "dev": true }, "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", + "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", "dev": true, "requires": { "d": "^1.0.1", - "ext": "^1.1.2" + "es5-ext": "^0.10.51" } }, "escape-html": { @@ -9592,9 +9551,9 @@ } }, "eslint": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.2.tgz", - "integrity": "sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -9636,12 +9595,6 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { - "acorn-jsx": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", - "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", - "dev": true - }, "ansi-escapes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", @@ -9682,26 +9635,6 @@ "estraverse": "^4.1.1" } }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "espree": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", - "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", - "dev": true, - "requires": { - "acorn": "^7.1.0", - "acorn-jsx": "^5.1.0", - "eslint-visitor-keys": "^1.1.0" - } - }, "figures": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", @@ -9731,9 +9664,9 @@ } }, "inquirer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", - "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", + "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", "dev": true, "requires": { "ansi-escapes": "^4.2.1", @@ -9745,7 +9678,7 @@ "lodash": "^4.17.15", "mute-stream": "0.0.8", "run-async": "^2.2.0", - "rxjs": "^6.4.0", + "rxjs": "^6.5.3", "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" @@ -9792,6 +9725,12 @@ "word-wrap": "~1.2.3" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -9808,6 +9747,15 @@ "signal-exit": "^3.0.2" } }, + "rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -9964,9 +9912,9 @@ "dev": true }, "schema-utils": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz", - "integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.4.1.tgz", + "integrity": "sha512-RqYLpkPZX5Oc3fw/kHHHyP56fg5Y+XBpIpV8nCg0znIALfq3OH+Ea9Hfeac9BAMwG5IICltiZ0vxFvJQONfA5w==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -10112,9 +10060,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.6.tgz", - "integrity": "sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -10217,6 +10165,17 @@ "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -10250,8 +10209,7 @@ "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "etag": { "version": "1.8.1", @@ -10467,23 +10425,6 @@ } } }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dev": true, - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", - "dev": true - } - } - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -11784,11 +11725,6 @@ "iterall": "^1.2.2" } }, - "graphql-iso-date": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/graphql-iso-date/-/graphql-iso-date-3.6.1.tgz", - "integrity": "sha512-AwFGIuYMJQXOEAgRlJlFL4H1ncFM8n8XmoVDTNypNOZyQ8LFDG2ppMFlsS862BSTCDcSUfHp8PD3/uJhv7t59Q==" - }, "graphql-tag": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", @@ -12227,6 +12163,14 @@ "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" + }, + "dependencies": { + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + } } }, "http-proxy-middleware": { @@ -13469,9 +13413,9 @@ }, "dependencies": { "acorn": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", - "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", "dev": true }, "jsdom": { @@ -13519,9 +13463,9 @@ } }, "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", "dev": true, "requires": { "lodash.sortby": "^4.7.0", @@ -14670,8 +14614,7 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "json-parse-better-errors": { "version": "1.0.2", @@ -16389,20 +16332,12 @@ } }, "node-releases": { - "version": "1.1.42", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.42.tgz", - "integrity": "sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.10.tgz", + "integrity": "sha512-KbUPCpfoBvb3oBkej9+nrU0/7xPlVhmhhUJ1PZqwIP5/1dJkRWKWD3OONjo6M2J7tSCBtDCumLwwqeI+DWWaLQ==", "dev": true, "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "semver": "^5.3.0" } }, "normalize-package-data": { @@ -17679,9 +17614,9 @@ } }, "postcss-initial": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.2.tgz", - "integrity": "sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.1.tgz", + "integrity": "sha512-I2Sz83ZSHybMNh02xQDK609lZ1/QOyYeuizCjzEhlMgeV/HcDJapQiH4yTqLjZss0X6/6VvKFXUeObaHpJoINw==", "dev": true, "requires": { "lodash.template": "^4.5.0", @@ -17974,6 +17909,46 @@ "postcss": "^7.0.17", "postcss-browser-comments": "^3.0.0", "sanitize.css": "^10.0.0" + }, + "dependencies": { + "browserslist": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", + "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001015", + "electron-to-chromium": "^1.3.322", + "node-releases": "^1.1.42" + } + }, + "caniuse-lite": { + "version": "1.0.30001017", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001017.tgz", + "integrity": "sha512-EDnZyOJ6eYh6lHmCvCdHAFbfV4KJ9lSdfv4h/ppEhrU/Yudkl7jujwMZ1we6RX7DXqBfT04pVMQ4J+1wcTlsKA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", + "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==", + "dev": true + }, + "node-releases": { + "version": "1.1.44", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.44.tgz", + "integrity": "sha512-NwbdvJyR7nrcGrXvKAvzc5raj/NkoJudkarh2yIpJ4t0NH4aqjUDz/486P+ynIW5eokKOfzGNRdYoLfBlomruw==", + "dev": true, + "requires": { + "semver": "^6.3.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 + } } }, "postcss-normalize-charset": { @@ -18235,6 +18210,95 @@ "postcss-replace-overflow-wrap": "^3.0.0", "postcss-selector-matches": "^4.0.0", "postcss-selector-not": "^4.0.0" + }, + "dependencies": { + "autoprefixer": { + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.4.tgz", + "integrity": "sha512-Koz2cJU9dKOxG8P1f8uVaBntOv9lP4yz9ffWvWaicv9gHBPhpQB22nGijwd8gqW9CNT+UdkbQOQNLVI8jN1ZfQ==", + "dev": true, + "requires": { + "browserslist": "^4.7.0", + "caniuse-lite": "^1.0.30000998", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.18", + "postcss-value-parser": "^4.0.2" + }, + "dependencies": { + "postcss": { + "version": "7.0.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.18.tgz", + "integrity": "sha512-/7g1QXXgegpF+9GJj4iN7ChGF40sYuGYJ8WZu8DZWnmhQ/G36hfdk3q9LBJmoK+lZ+yzZ5KYpOoxq7LF1BxE8g==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + } + } + }, + "browserslist": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", + "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000989", + "electron-to-chromium": "^1.3.247", + "node-releases": "^1.1.29" + } + }, + "caniuse-lite": { + "version": "1.0.30000999", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000999.tgz", + "integrity": "sha512-1CUyKyecPeksKwXZvYw0tEoaMCo/RwBlXmEtN5vVnabvO0KPd9RQLcaAuR9/1F+KDMv6esmOFWlsXuzDk+8rxg==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.277", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.277.tgz", + "integrity": "sha512-Czmsrgng89DOgJlIknnw9bn5431QdtnUwGp5YYiPwU1DbZQUxCLF+rc1ZC09VNAdalOPcvH6AE8BaA0H5HjI/w==", + "dev": true + }, + "node-releases": { + "version": "1.1.35", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.35.tgz", + "integrity": "sha512-JGcM/wndCN/2elJlU0IGdVEJQQnJwsLbgPCFd2pY7V0mxf17bZ0Gb/lgOtL29ZQhvEX5shnVhxQyZz3ex94N8w==", + "dev": true, + "requires": { + "semver": "^6.3.0" + } + }, + "postcss-value-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", + "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 + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "postcss-pseudo-class-any-link": { @@ -18823,9 +18887,9 @@ }, "dependencies": { "core-js": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.5.0.tgz", - "integrity": "sha512-Ifh3kj78gzQ7NAoJXeTu+XwzDld0QRIwjBLRqAMhuLhP3d2Av5wmgE9ycfnvK6NAEjTkQ1sDPeoEZAWO3Hx1Uw==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.1.tgz", + "integrity": "sha512-186WjSik2iTGfDjfdCZAxv2ormxtKgemjC3SI6PL31qOA0j5LhTDVjHChccoc7brwLvpvLPiMyRlcO88C4l1QQ==", "dev": true }, "regenerator-runtime": { @@ -19406,6 +19470,18 @@ "source-map": "^0.5.0" }, "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -19415,15 +19491,21 @@ } }, "@babel/generator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.4.tgz", - "integrity": "sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg==", - "dev": true, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.3.tgz", + "integrity": "sha512-hLhYbAb3pHwxjlijC4AQ7mqZdcoujiNaW7izCT04CIowHK8psN0IN8QjDv0iyFtycF5FowUOTwDloIheI25aMw==", "requires": { - "@babel/types": "^7.7.4", + "@babel/types": "^7.6.3", "jsesc": "^2.5.1", "lodash": "^4.17.13", - "source-map": "^0.5.0" + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } } }, "@babel/helper-annotate-as-pure": { @@ -20319,13 +20401,26 @@ "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" + }, + "dependencies": { + "@babel/generator": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.7.7.tgz", + "integrity": "sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + } } }, "@babel/types": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", - "dev": true, "requires": { "esutils": "^2.0.2", "lodash": "^4.17.13", @@ -20421,6 +20516,17 @@ "babel-plugin-transform-react-remove-prop-types": "0.4.24" } }, + "browserslist": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", + "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001015", + "electron-to-chromium": "^1.3.322", + "node-releases": "^1.1.42" + } + }, "cacache": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", @@ -20453,6 +20559,12 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "caniuse-lite": { + "version": "1.0.30001017", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001017.tgz", + "integrity": "sha512-EDnZyOJ6eYh6lHmCvCdHAFbfV4KJ9lSdfv4h/ppEhrU/Yudkl7jujwMZ1we6RX7DXqBfT04pVMQ4J+1wcTlsKA==", + "dev": true + }, "chownr": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", @@ -20489,6 +20601,12 @@ "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "dev": true }, + "electron-to-chromium": { + "version": "1.3.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", + "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==", + "dev": true + }, "eslint-plugin-import": { "version": "2.18.2", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", @@ -20710,6 +20828,15 @@ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, + "node-releases": { + "version": "1.1.44", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.44.tgz", + "integrity": "sha512-NwbdvJyR7nrcGrXvKAvzc5raj/NkoJudkarh2yIpJ4t0NH4aqjUDz/486P+ynIW5eokKOfzGNRdYoLfBlomruw==", + "dev": true, + "requires": { + "semver": "^6.3.0" + } + }, "open": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/open/-/open-7.0.0.tgz", @@ -21244,6 +21371,12 @@ } } }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -21891,9 +22024,9 @@ } }, "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", "dev": true }, "regexpu-core": { @@ -22039,24 +22172,42 @@ "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } } }, "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.15" } }, "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", "dev": true, "requires": { - "request-promise-core": "1.1.2", + "request-promise-core": "1.1.3", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" } @@ -22074,9 +22225,9 @@ "dev": true }, "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, "requires-port": { @@ -23099,9 +23250,9 @@ } }, "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.4.tgz", + "integrity": "sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig==", "dev": true }, "slash": { @@ -24185,18 +24336,6 @@ "find-up": "^3.0.0", "read-pkg": "^3.0.0" } - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true } } }, @@ -24328,8 +24467,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-object-path": { "version": "0.3.0", @@ -24390,21 +24528,13 @@ "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=" }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "tr46": { @@ -25973,9 +26103,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.7.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.6.tgz", - "integrity": "sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.2" @@ -26220,9 +26350,9 @@ "dev": true }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { @@ -26319,6 +26449,12 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true } } }, diff --git a/new-lamassu-admin/src/components/fake-table/Table.js b/new-lamassu-admin/src/components/fake-table/Table.js index a74d9a13..5189a939 100644 --- a/new-lamassu-admin/src/components/fake-table/Table.js +++ b/new-lamassu-admin/src/components/fake-table/Table.js @@ -71,9 +71,9 @@ const Table = ({ children, className, ...props }) => ( ) -const THead = ({ children }) => { +const THead = ({ children, className }) => { const classes = useStyles() - return
{children}
+ return
{children}
} const TBody = ({ children, className }) => { diff --git a/new-lamassu-admin/src/components/inputs/formik/PhoneNumberInput.js b/new-lamassu-admin/src/components/inputs/formik/PhoneNumberInput.js new file mode 100644 index 00000000..e0744515 --- /dev/null +++ b/new-lamassu-admin/src/components/inputs/formik/PhoneNumberInput.js @@ -0,0 +1,42 @@ +import React, { memo, useState } from 'react' +import { makeStyles } from '@material-ui/core' + +import TextInputFormik from './TextInput' +import { styles } from './TextInput.styles' + +const useStyles = makeStyles(styles) + +const mask = /(\+9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,3}){0,1}(\d{1,2}){0,1}$/ +const maskValue = value => value.replace(mask, '$1 $2 $3 $4 $5 $6') + +const PhoneNumberInputFormik = memo(({ ...props }) => { + const { onChange, value } = props.field + + const classes = useStyles() + + // Regex adapted from http://phoneregex.com/ + + const [maskedValue, setMaskedValue] = useState(maskValue(value)) + + const handleChange = event => { + setMaskedValue(maskValue(event.target.value)) + + onChange(event) + } + + return ( + <> + + + + ) +}) + +export { PhoneNumberInputFormik, mask, maskValue } diff --git a/new-lamassu-admin/src/components/inputs/formik/SecretInput.js b/new-lamassu-admin/src/components/inputs/formik/SecretInput.js new file mode 100644 index 00000000..214da002 --- /dev/null +++ b/new-lamassu-admin/src/components/inputs/formik/SecretInput.js @@ -0,0 +1,46 @@ +import React, { memo, useState } from 'react' +import classnames from 'classnames' +import { makeStyles } from '@material-ui/core' + +import TextInputFormik from './TextInput' +import { styles } from './TextInput.styles' + +const useStyles = makeStyles(styles) + +const SecretInputFormik = memo(({ ...props }) => { + const { value } = props.field + + const classes = useStyles() + + const [localTouched, setLocalTouched] = useState(false) + + const handleFocus = event => { + setLocalTouched(true) + props.onFocus() + } + + const spanClass = { + [classes.secretSpan]: true, + [classes.masked]: value && !localTouched, + [classes.hideSpan]: !value || localTouched + } + + const inputClass = { + [classes.maskedInput]: value && !localTouched + } + + return ( + <> + + + + ) +}) + +export default SecretInputFormik diff --git a/new-lamassu-admin/src/components/inputs/formik/TextInput.styles.js b/new-lamassu-admin/src/components/inputs/formik/TextInput.styles.js new file mode 100644 index 00000000..8cf534a0 --- /dev/null +++ b/new-lamassu-admin/src/components/inputs/formik/TextInput.styles.js @@ -0,0 +1,28 @@ +import { fontColor, offColor } from 'src/styling/variables' +import typographyStyles from 'src/components/typography/styles' + +const { info3 } = typographyStyles + +const styles = { + masked: { + position: 'absolute', + bottom: 5, + color: fontColor + }, + secretSpan: { + extend: info3, + color: offColor + }, + hideSpan: { + display: 'none' + }, + maskedInput: { + '& input': { + pointerEvents: 'none', + backgroundColor: 'transparent', + zIndex: -1 + } + } +} + +export { styles } diff --git a/new-lamassu-admin/src/components/single-row-table/SingleRowTable.js b/new-lamassu-admin/src/components/single-row-table/SingleRowTable.js new file mode 100644 index 00000000..2097bfe5 --- /dev/null +++ b/new-lamassu-admin/src/components/single-row-table/SingleRowTable.js @@ -0,0 +1,160 @@ +import React from 'react' +import classnames from 'classnames' +import { makeStyles } from '@material-ui/core' + +import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/white.svg' +import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg' +import { ReactComponent as WarningIcon } from 'src/styling/icons/warning-icon/comet.svg' +import { + offColor, + tableDisabledHeaderColor, + tableNewDisabledHeaderColor, + secondaryColorDarker +} from 'src/styling/variables' +import { Table, THead, TBody, Td, Th } from 'src/components/fake-table/Table' +import typographyStyles from 'src/components/typography/styles' + +const { label1, p } = typographyStyles + +const SingleRowTable = ({ + width = 380, + height = 160, + title, + items, + onEdit, + disabled, + newService, + className, + ...props +}) => { + const editButtonSize = 54 + + const styles = { + wrapper: { + width: width, + boxShadow: '0 0 4px 0 rgba(0, 0, 0, 0.08)' + }, + buttonTh: { + padding: [[0, 16]] + }, + disabledHeader: { + backgroundColor: tableDisabledHeaderColor, + color: offColor + }, + newDisabledHeader: { + backgroundColor: tableNewDisabledHeaderColor + }, + disabledBody: { + extend: p, + display: 'flex', + alignItems: 'center', + height: 104 + }, + itemWrapper: { + display: 'flex', + flexDirection: 'column', + marginTop: 16, + minHeight: 40, + '& > div:last-child': {} + }, + disabledWrapper: { + display: 'flex', + alignItems: 'center', + '& > span:first-child': { + display: 'flex' + }, + '& > span:last-child': { + paddingLeft: 16 + } + }, + label: { + extend: label1, + color: offColor, + marginBottom: 4 + }, + item: { + extend: p + }, + editButton: { + border: 'none', + backgroundColor: 'transparent', + cursor: 'pointer', + display: 'flex', + padding: 0 + }, + spanNew: { + color: secondaryColorDarker, + marginLeft: 12 + } + } + + const useStyles = makeStyles(styles) + + const classes = useStyles() + + const headerClasses = { + [classes.disabledHeader]: disabled, + [classes.newDisabledHeader]: newService && disabled + } + + const bodyClasses = { + [classes.disabledBody]: disabled + } + + return ( + <> + {items && ( + + + + + + + + +
+ {title} + {newService && New} + + {!disabled && ( + + )} + {disabled && ( + + )} +
+ {!disabled && ( + <> + {items[0] && ( +
+
{items[0].label}
+
{items[0].value}
+
+ )} + {items[1] && ( +
+
{items[1].label}
+
{items[1].value}
+
+ )} + + )} + {disabled && ( +
+ + + + This service is not being used +
+ )} +
+ )} + + ) +} + +export default SingleRowTable diff --git a/new-lamassu-admin/src/pages/Services/Bitgo.js b/new-lamassu-admin/src/pages/Services/Bitgo.js new file mode 100644 index 00000000..db92be4a --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Bitgo.js @@ -0,0 +1,250 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' + +import { Card, getValue as getValueAux, formatLong } from './aux' +import EditService from './EditService' + +const schema = { + token: { + code: 'token', + display: 'API Token' + }, + btcWalletId: { + code: 'BTCWalletId', + display: 'BTC Wallet ID' + }, + btcWalletPassphrase: { + code: 'BTCWalletPassphrase', + display: 'BTC Wallet Passphrase' + }, + ltcWalletId: { + code: 'LTCWalletId', + display: 'LTC Wallet ID' + }, + ltcWalletPassphrase: { + code: 'LTCWalletPassphrase', + display: 'LTC Wallet Passphrase' + }, + zecWalletId: { + code: 'ZECWalletId', + display: 'ZEC Wallet ID' + }, + zecWalletPassphrase: { + code: 'ZECWalletPassphrase', + display: 'ZEC Wallet Passphrase' + }, + bchWalletId: { + code: 'BCHWalletId', + display: 'BCH Wallet ID' + }, + bchWalletPassphrase: { + code: 'BCHWalletPassphrase', + display: 'BCH Wallet Passphrase' + }, + dashWalletId: { + code: 'DASHWalletId', + display: 'DASH Wallet ID' + }, + dashWalletPassphrase: { + code: 'DASHWalletPassphrase', + display: 'DASH Wallet Passphrase' + }, + environment: { + code: 'environment', + display: 'Environment' + } +} + +const BitgoCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const token = schema.token + const tokenValue = getValue(token.code) + + const items = [ + { + label: token.display, + value: formatLong(tokenValue) + } + ] + + return ( + + ) +}) + +const BitgoForm = ({ account, handleSubmit, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const token = getValue(schema.token.code) + const btcWalletId = getValue(schema.btcWalletId.code) + const btcWalletPassphrase = getValue(schema.btcWalletPassphrase.code) + const ltcWalletId = getValue(schema.ltcWalletId.code) + const ltcWalletPassphrase = getValue(schema.ltcWalletPassphrase.code) + const zecWalletId = getValue(schema.zecWalletId.code) + const zecWalletPassphrase = getValue(schema.zecWalletPassphrase.code) + const bchWalletId = getValue(schema.bchWalletId.code) + const bchWalletPassphrase = getValue(schema.bchWalletPassphrase.code) + const dashWalletId = getValue(schema.dashWalletId.code) + const dashWalletPassphrase = getValue(schema.dashWalletPassphrase.code) + const environment = getValue(schema.environment.code) + + const formik = { + initialValues: { + token: token, + BTCWalletId: btcWalletId, + BTCWalletPassphrase: btcWalletPassphrase, + LTCWalletId: ltcWalletId, + LTCWalletPassphrase: ltcWalletPassphrase, + ZECWalletId: zecWalletId, + ZECWalletPassphrase: zecWalletPassphrase, + BCHWalletId: bchWalletId, + BCHWalletPassphrase: bchWalletPassphrase, + DASHWalletId: dashWalletId, + DASHWalletPassphrase: dashWalletPassphrase, + environment: environment + }, + validationSchema: Yup.object().shape({ + token: Yup.string() + .max(100, 'Too long') + .required('Required'), + btcWalletId: Yup.string().max(100, 'Too long'), + btcWalletPassphrase: Yup.string().max(100, 'Too long'), + ltcWalletId: Yup.string().max(100, 'Too long'), + ltcWalletPassphrase: Yup.string().max(100, 'Too long'), + zecWalletId: Yup.string().max(100, 'Too long'), + zecWalletPassphrase: Yup.string().max(100, 'Too long'), + bchWalletId: Yup.string().max(100, 'Too long'), + bchWalletPassphrase: Yup.string().max(100, 'Too long'), + dashWalletId: Yup.string().max(100, 'Too long'), + dashWalletPassphrase: Yup.string().max(100, 'Too long'), + environment: Yup.string() + .matches(/(prod|test)/) + .required('Required') + }), + validate: values => { + const errors = {} + + if (values.btcWalletId && !values.btcWalletPassphrase) { + errors.btcWalletPassphrase = 'Required' + } + + if (values.ltcWalletId && !values.ltcWalletPassphrase) { + errors.ltcWalletPassphrase = 'Required' + } + + if (values.zecWalletId && !values.zecWalletPassphrase) { + errors.zecWalletPassphrase = 'Required' + } + + if (values.bchWalletId && !values.bchWalletPassphrase) { + errors.bchWalletPassphrase = 'Required' + } + + if (values.dashWalletId && !values.dashWalletPassphrase) { + errors.dashWalletPassphrase = 'Required' + } + + return errors + } + } + + const fields = [ + { + name: schema.token.code, + label: schema.token.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.btcWalletId.code, + label: schema.btcWalletId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.btcWalletPassphrase.code, + label: schema.btcWalletPassphrase.display, + type: 'text', + component: SecretInputFormik + }, + { + name: schema.ltcWalletId.code, + label: schema.ltcWalletId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.ltcWalletPassphrase.code, + label: schema.ltcWalletPassphrase.display, + type: 'text', + component: SecretInputFormik + }, + { + name: schema.zecWalletId.code, + label: schema.zecWalletId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.zecWalletPassphrase.code, + label: schema.zecWalletPassphrase.display, + type: 'text', + component: SecretInputFormik + }, + { + name: schema.bchWalletId.code, + label: schema.bchWalletId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.bchWalletPassphrase.code, + label: schema.bchWalletPassphrase.display, + type: 'text', + component: SecretInputFormik + }, + { + name: schema.dashWalletId.code, + label: schema.dashWalletId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.dashWalletPassphrase.code, + label: schema.dashWalletPassphrase.display, + type: 'text', + component: SecretInputFormik + }, + { + name: schema.environment.code, + label: schema.environment.display, + placeholder: 'prod or test', + type: 'text', + component: TextInputFormik + } + ] + + return ( + <> + + + ) +} + +export { BitgoForm, BitgoCard } diff --git a/new-lamassu-admin/src/pages/Services/Bitstamp.js b/new-lamassu-admin/src/pages/Services/Bitstamp.js new file mode 100644 index 00000000..b50e8023 --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Bitstamp.js @@ -0,0 +1,116 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' + +import { Card, getValue as getValueAux, formatLong } from './aux' +import EditService from './EditService' + +const schema = { + clientId: { + code: 'clientId', + display: 'Client ID' + }, + key: { + code: 'key', + display: 'API Key' + }, + secret: { + code: 'secret', + display: 'API Secret' + } +} + +const BitstampCard = memo(({ account, onEdit, ...props }) => { + const findValue = getValueAux(account) + + const clientId = schema.clientId + const key = schema.key + + const clientIdValue = findValue(clientId.code) + const keyValue = findValue(key.code) + + const items = [ + { + label: clientId.display, + value: formatLong(clientIdValue) + }, + { + label: key.display, + value: formatLong(keyValue) + } + ] + + return ( + + ) +}) + +const BitstampForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const clientId = getValue(schema.clientId.code) + const key = getValue(schema.key.code) + const secret = getValue(schema.secret.code) + + const formik = { + initialValues: { + clientId: clientId, + key: key, + secret: secret + }, + validationSchema: Yup.object().shape({ + clientId: Yup.string() + .max(100, 'Too long') + .required('Required'), + key: Yup.string() + .max(100, 'Too long') + .required('Required'), + secret: Yup.string() + .max(100, 'Too long') + .required('Required') + }) + } + + const fields = [ + { + name: schema.clientId.code, + label: schema.clientId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.key.code, + label: schema.key.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.secret.code, + label: schema.secret.display, + type: 'text', + component: SecretInputFormik + } + ] + + return ( + <> + + + ) +} + +export { BitstampForm, BitstampCard } diff --git a/new-lamassu-admin/src/pages/Services/Blockcypher.js b/new-lamassu-admin/src/pages/Services/Blockcypher.js new file mode 100644 index 00000000..e64b004f --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Blockcypher.js @@ -0,0 +1,101 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' + +import { Card, getValue as getValueAux, formatLong } from './aux' +import EditService from './EditService' + +const schema = { + token: { + code: 'token', + display: 'API Token' + }, + confidenceFactor: { + code: 'confidenceFactor', + display: 'Confidence Factor' + } +} + +const BlockcypherCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const token = schema.token + const confidenceFactor = schema.confidenceFactor + + const tokenValue = getValue(token.code) + const confidenceFactorValue = getValue(confidenceFactor.code) + + const items = [ + { + label: token.display, + value: formatLong(tokenValue) + }, + { + label: confidenceFactor.display, + value: confidenceFactorValue + } + ] + + return ( + + ) +}) + +const BlockcypherForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const token = getValue(schema.token.code) + const confidenceFactor = getValue(schema.confidenceFactor.code) + + const formik = { + initialValues: { + token: token, + confidenceFactor: confidenceFactor + }, + validationSchema: Yup.object().shape({ + token: Yup.string() + .max(100, 'Too long') + .required('Required'), + confidenceFactor: Yup.number() + .integer('Please input a positive integer') + .positive('Please input a positive integer') + .required('Required') + }) + } + + const fields = [ + { + name: schema.token.code, + label: schema.token.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.confidenceFactor.code, + label: schema.confidenceFactor.display, + type: 'text', + component: TextInputFormik + } + ] + + return ( + <> + + + ) +} + +export { BlockcypherForm, BlockcypherCard } diff --git a/new-lamassu-admin/src/pages/Services/EditService.js b/new-lamassu-admin/src/pages/Services/EditService.js new file mode 100644 index 00000000..32940cce --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/EditService.js @@ -0,0 +1,94 @@ +import React, { useState } from 'react' +import { Form, Formik, Field } from 'formik' +import classnames from 'classnames' +import { makeStyles, Paper } from '@material-ui/core' + +import { H2, Info3 } from 'src/components/typography' +import { Button } from 'src/components/buttons' +import { ReactComponent as CloseIcon } from 'src/styling/icons/action/close/zodiac.svg' +import { ReactComponent as ErrorIcon } from 'src/styling/icons/warning-icon/tomato.svg' + +import { editServiceStyles as styles } from './Services.styles' + +const useStyles = makeStyles(styles) + +const DEFAULT_ERROR_MESSAGE = 'Something went wrong. Please contact support.' + +const EditService = ({ + title, + code, + formik, + fields, + handleClose, + save, + ...props +}) => { + const [error, setError] = useState(props.error) + + const classes = useStyles() + + const submitWrapperClasses = { + [classes.submitWrapper]: true, + [classes.submitError]: error + } + + return ( + + +
+

{`Edit ${title}`}

+
+
+ { + save(code, values) + .then(m => handleClose()) + .catch(err => { + if (err) setError(true) + }) + }}> +
+
+ {fields && + fields.map((field, idx) => ( +
+ { + setError(null) + }} + /> +
+ ))} +
+
+
+ {error && ( +
+ + + {DEFAULT_ERROR_MESSAGE} + +
+ )} + +
+
+
+
+
+
+ ) +} + +export default EditService diff --git a/new-lamassu-admin/src/pages/Services/Infura.js b/new-lamassu-admin/src/pages/Services/Infura.js new file mode 100644 index 00000000..76987c2f --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Infura.js @@ -0,0 +1,117 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' + +import { Card, getValue as getValueAux, formatLong } from './aux' +import EditService from './EditService' + +const schema = { + apiKey: { + code: 'apiKey', + display: 'API Key' + }, + apiSecret: { + code: 'apiSecret', + display: 'API Secret' + }, + endpoint: { + code: 'endpoint', + display: 'Endpoint' + } +} + +const InfuraCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const apiKey = schema.apiKey + const apiSecret = schema.apiSecret + + const apiKeyValue = getValue(apiKey.code) + const apiSecretValue = getValue(apiSecret.code) + + const items = [ + { + label: apiKey.display, + value: formatLong(apiKeyValue) + }, + { + label: apiSecret.display, + value: formatLong(apiSecretValue) + } + ] + + return ( + + ) +}) + +const InfuraForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const apiKey = getValue(schema.apiKey.code) + const apiSecret = getValue(schema.apiSecret.code) + const endpoint = getValue(schema.endpoint.code) + + const formik = { + initialValues: { + apiKey: apiKey, + apiSecret: apiSecret, + endpoint: endpoint + }, + validationSchema: Yup.object().shape({ + apiKey: Yup.string() + .max(100, 'Too long') + .required('Required'), + apiSecret: Yup.string() + .max(100, 'Too long') + .required('Required'), + endpoint: Yup.string() + .max(100, 'Too long') + .url('Please input a valid url') + .required('Required') + }) + } + + const fields = [ + { + name: schema.apiKey.code, + label: schema.apiKey.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.apiSecret.code, + label: schema.apiSecret.display, + type: 'text', + component: SecretInputFormik + }, + { + name: schema.endpoint.code, + label: schema.endpoint.display, + type: 'text', + component: TextInputFormik + } + ] + + return ( + <> + + + ) +} + +export { InfuraCard, InfuraForm } diff --git a/new-lamassu-admin/src/pages/Services/Itbit.js b/new-lamassu-admin/src/pages/Services/Itbit.js new file mode 100644 index 00000000..7b7dee6c --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Itbit.js @@ -0,0 +1,126 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' + +import { Card, getValue as getValueAux, formatLong } from './aux' +import EditService from './EditService' + +const schema = { + userId: { + code: 'userId', + display: 'User ID' + }, + walletId: { + code: 'walletId', + display: 'Wallet ID' + }, + clientKey: { + code: 'clientKey', + display: 'Client Key' + }, + clientSecret: { + code: 'clientSecret', + display: 'Client Secret' + } +} + +const ItbitCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const userId = schema.userId + const walletId = schema.walletId + + const userIdValue = getValue(userId.code) + const walletIdValue = getValue(walletId.code) + + const items = [ + { + label: userId.display, + value: formatLong(userIdValue) + }, + { + label: walletId.display, + value: formatLong(walletIdValue) + } + ] + + return ( + + ) +}) + +const ItbitForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const userId = getValue(schema.userId.code) + const walletId = getValue(schema.walletId.code) + const clientKey = getValue(schema.clientKey.code) + const clientSecret = getValue(schema.clientSecret.code) + + const formik = { + initialValues: { + userId: userId, + walletId: walletId, + clientKey: clientKey, + clientSecret: clientSecret + }, + validationSchema: Yup.object().shape({ + userId: Yup.string() + .max(100, 'Too long') + .required('Required'), + walletId: Yup.string() + .max(100, 'Too long') + .required('Required'), + clientKey: Yup.string() + .max(100, 'Too long') + .required('Required'), + clientSecret: Yup.string() + .max(100, 'Too long') + .required('Required') + }) + } + + const fields = [ + { + name: schema.userId.code, + label: schema.userId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.walletId.code, + label: schema.walletId.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.clientKey.code, + label: schema.clientKey.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.clientSecret.code, + label: schema.clientSecret.display, + type: 'text', + component: SecretInputFormik + } + ] + + return ( + <> + + + ) +} + +export { ItbitCard, ItbitForm } diff --git a/new-lamassu-admin/src/pages/Services/Kraken.js b/new-lamassu-admin/src/pages/Services/Kraken.js new file mode 100644 index 00000000..7b1fa2dc --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Kraken.js @@ -0,0 +1,101 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' + +import { Card, getValue as getValueAux, formatLong } from './aux' +import EditService from './EditService' + +const schema = { + apiKey: { + code: 'apiKey', + display: 'API Key' + }, + privateKey: { + code: 'privateKey', + display: 'Private Key' + } +} + +const KrakenCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const apiKey = schema.apiKey + const privateKey = schema.privateKey + + const apiKeyValue = getValue(apiKey.code) + const privateKeyValue = getValue(privateKey.code) + + const items = [ + apiKey && { + label: apiKey.display, + value: formatLong(apiKeyValue) + }, + privateKey && { + label: privateKey.display, + value: formatLong(privateKeyValue) + } + ] + + return ( + + ) +}) + +const KrakenForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const apiKey = getValue(schema.apiKey.code) + const privateKey = getValue(schema.privateKey.code) + + const formik = { + initialValues: { + apiKey: apiKey, + privateKey: privateKey + }, + validationSchema: Yup.object().shape({ + apiKey: Yup.string() + .max(100, 'Too long') + .required('Required'), + privateKey: Yup.string() + .max(100, 'Too long') + .required('Required') + }) + } + + const fields = [ + { + name: schema.apiKey.code, + label: schema.apiKey.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.privateKey.code, + label: schema.privateKey.display, + type: 'text', + component: SecretInputFormik + } + ] + + return ( + <> + + + ) +} + +export { KrakenCard, KrakenForm } diff --git a/new-lamassu-admin/src/pages/Services/Mailgun.js b/new-lamassu-admin/src/pages/Services/Mailgun.js new file mode 100644 index 00000000..d822f839 --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Mailgun.js @@ -0,0 +1,132 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' + +import { Card, getValue as getValueAux } from './aux' +import EditService from './EditService' + +const schema = { + apiKey: { + code: 'apiKey', + display: 'API Key' + }, + domain: { + code: 'domain', + display: 'Domain' + }, + fromEmail: { + code: 'fromEmail', + display: 'From Email' + }, + toEmail: { + code: 'toEmail', + display: 'To Email' + } +} + +const MailgunCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const fromEmail = schema.fromEmail + const toEmail = schema.toEmail + + const fromEmailValue = getValue(fromEmail.code) + const toEmailValue = getValue(toEmail.code) + + const items = [ + { + label: fromEmail.display, + value: fromEmailValue + }, + { + label: toEmail.display, + value: toEmailValue + } + ] + + return ( + + ) +}) + +const MailgunForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const apiKey = getValue(schema.apiKey.code) + const domain = getValue(schema.domain.code) + const fromEmail = getValue(schema.fromEmail.code) + const toEmail = getValue(schema.toEmail.code) + + const formik = { + initialValues: { + apiKey: apiKey, + domain: domain, + fromEmail: fromEmail, + toEmail: toEmail + }, + validationSchema: Yup.object().shape({ + apiKey: Yup.string() + .max(100, 'Too long') + .required('Required'), + domain: Yup.string() + .max(100, 'Too long') + .required('Required'), + fromEmail: Yup.string() + .max(100, 'Too long') + .email('Please input a valid email address') + .required('Required'), + toEmail: Yup.string() + .max(100, 'Too long') + .email('Please input a valid email address') + .required('Required') + }) + } + + const fields = [ + { + name: schema.apiKey.code, + label: schema.apiKey.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.domain.code, + label: schema.domain.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.fromEmail.code, + label: schema.fromEmail.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.toEmail.code, + label: schema.toEmail.display, + type: 'text', + component: TextInputFormik + } + ] + + return ( + <> + + + ) +} + +export { MailgunCard, MailgunForm } diff --git a/new-lamassu-admin/src/pages/Services/Services.js b/new-lamassu-admin/src/pages/Services/Services.js new file mode 100644 index 00000000..4e5fb414 --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Services.js @@ -0,0 +1,242 @@ +import React, { useState } from 'react' +import * as R from 'ramda' +import { gql } from 'apollo-boost' +import { makeStyles, Modal } from '@material-ui/core' +import { useQuery, useMutation } from '@apollo/react-hooks' + +import Title from 'src/components/Title' + +import { BitgoCard, BitgoForm } from './Bitgo' +import { BitstampCard, BitstampForm } from './Bitstamp' +import { BlockcypherCard, BlockcypherForm } from './Blockcypher' +import { InfuraCard, InfuraForm } from './Infura' +import { ItbitCard, ItbitForm } from './Itbit' +import { KrakenCard, KrakenForm } from './Kraken' +import { MailgunCard, MailgunForm } from './Mailgun' +import { StrikeCard, StrikeForm } from './Strike' +import { TwilioCard, TwilioForm } from './Twilio' +import { servicesStyles as styles } from './Services.styles' + +const useStyles = makeStyles(styles) + +const GET_CONFIG = gql` + { + config + } +` + +const GET_ACCOUNTS = gql` + { + accounts { + code + display + class + cryptos + } + } +` + +const SAVE_CONFIG = gql` + mutation Save($config: JSONObject) { + saveConfig(config: $config) + } +` + +const Services = () => { + const [open, setOpen] = useState(false) + const [modalContent, setModalContent] = useState(null) + const [accountsConfig, setAccountsConfig] = useState(null) + const [saveConfig, { loading }] = useMutation(SAVE_CONFIG, { + onCompleted: data => setAccountsConfig(data.saveConfig.accounts) + }) + + const classes = useStyles() + + useQuery(GET_CONFIG, { + onCompleted: data => setAccountsConfig(data.config.accounts ?? {}) + }) + const { data: accountsResponse } = useQuery(GET_ACCOUNTS) + + const accounts = accountsResponse?.accounts + + const save = (code, it) => { + const newAccounts = R.clone(accountsConfig) + newAccounts[code] = it + return saveConfig({ variables: { config: { accounts: newAccounts } } }) + } + + const getAccount = code => { + return R.mergeDeepLeft( + R.find(R.propEq('code', code))(accounts) ?? {}, + accountsConfig[code] ?? {} + ) + } + + const handleOpen = content => { + setOpen(true) + setModalContent(content) + } + + const handleClose = (canClose = true) => { + if (canClose && !loading) { + setOpen(false) + setModalContent(null) + } + } + + if (!accounts || !accountsConfig) return null + + const codes = { + bitgo: 'bitgo', + bitstamp: 'bitstamp', + blockcypher: 'blockcypher', + infura: 'infura', + itbit: 'itbit', + kraken: 'kraken', + mailgun: 'mailgun', + strike: 'strike', + twilio: 'twilio' + } + + const bitgo = getAccount(codes.bitgo) + const bitstamp = getAccount(codes.bitstamp) + const blockcypher = getAccount(codes.blockcypher) + const infura = getAccount(codes.infura) + const itbit = getAccount(codes.itbit) + const kraken = getAccount(codes.kraken) + const mailgun = getAccount(codes.mailgun) + const strike = getAccount(codes.strike) + const twilio = getAccount(codes.twilio) + + return ( + <> +
+
+ 3rd Party Services +
+
+
+ + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> + + handleOpen( + + ) + } + /> +
+ {modalContent && ( + +
{modalContent}
+
+ )} + + ) +} + +export default Services diff --git a/new-lamassu-admin/src/pages/Services/Services.styles.js b/new-lamassu-admin/src/pages/Services/Services.styles.js new file mode 100644 index 00000000..818ea3d7 --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Services.styles.js @@ -0,0 +1,177 @@ +import { white, offColor, errorColor } from 'src/styling/variables' +import typographyStyles from 'src/components/typography/styles' +import baseStyles from 'src/pages/Logs.styles' + +const { titleWrapper } = baseStyles +const { label1, p } = typographyStyles + +const servicesStyles = { + titleWrapper, + titleContainer: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%' + }, + addServiceMenu: { + width: 215, + '& > ul': { + padding: [[18, 16, 21, 16]], + '& > li': { + display: 'flex', + justifyContent: 'space-between', + listStyle: 'none', + marginBottom: 23, + cursor: 'pointer', + '& > span:first-child': { + extend: p, + fontWeight: 'bold' + }, + '& > span:last-child': { + extend: label1, + color: offColor + }, + '&:last-child': { + marginBottom: 0 + } + } + } + }, + mainWrapper: { + display: 'flex', + flexWrap: 'wrap' + }, + modal: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + '& > div': { + outline: 'none' + } + }, + modalHeader: { + display: 'flex', + justifyContent: 'space-between', + '& button': { + border: 'none', + backgroundColor: 'transparent', + cursor: 'pointer' + } + }, + modalBody: { + '& > form': { + display: 'flex', + flexDirection: 'column', + position: 'relative', + minHeight: 400, + '& > div:last-child': { + display: 'flex', + alignItems: 'flex-end', + flex: 'auto', + alignSelf: 'flex-end', + '& > button': { + marginTop: 32 + } + } + } + }, + paper: { + position: 'absolute', + backgroundColor: white, + outline: '0 none', + padding: [[16, 20, 32, 24]] + }, + inputField: { + width: 434 + }, + formLabel: { + extend: label1 + } +} + +const editServiceStyles = { + paper: { + padding: [[5, 20, 32, 24]], + position: 'relative', + display: 'flex', + flexDirection: 'column', + minHeight: 524, + overflow: 'hidden', + '& > button': { + position: 'absolute', + top: 16, + right: 16, + border: 'none', + backgroundColor: 'transparent', + cursor: 'pointer', + '& svg': { + width: 18 + } + }, + '& form': { + display: 'flex', + flexDirection: 'column', + flexGrow: 2 + } + }, + modalHeader: { + display: 'flex', + marginBottom: 14 + }, + modalBody: { + display: 'flex', + flexGrow: 2 + }, + formBody: { + display: 'flex', + flexDirection: 'column' + }, + field: { + position: 'relative', + '& > div': { + width: 434 + } + }, + submitWrapper: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'flex-end', + flexGrow: 2, + marginTop: 32, + '& > div': { + display: 'flex', + alignItems: 'center', + width: '100%', + justifyContent: 'flex-end', + '& > button': { + '&:active': { + marginTop: 0 + } + } + } + }, + submitError: { + '& > div': { + justifyContent: 'space-between' + } + }, + messageWrapper: { + '& > div': { + display: 'flex', + alignItems: 'center', + '& > svg': { + marginRight: 10 + } + } + }, + message: { + display: 'flex', + alignItems: 'center', + color: errorColor, + margin: 0, + whiteSpace: 'break-spaces', + width: 250 + } +} + +export { servicesStyles, editServiceStyles } diff --git a/new-lamassu-admin/src/pages/Services/Strike.js b/new-lamassu-admin/src/pages/Services/Strike.js new file mode 100644 index 00000000..d8979cec --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Strike.js @@ -0,0 +1,79 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' + +import { Card, getValue as getValueAux, formatLong } from './aux' +import EditService from './EditService' + +const schema = { + token: { + code: 'token', + display: 'API Token' + } +} + +const StrikeCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const token = schema.token + + const tokenValue = getValue(token.code) + + const items = [ + { + label: token.display, + value: formatLong(tokenValue) + } + ] + + return ( + + ) +}) + +const StrikeForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const code = 'strike' + const token = getValue(schema.token.code) + + const formik = { + initialValues: { + token: token + }, + validationSchema: Yup.object().shape({ + token: Yup.string() + .max(100, 'Too long') + .required('Required') + }) + } + + const fields = [ + { + name: schema.token.code, + label: schema.token.display, + type: 'text', + component: SecretInputFormik + } + ] + + return ( + <> + + + ) +} + +export { StrikeCard, StrikeForm } diff --git a/new-lamassu-admin/src/pages/Services/Twilio.js b/new-lamassu-admin/src/pages/Services/Twilio.js new file mode 100644 index 00000000..16e16616 --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/Twilio.js @@ -0,0 +1,131 @@ +import React, { memo } from 'react' +import * as Yup from 'yup' + +import TextInputFormik from 'src/components/inputs/formik/TextInput' +import SecretInputFormik from 'src/components/inputs/formik/SecretInput' + +import { Card, getValue as getValueAux } from './aux' +import EditService from './EditService' + +const schema = { + accountSid: { + code: 'accountSid', + display: 'Account SID' + }, + authToken: { + code: 'authToken', + display: 'Auth Token' + }, + fromNumber: { + code: 'fromNumber', + display: 'From Number' + }, + toNumber: { + code: 'toNumber', + display: 'To Number' + } +} + +const TwilioCard = memo(({ account, onEdit, ...props }) => { + const getValue = getValueAux(account) + + const fromNumber = schema.fromNumber + const toNumber = schema.toNumber + + const fromNumberValue = getValue(fromNumber.code) + const toNumberValue = getValue(toNumber.code) + + const items = [ + { + label: fromNumber.display, + value: fromNumberValue + }, + { + label: toNumber.display, + value: toNumberValue + } + ] + + return ( + + ) +}) + +const TwilioForm = ({ account, ...props }) => { + const getValue = getValueAux(account) + + const { code } = account + const accountSid = getValue(schema.accountSid.code) + const authToken = getValue(schema.authToken.code) + const fromNumber = getValue(schema.fromNumber.code) + const toNumber = getValue(schema.toNumber.code) + + const formik = { + initialValues: { + accountSid: accountSid, + authToken: authToken, + fromNumber: fromNumber, + toNumber: toNumber + }, + validationSchema: Yup.object().shape({ + accountSid: Yup.string() + .max(100, 'Too long') + .required('Required'), + authToken: Yup.string() + .max(100, 'Too long') + .required('Required'), + fromNumber: Yup.string() + .max(100, 'Too long') + .required('Required'), + toNumber: Yup.string() + .max(100, 'Too long') + .required('Required') + }) + } + + const fields = [ + { + name: schema.accountSid.code, + label: schema.accountSid.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.authToken.code, + label: schema.authToken.display, + type: 'text', + component: SecretInputFormik + }, + { + name: schema.fromNumber.code, + label: schema.fromNumber.display, + type: 'text', + component: TextInputFormik + }, + { + name: schema.toNumber.code, + label: schema.toNumber.display, + type: 'text', + component: TextInputFormik + } + ] + + return ( + <> + + + ) +} + +export { TwilioCard, TwilioForm } diff --git a/new-lamassu-admin/src/pages/Services/aux.js b/new-lamassu-admin/src/pages/Services/aux.js new file mode 100644 index 00000000..032534a9 --- /dev/null +++ b/new-lamassu-admin/src/pages/Services/aux.js @@ -0,0 +1,44 @@ +import React from 'react' +import * as R from 'ramda' +import { makeStyles } from '@material-ui/core' + +import SingleRowTable from 'src/components/single-row-table/SingleRowTable' + +const getValue = R.curry((account, code) => account[code] ?? '') + +const formatLong = value => { + if (!value) return '' + if (value.length <= 20) return value + + return `${value.slice(0, 8)}(...)${value.slice( + value.length - 8, + value.length + )}` +} + +const styles = { + card: { + margin: [[0, 30, 32, 0]], + paddingBottom: 24, + '&:nth-child(3n+3)': { + marginRight: 0 + } + } +} + +const useStyles = makeStyles(styles) + +const Card = ({ account, title, items, onEdit, ...props }) => { + const classes = useStyles() + + return ( + + ) +} + +export { Card, getValue, formatLong } diff --git a/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js b/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js index a5de1601..61370218 100644 --- a/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js +++ b/new-lamassu-admin/src/pages/Transactions/CopyToClipboard.js @@ -10,6 +10,8 @@ import { comet } from 'src/styling/variables' import { cpcStyles } from './Transactions.styles' +const useStyles = makeStyles(cpcStyles) + const CopyToClipboard = ({ className, children, ...props }) => { const [anchorEl, setAnchorEl] = useState(null) @@ -17,8 +19,6 @@ const CopyToClipboard = ({ className, children, ...props }) => { if (anchorEl) setTimeout(() => setAnchorEl(null), 3000) }, [anchorEl]) - const useStyles = makeStyles(cpcStyles) - const classes = useStyles() const handleClick = event => { diff --git a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js index 33ed6d34..0ec9694d 100644 --- a/new-lamassu-admin/src/pages/Transactions/DetailsCard.js +++ b/new-lamassu-admin/src/pages/Transactions/DetailsCard.js @@ -19,18 +19,18 @@ import { onlyFirstToUpper } from 'src/utils/string' import CopyToClipboard from './CopyToClipboard' import { detailsRowStyles, labelStyles } from './Transactions.styles' -const Label = ({ children }) => { - const useStyles = makeStyles(labelStyles) +const labelUseStyles = makeStyles(labelStyles) - const classes = useStyles() +const Label = ({ children }) => { + const classes = labelUseStyles() return
{children}
} -const DetailsRow = ({ it: tx, ...props }) => { - const useStyles = makeStyles(detailsRowStyles) +const detailsUseStyles = makeStyles(detailsRowStyles) - const classes = useStyles() +const DetailsRow = ({ it: tx, ...props }) => { + const classes = detailsUseStyles() const addr = tx.toAddress const txHash = tx.txHash diff --git a/new-lamassu-admin/src/pages/Transactions/Transactions.js b/new-lamassu-admin/src/pages/Transactions/Transactions.js index bd88d55c..6c9f4ca9 100644 --- a/new-lamassu-admin/src/pages/Transactions/Transactions.js +++ b/new-lamassu-admin/src/pages/Transactions/Transactions.js @@ -19,6 +19,8 @@ import { toUnit } from 'src/utils/coin' import DetailsRow from './DetailsCard' import { mainStyles } from './Transactions.styles' +const useStyles = makeStyles(mainStyles) + // TODO customerIdCardData const GET_TRANSACTIONS = gql` { @@ -49,8 +51,6 @@ const GET_TRANSACTIONS = gql` const Transactions = () => { const [anchorEl, setAnchorEl] = useState(null) - const useStyles = makeStyles(mainStyles) - const classes = useStyles() const { data: txResponse } = useQuery(GET_TRANSACTIONS) diff --git a/new-lamassu-admin/src/routing/routes.js b/new-lamassu-admin/src/routing/routes.js index 5ef4b7a1..477adb7c 100644 --- a/new-lamassu-admin/src/routing/routes.js +++ b/new-lamassu-admin/src/routing/routes.js @@ -8,6 +8,7 @@ import Locales from 'src/pages/Locales' import Logs from 'src/pages/Logs' import ServerLogs from 'src/pages/ServerLogs' import Transactions from 'src/pages/Transactions/Transactions' +import Services from 'src/pages/Services/Services' import AuthRegister from 'src/pages/AuthRegister' const tree = [ @@ -38,7 +39,12 @@ const tree = [ label: 'Commissions', route: '/settings/commissions' }, - { key: 'locale', label: 'Locale', route: '/settings/locale' } + { key: 'locale', label: 'Locale', route: '/settings/locale' }, + { + key: 'services', + label: '3rd party services', + route: '/settings/3rd-party-services' + } ] } // compliance: { label: 'Compliance', children: [{ label: 'Locale', route: '/locale' }] } @@ -65,6 +71,7 @@ const Routes = () => ( /> + diff --git a/new-lamassu-admin/src/styling/icons/action/close/zodiac.svg b/new-lamassu-admin/src/styling/icons/action/close/zodiac.svg index 3763b842..7d02e306 100644 --- a/new-lamassu-admin/src/styling/icons/action/close/zodiac.svg +++ b/new-lamassu-admin/src/styling/icons/action/close/zodiac.svg @@ -1,24 +1,17 @@ - - - - icon/action/close/zodiac - Created with Sketch. - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + +icon/action/close/zodiac +Created with Sketch. + + + + + + diff --git a/new-lamassu-admin/src/styling/icons/warning-icon/comet.svg b/new-lamassu-admin/src/styling/icons/warning-icon/comet.svg new file mode 100644 index 00000000..e3329fdb --- /dev/null +++ b/new-lamassu-admin/src/styling/icons/warning-icon/comet.svg @@ -0,0 +1,12 @@ + + + + icon/warning-icon/comet + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/new-lamassu-admin/src/styling/icons/warning-icon/tomato.svg b/new-lamassu-admin/src/styling/icons/warning-icon/tomato.svg new file mode 100644 index 00000000..db15f8c2 --- /dev/null +++ b/new-lamassu-admin/src/styling/icons/warning-icon/tomato.svg @@ -0,0 +1,12 @@ + + + + icon/warning-icon/tomato + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/new-lamassu-admin/src/styling/variables.js b/new-lamassu-admin/src/styling/variables.js index 5fe36e30..c2573453 100644 --- a/new-lamassu-admin/src/styling/variables.js +++ b/new-lamassu-admin/src/styling/variables.js @@ -103,6 +103,8 @@ const tableSmCellHeight = 30 const tableLgCellHeight = 76 const tableHeaderColor = primaryColor +const tableDisabledHeaderColor = zircon +const tableNewDisabledHeaderColor = spring3 const tableCellColor = white const tableErrorColor = mistyRose const tableSuccessColor = spring3 @@ -172,6 +174,8 @@ export { tableSmCellHeight, tableLgCellHeight, tableHeaderColor, + tableDisabledHeaderColor, + tableNewDisabledHeaderColor, tableCellColor, tableErrorColor, tableSuccessColor diff --git a/package-lock.json b/package-lock.json index 0df0fa51..045cfb51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,7 +58,7 @@ "@ava/babel-preset-stage-4": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@ava/babel-preset-stage-4/-/babel-preset-stage-4-1.1.0.tgz", - "integrity": "sha1-rmC+iBoLq/fTX1Krp3DR9hlPdr0=", + "integrity": "sha512-oWqTnIGXW3k72UFidXzW0ONlO7hnO9x02S/QReJ7NBGeiBH9cUHY9+EfV6C8PXC6YJH++WrliEq03wMSJGNZFg==", "dev": true, "requires": { "babel-plugin-check-es2015-constants": "^6.8.0", @@ -4070,7 +4070,7 @@ }, "dotenv": { "version": "4.0.0", - "resolved": "http://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" }, "drbg.js": { @@ -6230,7 +6230,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, "globby": { @@ -6257,7 +6257,7 @@ "got": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha1-BUUP2ECU5rvqVvRRpDqcKJFmOFo=", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", "requires": { "decompress-response": "^3.2.0", "duplexer3": "^0.1.4", @@ -7146,7 +7146,7 @@ "hullabaloo-config-manager": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/hullabaloo-config-manager/-/hullabaloo-config-manager-1.1.1.tgz", - "integrity": "sha1-HZEXgTEprQNf2ehHfq8GaREmn+M=", + "integrity": "sha512-ztKnkZV0TmxnumCDHHgLGNiDnotu4EHCp9YMkznWuo4uTtCyJ+cu+RNcxUeXYKTllpvLFWnbfWry09yzszgg+A==", "dev": true, "requires": { "dot-prop": "^4.1.0", @@ -7668,7 +7668,7 @@ "isurl": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha1-sn9PSfPNqj6kSgpbfzRi5u3DnWc=", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "requires": { "has-to-string-tag-x": "^1.2.0", "is-object": "^1.0.1" @@ -8586,7 +8586,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } @@ -9163,7 +9163,7 @@ "p-cancelable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha1-ueEjgAvOu3rBOkeb4ZW1B7mNMPo=" + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" }, "p-each-series": { "version": "1.0.0", @@ -12642,7 +12642,6 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.6.tgz", "integrity": "sha1-PpcwauAk+yThCj11yIQwJWIhUSA=", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", @@ -12651,7 +12650,7 @@ "dependencies": { "bignumber.js": { "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git" + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" } } },