From fa099724babcc9d974f1d8900ee8a5f9c2faf052 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar Date: Wed, 24 Aug 2022 17:43:30 +0430 Subject: [PATCH 01/54] embedded plugins system initial commit --- .gitignore | 3 + package-lock.json | 233 + package.json | 10 + plugins/.babelrc | 42 + plugins/.eslintignore | 2 + plugins/.eslintrc.json | 35 + plugins/.eslintrc.yml | 3 + plugins/LICENSE | 21 + plugins/README.md | 58 + plugins/README_WEB_VIEW.md | 155 + plugins/generateJson.js | 80 + plugins/media/icon-large.png | Bin 0 -> 6114 bytes plugins/media/icon-small.png | Bin 0 -> 4073 bytes plugins/package-lock.json | 9421 +++++++++++++++++ plugins/package.json | 108 + plugins/remote-component.config.js | 25 + plugins/scripts/addBundles.js | 28 + plugins/scripts/addJsons.js | 24 + plugins/scripts/addPlugin.js | 66 + plugins/scripts/addView.js | 36 + plugins/scripts/generateJson.js | 51 + plugins/scripts/patterns.js | 70 + plugins/scripts/utils.js | 39 + plugins/server.js | 10 + .../src/components/Dialog/DesktopDialog.js | 87 + plugins/src/components/Dialog/MobileDialog.js | 73 + plugins/src/components/Dialog/index.js | 14 + plugins/src/components/Form/factoryFields.js | 27 + plugins/src/components/HeaderSection/index.js | 45 + .../KitContext/KitContextProvider.js | 15 + plugins/src/components/KitContext/index.js | 4 + plugins/src/components/KitContext/withKit.js | 17 + plugins/src/components/OtpForm/index.js | 93 + plugins/src/components/Tab/index.js | 30 + plugins/src/components/Title.js | 11 + plugins/src/constants/index.js | 1 + plugins/src/index.html | 9 + plugins/src/lib/__tests__/prop.test.js | 39 + plugins/src/lib/prop.js | 10 + .../plugins/hello-exchange/assets/icons.json | 3 + .../hello-exchange/assets/strings.json | 6 + .../plugins/hello-exchange/server/config.json | 35 + .../hello-exchange/server/hello-exchange.json | 40 + .../plugins/hello-exchange/server/script.js | 44 + .../plugins/hello-exchange/views/view/App.js | 20 + .../plugins/hello-exchange/views/view/Form.js | 37 + .../hello-exchange/views/view/index.js | 1 + .../hello-exchange/views/view/view.json | 18 + plugins/src/store/index.js | 11 + plugins/src/templates/assets/icons.json | 3 + plugins/src/templates/assets/strings.json | 5 + .../bank-verification/assets/icons.json | 3 + .../bank-verification/assets/strings.json | 8 + .../bank-verification/views/home/App.js | 20 + .../bank-verification/views/home/Form.js | 32 + .../bank-verification/views/home/index.js | 1 + .../bank-verification/views/home/view.json | 4 + .../views/verification/App.js | 20 + .../views/verification/Form.js | 54 + .../views/verification/index.js | 1 + .../views/verification/view.json | 4 + .../templates/fiat-wallet/assets/icons.json | 3 + .../templates/fiat-wallet/assets/strings.json | 5 + .../fiat-wallet/views/deposit/App.js | 20 + .../fiat-wallet/views/deposit/Form.js | 26 + .../fiat-wallet/views/deposit/index.js | 1 + .../fiat-wallet/views/deposit/view.json | 7 + .../fiat-wallet/views/withdraw/App.js | 20 + .../fiat-wallet/views/withdraw/Form.js | 26 + .../fiat-wallet/views/withdraw/index.js | 1 + .../fiat-wallet/views/withdraw/view.json | 7 + .../kyc-verification/assets/icons.json | 3 + .../kyc-verification/assets/strings.json | 8 + .../kyc-verification/views/home/App.js | 20 + .../kyc-verification/views/home/Form.js | 32 + .../kyc-verification/views/home/index.js | 1 + .../kyc-verification/views/home/view.json | 4 + .../views/verification/App.js | 20 + .../views/verification/Form.js | 56 + .../views/verification/index.js | 1 + .../views/verification/view.json | 4 + .../src/templates/new-page/assets/icons.json | 3 + .../templates/new-page/assets/strings.json | 6 + .../src/templates/new-page/views/view/App.js | 20 + .../src/templates/new-page/views/view/Form.js | 37 + .../templates/new-page/views/view/index.js | 1 + .../templates/new-page/views/view/view.json | 18 + .../src/templates/onramp/assets/icons.json | 3 + .../src/templates/onramp/assets/strings.json | 6 + .../src/templates/onramp/views/view/App.js | 20 + .../src/templates/onramp/views/view/Form.js | 23 + .../src/templates/onramp/views/view/index.js | 1 + .../src/templates/onramp/views/view/view.json | 6 + .../verification-tab/assets/icons.json | 3 + .../verification-tab/assets/strings.json | 8 + .../verification-tab/views/home/App.js | 20 + .../verification-tab/views/home/Form.js | 32 + .../verification-tab/views/home/index.js | 1 + .../verification-tab/views/home/view.json | 14 + .../views/verification/App.js | 20 + .../views/verification/Form.js | 56 + .../views/verification/index.js | 1 + .../views/verification/view.json | 6 + plugins/src/templates/view/App.js | 20 + plugins/src/templates/view/index.js | 1 + plugins/src/templates/view/view.json | 4 + plugins/src/utils/index.js | 154 + plugins/src/utils/link.js | 11 + plugins/test.js | 917 ++ plugins/webpack-dev.config.js | 96 + plugins/webpack-main.config.js | 90 + plugins/webpack.config.js | 3 + 112 files changed, 13231 insertions(+) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 plugins/.babelrc create mode 100644 plugins/.eslintignore create mode 100644 plugins/.eslintrc.json create mode 100644 plugins/.eslintrc.yml create mode 100644 plugins/LICENSE create mode 100644 plugins/README.md create mode 100644 plugins/README_WEB_VIEW.md create mode 100644 plugins/generateJson.js create mode 100644 plugins/media/icon-large.png create mode 100644 plugins/media/icon-small.png create mode 100644 plugins/package-lock.json create mode 100644 plugins/package.json create mode 100644 plugins/remote-component.config.js create mode 100644 plugins/scripts/addBundles.js create mode 100644 plugins/scripts/addJsons.js create mode 100644 plugins/scripts/addPlugin.js create mode 100644 plugins/scripts/addView.js create mode 100644 plugins/scripts/generateJson.js create mode 100644 plugins/scripts/patterns.js create mode 100644 plugins/scripts/utils.js create mode 100644 plugins/server.js create mode 100644 plugins/src/components/Dialog/DesktopDialog.js create mode 100644 plugins/src/components/Dialog/MobileDialog.js create mode 100644 plugins/src/components/Dialog/index.js create mode 100644 plugins/src/components/Form/factoryFields.js create mode 100644 plugins/src/components/HeaderSection/index.js create mode 100644 plugins/src/components/KitContext/KitContextProvider.js create mode 100644 plugins/src/components/KitContext/index.js create mode 100644 plugins/src/components/KitContext/withKit.js create mode 100644 plugins/src/components/OtpForm/index.js create mode 100644 plugins/src/components/Tab/index.js create mode 100644 plugins/src/components/Title.js create mode 100644 plugins/src/constants/index.js create mode 100644 plugins/src/index.html create mode 100644 plugins/src/lib/__tests__/prop.test.js create mode 100644 plugins/src/lib/prop.js create mode 100644 plugins/src/plugins/hello-exchange/assets/icons.json create mode 100644 plugins/src/plugins/hello-exchange/assets/strings.json create mode 100644 plugins/src/plugins/hello-exchange/server/config.json create mode 100644 plugins/src/plugins/hello-exchange/server/hello-exchange.json create mode 100644 plugins/src/plugins/hello-exchange/server/script.js create mode 100644 plugins/src/plugins/hello-exchange/views/view/App.js create mode 100644 plugins/src/plugins/hello-exchange/views/view/Form.js create mode 100644 plugins/src/plugins/hello-exchange/views/view/index.js create mode 100644 plugins/src/plugins/hello-exchange/views/view/view.json create mode 100644 plugins/src/store/index.js create mode 100644 plugins/src/templates/assets/icons.json create mode 100644 plugins/src/templates/assets/strings.json create mode 100644 plugins/src/templates/bank-verification/assets/icons.json create mode 100644 plugins/src/templates/bank-verification/assets/strings.json create mode 100644 plugins/src/templates/bank-verification/views/home/App.js create mode 100644 plugins/src/templates/bank-verification/views/home/Form.js create mode 100644 plugins/src/templates/bank-verification/views/home/index.js create mode 100644 plugins/src/templates/bank-verification/views/home/view.json create mode 100644 plugins/src/templates/bank-verification/views/verification/App.js create mode 100644 plugins/src/templates/bank-verification/views/verification/Form.js create mode 100644 plugins/src/templates/bank-verification/views/verification/index.js create mode 100644 plugins/src/templates/bank-verification/views/verification/view.json create mode 100644 plugins/src/templates/fiat-wallet/assets/icons.json create mode 100644 plugins/src/templates/fiat-wallet/assets/strings.json create mode 100644 plugins/src/templates/fiat-wallet/views/deposit/App.js create mode 100644 plugins/src/templates/fiat-wallet/views/deposit/Form.js create mode 100644 plugins/src/templates/fiat-wallet/views/deposit/index.js create mode 100644 plugins/src/templates/fiat-wallet/views/deposit/view.json create mode 100644 plugins/src/templates/fiat-wallet/views/withdraw/App.js create mode 100644 plugins/src/templates/fiat-wallet/views/withdraw/Form.js create mode 100644 plugins/src/templates/fiat-wallet/views/withdraw/index.js create mode 100644 plugins/src/templates/fiat-wallet/views/withdraw/view.json create mode 100644 plugins/src/templates/kyc-verification/assets/icons.json create mode 100644 plugins/src/templates/kyc-verification/assets/strings.json create mode 100644 plugins/src/templates/kyc-verification/views/home/App.js create mode 100644 plugins/src/templates/kyc-verification/views/home/Form.js create mode 100644 plugins/src/templates/kyc-verification/views/home/index.js create mode 100644 plugins/src/templates/kyc-verification/views/home/view.json create mode 100644 plugins/src/templates/kyc-verification/views/verification/App.js create mode 100644 plugins/src/templates/kyc-verification/views/verification/Form.js create mode 100644 plugins/src/templates/kyc-verification/views/verification/index.js create mode 100644 plugins/src/templates/kyc-verification/views/verification/view.json create mode 100644 plugins/src/templates/new-page/assets/icons.json create mode 100644 plugins/src/templates/new-page/assets/strings.json create mode 100644 plugins/src/templates/new-page/views/view/App.js create mode 100644 plugins/src/templates/new-page/views/view/Form.js create mode 100644 plugins/src/templates/new-page/views/view/index.js create mode 100644 plugins/src/templates/new-page/views/view/view.json create mode 100644 plugins/src/templates/onramp/assets/icons.json create mode 100644 plugins/src/templates/onramp/assets/strings.json create mode 100644 plugins/src/templates/onramp/views/view/App.js create mode 100644 plugins/src/templates/onramp/views/view/Form.js create mode 100644 plugins/src/templates/onramp/views/view/index.js create mode 100644 plugins/src/templates/onramp/views/view/view.json create mode 100644 plugins/src/templates/verification-tab/assets/icons.json create mode 100644 plugins/src/templates/verification-tab/assets/strings.json create mode 100644 plugins/src/templates/verification-tab/views/home/App.js create mode 100644 plugins/src/templates/verification-tab/views/home/Form.js create mode 100644 plugins/src/templates/verification-tab/views/home/index.js create mode 100644 plugins/src/templates/verification-tab/views/home/view.json create mode 100644 plugins/src/templates/verification-tab/views/verification/App.js create mode 100644 plugins/src/templates/verification-tab/views/verification/Form.js create mode 100644 plugins/src/templates/verification-tab/views/verification/index.js create mode 100644 plugins/src/templates/verification-tab/views/verification/view.json create mode 100644 plugins/src/templates/view/App.js create mode 100644 plugins/src/templates/view/index.js create mode 100644 plugins/src/templates/view/view.json create mode 100644 plugins/src/utils/index.js create mode 100644 plugins/src/utils/link.js create mode 100644 plugins/test.js create mode 100644 plugins/webpack-dev.config.js create mode 100644 plugins/webpack-main.config.js create mode 100644 plugins/webpack.config.js diff --git a/.gitignore b/.gitignore index 0cc1d73179..59b0aa0d80 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ web/yarn-error.log* web/src/**/*.css +plugins/dist +plugins/json + #HollaEx CLI related templates/local/nginx/conf.d/* templates/local/logs/* diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..f5e113eb55 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,233 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concurrently": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.3.0.tgz", + "integrity": "sha512-IiDwm+8DOcFEInca494A8V402tNTQlJaYq78RF2rijOrKEk/AOHTxhN4U1cp7GYKYX5Q6Ymh1dLTBlzIMN0ikA==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^17.3.1" + } + }, + "date-fns": { + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.2.tgz", + "integrity": "sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "rxjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "dev": true + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..b5965175dc --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "scripts": { + "plugin:kit": "npm run --prefix ./web dev:plugin --plugin=$npm_config_plugin", + "plugin:plugin": "npm run --prefix ./plugins start --plugin=$npm_config_plugin", + "plugin:dev": "concurrently \"npm run plugin:kit --plugin=$npm_config_plugin\" \"npm run plugin:plugin --plugin=$npm_config_plugin\"" + }, + "devDependencies": { + "concurrently": "7.3.0" + } +} diff --git a/plugins/.babelrc b/plugins/.babelrc new file mode 100644 index 0000000000..864bd1ed98 --- /dev/null +++ b/plugins/.babelrc @@ -0,0 +1,42 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "useBuiltIns": "usage", + "debug": false + } + ], + "@babel/preset-react" + ], + "plugins": [ + [ + "@babel/plugin-transform-runtime", + { + "regenerator": true + } + ], + [ + "@babel/plugin-proposal-class-properties", + { + "loose": true + } + ], + [ + "transform-react-remove-prop-types", + { + "removeImport": true + } + ] + ], + "env": { + "development": { + "sourceMaps": true, + "retainLines": true + }, + "test": { + "sourceMaps": true, + "retainLines": true + } + } +} \ No newline at end of file diff --git a/plugins/.eslintignore b/plugins/.eslintignore new file mode 100644 index 0000000000..d64c4ca286 --- /dev/null +++ b/plugins/.eslintignore @@ -0,0 +1,2 @@ +coverage/ +dist/ diff --git a/plugins/.eslintrc.json b/plugins/.eslintrc.json new file mode 100644 index 0000000000..84befc479e --- /dev/null +++ b/plugins/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "node": true, + "mocha": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 9, + "sourceType": "module" + }, + "rules": { + "indent": [ + "warn", + "tab", + { + "SwitchCase": 1 + } + ], + "linebreak-style": [ + "warn", + "unix" + ], + "quotes": [ + "warn", + "single" + ], + "semi": [ + "warn", + "always" + ] + } +} \ No newline at end of file diff --git a/plugins/.eslintrc.yml b/plugins/.eslintrc.yml new file mode 100644 index 0000000000..6ef13503d4 --- /dev/null +++ b/plugins/.eslintrc.yml @@ -0,0 +1,3 @@ +extends: ["@paciolan/react"] +rules: + react/prop-types: off diff --git a/plugins/LICENSE b/plugins/LICENSE new file mode 100644 index 0000000000..dd6bdf83ca --- /dev/null +++ b/plugins/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) +Copyright (c) 2019 Paciolan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 0000000000..f6a5888973 --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,58 @@ +# hollaex-plugins + +Usage: + +1. Install dependencies: + + ```bash + npm install + cd web/ && npm install + ``` +2. Run `npm run build --plugin=` to generate plugin JSON object: + + ```bash + npm run build --plugin=hello-exchange + + /* + { + "name": "hello-exchange", + "version": 1, + "type": null, + "author": "bitHolla", + "bio": "Say hello from an exchange", + "description": "Demo plugin for proof of concept", + "documentation": null, + "logo": null, + "icon": null, + "url": null, + "meta": { + "private": { + "type": "string", + "required": false, + "description": "A secret", + "value": "hello exchange..." + } + }, + "public_meta": { + "public": { + "type": "string", + "required": false, + "description": "Not a secret", + "value": "Hello Exchange!" + } + }, + "prescript": { + "install": [ + "hello-world-npm" + ], + "run": null + }, + "postscript": { + "run": null + }, + "web_view": null, + "admin_view": null, + "script": "const helloWorld=installedLibraries[\"hello-world-npm\"];app.get(\"/plugins/hello-exchange\",(e,l)=>l.json({publicMessage:publicMeta.public.value,privateMessage:meta.private.value,libraryMessage:helloWorld(),timestamp:moment().toISOString()}));" + } + */ + ``` diff --git a/plugins/README_WEB_VIEW.md b/plugins/README_WEB_VIEW.md new file mode 100644 index 0000000000..f2a876de65 --- /dev/null +++ b/plugins/README_WEB_VIEW.md @@ -0,0 +1,155 @@ +# Hollaex Plugin Starter + +Hollaex plugin starter is a package with some pre-defined configurations out of the box to create custom plugins for the [Hollaex kit software](https://github.com/bitholla/hollaex-kit). These plugins can be installed on the fly to add features to your exchange. + +Creating plugins has two different aspects, the server-side script and the client-side component. + +# Client-side component + +Client side codes in the plugins are actually nothing but a remote react component that is injected into the kit on the fly. We are using a package called [remote component](https://github.com/Paciolan/remote-component) to get a component by providing the url for that which is the address of the commonjs module bundle and add it to the kit using the smart target component. + + +## Smart Target component +To decide where to inject remote components, we are using the [smart target](https://github.com/bitholla/hollaex-kit/blob/master/web/src/components/SmartTarget/index.js) component in the kit. + +Smart target is actually a react component with a unique target id that renders a remote bundle when the id matches. + +Smart targets are also responsible for passing props to the remote components. These props are divided into two different categories. + +### Common props +Common props are passed to all remote components within the smart target component. They include but not limited to strings, icons, generateId function, renderFields function to generate forms, store values, edit and config context. +You can always check the latest available common props for remote components by checking the [smart target](https://github.com/bitholla/hollaex-kit/blob/master/web/src/components/SmartTarget/index.js) component in codebase. + +### Target specific props +Target specific props are passed to the smart target component from the parent component and may be different for each target. +To get the latest available target-specific props, you can check the parent component of each smart target component below: + +- [New Page](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/routes.js#L240) +- Fiat Wallet + - [Deposit](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Deposit/utils.js#L169) + - [Withdraw](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Withdraw/form.js#L257) +- New Verification Tab + - [Home](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Verification/index.js#L234) + - [Page Content](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Verification/index.js#L256) +- Bank Verification Tab + - [Home](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Verification/index.js#L355) + - [Page Content](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Verification/index.js#L506) +- KYC Verification Tab + - [Home](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Verification/index.js#L380) + - [Page Content](https://github.com/bitholla/hollaex-kit/blob/8e617abf15c503e2e8483ffc5f4ae3e7befa4401/web/src/containers/Verification/index.js#L523) + + +## Targets + +### Static Targets + +- Verification Page Bank Tab + - REMOTE_COMPONENT__BANK_VERIFICATION + - REMOTE_COMPONENT__BANK_VERIFICATION_HOME + +- Verification Page KYC Tab + - REMOTE_COMPONENT__KYC_VERIFICATION + - REMOTE_COMPONENT__KYC_VERIFICATION_HOME + + +### Dynamic Targets + +- New Page +- New verification tab +- Fiat wallet deposit and withdrawal page + +# Meta Object +Dynamic targets are generated based on meta object values. Below you can see essential fields to deine each plugin type. These values should be added to the meta object under the view.json file to define the type of the plugin. These valuse are already set when you are using templates. See Develop section for more information. + +#### New page: +```sh +{ + "meta": { + "is_page": true, + "path": "/route-name" + } +} +``` + +#### New verification tab: + +```sh + "meta": { + "is_verification_tab": true, + "type": "home" or "verification", + } +``` + +#### Fiat Wallet +```sh + "meta": { + "is_wallet": true, + "type": "deposit" or "withdraw", + "currency": "USD" /* currency symbol /* + } +``` + +# Develop +To start developing a plugin, you first need to decide about the type of the plugin. Below is the list of available plugin types: + +| Type | | +| ------ | ------ | +| page | adds a new page with customizable access from the side and top menus | +| verification-tab | adds a new verification tab to the user verification page | +| fiat-wallet | adds a deposit and withdraw page for a fiat currency | +| kyc | adds KYC tab to the user verification page | +| bank | adds bank verification tab to the user verification page | +| raw | adds a template without initial meta object values | + +To initialize a plugin template run: +```sh +npm run add-page --plugin= --type= +``` + +To add a view to a plugin template run: +```sh +npm run add-view --plugin= --webveiw= +``` + +Once the plugin is initialized, run the following commands: + +On the starter kit: + +```sh +npm start --plugin= +``` + +On the main kit: +```sh +npm run dev:plugin --plugin= +``` + +A page reload is required to reflect bundle changes in the browser. + +## Strings and icons + +You can use strings and icons from the main kit. + +You also can define new strings and icons by adding them to strings.json and icons.json under the assets folder respectively. + +These values are added to the kit strings and icons object during kit initialization. To use local assets in your component, you should convert the local id to the global one by using generateId function from the kit context. See kit context. + +## Kit context + +We can always directly use props passed from the kit to the remote component. However in order to prevent passing some props through many levels, a context is provided to make these props globally accessible. +You can partially subscribe to the context to access props from the kit in a more efficient way. + +```sh +import React from "react"; +import { withKit } from 'components/KitContext'; + +const Title = ({ user: { username } = {}, strings: STRINGS }) => ( +
+ {STRINGS.formatString(STRINGS[generateId('hello')], username)} +
+); + +const mapContextToProps = ({ user, generateId, strings }) => ({ user, generateId, strings }); + +export default withKit(mapContextToProps)(Title); +``` \ No newline at end of file diff --git a/plugins/generateJson.js b/plugins/generateJson.js new file mode 100644 index 0000000000..a08f071f7f --- /dev/null +++ b/plugins/generateJson.js @@ -0,0 +1,80 @@ +const fs = require('fs'); +const path = require('path'); +const uglifyEs = require('uglify-es'); +const { minify: htmlMinify } = require('html-minifier-terser'); +const { FILES, PATHS } = require('./scripts/patterns'); + +const { env: { PLUGIN: plugin } } = process; + +if (!plugin) { + console.error('No plugin name given'); + process.exit(1); +} + +const pluginPath = path.resolve(__dirname, PATHS.ROOT, plugin, PATHS.SERVER); + +if (!fs.existsSync(pluginPath)) { + console.error(`Plugin ${plugin} does not exist`); + process.exit(1); +} + +const scriptPath = path.resolve(pluginPath, FILES.SCRIPT); +const adminViewPath = path.resolve(pluginPath, FILES.ADMIN_VIEW); +const webViewPath = path.resolve(pluginPath, FILES.WEB_VIEW); + +console.log(`Generating plugin JSON object for plugin ${plugin}...\n`); + +const config = fs.readFileSync(path.resolve(pluginPath, FILES.CONFIG)); +let script = null; +let admin_view = null; +let web_view = null; + +if (fs.existsSync(scriptPath)) { + const rawScript = fs.readFileSync(scriptPath, 'utf-8'); + script = uglifyEs.minify(rawScript); + + if (script.error) { + console.error('Error occured while minifying script\n'); + console.error(script.error); + process.exit(1); + } + + script = script.code; +} + +if (fs.existsSync(adminViewPath)) { + const rawAdminView = fs.readFileSync(adminViewPath, 'utf-8'); + + try { + admin_view = htmlMinify(rawAdminView, { + minifyJS: true, + minifyCSS: true, + collapseWhitespace: true + }); + } catch (err) { + console.error('Error occured while minifying admin_view\n'); + console.error(err); + process.exit(1); + } +} + +if (fs.existsSync(webViewPath)) { + const web_view_json = fs.readFileSync(webViewPath); + const { web_view: view } = JSON.parse(web_view_json); + web_view = view +} + +const pluginJson = JSON.stringify({ + ...JSON.parse(config), + script, + admin_view, + web_view +}, null, '\t'); + +const finalJsonPath = path.resolve(pluginPath, `${plugin}.json`); + +fs.writeFileSync(finalJsonPath, pluginJson); + +console.log(pluginJson); + +process.exit(0); \ No newline at end of file diff --git a/plugins/media/icon-large.png b/plugins/media/icon-large.png new file mode 100644 index 0000000000000000000000000000000000000000..06bc4d2565815493d8ce711d6ed097574a550595 GIT binary patch literal 6114 zcmds5cTkgEmrp{Zi6+t!kpMx8K0tKyzVCjYGdnx8f9&iZo0-f!&%O7w-zoQ;C(h)w!2#C8tPlv~ z00ECPgFv9{;LpI!2v)Z069m9ZxQDK;2|-sEW#aGS=HclIfrzKLI66uaq{Q2uoE#n7 zdyY%6`UjiE#*)n(8=I*;)MiwRV=F2r!`}WgFYN0yqPYcY7gZ&E|(GW5WBOt37W3vxB*^!1i_~In6RZQ(NvHVoh z`)0kSF{;_e6jCjL@s(=6tUC5#>+QQdhuQp@kX^DNvM*)DWiu3bWv%7s~tV5QYC){aO zMNYPKe1}f2ILyGXgJz6rcK3V?xwA!}KEdAOs!k@tJ&y9Rd81?O|aZXl-ny z=HlZe<3#jvc9jY7@&$f^Kr}+sz@wLIpc5*@%hNkREkslJuM=wE`S&tL81>hYz)PCK z*2X3%T_1l}l#-01jI6L0D+-0u@F%*dnc?*RAqQ`o!WRMqebq3S;NW1HU}xdyoSd-w)=_;{m!^L29e2@2E{7XB^h zU%$WgbPe(NwtAnXwR&Nd>UOX$%pOI4lGM1p2StAuy!)U5LJ!q7EDdfs(KHLf|M9 zMJPG%!gW9a<7K%IC?8ya@e=x&4*_{<*+61ER6oBHUGFkt714rfF`q8_o_;VL1K zFfjh_zYq?4Uf;$(4f+^LHvAa+(Ow9}vWqqGuDw2N+vS0SqVX+UIRfl{9HKUDA{O;zB~it6QG3? zVD$Q>94ic&aS|eu35~V{y2=7woyK_gL7BTzq?B$_lO(W+7b-JyoP4j(bfRYGF=VPW zzJF-6@7%y9ijh8wsD=wg$H1Uu9JDy*i(c1=B60OY-G$-TbvqXW!>1^tO2j_4SjbIf zXcUeSCc{C++dtC^xQWFA=_IT$1C+wzh?Y5f|CKHZ1!QAUDN&>@02Jj(@0bu02_>UZ z$?aIGD~va;Yta2Wk~tQl&yK_sQJ>|ZA?X}>?VH=&Wm>}~ajp`n*~`ftLMo|F{*)O^gzG@$L* zIA2LVSIIL`eHLLnsWnYzPrqF(m&2-~#N?3@itbB$5Nr+`;+hO$b~bc!3Xp0mQ*BI~Bjno~sQ< zB?IU?usRHI)MpAre~QAp2iyg`Nnm6@3__|AAko+|hk!B@kyN~V@;eYSo1&zYO;P=; z%vcm~W@^-RMrJG(1Hiz@ZR86vB=?( zlBS1=IuXut`%KY7j&dM$9;)2l(mZ1?B%g|8z6sHPM9tP@-&csY1<7VAjtE1unxs^M zJaZ1ZfZTaalQ(jF4_06F*U;uxCYCq|jdv&m zQ>*y_&C;EwJk)xLZ3&S;mQwf=xDu7{N18|0#|)Q5?Z=Uaq6gWzjPR8ufyE(CFAu_AmB zdIFf`J&u}P3dQ6ioz`b_{AZIZj$%`{fYT*DWM0afV)}~RN!O4LoZF; z-B_TOfaO0bxdh`Y_PLvz*Gm^!-!}*kv7Rb2OgLd-l z#UtTiAElN;d}-M-%=ejb?XUIkc^X+)7EOI&80hmNHf6}v-NgnS z7MdSA>s>TbZ&17*7!o6we0EVGk@)Q7N_n19P6akb##Z{Kc4YQXOug^3XO;YDQVQ?& zbHxwY_uk}xPy3j+J}6-Jik5xtapv=sEQzB&o~ay9WGK-mB2LC|%V-5C&<=oF%oZin zDr;Fgnm@Tk$@`#?;!M#=B)W}dY+Q&D`S=NSZb4hUA~T2qV91bcD2?k`@HsV2|7BY| zKF&Wha7{L~h{)cvnm0Sb@7h>RdF>nnvLGgafFsbN6t&mL8+!&}pI2G>@sCpzdM~9k zpNKH6dFF(0jgR}_K*l9_vV2QlTkERpIYanVHBsDisu}{Yg-;*!2wRT}zxl2g278+=>;qkWWOiYw#@P1iy07WsDnt%G5xiirStB#C5WnGzu5dp+Y2oq~Ju?HJ+Rb5x#O2J%~uzVlcCxF@Fy-{<9$kioW|b^;86@Ch zVRImNiS~r}49!1&Q!!c9s_hJ0NAcC|uSe`WltGDnmA!#9%UwiWZq=sCA$35STxZr6sPUhm)$hdD9rfq#L)>pj>bSDK?KRBqv6i`f zz8WtD3iowW8#0=0zQDy9-PDX3-E&)hB%TARpuZJPO`yMbG7*t97pwkMO;t;V$1{}b z1e-Jx0Fc!VcuyQM`_hjX-TbjXUz^b77MpV2B6(gwT{nIaJM@gKrW~u zabX3QE9Q_HSsBTCcFGH}xp#qtRIUW?+&0~YAcb2wq37WeKN*u60{K&<;COMt zWsjp5kLNg5*KMcX)p%V2ig3l1!p7rQtL-!yq2ppE6Ak-0W0-wQ5{2HGJEh)CI$cuy zYpG`TwB??}%EQ%k{LUHW)Ac<&G$!S-tl$Y9b*mKx--mPINzM3hk>lRjANAu?@Nja@ z0!%}Y-F->z&Qr}x_Z8F!$Om$U^L{iutv1l(=`(^I86nD>dPyuSoEVyr<3=kjpH19Eq$T0bBKBQ*Fy#bs{nUN&ZsxmiL{R@1b@MQPPtUJ*AGm<-@xB#= zH(L(!{M^}9E4S5Z3f=w(ZBCi+PSVGrz}hduVlG?D*5zYA*bK!q$t}LpVi$`K7zC;u z(RY5j$r~p(Kx0y~q0x;@nkCYWUUpnG8nuviz`^G0=e;DXAd+R3&B{;}-3$;^O~ zM5oVUc3=78tY5f4&vS^RjPq;FTx#Eq@Y$UADPO&CX}y5qZg*3fHE-PHsU(>UAGGu8 zv|accf_8aDa%;N5<($kN7Fs8fTLG?8Dc5{Ot@Fa@>u*6;fh<2u>~r}cYaXCOS7cQ< z?jqeIf8N3USVptyR7W1TTHZOq+zM``WXwcJjc-AnwRdnU+)Va1%?_*L?HKbM zsA9u76hBT}-hszxm%=z10dR~?XKtvKId2U}UQJ^@a<29?fp6Folp#-xJEQueZ@J7H z$HmXIp4!4$zNoAI+HCdJs+iz}7P7oN7yU#h-hSK3fD&NsQq##B=P^|?41Y-9@OmpzZP8#GZWRlJ;&UP_-=H zXayvad!_|XKFp6jYtd#$L3evFh^0bM+|rW~XZypZ3lh@(EFaKE7S3hYD6O{P zr6gLZBM27v+HH*f?wIm$@WR<$1QGY(_YL94E%qT`HBmnE%MLAEqRrXw+skR6)uq$g zdZ5t}wr}irS+)BzcmL{JnymW{BJ`$WMAun0^{e-e-AWm^M>@(Xtso$SR4)-s+f|@p5t-IG4u zqk8IgD_+>7q{;AXS8Z^F5-f8*Z)hj~c{`2%GeK>tkWmNREAZTg_IJez`K$MWyE?ue z+jC6E#Zu1VH$Hw(W4K>GoJz*K$bfLMCrWt=+Jr_0j)zg$9A0+6Uc6>3F+L`|G_jQv z=nxcC`ns?Pq`gJyeB9#=e9iY)=G)JI6`oH{P7|}T7aqO3Ok&IGjc(DA(Hoz9RVw0R zaXHB7{;B&~9wjqP^puv*56*RPWf<2zHQIhgSNOK6;UL2kD_iNrOSmwXfY4ZeLm_Mz zMM(1t-mamXmpCtLw9kh&y;Ms-9m8FDBXeKbesE!NGQUlCnhtv5zgcA`x|fypbI
Ya2Ds9 z&u0JP{JQUb%lC7ZQ%-0}>t>E6hhQ)WdFXm<4z8L-7OK|~%Wn7Z5!-3J zyvZYHCz9_9G~S-iu61AQ3+3?9e4{>AW29Ek(YeWPnNTiJ1G?wAyf_Ora{`A`Yzk9U zh@|N6KD4-AS5j@=a3<<>T;i>-N3JYO^}dL^f_NPN@kHm`qt!2)qLj{uXTojU>M&+D zizwfvRJlPM7^PY-6>Q@4Zd6nJJBmJ9#DM-ge|Pzi#KO0<@`gyl5y9k^<`zj0<(GfAK0(yn;o&2Fb?ElQbaYxF5_i>8FyJ;KD`_kvQKKya22U1dC@8{QuuE zm!w5SrO5%D(XCsAEcON@48-}N8zei>rd7}PcnUoLrNOi*UK~CK zzM{Rf^l{q{5aTTBhs5jq_d^*ueut?*w0{S!2jgZq=G>Un_CV zXM2$pfymoFN>o&$pyd2K^SnGpmnGnxW*^NJaoulBVB6-Gr9c;q!X<%|;yj(pEJfY; zg*8_2Z|qq^U6fWF?4Ouit^)5U5o}GgarrDxwh@zkeDTt{O`u*#oIrcTc;}Ul>2~u! zQzBXrw9hq2idwow-Dx>I{7k+ewgJT;#b=6Aido9Miq=ZYO6nPe7CVS`ws5xhfL0c8sB=xrYXN?ADF*-9>fB2C;mwH~kyIQF)qD+b%! zr=!`f=Jd4JhO$yccS+yP>er^F4a3sL;+7cL6WBkpxF7ZC#X07=c~U#=s6!QNXAVzJ z>iMat4#j9=+c-{6PF^jaoU|oGexq7g(`5m~0x@$$EIaF|9Q58sC_eyTJjG7q45ckRY7*X*2+62Wg&eajyPO;2@kQ-cK_~N93;v&C~sv zSwRH+SBO7WN5tC146N_v>k7UIQGqCmz!<<_u(q#@o2I#e;Xm-xKOGSde}8XH1%<%C zKuDl6#LL%R0ji;)p`fUwprj;!8X@mT!23G|$>aS*|4#D%c??|roP9Cg{unPj_$;r} zEw2E79TAbULjQXH?$b30^Y2P{zkkL$9Z=!SqX2~{D*QK?KgR8Uz|K5>!~UAcxa75R(j7vxzdnx?)O*HeBaPrSCm8Bf3P_O~d1Sx;4gF=#9NOJNwp=fs9N0AQj*7+kjSpdq2KM0-oF zpTi5V&of#ZaIFVp(vd|ZF$TR_sRzkYIh)a!c#lNGjo+fXgp-rA&?*wktooEtv7@oB z@E=AhP-z>k$1&Ch9(+j8Rp6_!`xN2LE9LKmq}k>-8s7uf8^%`(rgtWTs~Z1oo|wYc zg!W9yq=!!H?r7Joy2pH9<#0oB@4mF?#2!R}Hdk)*EjpvfS5t=Un(Q@UY`}d8O~10q!RFHyU03{;yA`Yr_2m z!|$v*Gks3A{_vz7ud1+eE#DEuEu))5MZT=vJH@+ZipD&TVoic2c0@W@ti*q~Yc8k@ z!us@2xRGbX&LEtFWVymxvhKm|?dYvV=gyr$`*&EY|3PR7RY;DC^eB?X}ma^$mjbe;t z(%aXjMOu&76rgQa0@Z&*6J`<*T{5qkSXBsAUuFY=WwQpy!1phu7?OGQR9EcBBkP4!)Dr3bqgQf>8%_}h+^;^?7eWm>FGi?Q-yM9>$6(R}wck^bxk|d> zJ*&gK)C{M9$mKkV*ZNtWY@LJB^}%r*AKpt5Sc`?5U1l_HdigZYx5DTH<%1Q6qRb3a z$B3I1PRql`Mgi`Wt#p|878$E#Ta^C%PGHfYfFrA+s|V%nAYE=tTibibQ}lClLJ@V? zL7qe!&O{gkZyzawT6yH1X~Z~}`crc$JF6$5LEP!4nNFgY@v}$oUeT}RucZpwvas1>dHHTv+3=?vzK>w3k`{0X-Tbh z--t~gFnqNaOr`r)Jl0p-tW|`SI-`!a-h48sYlML*Tu`l+6Mub|S5q39%6>yizbDh_ zt+1-A=*2dRE94q-(GfVj@9LmM6L!5LZ_FtTdrjk6V>d)EkFL*}Q~}(#HcU?Xwhs z<@I6in_URfNzRw}wJ04&RJf5`jC zI@wLHRlnWqBPAemydId5~7;eD%}TZ(Njk2dV(!I!AMXhn*Uwl|gTr zOnwOZXH`N100zF?T*S{!rzdUOl%DrQ`b3+=D5``Gc~W1`z;O|LBr`q2Gf=&0c;cdd zPO#ZDqoJshBl>&;YWG=TU&av9OwrLEvfizB4gCE8VR5hJ-{q$a-&O#8SO9RVpcwJgiYp z)7L+e!$`XNOrlS6Up9vsmE_5EcLCy>d5!sDg5UdiYIbgAZm!wMK!A%oG_^{nb};VC z7m+kQ#MmOLi5A%D59_JCQD+ON6AOKv7z>B11b~6c+}_%_dZf5|JW~iEqTc%BaFs8a zRs1UESS8=y+*4WANY*=Q`3}qD7|Nf@uZY3clJ+QTc(oeiy_V)xH)G9AP=lDD+S3*% z)l6O>n#kB^?D=^Pk8G`o25o+L)Y^Yb4uhP9*z}o5WPLLd;~3R)7;}>E5^s1BvwK9j zft}1zKzFX|Vf+R6Q_clFNt`w>hb@h6t9yGeygB|sFNW&3$krXphAc4GGf`W8glo>S zJFe4>iw) zX)}6e)T$p-G(onEy*D_wzh5H8z=b-$L?YBj5gA2uYz>}l7o}|%fAU-$x>+_8tOSFp z^<>??4F#~&wPUopyOig!HjL&loTyGPO-ap9hWO?g&;e>`)AONRqoP{E*cX}3)Rx1Q zgw02Wir=FP(d(_CNuJ&{aCYQKEt)C<4iLpvD@0QzrX%k#H_hq1K%&VDGjBqF z?l^+CHZVWZN;ds$aHZ~iPF|lduyw%|mD_N9^c%Lkply2Mt7BG+8>K}O(B~%o@SWG| zMa576O8%;;UT4~7tJ1rq`L2&GMVyj+m6-4?2YfinkjYSQM$}_FQ~cvL9{E@;G+) zWD2=n)G%FrWc+#i@L;Y$J0@kJMqsqe^Sbd`aW`OBL!92_yMg=iiR8B85`dwfFpSK0 zS5WPFu|hBOJNHa_o-E3vs)qLi)adra*iL0AxON^{Vdvi{mN2~qEhR)L3j@3i zD>vK~@2uh6N-u;QjW40zlqzoZTqhna=az?j8(=DQ;J{n8Mtph8iF|cDebs}AB@M@} zM;cy;niNU08%Jzpz+9Pqd02!kp7RGqP?vSBzk%A139Jg(m0reeL(hdt}yv;hY#0l&hjo+CO?bpUAW|98;-uJjj$6=%#qGE$qEj1V`sa z$yZxU+iVrY$yyBtJT_cd!|4o4UCf}aAO$e}-1q7g3Kvjq3;*KzN?j*$Ub~QW=57^8 zh)gbd;Jo#%({O(|4UyY0S@}EjHMcWLqR9b%`FG29M*6VT^F;-= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "escape-latex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", + "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz", + "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^6.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", + "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", + "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0" + } + }, + "eslint-plugin-prettier": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz", + "integrity": "sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", + "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", + "object.fromentries": "^2.0.2", + "object.values": "^1.1.1", + "prop-types": "^15.7.2", + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + } + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fraction.js": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.12.tgz", + "integrity": "sha512-8Z1K0VTG4hzYY7kA/1sj4/r1/RWLBD3xwReT/RCrUCbzPszjNQCCsy3ktkU/eaEqX3MYa4pY37a52eiBlPMlhA==" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "dependencies": { + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "hollaex-web-lib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/hollaex-web-lib/-/hollaex-web-lib-0.3.0.tgz", + "integrity": "sha512-DDMFM5cVNAgWYwmsgJTck30xSBfCQB/Xe+kK2liVfQgkOeoFVj7F65uLi72IB7LBO55hfxmPj2bSt8XkN87ydA==", + "requires": { + "@material/button": "0.7.0", + "keycode": "2.2.0", + "react-copy-to-clipboard": "5.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + } + }, + "html-webpack-plugin": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz", + "integrity": "sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.15", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + } + } + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-server": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.0.0.tgz", + "integrity": "sha512-XTePIXAo5x72bI8SlKFSqsg7UuSHwsOa4+RJIe56YeMUvfTvGDy7TxFkTEhfIRmM/Dnf6x29ut541ythSBZdkQ==", + "dev": true, + "requires": { + "basic-auth": "^2.0.1", + "colors": "^1.4.0", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "insert-css": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/insert-css/-/insert-css-2.0.0.tgz", + "integrity": "sha1-610Ql7dUL0x56jBg067gfQU4gPQ=" + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-beautify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-beautify/-/json-beautify-1.1.1.tgz", + "integrity": "sha512-17j+Hk2lado0xqKtUcyAjK0AtoHnPSIgktWRsEXgdFQFG9UnaGw6CHa0J7xsvulxRpFl6CrkDFHght1p5ZJc4A==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=", + "requires": { + "string-convert": "^0.2.0" + } + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, + "lodash.has": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", + "integrity": "sha512-rnYUdIo6xRCJnQmbVFEwcxF144erlD+M3YcJUVesflU9paQaE8p+fJDcIQrlMYbxoANFL+AB9hZrzSBBk5PL+g==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "mathjs": { + "version": "5.10.3", + "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-5.10.3.tgz", + "integrity": "sha512-ySjg30BC3dYjQm73ILZtwcWzFJde0VU6otkXW/57IjjuYRa3Qaf0Kb8pydEuBZYtqW2OxreAtsricrAmOj3jIw==", + "requires": { + "complex.js": "2.0.11", + "decimal.js": "10.2.0", + "escape-latex": "1.2.0", + "fraction.js": "4.0.12", + "javascript-natural-sort": "0.7.1", + "seed-random": "2.2.0", + "tiny-emitter": "2.1.0", + "typed-function": "1.1.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mini-store": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/mini-store/-/mini-store-3.0.6.tgz", + "integrity": "sha512-YzffKHbYsMQGUWQRKdsearR79QsMzzJcDDmZKlJBqt5JNkqpyJHYlK6gP61O36X+sLf76sO9G6mhKBe83gIZIQ==", + "requires": { + "hoist-non-react-statics": "^3.3.2", + "shallowequal": "^1.0.2" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "nocache": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-3.0.1.tgz", + "integrity": "sha512-Gh39xwJwBKy0OvFmWfBs/vDO4Nl7JhnJtkqNP76OUinQz7BiMoszHYrIDHHAaqVl/QKVxCEy4ZxC/XZninu7nQ==", + "dev": true + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + } + } + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "numbro": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/numbro/-/numbro-1.11.1.tgz", + "integrity": "sha512-qL0Etqbunz4RtPx4bNjMONe9HyUpgbrM4Sa3VpWY5oRdp9ry5DufAj6lCvnIcluRBA9QUacrllYc73QK0G6VAw==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", + "integrity": "sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==", + "dev": true, + "requires": { + "array.prototype.reduce": "^1.0.4", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "omit.js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/omit.js/-/omit.js-2.0.2.tgz", + "integrity": "sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onchange": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/onchange/-/onchange-7.1.0.tgz", + "integrity": "sha512-ZJcqsPiWUAUpvmnJri5TPBooqJOPmC0ttN65juhN15Q8xA+Nbg3BaxBHXQ45EistKKlKElb0edmbPWnKSBkvMg==", + "dev": true, + "requires": { + "@blakeembrey/deque": "^1.0.5", + "@blakeembrey/template": "^1.0.0", + "arg": "^4.1.3", + "chokidar": "^3.3.1", + "cross-spawn": "^7.0.1", + "ignore": "^5.1.4", + "tree-kill": "^1.2.2" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + } + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dev": true, + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "dev": true, + "optional": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "portfinder": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", + "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", + "dev": true, + "requires": { + "async": "^2.6.4", + "debug": "^3.2.7", + "mkdirp": "^0.5.6" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true + }, + "postcss": { + "version": "8.4.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "requires": { + "performance-now": "^2.1.0" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc-align": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.11.tgz", + "integrity": "sha512-n9mQfIYQbbNTbefyQnRHZPWuTEwG1rY4a9yKlIWHSTbgwI+XUMGRYd0uJ5pE2UbrNX0WvnMBA1zJ3Lrecpra/A==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "dom-align": "^1.7.0", + "lodash": "^4.17.21", + "rc-util": "^5.3.0", + "resize-observer-polyfill": "^1.5.1" + }, + "dependencies": { + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + } + } + }, + "rc-animate": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.1.1.tgz", + "integrity": "sha512-8wg2Zg3EETy0k/9kYuis30NJNQg1D6/WSQwnCiz6SvyxQXNet/rVraRz3bPngwY6rcU2nlRvoShiYOorXyF7Sg==", + "requires": { + "@ant-design/css-animation": "^1.7.2", + "classnames": "^2.2.6", + "raf": "^3.4.0", + "rc-util": "^4.15.3" + }, + "dependencies": { + "rc-util": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz", + "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==", + "requires": { + "add-dom-event-listener": "^1.1.0", + "prop-types": "^15.5.10", + "react-is": "^16.12.0", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0" + } + } + } + }, + "rc-cascader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-1.3.0.tgz", + "integrity": "sha512-wayuMo/dSZixvdpiRFZB4Q6A3omKRXQcJ3CxN02+PNiTEcRnK2KDqKUzrx7GwgMsyH5tz90lUZ91lLaEPNFv0A==", + "requires": { + "array-tree-filter": "^2.1.0", + "rc-trigger": "^4.0.0", + "rc-util": "^5.0.1", + "warning": "^4.0.1" + } + }, + "rc-checkbox": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.3.2.tgz", + "integrity": "sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1" + } + }, + "rc-collapse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-2.0.1.tgz", + "integrity": "sha512-sRNqwQovzQoptTh7dCwj3kfxrdor2oNXrGSBz+QJxSFS7N3Ujgf8X/KlN2ElCkwBKf7nNv36t9dwH0HEku4wJg==", + "requires": { + "@ant-design/css-animation": "^1.7.2", + "classnames": "2.x", + "rc-animate": "3.x", + "rc-util": "^5.2.1", + "shallowequal": "^1.1.0" + } + }, + "rc-dialog": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.1.2.tgz", + "integrity": "sha512-yhyy3bxnornjrUPOiCXFdTt/nRKjQ/qhR+MMcQavRYWh1LPcxB8y1LbgrvYX7SV/lY/Mib237xf2q6WYXQ1kpA==", + "requires": { + "rc-animate": "3.x", + "rc-util": "^5.0.1" + } + }, + "rc-drawer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-4.1.0.tgz", + "integrity": "sha512-kjeQFngPjdzAFahNIV0EvEBoIKMOnvUsAxpkSPELoD/1DuR4nLafom5ryma+TIxGwkFJ92W6yjsMi1U9aiOTeQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.0.1" + } + }, + "rc-dropdown": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.1.3.tgz", + "integrity": "sha512-sqVMDZcyV32y2YIEUBfxzgRzOLXqi/v5JB1GPe0CMyGMadPvbi+YIRF8toKdQf26tcHZobZUOyFk8OOV2BRusw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-trigger": "^4.0.0" + } + }, + "rc-field-form": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.10.1.tgz", + "integrity": "sha512-aosTtNTqLYX2jsG5GyCv7axe+b57XH73T7TmmrX/cmhemhtFjvNE6RkRkmtP9VOJnZg5YGC5HfK172cnJ1Ij7Q==", + "requires": { + "@babel/runtime": "^7.8.4", + "async-validator": "^3.0.3", + "rc-util": "^5.0.0" + } + }, + "rc-image": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-3.0.6.tgz", + "integrity": "sha512-Dn8mTSlcgKJko417OX8+6yyNIL9+DEa81aexBfT78qWlEpcxtR4GgdsU0+zJLNqa2rnGZyjaBLFtaPw9tUuxYA==", + "requires": { + "@ant-design/icons": "^4.2.2", + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "rc-dialog": "~8.2.2", + "rc-util": "^5.0.6" + }, + "dependencies": { + "rc-dialog": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.2.2.tgz", + "integrity": "sha512-U4jR5bE7XpIbMC20JAIv91254b+vQ8LODd8Kxco0XvkL+eJ1aCYkOfRqevJ1ipOIzF3s6F08jSH8YvJqxvpAvA==", + "requires": { + "@babel/runtime": "^7.10.1", + "rc-animate": "3.x", + "rc-util": "^5.0.1" + } + } + } + }, + "rc-input-number": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-6.0.1.tgz", + "integrity": "sha512-cS1k6IB/V84VUQd5qWzGFrLHvZjWGHGmYbrvR0QP/C1Ju1SlBqlhqhOBTc6w+dpPs84PCH5caZtNzsHeWZ1zYA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + } + }, + "rc-mentions": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.4.2.tgz", + "integrity": "sha512-wSmHRF9kFwrbj59mR+u4yVr0KtcrfPw53PYOVizYxYeDfmwaCcSgk29F8OjlDy5jVqUaMhHX5nIiYCePu5Aytg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-menu": "^8.0.1", + "rc-textarea": "^0.3.0", + "rc-trigger": "^4.3.0", + "rc-util": "^5.0.1" + } + }, + "rc-menu": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-8.5.3.tgz", + "integrity": "sha512-OLdN+jwhabgyRZDvWYjYpO7RP7wLybhNuAulgGqx1oUPBJrtgVlG/X4HtPb7nypRx/n+eicj6H8CtbCs0L4m/Q==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "mini-store": "^3.0.1", + "omit.js": "^2.0.0", + "rc-motion": "^1.0.1", + "rc-trigger": "^4.4.0", + "rc-util": "^5.0.1", + "resize-observer-polyfill": "^1.5.0", + "shallowequal": "^1.1.0" + } + }, + "rc-motion": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-1.1.2.tgz", + "integrity": "sha512-YC/E7SSWKBFakYg4PENhSRWD4ZLDqkI7FKmutJcrMewZ91/ZIWfoZSDvPaBdKO0hsFrrzWepFhXQIq0FNnCMWA==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "raf": "^3.4.1", + "rc-util": "^5.0.6" + } + }, + "rc-notification": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.4.0.tgz", + "integrity": "sha512-IDeNAFGVeOsy1tv4zNVqMAXB9tianR80ewQbtObaAQfjwAjWfONdqdyjFkEU6nc6UQhSUYA5OcTGb7kwwbnh0g==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-animate": "3.x", + "rc-util": "^5.0.1" + } + }, + "rc-pagination": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.0.4.tgz", + "integrity": "sha512-9v9mmB7FTWS4kWRLFfWafm6LtvB+xdNi+pTIwUODSevzImrlrmMOIhDrOB3u2tEXiy8LyqvCnoyPYt5jQBapxA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1" + } + }, + "rc-picker": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.0.11.tgz", + "integrity": "sha512-pUEne2fikHvzqmOjWNLa1P/ss4/1J9lpHrtSU1IrueRiEbUPLIgXmnzoUeVt3syOZGBnWok6nNDu1FvIQfVMCw==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "date-fns": "^2.15.0", + "dayjs": "^1.8.30", + "moment": "^2.24.0", + "rc-trigger": "^4.0.0", + "rc-util": "^5.0.1", + "shallowequal": "^1.1.0" + } + }, + "rc-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.0.0.tgz", + "integrity": "sha512-dQv1KU3o6Vay604FMYMF4S0x4GNXAgXf1tbQ1QoxeIeQt4d5fUeB7Ri82YPu+G+aRvH/AtxYAlEcnxyVZ1/4Hw==", + "requires": { + "classnames": "^2.2.6" + } + }, + "rc-rate": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.8.2.tgz", + "integrity": "sha512-f9T/D+ZwWQrWHkpidpQbnXpnVMGMC4eSRAkwuu88a8Qv1C/9LNc4AErazoh8tpnZBFqq19F3j0Glv+sDgkfEig==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + } + }, + "rc-resize-observer": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-0.2.6.tgz", + "integrity": "sha512-YX6nYnd6fk7zbuvT6oSDMKiZjyngjHoy+fz+vL3Tez38d/G5iGdaDJa2yE7345G6sc4Mm1IGRUIwclvltddhmA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-util": "^5.0.0", + "resize-observer-polyfill": "^1.5.1" + } + }, + "rc-select": { + "version": "11.1.7", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-11.1.7.tgz", + "integrity": "sha512-HZozKGhFbLDI995OUKQW2uZ2ZcGyzNhWN6gTQqpW5/Z0rae1zftpgkI1yxZ79LukOc8lO2NKlDDKCGH/SJH2Cg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^1.0.1", + "rc-trigger": "^4.3.0", + "rc-util": "^5.0.1", + "rc-virtual-list": "^3.0.3", + "warning": "^4.0.3" + } + }, + "rc-slider": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.3.1.tgz", + "integrity": "sha512-c52PWPyrfJWh28K6dixAm0906L3/4MUIxqrNQA4TLnC/Z+cBNycWJUZoJerpwSOE1HdM3XDwixCsmtFc/7aWlQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-tooltip": "^4.0.0", + "rc-util": "^5.0.0", + "shallowequal": "^1.1.0" + } + }, + "rc-steps": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-4.1.4.tgz", + "integrity": "sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w==", + "requires": { + "@babel/runtime": "^7.10.2", + "classnames": "^2.2.3", + "rc-util": "^5.0.1" + } + }, + "rc-switch": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-3.2.2.tgz", + "integrity": "sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-util": "^5.0.1" + } + }, + "rc-table": { + "version": "7.9.10", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.9.10.tgz", + "integrity": "sha512-WtPBxYsBU/a5MIglilbMlVkiXkPKXpUM/CPCFaqA2veh1b7J40mbTGQmU8VT6S0FClkI5jm0QBtSp6LstPkOMQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "raf": "^3.4.1", + "rc-resize-observer": "^0.2.0", + "rc-util": "^5.0.4", + "shallowequal": "^1.1.0" + } + }, + "rc-tabs": { + "version": "11.6.2", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.6.2.tgz", + "integrity": "sha512-7Z5Lg+nP/H4V7dIlewrOC0+aogRVH3ASjTy4VIletYOeStGPWYSfwBnUTBdcCXcUuWuyyKnNkYrUD0yaRqUCIA==", + "requires": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "raf": "^3.4.1", + "rc-dropdown": "^3.1.3", + "rc-menu": "^8.6.1", + "rc-resize-observer": "^0.2.1", + "rc-util": "^5.0.0" + }, + "dependencies": { + "rc-menu": { + "version": "8.10.8", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-8.10.8.tgz", + "integrity": "sha512-0gnSR0nmR/60NnK+72EGd+QheHyPSQ3wYg1TwX1zl0JJ9Gm0purFFykCXVv/G0Jynpt0QySPAos+bpHpjMZdoQ==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "mini-store": "^3.0.1", + "rc-motion": "^2.0.1", + "rc-trigger": "^5.1.2", + "rc-util": "^5.7.0", + "resize-observer-polyfill": "^1.5.0", + "shallowequal": "^1.1.0" + } + }, + "rc-motion": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.4.4.tgz", + "integrity": "sha512-ms7n1+/TZQBS0Ydd2Q5P4+wJTSOrhIrwNxLXCZpR7Fa3/oac7Yi803HDALc2hLAKaCTQtw9LmQeB58zcwOsqlQ==", + "requires": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.2.1" + } + }, + "rc-trigger": { + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.10.tgz", + "integrity": "sha512-FkUf4H9BOFDaIwu42fvRycXMAvkttph9AlbCZXssZDVzz2L+QZ0ERvfB/4nX3ZFPh1Zd+uVGr1DEDeXxq4J1TA==", + "requires": { + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "rc-align": "^4.0.0", + "rc-motion": "^2.0.0", + "rc-util": "^5.5.0" + } + } + } + }, + "rc-textarea": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.3.5.tgz", + "integrity": "sha512-qa+k5vDn9ct65qr+SgD2KwJ9Xz6P84lG2z+TDht/RBr71WnM/K61PqHUAcUyU6YqTJD26IXgjPuuhZR7HMw7eA==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.7.0" + }, + "dependencies": { + "rc-resize-observer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.0.1.tgz", + "integrity": "sha512-OxO2mJI9e8610CAWBFfm52SPvWib0eNKjaSsRbbKHmLaJIxw944P+D61DlLJ/w2vuOjGNcalJu8VdqyNm/XCRg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-util": "^5.0.0", + "resize-observer-polyfill": "^1.5.1" + } + } + } + }, + "rc-tooltip": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-4.2.3.tgz", + "integrity": "sha512-7ySkaPGeqLLM4a/QYrKQ280aDthPxyvjJqQMstWX/AWX7/b1p23HIdHXdjBkziuvcnvXkW4lgZdFTVsylDiX1w==", + "requires": { + "@babel/runtime": "^7.11.2", + "rc-trigger": "^4.2.1" + } + }, + "rc-tree": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-3.9.5.tgz", + "integrity": "sha512-ZGVl1o83hZoz971pzY9Y7yZM+f9qcia1Gym+QNyc3zMGQVshbr6CX2WZ8xUK18tTkdRSqbTXmZFnvYf1lfqT8A==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^1.0.0", + "rc-util": "^5.0.0", + "rc-virtual-list": "^3.0.1" + } + }, + "rc-tree-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-4.1.3.tgz", + "integrity": "sha512-vk/T1vHNvuBZyoq8CvOF6iaiyVe6Y8QmQflTYFgabVsTJ1d/obkO9tAXOvJELZgKJ9ljduDVaAZAgcq0Yap+mg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "^11.1.1", + "rc-tree": "^3.8.0", + "rc-util": "^5.0.5" + } + }, + "rc-trigger": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-4.4.3.tgz", + "integrity": "sha512-yq/WyuiPwxd2q6jy+VPyy0GUCRFJ2eFqAaCwPE27AOftXeIupOcJ/2t1wakSq63cfk7qtzev5DKHUAjb8LOJCw==", + "requires": { + "@babel/runtime": "^7.11.2", + "classnames": "^2.2.6", + "raf": "^3.4.1", + "rc-align": "^4.0.0", + "rc-motion": "^1.0.0", + "rc-util": "^5.0.1" + } + }, + "rc-upload": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-3.2.1.tgz", + "integrity": "sha512-gmIy08tco2YFTSiru9zgeTmUcDKPyUMUUBdUIjG2CcHz4jdbpaPx/RL/Wz9CMD6ppQizK0gES0rcQ1+o5frK2Q==", + "requires": { + "classnames": "^2.2.5" + } + }, + "rc-util": { + "version": "5.13.2", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.13.2.tgz", + "integrity": "sha512-eYc71XXGlp96RMzg01Mhq/T3BL6OOVTDSS0urFEuvpi+e7slhJRhaHGCKy2hqJm18m9ff7VoRoptplKu60dYog==", + "requires": { + "@babel/runtime": "^7.12.5", + "react-is": "^16.12.0", + "shallowequal": "^1.1.0" + } + }, + "rc-virtual-list": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.2.tgz", + "integrity": "sha512-OyVrrPvvFcHvV0ssz5EDZ+7Rf5qLat/+mmujjchNw5FfbJWNDwkpQ99EcVE6+FtNRmX9wFa1LGNpZLUTvp/4GQ==", + "requires": { + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.0.7" + }, + "dependencies": { + "rc-resize-observer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.0.1.tgz", + "integrity": "sha512-OxO2mJI9e8610CAWBFfm52SPvWib0eNKjaSsRbbKHmLaJIxw944P+D61DlLJ/w2vuOjGNcalJu8VdqyNm/XCRg==", + "requires": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-util": "^5.0.0", + "resize-observer-polyfill": "^1.5.1" + } + } + } + }, + "react": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", + "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-copy-to-clipboard": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz", + "integrity": "sha512-ELKq31/E3zjFs5rDWNCfFL4NvNFQvGRoJdAKReD/rUPA+xxiLPQmZBZBvy2vgH7V0GE9isIQpT9WXbwIVErYdA==", + "requires": { + "copy-to-clipboard": "^3", + "prop-types": "^15.5.8" + } + }, + "react-device-detect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-1.6.2.tgz", + "integrity": "sha512-XIBgwIfpGAknm7tXe/YNbx4ieIR7IyFI3KNfSQk4UjHVy97UHe/nB7iJj8R/dDsI+I/ZzPR4HJ39Gh5tI4nhxw==" + }, + "react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-event-listener": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.6.6.tgz", + "integrity": "sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw==", + "requires": { + "@babel/runtime": "^7.2.0", + "prop-types": "^15.6.0", + "warning": "^4.0.1" + } + }, + "react-ionicons": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/react-ionicons/-/react-ionicons-2.1.6.tgz", + "integrity": "sha1-ycRywkL0HyKKYmH9bOFW1U4Odnc=", + "requires": { + "prop-types": "15.5.10", + "react": "15.4.2", + "react-dom": "15.4.2", + "styled-components": "2.2.3" + }, + "dependencies": { + "prop-types": { + "version": "15.5.10", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.5.10.tgz", + "integrity": "sha1-J5ffwxJhguOpXj37suiT3ddFYVQ=", + "requires": { + "fbjs": "^0.8.9", + "loose-envify": "^1.3.1" + } + }, + "react": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react/-/react-15.4.2.tgz", + "integrity": "sha1-QfeZGyYYU5K6m66WyIiefgGDl+8=", + "requires": { + "fbjs": "^0.8.4", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.0" + } + }, + "react-dom": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.4.2.tgz", + "integrity": "sha1-AVNj8FsKH9Uq6e/dOgBg2QaVII8=", + "requires": { + "fbjs": "^0.8.1", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.0" + } + } + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-modal": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.8.1.tgz", + "integrity": "sha512-aLKeZM9pgXpIKVwopRHMuvqKWiBajkqisDA8UzocdCF6S4fyKVfLWmZR5G1Q0ODBxxxxf2XIwiCP8G/11GJAuw==", + "requires": { + "exenv": "^1.2.0", + "prop-types": "^15.5.10", + "react-lifecycles-compat": "^3.0.0", + "warning": "^3.0.0" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, + "react-redux": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-6.0.1.tgz", + "integrity": "sha512-T52I52Kxhbqy/6TEfBv85rQSDz6+Y28V/pf52vDWs1YRXG19mcFOGfHnY2HsNFHyhP+ST34Aih98fvt6tqwVcQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "hoist-non-react-statics": "^3.3.0", + "invariant": "^2.2.4", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.8.2" + } + }, + "react-svg": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/react-svg/-/react-svg-11.2.2.tgz", + "integrity": "sha512-Q9lAuUgaI8c55OluftgrAyE4GAmIvmqVHJXt1fIzXFHcuIauKqVjhUH/BiizOqjPmY+R27kiTkv9g7AxY7O+wA==", + "requires": { + "@babel/runtime": "^7.12.5", + "@tanem/svg-injector": "^8.2.1", + "prop-types": "^15.7.2" + } + }, + "read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha512-+UBirHHDm5J+3WDmLBZYSklRYg82nMlz+enn+GMZ22nSR2f4bzxmhso6rzQW/3mT2PVzpzDTiYIZahk8UmZ44w==", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "redux": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz", + "integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "redux-form": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/redux-form/-/redux-form-8.1.0.tgz", + "integrity": "sha512-d2+0OaJpSq3kwkbPtFlG3W/HENWLxX8NqqTHSOnfgIrID/9faH/rxejLa1X3HChilCTm71zWe/g9zaLPCMCofQ==", + "requires": { + "@babel/runtime": "^7.2.0", + "es6-error": "^4.1.1", + "hoist-non-react-statics": "^3.2.1", + "invariant": "^2.2.4", + "is-promise": "^2.1.0", + "lodash": "^4.17.11", + "lodash-es": "^4.17.11", + "prop-types": "^15.6.1", + "react-is": "^16.7.0", + "react-lifecycles-compat": "^3.0.4" + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "regexpu-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz", + "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", + "dev": true + }, + "regjsparser": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "optional": true + }, + "renderkid": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "dev": true, + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "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 + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "scroll-into-view-if-needed": { + "version": "2.2.28", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz", + "integrity": "sha512-8LuxJSuFVc92+0AdNv4QOxRL4Abeo1DgLnGNkn1XlaujPH/3cCFz3QI60r2VNu4obJJROzgnIUw5TKQkZvZI1w==", + "requires": { + "compute-scroll-into-view": "^1.0.17" + } + }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", + "dev": true + }, + "seed-random": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", + "integrity": "sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ=" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "style-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz", + "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "styled-components": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-2.2.3.tgz", + "integrity": "sha512-KzdZv4zyZPLoM4V90Tu+3evqTBZt1quFC1DBt5SA7k4dY3ANWmK+LZiIk/Q99GzLisBiEjV+Fn9nyty9rrZ1jw==", + "requires": { + "buffer": "^5.0.3", + "css-to-react-native": "^2.0.3", + "fbjs": "^0.8.9", + "hoist-non-react-statics": "^1.2.0", + "is-function": "^1.0.1", + "is-plain-object": "^2.0.1", + "prop-types": "^15.5.4", + "stylis": "3.x", + "supports-color": "^3.2.3" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "hoist-non-react-statics": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", + "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=" + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "stylis": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", + "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "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 + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-1.1.0.tgz", + "integrity": "sha512-TuQzwiT4DDg19beHam3E66oRXhyqlyfgjHB/5fcvsRXbfmWPJfto9B4a0TBdTrQAPGlGmXh/k7iUI+WsObgORA==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.28", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz", + "integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==" + }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "requires": { + "commander": "~2.13.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", + "dev": true + }, + "union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "requires": { + "qs": "^6.4.0" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "optional": true + }, + "update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "dev": true + } + } + }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dev": true, + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + } + } + }, + "webpack": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", + "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.3.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "webpack-assets-manifest": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/webpack-assets-manifest/-/webpack-assets-manifest-3.1.1.tgz", + "integrity": "sha512-JV9V2QKc5wEWQptdIjvXDUL1ucbPLH2f27toAY3SNdGZp+xSaStAgpoMcvMZmqtFrBc9a5pTS1058vxyMPOzRQ==", + "dev": true, + "requires": { + "chalk": "^2.0", + "lodash.get": "^4.0", + "lodash.has": "^4.0", + "mkdirp": "^0.5", + "schema-utils": "^1.0.0", + "tapable": "^1.0.0", + "webpack-sources": "^1.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "webpack-bundle-analyzer": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz", + "integrity": "sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.19", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + } + } + }, + "webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "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" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.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==", + "dev": true + } + } + }, + "whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/plugins/package.json b/plugins/package.json new file mode 100644 index 0000000000..5ac163bc9c --- /dev/null +++ b/plugins/package.json @@ -0,0 +1,108 @@ +{ + "name": "hollaex-plugins", + "version": "1.0.0", + "description": "HollaEx Official Plugins Repo", + "private": true, + "browser": "dist/main.js", + "repository": { + "type": "git", + "url": "git+https://github.com/bitholla/hollaex-plugins.git" + }, + "author": "bitHolla", + "license": "ISC", + "scripts": { + "kill-8080": "lsof -ti:8080 | xargs kill || exit 0", + "build:web": "npm run clean && cross-env NODE_ENV=production webpack --env.plugin=$npm_config_plugin --mode production", + "build:dev": "npm run clean && cross-env NODE_ENV=development webpack --env.plugin=$npm_config_plugin --mode development", + "start": "cross-env NODE_ENV=development concurrently \"npm run dev --plugin=$npm_config_plugin\" \"npm run json:watch --plugin=$npm_config_plugin\" \"npm run server\"", + "dev": "npm run clean && cross-env NODE_ENV=development webpack --env.plugin=$npm_config_plugin --mode development --config webpack-dev.config.js", + "clean": "rimraf dist", + "remove:json": "rimraf json", + "lint": "eslint .", + "json": "PLUGIN=$npm_config_plugin node scripts/generateJson.js", + "generate-json": "npm run remove:json && PLUGIN=$npm_config_plugin node scripts/generateJson.js", + "add-plugin": "PLUGIN=$npm_config_plugin TYPE=$npm_config_type node scripts/addPlugin.js", + "add-view": "PLUGIN=$npm_config_plugin WEB_VIEW=$npm_config_webview node scripts/addView.js", + "publish": "npm run build:web --plugin=$npm_config_plugin && npm run generate-json --plugin=$npm_config_plugin", + "publish:dev": "npm run build:dev --plugin=$npm_config_plugin && npm run generate-json --plugin=$npm_config_plugin", + "json:watch": "npm run remove:json && onchange -i 'src/plugins/**/assets/*.json' 'src/plugins/**/views/**/*.json' -- npm run json --plugin=$npm_config_plugin", + "server": "npm run kill-8080 && node server.js", + "test": "echo \"Error: no test specified\" && exit 1", + "build": "npm run publish:web --plugin=$npm_config_plugin && npm run generate:json --plugin=$npm_config_plugin", + "generate:json": "PLUGIN=$npm_config_plugin node generateJson.js", + "add-bundles": "node scripts/addBundles.js", + "add-jsons": "node scripts/addJsons.js", + "publish:web": "npm run publish --plugin=$npm_config_plugin && npm run add-bundles && npm run add-jsons" + }, + "dependencies": { + "@ant-design/icons": "4.2.2", + "antd": "4.6.2", + "axios": "0.21.1", + "classnames": "2.2.6", + "hollaex-web-lib": "0.3.0", + "html-minifier-terser": "5.1.1", + "lodash.debounce": "4.0.8", + "mathjs": "5.10.3", + "moment": "2.24.0", + "numbro": "1.11.1", + "prop-types": "15.7.2", + "react": "16.13.1", + "react-device-detect": "1.6.2", + "react-event-listener": "0.6.6", + "react-ionicons": "2.1.6", + "react-modal": "3.8.1", + "react-redux": "6.0.1", + "react-svg": "11.2.2", + "redux": "4.0.1", + "redux-form": "8.1.0", + "uglify-es": "3.3.9", + "validator": "10.11.0" + }, + "devDependencies": { + "@babel/cli": "7.12.10", + "@babel/core": "7.12.10", + "@babel/plugin-proposal-class-properties": "7.12.1", + "@babel/plugin-transform-runtime": "7.12.10", + "@babel/preset-env": "7.12.10", + "@babel/preset-react": "7.12.10", + "@babel/runtime": "7.12.5", + "@paciolan/eslint-config-react": "1.0.4", + "@paciolan/remote-component": "2.10.2", + "babel-eslint": "10.1.0", + "babel-loader": "8.2.2", + "babel-plugin-transform-react-remove-prop-types": "0.4.24", + "concurrently": "5.3.0", + "copy-dir": "1.3.0", + "core-js": "2.6.12", + "cross-env": "7.0.3", + "css-loader": "5.2.6", + "eslint": "7.15.0", + "eslint-config-prettier": "6.15.0", + "eslint-plugin-babel": "5.3.1", + "eslint-plugin-prettier": "3.3.0", + "eslint-plugin-react": "7.21.5", + "express": "4.17.1", + "glob": "7.1.7", + "html-webpack-plugin": "4.5.0", + "http-server": "14.0.0", + "json-beautify": "1.1.1", + "lodash.merge": "4.6.2", + "mkdirp": "1.0.4", + "nocache": "3.0.1", + "onchange": "7.1.0", + "path": "0.12.7", + "prettier": "2.2.1", + "react-dom": "16.14.0", + "regenerator-runtime": "0.13.7", + "rimraf": "3.0.2", + "style-loader": "2.0.0", + "webpack": "4.44.2", + "webpack-assets-manifest": "3.1.1", + "webpack-bundle-analyzer": "3.9.0", + "webpack-cli": "3.3.12" + }, + "bugs": { + "url": "https://github.com/bitholla/hollaex-plugins/issues" + }, + "homepage": "https://github.com/bitholla/hollaex-plugins#readme" +} diff --git a/plugins/remote-component.config.js b/plugins/remote-component.config.js new file mode 100644 index 0000000000..8b9f079fb7 --- /dev/null +++ b/plugins/remote-component.config.js @@ -0,0 +1,25 @@ +/** + * Dependencies for Remote Components + */ + +module.exports = { + resolve: { + axios: require('axios'), + classnames: require('classnames'), + mathjs: require('mathjs'), + numbro: require('numbro'), + 'prop-types': require('prop-types'), + react: require('react'), + 'react-device-detect': require('react-device-detect'), + 'react-redux': require('react-redux'), + 'react-svg': require('react-svg'), + redux: require('redux'), + 'redux-form': require('redux-form'), + validator: require('validator'), + '@ant-design/icons': require('@ant-design/icons'), + 'react-event-listener': require('react-event-listener'), + 'hollaex-web-lib': require('hollaex-web-lib'), + 'antd': require('antd'), + moment: require('moment'), + } +}; diff --git a/plugins/scripts/addBundles.js b/plugins/scripts/addBundles.js new file mode 100644 index 0000000000..cfbb6fb85f --- /dev/null +++ b/plugins/scripts/addBundles.js @@ -0,0 +1,28 @@ +const fs = require("fs"); +const path = require("path"); +const glob = require("glob"); +const mkdirp = require('mkdirp'); +const { PATTERNS, PATHS } = require("./patterns"); + +const bundles = glob.sync(PATTERNS.BUNDLES); + +bundles.forEach((pathname) => { + const bundle = path.basename(pathname, '.js'); + const [plugin, view] = bundle.split('__'); + const pluginPath = path.resolve(__dirname, '..', PATHS.ROOT, plugin); + const bundlesPath = path.resolve(__dirname, '..', PATHS.ROOT, plugin, PATHS.BUNDLES); + + if (view) { + const destinationPath = path.resolve(bundlesPath, `${bundle}.js`); + + if (!fs.existsSync(pluginPath)) { + mkdirp.sync(pluginPath); + } + + if (!fs.existsSync(bundlesPath)) { + mkdirp.sync(bundlesPath); + } + + fs.copyFileSync(pathname, destinationPath); + } +}) \ No newline at end of file diff --git a/plugins/scripts/addJsons.js b/plugins/scripts/addJsons.js new file mode 100644 index 0000000000..2e193bde87 --- /dev/null +++ b/plugins/scripts/addJsons.js @@ -0,0 +1,24 @@ +const fs = require("fs"); +const path = require("path"); +const glob = require("glob"); +const mkdirp = require('mkdirp'); +const { PATTERNS, FILES, PATHS } = require("./patterns"); + +const jsons = glob.sync(PATTERNS.JSONS); + +jsons.forEach((pathname) => { + const plugin = path.basename(pathname, '.json'); + const pluginPath = path.resolve(__dirname, '..', PATHS.ROOT, plugin); + const serverPath = path.resolve(__dirname, '..', PATHS.ROOT, plugin, PATHS.SERVER); + const destinationPath = path.resolve(__dirname, '..', PATHS.ROOT, plugin, PATHS.SERVER, FILES.WEB_VIEW); + + if (!fs.existsSync(pluginPath)) { + mkdirp.sync(pluginPath); + } + + if (!fs.existsSync(serverPath)) { + mkdirp.sync(serverPath); + } + + fs.copyFileSync(pathname, destinationPath); +}) \ No newline at end of file diff --git a/plugins/scripts/addPlugin.js b/plugins/scripts/addPlugin.js new file mode 100644 index 0000000000..a1efe029df --- /dev/null +++ b/plugins/scripts/addPlugin.js @@ -0,0 +1,66 @@ +const glob = require("glob"); +const path = require("path"); +const copydir = require('copy-dir'); +const mkdirp = require('mkdirp'); +const { PATTERNS, TEMPLATES, PATHS } = require("./patterns"); + +const { env: { PLUGIN: plugin, TYPE } } = process; +const type = TYPE ? TYPE.toLowerCase() : TYPE; + +if (!plugin) { + console.log('You must pass plugin argument'); + console.log('npm run add-plugin --plugin=PLUGIN_NAME --type=PLUGIN_TYPE'); +} else if (!type) { + console.log('You must pass type argument'); + console.log('npm run add-plugin --plugin=PLUGIN_NAME --type=PLUGIN_TYPE'); +} else { + const plugins = glob.sync(PATTERNS.PLUGINS) + .reduce((acc, curr) => { + const pluginName = curr.split(path.sep)[2]; + return [...acc, pluginName]; + }, []) + + if (plugins.includes(plugin)) { + console.log('This plugin already exists, try another plugin name'); + } else { + switch (type) { + case TEMPLATES.RAW.type: + return ( + mkdirp(`${PATHS.ROOT}/${plugin}/views`) + .then(() => { + mkdirp(`${PATHS.ROOT}/${plugin}/${PATHS.SERVER}`) + .then(() => { + copydir.sync(TEMPLATES.RAW.template.VIEW, `${PATHS.ROOT}/${plugin}/views/view`); + copydir.sync(TEMPLATES.RAW.template.ASSETS, `${PATHS.ROOT}/${plugin}/assets`); + console.log('Plugin has been added successfully'); + }) + }) + ); + case TEMPLATES.PAGE.type: + case TEMPLATES.VERIFICATION_TAB.type: + case TEMPLATES.FIAT_WALLET.type: + case TEMPLATES.KYC.type: + case TEMPLATES.BANK.type: + case TEMPLATES.ONRAMP.type: + return ( + mkdirp(`${PATHS.ROOT}/${plugin}`) + .then(() => { + mkdirp(`${PATHS.ROOT}/${plugin}/${PATHS.SERVER}`) + .then(() => { + const [, { template }] = Object.entries(TEMPLATES).find(([, { type: templateType }]) => type === templateType); + copydir.sync(template, `${PATHS.ROOT}/${plugin}`); + console.log('Plugin has been added successfully'); + }) + }) + ); + case TEMPLATES.SERVER.type: + return ( + mkdirp(`${PATHS.ROOT}/${plugin}/${PATHS.SERVER}`) + ); + default: + return ( + console.log(`type ${type} does not exist, try another type. See doc for supported plugin types.`) + ); + } + } +} \ No newline at end of file diff --git a/plugins/scripts/addView.js b/plugins/scripts/addView.js new file mode 100644 index 0000000000..2d16a7cee3 --- /dev/null +++ b/plugins/scripts/addView.js @@ -0,0 +1,36 @@ +const glob = require("glob"); +const path = require("path"); +const copydir = require('copy-dir'); +const { PATTERNS, PATHS } = require("./patterns") + +const { env: { PLUGIN: plugin, WEB_VIEW: view = 'view' } } = process; +const viewsPattern = `${PATHS.ROOT}/${plugin}/views/*`; + + +if (!plugin) { + console.log('You must pass plugin argument') + console.log('npm run add-view --plugin=PLUGIN_NAME'); +} else { + const plugins = glob.sync(PATTERNS.PLUGINS) + .reduce((acc, curr) => { + const pluginName = curr.split(path.sep)[2]; + return [...acc, pluginName]; + }, []) + + if (plugins.includes(plugin)) { + const views = glob.sync(viewsPattern) + .reduce((acc, curr) => { + const viewName = curr.split(path.sep)[4]; + return [...acc, viewName]; + }, []); + + if (views.includes(view)) { + console.log('This view already exists, try another view name'); + } else { + copydir.sync('src/templates/view', `${PATHS.ROOT}/${plugin}/views/${view}`); + console.log(`A view has been successfully added to ${plugin} plugin`); + } + } else { + console.log(`Plugin ${plugin} does not exist`); + } +} \ No newline at end of file diff --git a/plugins/scripts/generateJson.js b/plugins/scripts/generateJson.js new file mode 100644 index 0000000000..0538379f12 --- /dev/null +++ b/plugins/scripts/generateJson.js @@ -0,0 +1,51 @@ +const fs = require("fs"); +const path = require("path"); +const glob = require("glob"); +const merge = require("lodash.merge"); +const mkdirp = require('mkdirp'); +const { PATTERNS, FILES, PATHS } = require("./patterns"); +const { readFile, saveFile, getBundlePath } = require("./utils"); + +const { env: { PLUGIN: plugin }} = process; +const pluginsPattern = plugin ? `${PATHS.ROOT}/${plugin}` : PATTERNS.PLUGINS; + +const plugins = glob.sync(pluginsPattern); + +if (!fs.existsSync('json')) { + mkdirp.sync('json') +} + +plugins.forEach(pluginPath => { + const pluginName = pluginPath.split(path.sep)[2] + const assetsPath = `${PATHS.ROOT}/${pluginName}/${PATHS.ASSETS}` + const pluginPattern = `${PATHS.ROOT}/${pluginName}/${PATTERNS.VIEW}`; + + let assetsAdded = false; + const assets = { + strings: readFile(`${assetsPath}/${FILES.STRINGS}`), + icons: readFile(`${assetsPath}/${FILES.ICONS}`), + }; + + const webViews = glob.sync(pluginPattern, { noglobstar: true }) + .reduce((acc, curr) => { + const view = readFile(`${path.dirname(curr)}/${FILES.VIEW}`); + const generatedView = { + src: getBundlePath(curr), + ...(assetsAdded ? {} : { meta: { ...assets }}), + }; + + // development + // const webView = merge({}, view, generatedView); + const webView = merge({}, generatedView, view); + + assetsAdded = true; + + return [...acc, webView] + }, []); + + const plugin = { + web_view: webViews + } + + saveFile(`json/${pluginName}.json`, plugin); +}) \ No newline at end of file diff --git a/plugins/scripts/patterns.js b/plugins/scripts/patterns.js new file mode 100644 index 0000000000..5f4562d424 --- /dev/null +++ b/plugins/scripts/patterns.js @@ -0,0 +1,70 @@ +const PLUGINS_PATH = 'https://bitholla.s3.ap-northeast-2.amazonaws.com/scripts/plugins'; + +const PATTERNS = { + BUNDLES: "dist/**.js", + JSONS: "json/**.json", + PLUGINS: "src/plugins/*", + VIEW: "views/**/index.js" +}; + +const FILES = { + SCRIPT: 'script.js', + ADMIN_VIEW: 'admin_view.html', + WEB_VIEW: 'web_view.json', + CONFIG: 'config.json', + STRINGS: "strings.json", + ICONS: "icons.json", + VIEW: "view.json", +}; + +const PATHS = { + ROOT: 'src/plugins', + SERVER: 'server', + BUNDLES: 'bundles', + ASSETS: 'assets', +}; + +const TEMPLATES = { + RAW: { + type: 'raw', + template: { + VIEW: "src/templates/view", + ASSETS: "src/templates/assets", + }, + }, + PAGE: { + type: 'page', + template: 'src/templates/new-page', + }, + VERIFICATION_TAB: { + type: 'verification-tab', + template: 'src/templates/verification-tab', + }, + FIAT_WALLET: { + type: 'fiat-wallet', + template: 'src/templates/fiat-wallet', + }, + KYC: { + type: 'kyc', + template: 'src/templates/kyc-verification', + }, + BANK: { + type: 'bank', + template: 'src/templates/bank-verification', + }, + ONRAMP: { + type: 'onramp', + template: 'src/templates/onramp', + }, + SERVER: { + type: 'server', + } +}; + +module.exports = { + PLUGINS_PATH, + FILES, + TEMPLATES, + PATHS, + PATTERNS, +} \ No newline at end of file diff --git a/plugins/scripts/utils.js b/plugins/scripts/utils.js new file mode 100644 index 0000000000..b4487dfcd5 --- /dev/null +++ b/plugins/scripts/utils.js @@ -0,0 +1,39 @@ +const fs = require("fs"); +const path = require("path"); +const beautify = require("json-beautify"); +const { PLUGINS_PATH, PATHS, FILES } = require("./patterns"); + +const saveFile = (output, content) => { + fs.writeFileSync(output, beautify(content, null, 4, 100)); +} + +const readFile = (pathname) => { + try { + const contents = fs.readFileSync(pathname, "utf-8") + return JSON.parse(contents); + } catch(err) { + console.log(err); + return {}; + } +} + +const getBundlePath = (pathname) => { + const dir = pathname.split(path.sep); + const pluginName = dir[2]; + const bundleName = `${dir[2]}__${dir[4]}`; + + if(process.env.NODE_ENV === "development") { + return `http://localhost:8080/${bundleName}.js` + } + + const configFile = path.resolve(__dirname, '..', PATHS.ROOT, pluginName, PATHS.SERVER, FILES.CONFIG); + const { version = 0 } = fs.existsSync(configFile) ? readFile(configFile) : {}; + + return `${PLUGINS_PATH}/${pluginName}/v${version}/${bundleName}.js` +} + +module.exports = { + saveFile, + readFile, + getBundlePath, +} \ No newline at end of file diff --git a/plugins/server.js b/plugins/server.js new file mode 100644 index 0000000000..8234599259 --- /dev/null +++ b/plugins/server.js @@ -0,0 +1,10 @@ +const express = require('express'); +const nocache = require('nocache'); +const app = express(); +const PORT = 8080; + +app.use(nocache()); +app.use(express.static('dist')); +app.use(express.static('json')); + +app.listen(PORT, () => console.log(`Server listening on port: ${PORT}`)); \ No newline at end of file diff --git a/plugins/src/components/Dialog/DesktopDialog.js b/plugins/src/components/Dialog/DesktopDialog.js new file mode 100644 index 0000000000..1cdd7afd9b --- /dev/null +++ b/plugins/src/components/Dialog/DesktopDialog.js @@ -0,0 +1,87 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import Modal from 'react-modal'; +import Ionicon from 'react-ionicons'; +import { ActionNotification, Button } from 'hollaex-web-lib'; + +class Dialog extends PureComponent { + static propTypes = { + isOpen: PropTypes.bool.isRequired, + label: PropTypes.string.isRequired, + closeButton: PropTypes.func, + onCloseDialog: PropTypes.func, + children: PropTypes.node.isRequired, + disableTheme: PropTypes.bool, + }; + + onRequestClose = (e) => { + if (this.props.onCloseDialog) { + this.props.onCloseDialog(e); + } + }; + + render() { + const { + isOpen, + children, + label, + closeButton, + shouldCloseOnOverlayClick, + showCloseText, + dialogId, + theme, + className, + disableTheme, + bodyOpenClassName, + strings: STRINGS, + } = this.props; + + return ( + + {showCloseText && !closeButton && ( + + } + onClick={this.onRequestClose} + className="close-button" + /> + )} + {children} + {closeButton && ( +
+
+ )} +
+ ); + } +} + +Modal.setAppElement('#root'); + +Dialog.defaultProps = { + disableTheme: false, + shouldCloseOnOverlayClick: true, + showCloseText: true, + theme: '', + className: '', + strings: {}, +}; + +export default Dialog; diff --git a/plugins/src/components/Dialog/MobileDialog.js b/plugins/src/components/Dialog/MobileDialog.js new file mode 100644 index 0000000000..8fa31921b4 --- /dev/null +++ b/plugins/src/components/Dialog/MobileDialog.js @@ -0,0 +1,73 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import Modal from 'react-modal'; + +const RegularContent = ({ children }) => { + return ( +
+
{children}
+
+ ); +}; + +class Dialog extends PureComponent { + static propTypes = { + isOpen: PropTypes.bool.isRequired, + label: PropTypes.string.isRequired, + closeButton: PropTypes.func, + onCloseDialog: PropTypes.func, + children: PropTypes.node.isRequired, + }; + + onRequestClose = (e) => { + if (this.props.onCloseDialog) { + this.props.onCloseDialog(e); + } + }; + + render() { + const { + isOpen, + children, + label, + dialogId, + className, + useFullScreen = false, + compressed = false, + } = this.props; + + return ( + + + {children} + + + ); + } +} + +Modal.setAppElement('#root'); + +Dialog.defaultProps = { + shouldCloseOnOverlayClick: true, + showCloseText: true, + theme: '', + className: '', +}; + +export default Dialog; diff --git a/plugins/src/components/Dialog/index.js b/plugins/src/components/Dialog/index.js new file mode 100644 index 0000000000..ef0da3afcb --- /dev/null +++ b/plugins/src/components/Dialog/index.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { isMobile } from 'react-device-detect'; +import MobileDialog from './MobileDialog'; +import DesktopDialog from './DesktopDialog'; + +const Dialog = (props) => { + if (isMobile) { + return ; + } else { + return ; + } +}; + +export default Dialog; diff --git a/plugins/src/components/Form/factoryFields.js b/plugins/src/components/Form/factoryFields.js new file mode 100644 index 0000000000..c419dc03d0 --- /dev/null +++ b/plugins/src/components/Form/factoryFields.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { Field } from 'redux-form'; +import { getFormFieldComponentByType } from 'hollaex-web-lib'; + +const renderFields = (fields = {}, callback) => { + return ( +
+ {Object.keys(fields).map((key, index) => { + const { type, validate = [], ishorizontalfield, ...rest } = fields[key]; + const commonProps = { + callback, + key, + name: key, + type, + validate, + ishorizontalfield, + ...rest, + }; + + const component = getFormFieldComponentByType(type); + return () + })} +
+ ); +}; + +export default renderFields; diff --git a/plugins/src/components/HeaderSection/index.js b/plugins/src/components/HeaderSection/index.js new file mode 100644 index 0000000000..966eff5d7d --- /dev/null +++ b/plugins/src/components/HeaderSection/index.js @@ -0,0 +1,45 @@ +import React from "react"; +import { Image, ActionNotification, Editable } from "hollaex-web-lib"; + +export const HeaderSection = ({ + title, + children, + openContactForm, + icon, + strings: STRINGS = {}, + icons: ICONS = {}, + stringId + }) => { + return ( +
+
+ {!!icon && ( +
+ +
+ )} +
+
+
+ {title} + {stringId && } +
+ {!!openContactForm && ( +
+ +
+ )} +
+ {children &&
{children}
} +
+
+
+ ); +}; diff --git a/plugins/src/components/KitContext/KitContextProvider.js b/plugins/src/components/KitContext/KitContextProvider.js new file mode 100644 index 0000000000..8594a4a570 --- /dev/null +++ b/plugins/src/components/KitContext/KitContextProvider.js @@ -0,0 +1,15 @@ +import React, { Component } from 'react'; +import { KitContext } from './index'; + +class KitContextProvider extends Component { + render() { + const { children, ...rest } = this.props; + return ( + + {children} + + ); + } +} + +export default KitContextProvider; diff --git a/plugins/src/components/KitContext/index.js b/plugins/src/components/KitContext/index.js new file mode 100644 index 0000000000..267c1c595a --- /dev/null +++ b/plugins/src/components/KitContext/index.js @@ -0,0 +1,4 @@ +import { createContext } from 'react'; +export { default as KitContextProvider } from './KitContextProvider'; +export { default as withKit } from './withKit'; +export const KitContext = createContext(); \ No newline at end of file diff --git a/plugins/src/components/KitContext/withKit.js b/plugins/src/components/KitContext/withKit.js new file mode 100644 index 0000000000..cf5b4d59ea --- /dev/null +++ b/plugins/src/components/KitContext/withKit.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { KitContext } from './index'; + +const withKit = (mapContextToProps) => (Component) => { + return (props) => ( + + {(context) => ( + + )} + + ); +}; + +export default withKit; diff --git a/plugins/src/components/OtpForm/index.js b/plugins/src/components/OtpForm/index.js new file mode 100644 index 0000000000..d6e8d6afaa --- /dev/null +++ b/plugins/src/components/OtpForm/index.js @@ -0,0 +1,93 @@ +import React, { Component } from 'react'; +import { reduxForm } from 'redux-form'; +import { required, validateOtp } from 'utils'; +import renderFields from 'components/Form/factoryFields'; +import { Button, IconTitle } from 'hollaex-web-lib'; + +class Form extends Component { + state = { + formValues: {}, + }; + + componentWillMount() { + this.setFormValues(); + } + + UNSAFE_componentWillReceiveProps = (nextProps) => { + if ( + this.props.dirty !== nextProps.dirty || + this.props.submitFailed !== nextProps.submitFailed || + this.props.valid !== nextProps.valid + ) { + if (nextProps.dirty && nextProps.submitFailed && !nextProps.valid) { + this.setFormRef(this.otpFormRef); + } + } + }; + setFormValues = () => { + const { strings: STRINGS } = this.props; + const formValues = { + otp_code: { + type: 'number', + stringId: + 'OTP_FORM.OTP_LABEL,OTP_FORM.OTP_PLACEHOLDER,OTP_FORM.ERROR_INVALID', + label: STRINGS['OTP_FORM.OTP_LABEL'], + placeholder: STRINGS['OTP_FORM.OTP_PLACEHOLDER'], + validate: [required, validateOtp(STRINGS['OTP_FORM.ERROR_INVALID'])], + fullWidth: true, + }, + }; + + this.setState({ formValues }); + }; + + setFormRef = (el) => { + if (el) { + this.otpFormRef = el; + el.getElementsByTagName('input')[0].focus(); + } + }; + + render() { + const { + handleSubmit, + submitting, + pristine, + error, + valid, + icons: ICONS = {}, + strings: STRINGS = {}, + } = this.props; + const { formValues } = this.state; + + return ( +
+ +
+ + {STRINGS['OTP_FORM.OTP_FORM_TITLE']} + +
+
+
+ {renderFields(formValues)} + {error &&
{error}
} +
+
+ ); + } +} + +export default reduxForm({ + form: 'FiatOtpForm', +})(Form); diff --git a/plugins/src/components/Tab/index.js b/plugins/src/components/Tab/index.js new file mode 100644 index 0000000000..400dd32fba --- /dev/null +++ b/plugins/src/components/Tab/index.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { Image } from 'hollaex-web-lib'; +import classnames from 'classnames'; + +export const Tab = ({ + icon, + title, + className, + }) => { + return ( +
+
+ +
+ {title && ( +
+ {title} +
+ )} +
+ ); +}; \ No newline at end of file diff --git a/plugins/src/components/Title.js b/plugins/src/components/Title.js new file mode 100644 index 0000000000..31fc6170fd --- /dev/null +++ b/plugins/src/components/Title.js @@ -0,0 +1,11 @@ +import React from "react"; +import { withKit } from 'components/KitContext'; + +const Title = ({ user: { username } = {}, strings: STRINGS, generateId }) => ( +
+ {STRINGS.formatString(STRINGS[generateId('hello')], username)} +
+); + +const mapContextToProps = ({ user, generateId, strings }) => ({ user, generateId, strings }); +export default withKit(mapContextToProps)(Title); diff --git a/plugins/src/constants/index.js b/plugins/src/constants/index.js new file mode 100644 index 0000000000..595768ca02 --- /dev/null +++ b/plugins/src/constants/index.js @@ -0,0 +1 @@ +export const verifiedBankStatus = 3; \ No newline at end of file diff --git a/plugins/src/index.html b/plugins/src/index.html new file mode 100644 index 0000000000..132678c44d --- /dev/null +++ b/plugins/src/index.html @@ -0,0 +1,9 @@ + + + + + + +
+ + diff --git a/plugins/src/lib/__tests__/prop.test.js b/plugins/src/lib/__tests__/prop.test.js new file mode 100644 index 0000000000..b9fcbb947a --- /dev/null +++ b/plugins/src/lib/__tests__/prop.test.js @@ -0,0 +1,39 @@ +const { prop } = require("../prop"); + +describe("lib/prop", () => { + test("prop on undefined returns undefined", () => { + const expected = undefined; + const actual = prop(["a"], undefined); + expect(actual).toBe(expected); + }); + + test("prop on null returns undefined", () => { + const expected = undefined; + const actual = prop(["a"], null); + expect(actual).toBe(expected); + }); + + test("prop[] returns object", () => { + const expected = {}; + const actual = prop([], expected); + expect(actual).toBe(expected); + }); + + test("prop[a] returns object[a]", () => { + const expected = "SUCCESS"; + const actual = prop(["a"], { a: expected }); + expect(actual).toBe(expected); + }); + + test("prop missing prop returns undefined", () => { + const expected = undefined; + const actual = prop(["a", "b"], { a: 123 }); + expect(actual).toBe(expected); + }); + + test("prop nested returns value", () => { + const expected = "SUCCESS"; + const actual = prop(["a", "b"], { a: { b: expected } }); + expect(actual).toBe(expected); + }); +}); diff --git a/plugins/src/lib/prop.js b/plugins/src/lib/prop.js new file mode 100644 index 0000000000..6ec0da268b --- /dev/null +++ b/plugins/src/lib/prop.js @@ -0,0 +1,10 @@ +/** + * Safely gets nested properties from an object + * @param {Array} key List of properties + * @param {object} object Object to query + * @returns {*} value + */ +export const prop = ([key, ...rest], object) => + key == null ? object + : object == null ? undefined + : prop(rest, object[key]); // prettier-ignore diff --git a/plugins/src/plugins/hello-exchange/assets/icons.json b/plugins/src/plugins/hello-exchange/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/plugins/hello-exchange/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/plugins/hello-exchange/assets/strings.json b/plugins/src/plugins/hello-exchange/assets/strings.json new file mode 100644 index 0000000000..ab9c4de4f6 --- /dev/null +++ b/plugins/src/plugins/hello-exchange/assets/strings.json @@ -0,0 +1,6 @@ +{ + "en": { + "title": "New Page", + "content": "{0} content" + } +} \ No newline at end of file diff --git a/plugins/src/plugins/hello-exchange/server/config.json b/plugins/src/plugins/hello-exchange/server/config.json new file mode 100644 index 0000000000..6345223a3d --- /dev/null +++ b/plugins/src/plugins/hello-exchange/server/config.json @@ -0,0 +1,35 @@ +{ + "name": "hello-exchange", + "version": 1, + "type": null, + "author": "bitHolla", + "bio": "Say hello from an exchange", + "description": "Demo plugin for proof of concept", + "documentation": null, + "logo": null, + "icon": null, + "url": null, + "public_meta": { + "public_message": { + "type": "string", + "required": false, + "description": "Not a secret", + "value": "Hello Exchange!" + } + }, + "meta": { + "private_message": { + "type": "string", + "required": false, + "description": "A secret", + "value": "hello exchange..." + } + }, + "prescript": { + "install": ["hello-world-npm"], + "run": null + }, + "postscript": { + "run": null + } +} \ No newline at end of file diff --git a/plugins/src/plugins/hello-exchange/server/hello-exchange.json b/plugins/src/plugins/hello-exchange/server/hello-exchange.json new file mode 100644 index 0000000000..97701b3788 --- /dev/null +++ b/plugins/src/plugins/hello-exchange/server/hello-exchange.json @@ -0,0 +1,40 @@ +{ + "name": "hello-exchange", + "version": 1, + "type": null, + "author": "bitHolla", + "bio": "Say hello from an exchange", + "description": "Demo plugin for proof of concept", + "documentation": null, + "logo": null, + "icon": null, + "url": null, + "public_meta": { + "public_message": { + "type": "string", + "required": false, + "description": "Not a secret", + "value": "Hello Exchange!" + } + }, + "meta": { + "private_message": { + "type": "string", + "required": false, + "description": "A secret", + "value": "hello exchange..." + } + }, + "prescript": { + "install": [ + "hello-world-npm" + ], + "run": null + }, + "postscript": { + "run": null + }, + "script": "\"use strict\";const{publicMeta:publicMeta,meta:meta}=this.configValues,{app:app,loggerPlugin:loggerPlugin,toolsLib:toolsLib}=this.pluginLibraries,helloWorld=require(\"hello-world-npm\"),moment=require(\"moment\"),init=async()=>{if(loggerPlugin.info(\"HELLO-EXCHANGE PLUGIN initializing...\"),!meta.private.value)throw new Error(\"Configuration value private required\")};init().then(()=>{app.get(\"/plugins/hello-exchange/info\",(e,i)=>(loggerPlugin.verbose(e.uuid,\"GET /plugins/hello-exchange/info\"),i.json({public_message:publicMeta.public.value,private_message:meta.private.value,library_message:helloWorld(),moment_timestamp:moment().toISOString(),exchange_info:toolsLib.getKitConfig().info})))}).catch(e=>{loggerPlugin.error(\"HELLO-EXCHANGE PLUGIN error during initialization\",e.message)});", + "admin_view": null, + "web_view": null +} \ No newline at end of file diff --git a/plugins/src/plugins/hello-exchange/server/script.js b/plugins/src/plugins/hello-exchange/server/script.js new file mode 100644 index 0000000000..29de80528b --- /dev/null +++ b/plugins/src/plugins/hello-exchange/server/script.js @@ -0,0 +1,44 @@ +'use strict'; + +const { publicMeta, meta } = this.configValues; +const { + app, + loggerPlugin, + toolsLib +} = this.pluginLibraries; +const helloWorld = require('hello-world-npm'); +const moment = require('moment'); + +const init = async () => { + loggerPlugin.info( + 'HELLO-EXCHANGE PLUGIN initializing...' + ); + + if (!meta.private_message.value) { + throw new Error('Configuration value private required'); + } +}; + +init() + .then(() => { + app.get('/plugins/hello-exchange/info', (req, res) => { + loggerPlugin.verbose( + req.uuid, + 'GET /plugins/hello-exchange/info' + ); + + return res.json({ + public_message: publicMeta.public_message.value, + private_message: meta.private_message.value, + library_message: helloWorld(), + moment_timestamp: moment().toISOString(), + exchange_info: toolsLib.getKitConfig().info + }); + }); + }) + .catch((err) => { + loggerPlugin.error( + 'HELLO-EXCHANGE PLUGIN error during initialization', + err.message + ); + }); diff --git a/plugins/src/plugins/hello-exchange/views/view/App.js b/plugins/src/plugins/hello-exchange/views/view/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/plugins/hello-exchange/views/view/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + +
+ + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/plugins/hello-exchange/views/view/Form.js b/plugins/src/plugins/hello-exchange/views/view/Form.js new file mode 100644 index 0000000000..ab0498fcb5 --- /dev/null +++ b/plugins/src/plugins/hello-exchange/views/view/Form.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { IconTitle } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; + +const Form = ({ + strings: STRINGS, + icons: ICONS, + generateId +}) => { + + return ( +
+ + +
+
+ {STRINGS.formatString(STRINGS[generateId('content')], STRINGS[generateId('title')])} +
+
+ +
+ ) +} + +const mapContextToProps = ({ strings, activeLanguage, icons, generateId }) => ({ + strings, + activeLanguage, + icons, + generateId, +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/plugins/hello-exchange/views/view/index.js b/plugins/src/plugins/hello-exchange/views/view/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/plugins/hello-exchange/views/view/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/plugins/hello-exchange/views/view/view.json b/plugins/src/plugins/hello-exchange/views/view/view.json new file mode 100644 index 0000000000..b4b2b347de --- /dev/null +++ b/plugins/src/plugins/hello-exchange/views/view/view.json @@ -0,0 +1,18 @@ +{ + "meta": { + "is_page": true, + "path": "/hello-exchange", + "hide_from_appbar": true, + "hide_from_sidebar": false, + "hide_from_menulist": false, + "hide_from_bottom_nav": true, + "string": { + "id": "title", + "is_global": false + }, + "icon": { + "id": "SIDEBAR_HELP", + "is_global": true + } + } +} \ No newline at end of file diff --git a/plugins/src/store/index.js b/plugins/src/store/index.js new file mode 100644 index 0000000000..3dbd7fd70d --- /dev/null +++ b/plugins/src/store/index.js @@ -0,0 +1,11 @@ +import { createStore, combineReducers } from "redux"; +import { reducer as formReducer } from "redux-form"; + +const rootReducer = combineReducers({ + // ...your other reducers here + // you have to pass formReducer under 'form' key, + // for custom keys look up the docs for 'getFormState' + form: formReducer +}); + +export default createStore(rootReducer); diff --git a/plugins/src/templates/assets/icons.json b/plugins/src/templates/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/templates/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/templates/assets/strings.json b/plugins/src/templates/assets/strings.json new file mode 100644 index 0000000000..6a691ed1b8 --- /dev/null +++ b/plugins/src/templates/assets/strings.json @@ -0,0 +1,5 @@ +{ + "en": { + "hello": "Hello {0}" + } +} \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/assets/icons.json b/plugins/src/templates/bank-verification/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/templates/bank-verification/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/assets/strings.json b/plugins/src/templates/bank-verification/assets/strings.json new file mode 100644 index 0000000000..c85476dd7f --- /dev/null +++ b/plugins/src/templates/bank-verification/assets/strings.json @@ -0,0 +1,8 @@ +{ + "en": { + "title": "Bank verification", + "go_to_tab": "Go to {0}", + "content": "{0} content", + "home-content": "{0} home content" + } +} \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/views/home/App.js b/plugins/src/templates/bank-verification/views/home/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/bank-verification/views/home/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + +
+ + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/views/home/Form.js b/plugins/src/templates/bank-verification/views/home/Form.js new file mode 100644 index 0000000000..f201372eee --- /dev/null +++ b/plugins/src/templates/bank-verification/views/home/Form.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { Button, Editable as EditWrapper } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; + +export const PLUGIN_NAME = 'bank'; + +const Form = ({ setActivePageContent, strings: STRINGS, generateId }) => { + return ( +
+
+ {STRINGS.formatString(STRINGS[generateId('home-content')], STRINGS[generateId('title')])} +
+
+
+ +
+
+
+ ) +} + +const mapContextToProps = ({ setActivePageContent, strings, generateId }) => ({ + setActivePageContent, + strings, + generateId +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/views/home/index.js b/plugins/src/templates/bank-verification/views/home/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/bank-verification/views/home/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/bank-verification/views/home/view.json b/plugins/src/templates/bank-verification/views/home/view.json new file mode 100644 index 0000000000..9f9d14cfc1 --- /dev/null +++ b/plugins/src/templates/bank-verification/views/home/view.json @@ -0,0 +1,4 @@ +{ + "target": "REMOTE_COMPONENT__BANK_VERIFICATION_HOME", + "meta": {} +} \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/views/verification/App.js b/plugins/src/templates/bank-verification/views/verification/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/bank-verification/views/verification/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + + + + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/views/verification/Form.js b/plugins/src/templates/bank-verification/views/verification/Form.js new file mode 100644 index 0000000000..1ccc583c71 --- /dev/null +++ b/plugins/src/templates/bank-verification/views/verification/Form.js @@ -0,0 +1,54 @@ +import React from 'react'; +import { Button, IconTitle, Editable as EditWrapper } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; +import { PLUGIN_NAME } from '../home/Form'; + +const Form = ({ + strings: STRINGS, + handleBack, + generateId, + setActivePageContent, +}) => { + + const onGoBack = () => { + setActivePageContent('email'); + handleBack(PLUGIN_NAME); + }; + + return ( +
+ + +
+
+ {STRINGS.formatString(STRINGS[generateId('content')], STRINGS[generateId('title')])} +
+
+
+
+ +
+
+ +
+ ) +} + +const mapContextToProps = ({ strings, handleBack, activeLanguage, icons, generateId, setActivePageContent }) => ({ + strings, + handleBack, + activeLanguage, + icons, + generateId, + setActivePageContent, +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/bank-verification/views/verification/index.js b/plugins/src/templates/bank-verification/views/verification/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/bank-verification/views/verification/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/bank-verification/views/verification/view.json b/plugins/src/templates/bank-verification/views/verification/view.json new file mode 100644 index 0000000000..a7faa5b752 --- /dev/null +++ b/plugins/src/templates/bank-verification/views/verification/view.json @@ -0,0 +1,4 @@ +{ + "target": "REMOTE_COMPONENT__BANK_VERIFICATION", + "meta": {} +} \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/assets/icons.json b/plugins/src/templates/fiat-wallet/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/templates/fiat-wallet/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/assets/strings.json b/plugins/src/templates/fiat-wallet/assets/strings.json new file mode 100644 index 0000000000..6a691ed1b8 --- /dev/null +++ b/plugins/src/templates/fiat-wallet/assets/strings.json @@ -0,0 +1,5 @@ +{ + "en": { + "hello": "Hello {0}" + } +} \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/views/deposit/App.js b/plugins/src/templates/fiat-wallet/views/deposit/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/deposit/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + +
+ + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/views/deposit/Form.js b/plugins/src/templates/fiat-wallet/views/deposit/Form.js new file mode 100644 index 0000000000..ec24b3d832 --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/deposit/Form.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { Image } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; + + +const Form = ({ icons: ICONS, currency, titleSection }) => { + return ( +
+
+ + {titleSection} +
+
+ ) +} + +const mapContextToProps = ({ icons, currency, titleSection }) => ({ + icons, + currency, + titleSection, +}) + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/views/deposit/index.js b/plugins/src/templates/fiat-wallet/views/deposit/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/deposit/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/fiat-wallet/views/deposit/view.json b/plugins/src/templates/fiat-wallet/views/deposit/view.json new file mode 100644 index 0000000000..063cfb71c0 --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/deposit/view.json @@ -0,0 +1,7 @@ +{ + "meta": { + "is_wallet": true, + "type": "deposit", + "currency": "USD" + } +} \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/views/withdraw/App.js b/plugins/src/templates/fiat-wallet/views/withdraw/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/withdraw/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + + + + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/views/withdraw/Form.js b/plugins/src/templates/fiat-wallet/views/withdraw/Form.js new file mode 100644 index 0000000000..ec24b3d832 --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/withdraw/Form.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { Image } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; + + +const Form = ({ icons: ICONS, currency, titleSection }) => { + return ( +
+
+ + {titleSection} +
+
+ ) +} + +const mapContextToProps = ({ icons, currency, titleSection }) => ({ + icons, + currency, + titleSection, +}) + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/fiat-wallet/views/withdraw/index.js b/plugins/src/templates/fiat-wallet/views/withdraw/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/withdraw/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/fiat-wallet/views/withdraw/view.json b/plugins/src/templates/fiat-wallet/views/withdraw/view.json new file mode 100644 index 0000000000..79e02c426a --- /dev/null +++ b/plugins/src/templates/fiat-wallet/views/withdraw/view.json @@ -0,0 +1,7 @@ +{ + "meta": { + "is_wallet": true, + "type": "withdraw", + "currency": "USD" + } +} \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/assets/icons.json b/plugins/src/templates/kyc-verification/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/templates/kyc-verification/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/assets/strings.json b/plugins/src/templates/kyc-verification/assets/strings.json new file mode 100644 index 0000000000..a3cd5e0beb --- /dev/null +++ b/plugins/src/templates/kyc-verification/assets/strings.json @@ -0,0 +1,8 @@ +{ + "en": { + "title": "KYC", + "go_to_tab": "Go to {0}", + "content": "{0} content", + "home-content": "{0} home content" + } +} \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/views/home/App.js b/plugins/src/templates/kyc-verification/views/home/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/home/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + + + + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/views/home/Form.js b/plugins/src/templates/kyc-verification/views/home/Form.js new file mode 100644 index 0000000000..0b122adf6c --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/home/Form.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { Button, Editable as EditWrapper } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; + +export const PLUGIN_NAME = 'kyc'; + +const Form = ({ setActivePageContent, strings: STRINGS, generateId }) => { + return ( +
+
+ {STRINGS.formatString(STRINGS[generateId('home-content')], STRINGS[generateId('title')])} +
+
+
+ +
+
+
+ ) +} + +const mapContextToProps = ({ setActivePageContent, strings, generateId }) => ({ + setActivePageContent, + strings, + generateId +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/views/home/index.js b/plugins/src/templates/kyc-verification/views/home/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/home/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/kyc-verification/views/home/view.json b/plugins/src/templates/kyc-verification/views/home/view.json new file mode 100644 index 0000000000..94d8ab5c9f --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/home/view.json @@ -0,0 +1,4 @@ +{ + "target": "REMOTE_COMPONENT__KYC_VERIFICATION_HOME", + "meta": {} +} \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/views/verification/App.js b/plugins/src/templates/kyc-verification/views/verification/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/verification/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + + + + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/views/verification/Form.js b/plugins/src/templates/kyc-verification/views/verification/Form.js new file mode 100644 index 0000000000..8d71a2fab5 --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/verification/Form.js @@ -0,0 +1,56 @@ +import React from 'react'; +import { Button, IconTitle, Editable as EditWrapper } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; +import { PLUGIN_NAME } from '../home/Form'; + +const Form = ({ + strings: STRINGS, + handleBack, + icons: ICONS, + generateId, + setActivePageContent, +}) => { + + const onGoBack = () => { + setActivePageContent('email'); + handleBack(PLUGIN_NAME); + }; + + return ( +
+ + +
+
+ {STRINGS.formatString(STRINGS[generateId('content')], STRINGS[generateId('title')])} +
+
+
+
+ +
+
+ +
+ ) +} + +const mapContextToProps = ({ strings, handleBack, activeLanguage, icons, generateId, setActivePageContent }) => ({ + strings, + handleBack, + activeLanguage, + icons, + generateId, + setActivePageContent, +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/kyc-verification/views/verification/index.js b/plugins/src/templates/kyc-verification/views/verification/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/verification/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/kyc-verification/views/verification/view.json b/plugins/src/templates/kyc-verification/views/verification/view.json new file mode 100644 index 0000000000..de8e6ec7eb --- /dev/null +++ b/plugins/src/templates/kyc-verification/views/verification/view.json @@ -0,0 +1,4 @@ +{ + "target": "REMOTE_COMPONENT__KYC_VERIFICATION", + "meta": {} +} \ No newline at end of file diff --git a/plugins/src/templates/new-page/assets/icons.json b/plugins/src/templates/new-page/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/templates/new-page/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/templates/new-page/assets/strings.json b/plugins/src/templates/new-page/assets/strings.json new file mode 100644 index 0000000000..ab9c4de4f6 --- /dev/null +++ b/plugins/src/templates/new-page/assets/strings.json @@ -0,0 +1,6 @@ +{ + "en": { + "title": "New Page", + "content": "{0} content" + } +} \ No newline at end of file diff --git a/plugins/src/templates/new-page/views/view/App.js b/plugins/src/templates/new-page/views/view/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/new-page/views/view/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + +
+ + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/new-page/views/view/Form.js b/plugins/src/templates/new-page/views/view/Form.js new file mode 100644 index 0000000000..ab0498fcb5 --- /dev/null +++ b/plugins/src/templates/new-page/views/view/Form.js @@ -0,0 +1,37 @@ +import React from 'react'; +import { IconTitle } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; + +const Form = ({ + strings: STRINGS, + icons: ICONS, + generateId +}) => { + + return ( +
+ + +
+
+ {STRINGS.formatString(STRINGS[generateId('content')], STRINGS[generateId('title')])} +
+
+ +
+ ) +} + +const mapContextToProps = ({ strings, activeLanguage, icons, generateId }) => ({ + strings, + activeLanguage, + icons, + generateId, +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/new-page/views/view/index.js b/plugins/src/templates/new-page/views/view/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/new-page/views/view/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/new-page/views/view/view.json b/plugins/src/templates/new-page/views/view/view.json new file mode 100644 index 0000000000..9bf040d9de --- /dev/null +++ b/plugins/src/templates/new-page/views/view/view.json @@ -0,0 +1,18 @@ +{ + "meta": { + "is_page": true, + "path": "/custom-route", + "hide_from_appbar": true, + "hide_from_sidebar": false, + "hide_from_menulist": false, + "hide_from_bottom_nav": true, + "string": { + "id": "title", + "is_global": false + }, + "icon": { + "id": "SIDEBAR_HELP", + "is_global": true + } + } +} \ No newline at end of file diff --git a/plugins/src/templates/onramp/assets/icons.json b/plugins/src/templates/onramp/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/templates/onramp/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/templates/onramp/assets/strings.json b/plugins/src/templates/onramp/assets/strings.json new file mode 100644 index 0000000000..cc9964b402 --- /dev/null +++ b/plugins/src/templates/onramp/assets/strings.json @@ -0,0 +1,6 @@ +{ + "en": { + "title": "Onramp plugin", + "content": "{0} content" + } +} \ No newline at end of file diff --git a/plugins/src/templates/onramp/views/view/App.js b/plugins/src/templates/onramp/views/view/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/onramp/views/view/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + +
+ + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/onramp/views/view/Form.js b/plugins/src/templates/onramp/views/view/Form.js new file mode 100644 index 0000000000..63699e74a3 --- /dev/null +++ b/plugins/src/templates/onramp/views/view/Form.js @@ -0,0 +1,23 @@ +import React from 'react'; +import { withKit } from 'components/KitContext'; + +const Form = ({ + strings: STRINGS, + generateId +}) => { + return ( +
+
+ {STRINGS.formatString(STRINGS[generateId('content')], STRINGS[generateId('title')])} +
+
+ ) +} + +const mapContextToProps = ({ strings, activeLanguage, generateId }) => ({ + strings, + activeLanguage, + generateId, +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/onramp/views/view/index.js b/plugins/src/templates/onramp/views/view/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/onramp/views/view/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/onramp/views/view/view.json b/plugins/src/templates/onramp/views/view/view.json new file mode 100644 index 0000000000..c73b426aec --- /dev/null +++ b/plugins/src/templates/onramp/views/view/view.json @@ -0,0 +1,6 @@ +{ + "meta": { + "is_ultimate_fiat": true, + "type": "onramp" + } +} \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/assets/icons.json b/plugins/src/templates/verification-tab/assets/icons.json new file mode 100644 index 0000000000..3815a2bd63 --- /dev/null +++ b/plugins/src/templates/verification-tab/assets/icons.json @@ -0,0 +1,3 @@ +{ + "dark": {} +} \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/assets/strings.json b/plugins/src/templates/verification-tab/assets/strings.json new file mode 100644 index 0000000000..9e26c53970 --- /dev/null +++ b/plugins/src/templates/verification-tab/assets/strings.json @@ -0,0 +1,8 @@ +{ + "en": { + "title": "Verification", + "go_to_tab": "Go to {0}", + "content": "{0} content", + "home-content": "{0} home content" + } +} \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/views/home/App.js b/plugins/src/templates/verification-tab/views/home/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/verification-tab/views/home/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + + + + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/views/home/Form.js b/plugins/src/templates/verification-tab/views/home/Form.js new file mode 100644 index 0000000000..c59d7adf85 --- /dev/null +++ b/plugins/src/templates/verification-tab/views/home/Form.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { Button, Editable as EditWrapper } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; + +export const PLUGIN_NAME = 'verification-tab'; + +const Form = ({ setActivePageContent, strings: STRINGS, generateId }) => { + return ( +
+
+ {STRINGS.formatString(STRINGS[generateId('home-content')], STRINGS[generateId('title')])} +
+
+
+ +
+
+
+ ) +} + +const mapContextToProps = ({ setActivePageContent, strings, generateId }) => ({ + setActivePageContent, + strings, + generateId +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/views/home/index.js b/plugins/src/templates/verification-tab/views/home/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/verification-tab/views/home/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/verification-tab/views/home/view.json b/plugins/src/templates/verification-tab/views/home/view.json new file mode 100644 index 0000000000..70ad04103b --- /dev/null +++ b/plugins/src/templates/verification-tab/views/home/view.json @@ -0,0 +1,14 @@ +{ + "meta": { + "is_verification_tab": true, + "type": "home", + "string": { + "id": "title", + "is_global": false + }, + "icon": { + "id": "SIDEBAR_HELP", + "is_global": true + } + } +} \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/views/verification/App.js b/plugins/src/templates/verification-tab/views/verification/App.js new file mode 100644 index 0000000000..3c337b271f --- /dev/null +++ b/plugins/src/templates/verification-tab/views/verification/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Form from './Form'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + + + + + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/views/verification/Form.js b/plugins/src/templates/verification-tab/views/verification/Form.js new file mode 100644 index 0000000000..e4e9a96df4 --- /dev/null +++ b/plugins/src/templates/verification-tab/views/verification/Form.js @@ -0,0 +1,56 @@ +import React from 'react'; +import { Button, IconTitle, Editable as EditWrapper } from 'hollaex-web-lib'; +import { withKit } from 'components/KitContext'; +import { PLUGIN_NAME } from '../home/Form'; + +const Form = ({ + strings: STRINGS, + handleBack, + icons: ICONS, + generateId, + setActivePageContent, +}) => { + + const onGoBack = () => { + setActivePageContent('email'); + handleBack(PLUGIN_NAME); + }; + + return ( +
+ + +
+
+ {STRINGS.formatString(STRINGS[generateId('content')], STRINGS[generateId('title')])} +
+
+
+
+ +
+
+ +
+ ) +} + +const mapContextToProps = ({ strings, handleBack, activeLanguage, icons, generateId, setActivePageContent }) => ({ + strings, + handleBack, + activeLanguage, + icons, + generateId, + setActivePageContent, +}); + +export default withKit(mapContextToProps)(Form); \ No newline at end of file diff --git a/plugins/src/templates/verification-tab/views/verification/index.js b/plugins/src/templates/verification-tab/views/verification/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/verification-tab/views/verification/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/verification-tab/views/verification/view.json b/plugins/src/templates/verification-tab/views/verification/view.json new file mode 100644 index 0000000000..c99e7e3a89 --- /dev/null +++ b/plugins/src/templates/verification-tab/views/verification/view.json @@ -0,0 +1,6 @@ +{ + "meta": { + "is_verification_tab": true, + "type": "verification" + } +} \ No newline at end of file diff --git a/plugins/src/templates/view/App.js b/plugins/src/templates/view/App.js new file mode 100644 index 0000000000..fbe8743c25 --- /dev/null +++ b/plugins/src/templates/view/App.js @@ -0,0 +1,20 @@ +import React, { Component } from "react"; +import { Provider } from "react-redux"; +import store from "store"; +import Title from 'components/Title'; +import { KitContextProvider } from "components/KitContext"; + +class App extends Component { + render() { + const { children: defaultView, ...rest } = this.props; + return ( + + + + </KitContextProvider> + </Provider> + ); + } +}; + +export { App }; \ No newline at end of file diff --git a/plugins/src/templates/view/index.js b/plugins/src/templates/view/index.js new file mode 100644 index 0000000000..7ea636958d --- /dev/null +++ b/plugins/src/templates/view/index.js @@ -0,0 +1 @@ +export { App as default } from "./App"; diff --git a/plugins/src/templates/view/view.json b/plugins/src/templates/view/view.json new file mode 100644 index 0000000000..c123454499 --- /dev/null +++ b/plugins/src/templates/view/view.json @@ -0,0 +1,4 @@ +{ + "target": "", + "meta": {} +} \ No newline at end of file diff --git a/plugins/src/utils/index.js b/plugins/src/utils/index.js new file mode 100644 index 0000000000..f5aa416850 --- /dev/null +++ b/plugins/src/utils/index.js @@ -0,0 +1,154 @@ +import React from 'react'; +import math from 'mathjs'; +import numbro from 'numbro'; +import validator from 'validator'; +import isEmail from 'validator/lib/isEmail'; + +export const required = value => (!value ? "Required" : undefined); + +export const editableRequired = (string) => (value) => (!value ? (string || "Required") : undefined); + +export const validateOtp = (message) => ( + value = '' +) => { + let error = undefined; + if (value.length !== 6 || !validator.isNumeric(value)) { + error = message; + } + return error; +}; + +export const DEFAULT_COIN_DATA = { + fullname: '', + symbol: '', + min: 0.001, +}; + +const local_base_currnecy = localStorage.getItem('base_currnecy'); + +export const BASE_CURRENCY = local_base_currnecy + ? local_base_currnecy.toLowerCase() + : 'usdt'; + +export const CURRENCY_PRICE_FORMAT = '{0} {1}'; + +export const formatToCurrency = (amount = 0, min = 0, fullFormat = false) => { + let formatObj = getFormat(min, fullFormat); + return numbro(roundNumber(amount, formatObj.digit)).format(formatObj.format); +}; + +export const roundNumber = (number = 0, decimals = 4) => { + if (number === 0) { + return 0; + } else if (decimals > 0) { + const multipliedNumber = math.multiply( + math.fraction(number), + math.pow(10, decimals) + ); + const dividedNumber = math.divide( + math.floor(multipliedNumber), + math.pow(10, decimals) + ); + return math.number(dividedNumber); + } else { + return math.floor(number); + } +}; + +export const getFormat = (min = 0, fullFormat) => { + let value = math.format(min, { notation: 'fixed' }); + if (fullFormat) { + return { digit: 8, format: '0,0.[00000000]' }; + } else if (min % 1) { + let point = value.toString().split('.')[1] + ? value.toString().split('.')[1] + : ''; + let res = point + .split('') + .map((val) => 0) + .join(''); + return { digit: point.length, format: `0,0.[${res}]` }; + } else { + return { digit: 4, format: `0,0.[0000]` }; + } +}; + +export const getDecimals = (value = 0) => { + let result = math.format(math.number(value), { notation: 'fixed' }); + return value % 1 + ? result.toString().split('.')[1] + ? result.toString().split('.')[1].length + : 0 + : 0; +}; + +export const normalizeBTC = (value = 0) => (value ? roundNumber(value, 8) : ''); + +export const maxValue = (maxValue, message) => (value = 0) => + value > maxValue + ? message + : undefined; + +export const minValue = (minValue, message) => (value = 0) => + value < minValue + ? message + : undefined; + +export const checkBalance = (available, message, fee = 0) => (value = 0) => { + const operation = + fee > 0 + ? math.number( + math.add( + math.fraction(value), + math.multiply(math.fraction(value), math.fraction(fee)) + ) + ) + : value; + + if (operation > available) { + return message; + } + return undefined; +}; + +export const checkBalance_new = (available, message, fee = 0) => (value = 0) => { + const operation = + fee > 0 + ? math.number( + math.add( + math.fraction(value), + math.fraction(fee) + ) + ) + : value; + + if (operation > available) { + return message; + } + return undefined; +}; + +export const toFixed = (exponential) => { + if (Math.abs(exponential) < 1.0) { + let e = parseInt(exponential.toString().split('e-')[1], 10); + if (e) { + exponential *= Math.pow(10, e - 1); + exponential = + '0.' + new Array(e).join('0') + exponential.toString().substring(2); + } + } else { + let e = parseInt(exponential.toString().split('+')[1], 10); + if (e > 20) { + e -= 20; + exponential /= Math.pow(10, e); + exponential += new Array(e + 1).join('0'); + } + } + return exponential; +}; + +export const email = (value = '') => + value && !isEmail(value) ? 'Invalid email address' : undefined; + +export const maxLength = (length, message) => (value = "") => + value.length > length ? message : undefined; \ No newline at end of file diff --git a/plugins/src/utils/link.js b/plugins/src/utils/link.js new file mode 100644 index 0000000000..0f8ee72a88 --- /dev/null +++ b/plugins/src/utils/link.js @@ -0,0 +1,11 @@ +export const open = (url, target = '_blank') => { + const a = document.createElement('a'); + a.style = 'display: none'; + a.href = url; + a.target = target; + a.rel = 'noopener noreferrer'; + + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); +}; \ No newline at end of file diff --git a/plugins/test.js b/plugins/test.js new file mode 100644 index 0000000000..3cffb46496 --- /dev/null +++ b/plugins/test.js @@ -0,0 +1,917 @@ +'use strict'; + +const crypto = require('crypto'); + +const { + meta, + publicMeta, + toolsLib, + lodash, + moment, + app, + loggerPlugin, + expressValidator, + bluebird, + rp +} = this; + +const { + webhook_secret: { value: WEBHOOK_SECRET }, + client_secret: { value: CLIENT_SECRET }, + manual_review: { value: MANUAL_REVIEW } +} = meta; +const { + client_id: { value: CLIENT_ID }, + flow_id: { value: FLOW_ID } +} = publicMeta; + +const VERIFY_STATUS = { + EMPTY: 0, + PENDING: 1, + REJECTED: 2, + COMPLETED: 3 +}; + +const + MATI_API_URL_AUTH = 'https://api.getmati.com/oauth', + getDomainUrl = (path) => `${toolsLib.getDomain()}${path}`; + +const init = async () => { + if (!WEBHOOK_SECRET) { + throw new Error('webhook_secret required value'); + } + if (!CLIENT_SECRET) { + throw new Error('client_secret required value'); + } + if (!CLIENT_ID) { + throw new Error('client_id required value'); + } + if (!FLOW_ID) { + throw new Error('flow_id required value'); + } + if (typeof MANUAL_REVIEW !== 'boolean') { + throw new Error('manual_review invalid value'); + } +}; + +const convertGender = (gender) => { + return gender ? 'Female' : 'Male'; +}; + +const parseObjToList = (data) => { + const result = { + html: '', + text: '' + }; + + for (let field in data) { + if (!lodash.isNil(data[field])) { + if (field === 'gender') { + data[field] = convertGender(data[field]); + } + + if (toolsLib.isDatetime(data[field])) { + data[field] = moment(data[field]).format('YYYY/MM/DD'); + } + result.html += `<li>${lodash.startCase(field)}: ${data[field]}</li>`; + result.text += `${lodash.startCase(field)}: ${data[field]}\n`; + } + } + + return result; +}; + +const documentApprovedEmail = (email, data = {}) => { + const idData = parseObjToList(data); + + const html = ` + <div> + <p> + Dear ${email}, + </p> + <p> + Your uploaded KYC documents have been approved.<br> + You now have access to all exchange features that require identity verification. + </p> + <ul> + ${idData.html} + </ul> + <p> + To view your approved documents, visit your <a href=${getDomainUrl('/verification')}>Verification page</a>. + </p> + <p> + Regards,<br> + ${toolsLib.getKitConfig().api_name} team + </p> + </div> + `; + + const text = ` + Dear ${email}, + + Your uploaded KYC documents have been approved. + You now have access to all exchange features that require identity verification. + + ${idData.text} + + To view your approved documents, visit your Verification page. + + Regards, + ${toolsLib.getKitConfig().api_name} team + `; + + const subject = 'KYC Documents Approved'; + + return toolsLib.sendCustomEmail( + email, + subject, + toolsLib.emailHtmlBoilerplate(html), + { + bcc: 'default', + text + } + ); +}; + +const documentPendingEmail = (email) => { + const html = ` + <div> + <p> + Dear ${email}, + </p> + <p> + Your uploaded documents are currently being processed.<br> + We will notify you when your documents are approved or denied. + </p> + <p> + To view the status of your pending documents, visit your <a href=${getDomainUrl('/verification')}>Verification page</a>. + </p> + <p> + Regards,<br> + ${toolsLib.getKitConfig().api_name} team + </p> + </div> + `; + + const text = ` + Dear ${email}, + + Your uploaded documents are currently being processed. + We will notify you when your documents are approved or denied. + + To view the status of your pending documents, visit your Verification page. + + Regards, + ${toolsLib.getKitConfig().api_name} team + `; + + const subject = 'KYC Documents Pending'; + + return toolsLib.sendCustomEmail( + email, + subject, + toolsLib.emailHtmlBoilerplate(html), + { + bcc: 'default', + text + } + ); +}; + +const documentRejectedEmail = (email, reasons = {}) => { + const parsedReasons = parseObjToList(reasons); + + const html = ` + <div> + <p> + Dear ${email}, + </p> + <p> + Unfortunately, your uploaded KYC documents have been rejected.<br> + The reasons for your documents being rejected are listed below.<br> + </p> + <div> + ${parsedReasons.html} + </div> + <p> + If you feel these reasons are invalid, please feel free to reply to this email.<br> + Otherwise, please reupload valid documents in order to verify your identity. + </p> + <p> + Regards,<br> + ${toolsLib.getKitConfig().api_name} team + </p> + </div> + `; + + const text = ` + Dear ${email}, + + Unfortunately, your uploaded KYC documents have been rejected. + The reasons for your documents being rejected are listed below. + + ${parsedReasons.text} + + If you feel these reasons are invalid, please feel free to reply to this email. + Otherwise, please reupload valid documents in order to verify your identity. + + Regards, + ${toolsLib.getKitConfig().api_name} team + `; + + const subject = 'KYC Documents Rejected'; + + return toolsLib.sendCustomEmail( + email, + subject, + toolsLib.emailHtmlBoilerplate(html), + { + bcc: 'default', + text + } + ); +}; + +const documentExpiredEmail = (email) => { + const html = ` + <div> + <p> + Dear ${email}, + </p> + <p> + Your iDenfy document upload token as expired.<br> + You will no longer be able to use your token to upload your documents.<br> + To generate a new token, please go through the KYC process in your <a href=${getDomainUrl('/verification')}>Verification page</a>. + </p> + <p> + Regards,<br> + ${toolsLib.getKitConfig().api_name} team + </p> + </div> + `; + + const text = ` + Dear ${email}, + + Your iDenfy document upload token as expired. + You will no longer be able to use your token to upload your documents. + To generate a new token, please go through the KYC process in your Verification page. + + Regards, + ${toolsLib.getKitConfig().api_name} team + `; + + const subject = 'iDenfy Token Expired'; + + return toolsLib.sendCustomEmail( + email, + subject, + toolsLib.emailHtmlBoilerplate(html), + { + bcc: 'default', + text + } + ); +}; + +const adminAlertEmail = async (data = {}) => { + const { email, id } = data; + + const html = ` + <div> + <p> + Documents provided by user ${email} with ID ${id} have been automatically approved and are awaiting manual approval.<br> + <br> + You can manually approve or reject these documents through the <a href=${getDomainUrl(`/admin/user?id=${id}`)}>Operator Controls Panel</a>.<br> + Once reviewed, the user will be notified of the updated status. + </p> + </div> + `; + + const text = ` + Documents provided by user ${email} with ID ${id} have been automatically approved and are awaiting manual approval. + + You can manually approve or reject these documents through the Operator Controls Panel. + Once reviewed, the user will be notified of the updated status. + `; + + const subject = 'KYC Documents Awaiting Manual Review'; + + const kycOperators = await toolsLib.database.findAll('user', { + where: { + is_kyc: true + }, + attributes: ['email'], + raw: true + }); + + let cc = null; + + if (kycOperators.length > 0) { + cc = kycOperators.map((operator) => operator.email).join(','); + } + + return toolsLib.sendCustomEmail( + toolsLib.getKitSecrets().emails.audit, + subject, + toolsLib.emailHtmlBoilerplate(html), + { + cc, + text + } + ); +}; + +const getGender = (docSex) => { + if (docSex && docSex !== 'UNDEFINED') { + return docSex === 'F'; + } + + return false; +}; + +const generateUpdatedUserData = (status, data, eventName) => { + let result = {}; + if (eventName === 'verification_started' || eventName === 'verification_inputs_completed') { + result = { + id_data: { + status + } + }; + return result; + + } else if (eventName === 'verification_expired') { + result = { + id_data: { + status + } + }; + result.id_data.mati.resource = data.resource; + + return result; + + } else if (eventName === 'verification_updated' || eventName === 'verification_completed') { + bluebird.all([ + data.resource, + generateMatiToken() + ]) + .then(([resourceURL, responseToken]) => { + if (!responseToken) + throw new Error('Not authentication Mati'); + + loggerPlugin.verbose( + data.metadata.user_id, + 'GET /plugins/mati/admin/files request getMatiFiles', + responseToken + ); + responseToken = JSON.parse(responseToken); + return getMatiFiles(resourceURL, responseToken.access_token); + }) + .then((documentUser) => { + + result = { + full_name: '', + nationality: '', + gender: false, + dob: null, + id_data: { + status + } + }; + + loggerPlugin.verbose( + data.metadata.user_id, + 'GET /plugins/mati/admin/files response data', + documentUser + ); + + const { + fullName: { value: fullName }, + documentNumber: { value: documentNumber }, + dateOfBirt: { value: dateOfBirt }, + expirationDate: { value: expirationDate }, + documentType: { value: documentType }, + firstName: { value: firstName }, + issueCountry: { value: issueCountry }, + nationality: { value: nationality }, + personalNumber: { value: personalNumber }, + sex: { value: sex }, + surname: { value: surname } + } = documentUser.documents.fields; + + result.id_data.mati = documentUser.documents.data; + result.id_data.mati.resource = documentUser.resource; + if (documentType) { + result.id_data.type = documentType.toLowerCase(); + } + + if (documentNumber) { + result.id_data.number = documentNumber; + } + + if (expirationDate) { + result.id_data.expiration_date = moment(expirationDate).toISOString(); + } + + if (nationality) { + result.nationality = nationality; + } + + if (dateOfBirt) { + result.dob = moment(dateOfBirt).toISOString(); + } + + if (fullName) { + result.full_name = fullName; + } + if (sex) { + result.gender = getGender(sex); + } + return result; + }); + } +}; + +const generateMatiToken = async () => { + const method = 'POST'; + const headers = { + 'content-type': 'application/x-www-form-urlencoded', + 'Authorization': 'Basic ' + new Buffer.from(CLIENT_ID + ':' + CLIENT_SECRET, 'utf8').toString('base64') + }; + const form = { + 'grant_type': 'client_credentials' + }; + const option = { + headers, + method, + uri: MATI_API_URL_AUTH, + form + }; + + return rp(option); +}; + +const getMatiFiles = async (resource, accessToken) => { + + const method = 'GET'; + const headers = { + 'content-type': 'application/x-www-form-urlencoded', + 'Authorization': 'Bearer ' + accessToken + }; + const url = resource; + loggerPlugin.verbose( + resource, + accessToken, + 'getMatiFiles request' + ); + return rp({ + headers, + method, + url + }); +}; + +const verifyRequest = async (signature, secret, payloadBody) => { + let hash = crypto.createHmac('sha256', secret); + hash = hash.update(payloadBody).digest('hex'); + const isValid = crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(signature)); + + loggerPlugin.error( + 'MATI PLUGIN cannot verify notification request' + ); + + if (!isValid) { + throw new Error('Invalid request'); + } +}; + +init() + .then(() => { + app.post('/plugins/mati/notification', (req, res) => { + loggerPlugin.verbose( + req.uuid, + 'POST /plugins/mati/notification body URL webhook', + req.body + ); + + const signature = req.headers['x-signature']; + const data = req.body; + + verifyRequest(signature, WEBHOOK_SECRET, JSON.stringify(data)) + .then(() => { + if (!data.metadata || !data.metadata.user_id) { + throw new Error('Meta data user_id not given'); + } + + return toolsLib.database.findOne('user', { + where: { + id: data.metadata.user_id + }, + attributes: [ + 'id', + 'email', + 'network_id', + 'full_name', + 'gender', + 'nationality', + 'dob', + 'id_data' + ] + }); + }) + .then(async (user) => { + if (!user) { + throw new Error('User not found'); + } + + const { eventName } = data; + + let updateStatus; + + if (eventName === 'verification_started') { + updateStatus = VERIFY_STATUS.PENDING; + } else if (eventName === 'verification_inputs_completed') { + updateStatus = VERIFY_STATUS.PENDING; + } else if (eventName === 'verification_updated') { + if (MANUAL_REVIEW) { + updateStatus = VERIFY_STATUS.PENDING; + } else { + updateStatus = VERIFY_STATUS.COMPLETED; + } + } else if (eventName === 'verification_completed') { + if (MANUAL_REVIEW) { + updateStatus = VERIFY_STATUS.PENDING; + } else { + updateStatus = VERIFY_STATUS.COMPLETED; + } + } else if (eventName === 'verification_expired') { + updateStatus = VERIFY_STATUS.REJECTED; + } + + const previousStatus = user.id_data.status; + + loggerPlugin.verbose( + req.uuid, + 'POST /plugins/mati/notification status', + 'mati eventName', + eventName, + 'previous id data status:', + previousStatus, + 'updating status:', + updateStatus + ); + + if (updateStatus) { + const updateData = await generateUpdatedUserData(updateStatus, data, eventName); + + loggerPlugin.verbose( + req.uuid, + 'POST /plugins/mati/notification updated user', + updateData + ); + const updatedUser = await user.update(updateData); + + loggerPlugin.verbose( + req.uuid, + 'POST /plugins/mati/notification updated user', + updatedUser + ); + + try { + if (updateStatus === VERIFY_STATUS.PENDING && MANUAL_REVIEW) { + adminAlertEmail({ + email: user.email, + id: user.id + }); + } + } catch (err) { + loggerPlugin.error( + req.uuid, + 'POST /plugins/mati/notification error while sending manual review required email', + err.message + ); + } + + try { + if (updateStatus === VERIFY_STATUS.REJECTED) { + documentRejectedEmail( + user.email + ); + } else if (updateStatus === VERIFY_STATUS.PENDING) { + documentPendingEmail(user.email); + } else if (updateStatus === VERIFY_STATUS.COMPLETED) { + documentApprovedEmail(user.email, { + full_name: updatedUser.full_name ? updatedUser.full_name : null, + dob: updatedUser.dob, + gender: lodash.isBoolean(updatedUser.gender) ? updatedUser.gender : null, + nationality: updatedUser.nationality ? updatedUser.nationality : null, + ...lodash.omit(updatedUser.id_data, ['status', 'mati']) + }); + } + } catch (err) { + loggerPlugin.error( + req.uuid, + 'POST /plugins/mati/notification error while sending email', + err.message + ); + } + } + return res.json({ message: 'Success' }); + + }) + .catch((err) => { + loggerPlugin.error( + req.uuid, + 'POST /plugins/mati/notification err', + err + ); + return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); + }); + }); + + app.get('/plugins/mati/admin/files', [ + toolsLib.security.verifyBearerTokenExpressMiddleware(['admin', 'supervisor', 'support', 'kyc']), + expressValidator.checkSchema({ + user_id: { + in: ['query'], + errorMessage: 'must be an integer', + isInt: true, + optional: false + } + }) + ], (req, res) => { + const errors = expressValidator.validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + loggerPlugin.verbose( + req.uuid, + 'GET /plugins/mati/admin/files auth', + req.auth.sub + ); + + const { user_id } = req.query; + toolsLib.user.getUserByKitId(user_id) + .then((user) => { + if (!user) { + throw new Error('User not found'); + } + + if ( + !user.id_data + || !user.id_data.mati + || !user.id_data.mati.resource + || user.id_data.status === VERIFY_STATUS.EMPTY + ) { + throw new Error('User does not have uploaded documents'); + } + loggerPlugin.verbose( + user_id, + 'GET /plugins/mati/admin/files request generateMatiToken' + ); + + return bluebird.all([ + user, + generateMatiToken() + ]); + }) + .then(([user, responseToken]) => { + if (!responseToken) + throw new Error('Not authentication Mati'); + loggerPlugin.verbose( + user_id, + 'GET /plugins/mati/admin/files request getMatiFiles', + responseToken + ); + responseToken = JSON.parse(responseToken); + return getMatiFiles(user.id_data.mati.resource, responseToken.access_token); + }) + .then((data) => { + + loggerPlugin.verbose( + user_id, + 'GET /plugins/mati/admin/files response data', + data + ); + + return res.json(data); + }) + .catch((err) => { + loggerPlugin.error( + req.uuid, + 'GET /plugins/mati/admin/files err', + err.message + ); + return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); + }); + }); + + app.get('/plugins/mati/admin/file1/:location', [], (req, res) => { + const { location } = req.params; + + generateMatiToken() + .then((responseToken) => { + if (!responseToken) + throw new Error('Not authentication Mati'); + responseToken = JSON.parse(responseToken); + return + const method = 'GET'; + const headers = { + 'Authorization': 'Bearer ' + responseToken + }; + const url = 'https://media.getmati.com/file?location='+location; + + return rp({ + headers, + method, + url + }) + }) + .then((data) => { + console.log(data, "data"); + res.contentType('image/jpeg'); + return res.send(data); + }) + .catch((err) => { + loggerPlugin.error( + req.uuid, + 'GET /plugins/mati/admin/file err', + err.message + ); + return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); + }); + }); + + app.post('/plugins/mati/verify', [ + toolsLib.security.verifyBearerTokenExpressMiddleware(['admin', 'kyc', 'support', 'supervisor']), + expressValidator.checkSchema({ + user_id: { + in: ['body'], + errorMessage: 'must be an integer', + isInt: true, + optional: false + } + }) + ], (req, res) => { + const errors = expressValidator.validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + loggerPlugin.verbose( + req.uuid, + 'POST /plugins/mati/verify auth', + req.auth.sub + ); + + const { user_id } = req.body; + + toolsLib.user.getUserByKitId(user_id, false, false) + .then((user) => { + if (!user) { + throw new Error('User not found'); + } + + if ( + !user.id_data + || lodash.isNil(user.id_data.status) + || user.id_data.status === VERIFY_STATUS.EMPTY + ) { + throw new Error('User documents are not pending'); + } + + if (user.id_data.status === VERIFY_STATUS.COMPLETED) { + throw new Error('User documents are already verified'); + } + + return user.update({ + id_data: { + ...user.id_data, + status: VERIFY_STATUS.COMPLETED + } + }); + }) + .then((data) => { + try { + documentApprovedEmail(data.email, { + full_name: data.full_name ? data.full_name : null, + dob: data.dob, + gender: lodash.isBoolean(data.gender) ? data.gender : null, + nationality: data.nationality ? data.nationality : null, + ...lodash.omit(data.id_data, ['status', 'idenfy']) + }); + } catch (err) { + loggerPlugin.error( + req.uuid, + 'POST /plugins/mati/verify err while sending email', + err.message + ); + } + return res.json(lodash.pick(data, [ + 'id', + 'email', + 'full_name', + 'dob', + 'nationality', + 'gender', + 'id_data' + ])); + }) + .catch((err) => { + loggerPlugin.error( + req.uuid, + 'POST /plugins/mati/verify err', + err.message + ); + return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); + }); + }); + + app.post('/plugins/mati/revoke', [ + toolsLib.security.verifyBearerTokenExpressMiddleware(['admin', 'kyc', 'support', 'supervisor']), + expressValidator.checkSchema({ + user_id: { + in: ['body'], + errorMessage: 'must be an integer', + isInt: true, + optional: false + } + }) + ], (req, res) => { + const errors = expressValidator.validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + loggerPlugin.verbose( + req.uuid, + 'POST /plugins/mati/revoke auth', + req.auth.sub + ); + + const user_id = req.body.user_id; + + toolsLib.user.getUserByKitId(user_id, false, false) + .then((user) => { + if (!user) { + throw new Error('User not found'); + } + + if ( + !user.id_data + || lodash.isNil(user.id_data.status) + || user.id_data.status === VERIFY_STATUS.EMPTY + ) { + throw new Error('User documents are not pending'); + } + + if (user.id_data.status === VERIFY_STATUS.REJECTED) { + throw new Error('User documents are already rejected'); + } + + return user.update({ + id_data: { + ...user.id_data, + status: VERIFY_STATUS.REJECTED + } + }); + }) + .then((data) => { + try { + documentRejectedEmail( + data.email + ); + } catch (err) { + loggerPlugin.error( + req.uuid, + 'POST /plugins/mati/revoke err while sending email', + err.message + ); + } + return res.json(lodash.pick(data, [ + 'id', + 'email', + 'full_name', + 'dob', + 'nationality', + 'gender', + 'id_data' + ])); + }) + .catch((err) => { + loggerPlugin.error( + req.uuid, + 'GET /plugins/mati/revoke err', + err.message + ); + return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); + }); + }); + }) + .catch((err) => { + loggerPlugin.error( + 'DOMINICAN EXCHANGE KYC PLUGIN err', + err.message + ); + }); \ No newline at end of file diff --git a/plugins/webpack-dev.config.js b/plugins/webpack-dev.config.js new file mode 100644 index 0000000000..a48cc1e6e6 --- /dev/null +++ b/plugins/webpack-dev.config.js @@ -0,0 +1,96 @@ +/** + * generates: + * - dist/main.js + * - dist/manifest.json + * - dist/webpack-bundle-analyzer-report.html + */ +const webpack = require("webpack"); +const fs = require('fs'); +const WebpackAssetsManifest = require("webpack-assets-manifest"); +const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); +const glob = require("glob") +const path = require("path") +const remoteComponentConfig = require("./remote-component.config").resolve; + +const generateEntires = (plugin) => { + const pattern = `src/plugins/${plugin ? plugin : '**'}/views/**/index.js`; + const entry = glob.sync(pattern, { noglobstar: true }) + .reduce((x, y) => { + const dir = y.split(path.sep); + + if (fs.existsSync(y)) { + return Object.assign(x, { + [`${dir[2]}__${dir[4]}`]: `./${y}`, + }) + } else { + return Object.assign(x, {}) + } + + }, {}); + + if ( Object.keys(entry).length === 0) { + process.exit(); + } else { + return entry; + } +} + +const externals = Object.keys(remoteComponentConfig).reduce( + (obj, key) => ({ ...obj, [key]: key }), + {} +); + +module.exports = (env) => { + const { plugin } = env; + const entry = generateEntires(plugin); + return { + plugins: [ + new webpack.EnvironmentPlugin({ + "process.env.NODE_ENV": process.env.NODE_ENV + }), + new BundleAnalyzerPlugin({ + analyzerMode: "static", + openAnalyzer: false, + reportFilename: "webpack-bundle-analyzer-report.html" + }), + new WebpackAssetsManifest() + ], + entry, + watch: true, + watchOptions: { + aggregateTimeout: 200, + poll: 1000, + ignored: /node_modules/, + }, + output: { + libraryTarget: "commonjs" + }, + externals: { + ...externals, + "remote-component.config.js": "remote-component.config.js" + }, + module: { + rules: [ + { + test: /\.m?js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: "babel-loader" + } + }, + { + test: /\.(sass|less|css)$/, + use: ["style-loader", "css-loader"] + }, + ] + }, + resolve: { + alias: { + "components": path.resolve("./src/components"), + "utils": path.resolve("./src/utils"), + "store": path.resolve("./src/store"), + "constants": path.resolve("./src/constants") + } + } + } +}; diff --git a/plugins/webpack-main.config.js b/plugins/webpack-main.config.js new file mode 100644 index 0000000000..2465115523 --- /dev/null +++ b/plugins/webpack-main.config.js @@ -0,0 +1,90 @@ +/** + * generates: + * - dist/main.js + * - dist/manifest.json + * - dist/webpack-bundle-analyzer-report.html + */ +const webpack = require("webpack"); +const fs = require('fs'); +const WebpackAssetsManifest = require("webpack-assets-manifest"); +const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); +const glob = require("glob") +const path = require("path") +const remoteComponentConfig = require("./remote-component.config").resolve; + +const generateEntires = (plugin) => { + const pattern = `src/plugins/${plugin ? plugin : '**'}/views/**/index.js`; + const entry = glob.sync(pattern, { noglobstar: true }) + .reduce((x, y) => { + const dir = y.split(path.sep); + + if (fs.existsSync(y)) { + return Object.assign(x, { + [`${dir[2]}__${dir[4]}`]: `./${y}`, + }) + } else { + return Object.assign(x, {}) + } + + }, {}); + + if ( Object.keys(entry).length === 0) { + process.exit(); + } else { + return entry; + } +} + +const externals = Object.keys(remoteComponentConfig).reduce( + (obj, key) => ({ ...obj, [key]: key }), + {} +); + +module.exports = (env) => { + const { plugin } = env; + const entry = generateEntires(plugin); + return { + plugins: [ + new webpack.EnvironmentPlugin({ + "process.env.NODE_ENV": process.env.NODE_ENV + }), + new BundleAnalyzerPlugin({ + analyzerMode: "static", + openAnalyzer: false, + reportFilename: "webpack-bundle-analyzer-report.html" + }), + new WebpackAssetsManifest() + ], + entry, + output: { + libraryTarget: "commonjs" + }, + externals: { + ...externals, + "remote-component.config.js": "remote-component.config.js" + }, + module: { + rules: [ + { + test: /\.m?js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: "babel-loader" + } + }, + { + test: /\.(sass|less|css)$/, + use: ["style-loader", "css-loader"] + }, + ] + }, + resolve: { + alias: { + "components": path.resolve("./src/components"), + "utils": path.resolve("./src/utils"), + "store": path.resolve("./src/store"), + "constants": path.resolve("./src/constants") + } + } + } +}; diff --git a/plugins/webpack.config.js b/plugins/webpack.config.js new file mode 100644 index 0000000000..aea8894bd1 --- /dev/null +++ b/plugins/webpack.config.js @@ -0,0 +1,3 @@ +const webpackMainConfig = require("./webpack-main.config"); + +module.exports = [webpackMainConfig]; From b23352c60c8141d19dfcf3b9f4cf9c6cc71d29be Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Wed, 31 Aug 2022 12:09:10 +0430 Subject: [PATCH 02/54] plugin updates for server script development --- .gitignore | 1 + package-lock.json | 233 -------------- package.json | 10 - plugins/package-lock.json | 296 ++++++++++-------- plugins/package.json | 42 +-- plugins/scripts/generateConfig.js | 76 +++++ plugins/scripts/generateJson.js | 42 +-- .../generatePlugin.js} | 4 +- plugins/scripts/utils.js | 35 ++- plugins/server.js | 1 + 10 files changed, 313 insertions(+), 427 deletions(-) delete mode 100644 package-lock.json delete mode 100644 package.json create mode 100644 plugins/scripts/generateConfig.js rename plugins/{generateJson.js => scripts/generatePlugin.js} (93%) diff --git a/.gitignore b/.gitignore index 59b0aa0d80..fd1540df11 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ web/src/**/*.css plugins/dist plugins/json +plugins/config #HollaEx CLI related templates/local/nginx/conf.d/* diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index f5e113eb55..0000000000 --- a/package-lock.json +++ /dev/null @@ -1,233 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concurrently": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.3.0.tgz", - "integrity": "sha512-IiDwm+8DOcFEInca494A8V402tNTQlJaYq78RF2rijOrKEk/AOHTxhN4U1cp7GYKYX5Q6Ymh1dLTBlzIMN0ikA==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "date-fns": "^2.16.1", - "lodash": "^4.17.21", - "rxjs": "^7.0.0", - "shell-quote": "^1.7.3", - "spawn-command": "^0.0.2-1", - "supports-color": "^8.1.0", - "tree-kill": "^1.2.2", - "yargs": "^17.3.1" - } - }, - "date-fns": { - "version": "2.29.2", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.2.tgz", - "integrity": "sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "rxjs": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", - "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "spawn-command": { - "version": "0.0.2-1", - "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", - "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index b5965175dc..0000000000 --- a/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "scripts": { - "plugin:kit": "npm run --prefix ./web dev:plugin --plugin=$npm_config_plugin", - "plugin:plugin": "npm run --prefix ./plugins start --plugin=$npm_config_plugin", - "plugin:dev": "concurrently \"npm run plugin:kit --plugin=$npm_config_plugin\" \"npm run plugin:plugin --plugin=$npm_config_plugin\"" - }, - "devDependencies": { - "concurrently": "7.3.0" - } -} diff --git a/plugins/package-lock.json b/plugins/package-lock.json index 93b770a3cd..7966f37aab 100644 --- a/plugins/package-lock.json +++ b/plugins/package-lock.json @@ -2820,30 +2820,174 @@ } }, "concurrently": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-5.3.0.tgz", - "integrity": "sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.3.0.tgz", + "integrity": "sha512-IiDwm+8DOcFEInca494A8V402tNTQlJaYq78RF2rijOrKEk/AOHTxhN4U1cp7GYKYX5Q6Ymh1dLTBlzIMN0ikA==", "dev": true, "requires": { - "chalk": "^2.4.2", - "date-fns": "^2.0.1", - "lodash": "^4.17.15", - "read-pkg": "^4.0.1", - "rxjs": "^6.5.2", + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^7.0.0", + "shell-quote": "^1.7.3", "spawn-command": "^0.0.2-1", - "supports-color": "^6.1.0", + "supports-color": "^8.1.0", "tree-kill": "^1.2.2", - "yargs": "^13.3.0" + "yargs": "^17.3.1" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "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==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true } } }, @@ -3545,15 +3689,6 @@ "prr": "~1.0.1" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, "es-abstract": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", @@ -4763,12 +4898,6 @@ "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", "dev": true }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, "html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -5067,12 +5196,6 @@ } } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -5942,18 +6065,6 @@ "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -6248,16 +6359,6 @@ "safe-buffer": "^5.1.1" } }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", @@ -7327,25 +7428,6 @@ "prop-types": "^15.7.2" } }, - "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha512-+UBirHHDm5J+3WDmLBZYSklRYg82nMlz+enn+GMZ22nSR2f4bzxmhso6rzQW/3mT2PVzpzDTiYIZahk8UmZ44w==", - "dev": true, - "requires": { - "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true - } - } - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -7673,12 +7755,12 @@ } }, "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", "dev": true, "requires": { - "tslib": "^1.9.0" + "tslib": "^2.1.0" } }, "safe-buffer": { @@ -7867,6 +7949,12 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shell-quote": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "dev": true + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -8061,38 +8149,6 @@ "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", "dev": true }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true - }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -8608,9 +8664,9 @@ "dev": true }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, "tty-browserify": { @@ -8919,16 +8975,6 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "validator": { "version": "10.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", diff --git a/plugins/package.json b/plugins/package.json index 5ac163bc9c..df71b8305a 100644 --- a/plugins/package.json +++ b/plugins/package.json @@ -12,27 +12,29 @@ "license": "ISC", "scripts": { "kill-8080": "lsof -ti:8080 | xargs kill || exit 0", - "build:web": "npm run clean && cross-env NODE_ENV=production webpack --env.plugin=$npm_config_plugin --mode production", - "build:dev": "npm run clean && cross-env NODE_ENV=development webpack --env.plugin=$npm_config_plugin --mode development", - "start": "cross-env NODE_ENV=development concurrently \"npm run dev --plugin=$npm_config_plugin\" \"npm run json:watch --plugin=$npm_config_plugin\" \"npm run server\"", - "dev": "npm run clean && cross-env NODE_ENV=development webpack --env.plugin=$npm_config_plugin --mode development --config webpack-dev.config.js", - "clean": "rimraf dist", + "generate:bundle:production": "npm run remove:dist && cross-env NODE_ENV=production webpack --env.plugin=$npm_config_plugin --mode production", + "generate:bundle:development": "npm run remove:dist && cross-env NODE_ENV=development webpack --env.plugin=$npm_config_plugin --mode development", + "plugin:development": "cross-env NODE_ENV=development concurrently \"npm run webpack:development --plugin=$npm_config_plugin\" \"npm run watch:webview:json --plugin=$npm_config_plugin\" \"npm run watch:config:json --plugin=$npm_config_plugin\" \"npm run server\"", + "webpack:development": "npm run remove:dist && cross-env NODE_ENV=development webpack --env.plugin=$npm_config_plugin --mode development --config webpack-dev.config.js", + "remove:dist": "rimraf dist", "remove:json": "rimraf json", - "lint": "eslint .", - "json": "PLUGIN=$npm_config_plugin node scripts/generateJson.js", - "generate-json": "npm run remove:json && PLUGIN=$npm_config_plugin node scripts/generateJson.js", - "add-plugin": "PLUGIN=$npm_config_plugin TYPE=$npm_config_type node scripts/addPlugin.js", - "add-view": "PLUGIN=$npm_config_plugin WEB_VIEW=$npm_config_webview node scripts/addView.js", - "publish": "npm run build:web --plugin=$npm_config_plugin && npm run generate-json --plugin=$npm_config_plugin", - "publish:dev": "npm run build:dev --plugin=$npm_config_plugin && npm run generate-json --plugin=$npm_config_plugin", - "json:watch": "npm run remove:json && onchange -i 'src/plugins/**/assets/*.json' 'src/plugins/**/views/**/*.json' -- npm run json --plugin=$npm_config_plugin", + "remove:config": "rimraf config", + "generate:webview:json": "PLUGIN=$npm_config_plugin node scripts/generateJson.js", + "generate:webview:json:clean": "npm run remove:json && npm run generate:webview:json --plugin=$npm_config_plugin", + "generate:config:json": "PLUGIN=$npm_config_plugin node scripts/generateConfig.js", + "add:plugin": "PLUGIN=$npm_config_plugin TYPE=$npm_config_type node scripts/addPlugin.js", + "add:view": "PLUGIN=$npm_config_plugin WEB_VIEW=$npm_config_webview node scripts/addView.js", + "generate:webview:production": "npm run generate:bundle:production --plugin=$npm_config_plugin && npm run generate:webview:json:clean --plugin=$npm_config_plugin", + "generate:webview:development": "npm run generate:bundle:development --plugin=$npm_config_plugin && npm run generate:webview:json:clean --plugin=$npm_config_plugin", + "watch:webview:json": "npm run remove:json && onchange -i 'src/plugins/**/assets/*.json' 'src/plugins/**/views/**/*.json' -- npm run generate:webview:json --plugin=$npm_config_plugin", + "watch:config:json": "npm run remove:config && onchange -i 'src/plugins/**/assets/*.json' 'src/plugins/**/views/**/*.json' 'src/plugins/**/server/*' -- npm run generate:config:json --plugin=$npm_config_plugin", "server": "npm run kill-8080 && node server.js", - "test": "echo \"Error: no test specified\" && exit 1", - "build": "npm run publish:web --plugin=$npm_config_plugin && npm run generate:json --plugin=$npm_config_plugin", - "generate:json": "PLUGIN=$npm_config_plugin node generateJson.js", - "add-bundles": "node scripts/addBundles.js", - "add-jsons": "node scripts/addJsons.js", - "publish:web": "npm run publish --plugin=$npm_config_plugin && npm run add-bundles && npm run add-jsons" + "build": "npm run build:webview --plugin=$npm_config_plugin && npm run generate:plugin:json --plugin=$npm_config_plugin", + "generate:plugin:json": "PLUGIN=$npm_config_plugin node scripts/generatePlugin.js", + "add:webview:bundles": "node scripts/addBundles.js", + "add:webview:jsons": "node scripts/addJsons.js", + "build:webview": "npm run generate:webview:production --plugin=$npm_config_plugin && npm run add:webview:bundles && npm run add:webview:jsons", + "start": "concurrently \"npm run --prefix ../web dev:plugin --plugin=$npm_config_plugin\" \"npm run plugin:development --plugin=$npm_config_plugin\"" }, "dependencies": { "@ant-design/icons": "4.2.2", @@ -71,7 +73,7 @@ "babel-eslint": "10.1.0", "babel-loader": "8.2.2", "babel-plugin-transform-react-remove-prop-types": "0.4.24", - "concurrently": "5.3.0", + "concurrently": "7.3.0", "copy-dir": "1.3.0", "core-js": "2.6.12", "cross-env": "7.0.3", diff --git a/plugins/scripts/generateConfig.js b/plugins/scripts/generateConfig.js new file mode 100644 index 0000000000..ad3184d453 --- /dev/null +++ b/plugins/scripts/generateConfig.js @@ -0,0 +1,76 @@ +const fs = require('fs'); +const path = require('path'); +const uglifyEs = require('uglify-es'); +const mkdirp = require('mkdirp'); +const { minify: htmlMinify } = require('html-minifier-terser'); +const { FILES, PATHS } = require('./patterns'); +const { getWebView } = require('./utils') + +const { env: { PLUGIN: plugin } } = process; + +if (!fs.existsSync('config')) { + mkdirp.sync('config') +} + +if (!plugin) { + console.error('No plugin name given'); + process.exit(1); +} + +const pluginPath = path.resolve(__dirname, '..', PATHS.ROOT, plugin, PATHS.SERVER); + +if (!fs.existsSync(pluginPath)) { + console.error(`Plugin ${plugin} does not exist`); + process.exit(1); +} + +const scriptPath = path.resolve(pluginPath, FILES.SCRIPT); +const adminViewPath = path.resolve(pluginPath, FILES.ADMIN_VIEW); + +console.log(`Generating plugin JSON object for plugin ${plugin}...\n`); + +const config = fs.readFileSync(path.resolve(pluginPath, FILES.CONFIG)); +let script = null; +let admin_view = null; + +if (fs.existsSync(scriptPath)) { + const rawScript = fs.readFileSync(scriptPath, 'utf-8'); + script = uglifyEs.minify(rawScript); + + if (script.error) { + console.error('Error occured while minifying script\n'); + console.error(script.error); + process.exit(1); + } + + script = script.code; +} + +if (fs.existsSync(adminViewPath)) { + const rawAdminView = fs.readFileSync(adminViewPath, 'utf-8'); + + try { + admin_view = htmlMinify(rawAdminView, { + minifyJS: true, + minifyCSS: true, + collapseWhitespace: true + }); + } catch (err) { + console.error('Error occured while minifying admin_view\n'); + console.error(err); + process.exit(1); + } +} + +const pluginJson = JSON.stringify({ + ...JSON.parse(config), + script, + admin_view, + web_view: getWebView(plugin) +}, null, '\t'); + +fs.writeFileSync('config/config.json', pluginJson); + +console.log(pluginJson); + +process.exit(0); \ No newline at end of file diff --git a/plugins/scripts/generateJson.js b/plugins/scripts/generateJson.js index 0538379f12..2b7368a6e5 100644 --- a/plugins/scripts/generateJson.js +++ b/plugins/scripts/generateJson.js @@ -1,10 +1,9 @@ const fs = require("fs"); const path = require("path"); const glob = require("glob"); -const merge = require("lodash.merge"); const mkdirp = require('mkdirp'); -const { PATTERNS, FILES, PATHS } = require("./patterns"); -const { readFile, saveFile, getBundlePath } = require("./utils"); +const { PATTERNS, PATHS } = require("./patterns"); +const { saveFile, getWebView } = require("./utils"); const { env: { PLUGIN: plugin }} = process; const pluginsPattern = plugin ? `${PATHS.ROOT}/${plugin}` : PATTERNS.PLUGINS; @@ -15,37 +14,12 @@ if (!fs.existsSync('json')) { mkdirp.sync('json') } -plugins.forEach(pluginPath => { - const pluginName = pluginPath.split(path.sep)[2] - const assetsPath = `${PATHS.ROOT}/${pluginName}/${PATHS.ASSETS}` - const pluginPattern = `${PATHS.ROOT}/${pluginName}/${PATTERNS.VIEW}`; +plugins.forEach((pluginPath) => { + const plugin = pluginPath.split(path.sep)[2] - let assetsAdded = false; - const assets = { - strings: readFile(`${assetsPath}/${FILES.STRINGS}`), - icons: readFile(`${assetsPath}/${FILES.ICONS}`), - }; - - const webViews = glob.sync(pluginPattern, { noglobstar: true }) - .reduce((acc, curr) => { - const view = readFile(`${path.dirname(curr)}/${FILES.VIEW}`); - const generatedView = { - src: getBundlePath(curr), - ...(assetsAdded ? {} : { meta: { ...assets }}), - }; - - // development - // const webView = merge({}, view, generatedView); - const webView = merge({}, generatedView, view); - - assetsAdded = true; - - return [...acc, webView] - }, []); - - const plugin = { - web_view: webViews + const content = { + web_view: getWebView(plugin) } - saveFile(`json/${pluginName}.json`, plugin); -}) \ No newline at end of file + saveFile(`json/${plugin}.json`, content); +}); \ No newline at end of file diff --git a/plugins/generateJson.js b/plugins/scripts/generatePlugin.js similarity index 93% rename from plugins/generateJson.js rename to plugins/scripts/generatePlugin.js index a08f071f7f..5c80621776 100644 --- a/plugins/generateJson.js +++ b/plugins/scripts/generatePlugin.js @@ -2,7 +2,7 @@ const fs = require('fs'); const path = require('path'); const uglifyEs = require('uglify-es'); const { minify: htmlMinify } = require('html-minifier-terser'); -const { FILES, PATHS } = require('./scripts/patterns'); +const { FILES, PATHS } = require('./patterns'); const { env: { PLUGIN: plugin } } = process; @@ -11,7 +11,7 @@ if (!plugin) { process.exit(1); } -const pluginPath = path.resolve(__dirname, PATHS.ROOT, plugin, PATHS.SERVER); +const pluginPath = path.resolve(__dirname, '..', PATHS.ROOT, plugin, PATHS.SERVER); if (!fs.existsSync(pluginPath)) { console.error(`Plugin ${plugin} does not exist`); diff --git a/plugins/scripts/utils.js b/plugins/scripts/utils.js index b4487dfcd5..4afbbdaebb 100644 --- a/plugins/scripts/utils.js +++ b/plugins/scripts/utils.js @@ -1,7 +1,9 @@ const fs = require("fs"); const path = require("path"); const beautify = require("json-beautify"); -const { PLUGINS_PATH, PATHS, FILES } = require("./patterns"); +const glob = require("glob"); +const merge = require("lodash.merge"); +const { PLUGINS_PATH, PATHS, FILES, PATTERNS } = require("./patterns"); const saveFile = (output, content) => { fs.writeFileSync(output, beautify(content, null, 4, 100)); @@ -32,8 +34,35 @@ const getBundlePath = (pathname) => { return `${PLUGINS_PATH}/${pluginName}/v${version}/${bundleName}.js` } +const getWebView = (plugin) => { + const assetsPath = `${PATHS.ROOT}/${plugin}/${PATHS.ASSETS}`; + const viewsPattern = `${PATHS.ROOT}/${plugin}/${PATTERNS.VIEW}`; + + let assetsAdded = false; + const assets = { + strings: readFile(`${assetsPath}/${FILES.STRINGS}`), + icons: readFile(`${assetsPath}/${FILES.ICONS}`), + }; + + const webViews = glob.sync(viewsPattern, { noglobstar: true }) + .reduce((acc, curr) => { + const view = readFile(`${path.dirname(curr)}/${FILES.VIEW}`); + const generatedView = { + src: getBundlePath(curr), + ...(assetsAdded ? {} : { meta: { ...assets }}), + }; + + const webView = merge({}, generatedView, view); + + assetsAdded = true; + + return [...acc, webView] + }, []); + + return webViews.length !== 0 ? webViews : null; +} + module.exports = { saveFile, - readFile, - getBundlePath, + getWebView, } \ No newline at end of file diff --git a/plugins/server.js b/plugins/server.js index 8234599259..9266217980 100644 --- a/plugins/server.js +++ b/plugins/server.js @@ -6,5 +6,6 @@ const PORT = 8080; app.use(nocache()); app.use(express.static('dist')); app.use(express.static('json')); +app.use(express.static('config')); app.listen(PORT, () => console.log(`Server listening on port: ${PORT}`)); \ No newline at end of file From 77cbb7af4dff4dac9897ea17787a2a964c4f2380 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Wed, 14 Sep 2022 19:28:47 +0430 Subject: [PATCH 03/54] apps section initial commit --- web/src/config/icons/dark.js | 6 ++ web/src/config/lang/en.json | 25 ++++++ web/src/config/menu.js | 6 ++ web/src/containers/AppDetails/index.js | 55 ++++++++++++ web/src/containers/Apps/All.js | 62 ++++++++++++++ web/src/containers/Apps/User.js | 75 ++++++++++++++++ web/src/containers/Apps/index.js | 114 +++++++++++++++++++++++++ web/src/containers/index.js | 2 + web/src/routes.js | 9 ++ 9 files changed, 354 insertions(+) create mode 100644 web/src/containers/AppDetails/index.js create mode 100644 web/src/containers/Apps/All.js create mode 100644 web/src/containers/Apps/User.js create mode 100644 web/src/containers/Apps/index.js diff --git a/web/src/config/icons/dark.js b/web/src/config/icons/dark.js index 5084dfecd8..79a86fb7b2 100644 --- a/web/src/config/icons/dark.js +++ b/web/src/config/icons/dark.js @@ -39,6 +39,7 @@ const nestedIcons = { SECURITY: '/assets/images/tab-security.svg', VERIFY: '/assets/images/tab-verify.svg', SETTING: '/assets/images/tab-setting.svg', + APPS: '/assets/images/tab-setting.svg', API: '/assets/images/tab-api.svg', STAKE: '/assets/images/stake-page-icon.svg', }, @@ -76,6 +77,11 @@ const nestedIcons = { RISK_MANAGE_WARNING_ICON: '/assets/images/risk-manage-pop-warning.svg', }, + APPS: { + ALL: '/assets/images/tab-setting.svg', + USER: '/assets/images/tab-setting.svg', + }, + SECURITY: { OTP_ICON: '/assets/images/2fa-security-icon.svg', CHANGE_PASSWORD_ICON: '/assets/images/password-security-icon.svg', diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json index 297a45964e..b9f1a85934 100644 --- a/web/src/config/lang/en.json +++ b/web/src/config/lang/en.json @@ -60,6 +60,7 @@ "TAB_VERIFICATION": "Verification", "TAB_SECURITY": "Security", "TAB_SETTINGS": "Settings", + "TAB_APPS": "Apps", "TAB_WALLET": "Wallet", "TAB_SUMMARY": "Summary", "TAB_HISTORY": "History", @@ -471,6 +472,30 @@ "WARNING_POP_UP": "Warning pop ups" } }, + "USER_APPS": { + "TITLE": "Your exchange apps", + "SUBTITLE": "Your exchange account applications information and extra functionality below.", + "ALL_APPS": { + "TAB_TITLE": "All apps", + "TITLE": "Exchange apps", + "SUBTITLE": "Get more functionality from your exchange account by simply selecting an app below and clicking Add button." + }, + "MY_APPS": { + "TAB_TITLE": "My apps", + "TITLE": "My exchange apps", + "SUBTITLE": "Below are your active exchange applications. You can click to see expand on each applications information, functions and add/remove them. Apps are designed to provide more your functionality to your exchange experience." + }, + "TABLE": { + "APP_NAME": "App name", + "DESCRIPTION": "Description", + "ACTION": "Action", + "VIEW_APP": "View app" + }, + "APP_DETAILS": { + "BACK_TO_APPS": "{0} to my apps", + "BACK": "Back" + } + }, "TRANSACTION_HISTORY": { "TITLE": "History", "TITLE_TRADES": "Trades History", diff --git a/web/src/config/menu.js b/web/src/config/menu.js index f2b2125d5b..1d6c719d72 100644 --- a/web/src/config/menu.js +++ b/web/src/config/menu.js @@ -92,6 +92,12 @@ export const MENU_ITEMS = { hide_from_appbar: true, hide_from_bottom_nav: true, }, + { + path: '/apps', + icon_id: 'TAB_APPS', + string_id: 'ACCOUNTS.TAB_APPS', + hide_from_bottom_nav: true, + }, ], bottom: [ { diff --git a/web/src/containers/AppDetails/index.js b/web/src/containers/AppDetails/index.js new file mode 100644 index 0000000000..692d18d72a --- /dev/null +++ b/web/src/containers/AppDetails/index.js @@ -0,0 +1,55 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { isMobile } from 'react-device-detect'; +import { openContactForm } from 'actions/appActions'; +import { IconTitle, HeaderSection, EditWrapper } from 'components'; +import STRINGS from 'config/localizedStrings'; +import withConfig from 'components/ConfigProvider/withConfig'; + +const Index = ({ openContactForm, icons: ICONS, router }) => { + const { + params: { app }, + } = router; + const goBack = () => router.push('/apps'); + + return ( + <div className="presentation_container apply_rtl settings_container"> + {!isMobile && ( + <IconTitle + stringId="ACCOUNTS.TAB_APPS" + text={STRINGS['ACCOUNTS.TAB_APPS']} + textType="title" + iconPath={ICONS['TAB_SETTING']} + iconId={STRINGS['ACCOUNTS.TAB_APPS']} + /> + )} + + <HeaderSection title={app} openContactForm={openContactForm}> + <div className="header-content"> + <div> + <EditWrapper stringId="USER_APPS.APP_DETAILS.BACK_TO_APPS,USER_APPS.APP_DETAILS.BACK"> + {STRINGS.formatString( + STRINGS['USER_APPS.APP_DETAILS.BACK_TO_APPS'], + <span + className="blue-link underline-text pointer" + onClick={goBack} + > + {STRINGS['USER_APPS.APP_DETAILS.BACK']} + </span> + )} + </EditWrapper> + </div> + </div> + </HeaderSection> + </div> + ); +}; + +const mapStateToProps = (state) => ({}); + +const mapDispatchToProps = (dispatch) => ({ + openContactForm: bindActionCreators(openContactForm, dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(withConfig(Index)); diff --git a/web/src/containers/Apps/All.js b/web/src/containers/Apps/All.js new file mode 100644 index 0000000000..17390d7489 --- /dev/null +++ b/web/src/containers/Apps/All.js @@ -0,0 +1,62 @@ +import React from 'react'; +import { IconTitle, EditWrapper, Table } from 'components'; +import STRINGS from 'config/localizedStrings'; +import withConfig from 'components/ConfigProvider/withConfig'; + +const data = [ + { + id: 0, + name: 'Name of the app', + description: 'App description short sentence here', + }, +]; + +const generateHeaders = () => { + return [ + { + stringId: 'USER_APPS.TABLE.APP_NAME', + label: STRINGS['USER_APPS.TABLE.APP_NAME'], + key: 'name', + }, + { + stringId: 'USER_APPS.TABLE.DESCRIPTION', + label: STRINGS['USER_APPS.TABLE.DESCRIPTION'], + key: 'description', + }, + { + label: '', + key: 'name', + }, + ]; +}; + +const All = ({ icons: ICONS }) => { + return ( + <div> + <div className="settings-form-wrapper"> + <div className="settings-form"> + <IconTitle + stringId="USER_APPS.ALL_APPS.TITLE" + text={STRINGS['USER_APPS.ALL_APPS.TITLE']} + textType="title" + iconPath={ICONS['APPS_ALL']} + /> + <div> + <EditWrapper stringId="USER_APPS.ALL_APPS.SUBTITLE"> + {STRINGS['USER_APPS.ALL_APPS.SUBTITLE']} + </EditWrapper> + </div> + <Table + rowClassName="pt-2 pb-2" + headers={generateHeaders()} + count={data.length} + data={data} + rowKey={({ id }) => id} + /> + </div> + </div> + </div> + ); +}; + +export default withConfig(All); diff --git a/web/src/containers/Apps/User.js b/web/src/containers/Apps/User.js new file mode 100644 index 0000000000..075faf8667 --- /dev/null +++ b/web/src/containers/Apps/User.js @@ -0,0 +1,75 @@ +import React from 'react'; +import { IconTitle, EditWrapper, Table } from 'components'; +import STRINGS from 'config/localizedStrings'; +import withConfig from 'components/ConfigProvider/withConfig'; +import { withRouter } from 'react-router'; + +const data = [ + { + id: 0, + name: 'Name of the app', + description: 'App description short sentence here', + }, +]; + +const generateHeaders = (goToDetails) => { + return [ + { + stringId: 'USER_APPS.TABLE.APP_NAME', + label: STRINGS['USER_APPS.TABLE.APP_NAME'], + key: 'name', + }, + { + stringId: 'USER_APPS.TABLE.DESCRIPTION', + label: STRINGS['USER_APPS.TABLE.DESCRIPTION'], + key: 'description', + }, + { + stringId: 'USER_APPS.TABLE.ACTION', + label: STRINGS['USER_APPS.TABLE.ACTION'], + renderCell: ({ id, name }, key) => ( + <td key={`${key}-${id}-app`}> + <span + className="blue-link underline-text pointer" + onClick={() => goToDetails(name)} + > + {STRINGS['USER_APPS.TABLE.VIEW_APP']} + </span> + </td> + ), + }, + ]; +}; + +const User = ({ icons: ICONS, router }) => { + const goToDetails = (name) => router.push(`apps/details/${name}`); + + return ( + <div> + <div className="settings-form-wrapper"> + <div className="settings-form"> + <IconTitle + stringId="USER_APPS.MY_APPS.TITLE" + text={STRINGS['USER_APPS.MY_APPS.TITLE']} + textType="title" + iconPath={ICONS['APPS_USER']} + /> + <div> + <EditWrapper stringId="USER_APPS.MY_APPS.SUBTITLE"> + {STRINGS['USER_APPS.MY_APPS.SUBTITLE']} + </EditWrapper> + </div> + <Table + rowClassName="pt-2 pb-2" + headers={generateHeaders(goToDetails)} + count={data.length} + data={data} + rowKey={({ id }) => id} + /> + </div> + </div> + </div> + ); +}; + +export default withRouter(withConfig(User)); diff --git a/web/src/containers/Apps/index.js b/web/src/containers/Apps/index.js new file mode 100644 index 0000000000..f3d16e8cc0 --- /dev/null +++ b/web/src/containers/Apps/index.js @@ -0,0 +1,114 @@ +import React, { useState, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { isMobile } from 'react-device-detect'; +import STRINGS from 'config/localizedStrings'; +import withConfig from 'components/ConfigProvider/withConfig'; +import { + IconTitle, + HeaderSection, + EditWrapper, + CustomMobileTabs, + TabController, + MobileTabBar, +} from 'components'; +import { openContactForm } from 'actions/appActions'; +import All from './All'; +import User from './User'; + +const Index = ({ icons: ICONS, openContactForm }) => { + const [tabs, setTabs] = useState([]); + const [activeTab, setActiveTab] = useState(); + + useEffect(() => { + updateTabs(); + }, []); + + const updateTabs = () => { + const tabs = [ + { + title: isMobile ? ( + <CustomMobileTabs + title={STRINGS['USER_APPS.ALL_APPS.TAB_TITLE']} + // icon={ICONS['SETTING_NOTIFICATION_ICON']} + /> + ) : ( + <div>{STRINGS['USER_APPS.ALL_APPS.TAB_TITLE']}</div> + ), + content: <All />, + }, + { + title: isMobile ? ( + <CustomMobileTabs + title={STRINGS['USER_APPS.MY_APPS.TAB_TITLE']} + // icon={ICONS['SETTING_NOTIFICATION_ICON']} + /> + ) : ( + <div>{STRINGS['USER_APPS.MY_APPS.TAB_TITLE']}</div> + ), + content: <User />, + }, + ]; + setTabs(tabs); + }; + + const renderContent = (tabs, activeTab) => + tabs[activeTab] && tabs[activeTab].content ? ( + tabs[activeTab].content + ) : ( + <div /> + ); + + return ( + <div className="presentation_container apply_rtl settings_container"> + {!isMobile && ( + <IconTitle + stringId="ACCOUNTS.TAB_APPS" + text={STRINGS['ACCOUNTS.TAB_APPS']} + textType="title" + iconPath={ICONS['TAB_SETTING']} + iconId={STRINGS['ACCOUNTS.TAB_APPS']} + /> + )} + + <HeaderSection + stringId="USER_APPS.TITLE" + title={STRINGS['USER_APPS.TITLE']} + openContactForm={openContactForm} + > + <div className="header-content"> + <div> + <EditWrapper stringId="USER_APPS.SUBTITLE"> + {STRINGS['USER_APPS.SUBTITLE']} + </EditWrapper> + </div> + </div> + </HeaderSection> + + {!isMobile ? ( + <TabController + activeTab={activeTab} + setActiveTab={setActiveTab} + tabs={tabs} + /> + ) : ( + <MobileTabBar + activeTab={activeTab} + renderContent={renderContent} + setActiveTab={setActiveTab} + tabs={tabs} + /> + )} + + {isMobile ? <div className="my-4" /> : renderContent(tabs, activeTab)} + </div> + ); +}; + +const mapStateToProps = (state) => ({}); + +const mapDispatchToProps = (dispatch) => ({ + openContactForm: bindActionCreators(openContactForm, dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(withConfig(Index)); diff --git a/web/src/containers/index.js b/web/src/containers/index.js index 0d72f6f0d3..33cd4d5027 100644 --- a/web/src/containers/index.js +++ b/web/src/containers/index.js @@ -31,6 +31,8 @@ export { default as TermsOfService } from './TermsOfService'; export { default as DepositFunds } from './TermsOfService/DepositFunds'; export { default as Stake } from './Stake'; export { default as StakeDetails } from './StakeDetails'; +export { default as Apps } from './Apps'; +export { default as AppDetails } from './AppDetails'; // ADMIN PAGE export { default as AdminDashboard } from './Admin/Dashboard'; diff --git a/web/src/routes.js b/web/src/routes.js index ace566c1e8..9b7adbfd1e 100644 --- a/web/src/routes.js +++ b/web/src/routes.js @@ -28,6 +28,8 @@ import { AddTradeTabs, Stake, StakeDetails, + Apps, + AppDetails, // ADMIN User, AppWrapper as AdminContainer, @@ -348,6 +350,13 @@ export const generateRoutes = (routes = []) => { component={Account} onEnter={requireAuth} /> + <Route path="apps" name="Apps" component={Apps} onEnter={requireAuth} /> + <Route + path="apps/details/:app" + name="AppDetails" + component={AppDetails} + onEnter={requireAuth} + /> <Route path="summary" name="Summary" From d0000d82e355ddfa3b6ec05ffff6353f6f24f902 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Fri, 16 Sep 2022 16:42:45 +0300 Subject: [PATCH 04/54] Onboarding provide consistent way to navigate back --- web/src/config/lang/en.json | 4 +- .../containers/RequestResetPassword/index.js | 20 +++++++ .../VerificationEmailRequest/index.js | 52 ++++++++++++------- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json index 297a45964e..16c8285730 100644 --- a/web/src/config/lang/en.json +++ b/web/src/config/lang/en.json @@ -234,7 +234,9 @@ }, "VERIFICATION_EMAIL_REQUEST": { "TITLE": "Resend Email Request", - "BUTTON": "Request Email" + "BUTTON": "Request Email", + "SUBTITLE": "Make another email verification request below", + "SUPPORT": "Contact Support" }, "VERIFICATION_EMAIL_REQUEST_SUCCESS": { "TITLE": "Resent Email", diff --git a/web/src/containers/RequestResetPassword/index.js b/web/src/containers/RequestResetPassword/index.js index 9bb9af036c..cc42c206d1 100644 --- a/web/src/containers/RequestResetPassword/index.js +++ b/web/src/containers/RequestResetPassword/index.js @@ -3,6 +3,7 @@ import classnames from 'classnames'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { isMobile } from 'react-device-detect'; +import { Link } from 'react-router'; import { SubmissionError, change } from 'redux-form'; import { requestResetPassword } from 'actions/authAction'; @@ -17,6 +18,23 @@ import { openContactForm } from 'actions/appActions'; let errorTimeOut = null; +const BottomLink = () => ( + <> + <div className={classnames('f-1', 'link_wrapper')}> + {STRINGS['SIGN_UP.HAVE_ACCOUNT']} + <Link to="/login" className={classnames('blue-link')}> + {STRINGS['SIGN_UP.GOTO_LOGIN']} + </Link> + </div> + <div className={classnames('f-1', 'link_wrapper')}> + {STRINGS['LOGIN.NO_ACCOUNT']} + <Link to="/signup" className={classnames('blue-link')}> + {STRINGS['LOGIN.CREATE_ACCOUNT']} + </Link> + </div> + </> +); + class RequestResetPassword extends Component { constructor(props) { super(props); @@ -131,6 +149,7 @@ class RequestResetPassword extends Component { onSubmit={this.onSubmitRequestResetPassword} formFields={formFields} /> + {isMobile && <BottomLink />} </div> </div> )} @@ -149,6 +168,7 @@ class RequestResetPassword extends Component { onClose={this.onCloseDialog} /> </Dialog> + {!isMobile && <BottomLink />} </div> ); } diff --git a/web/src/containers/VerificationEmailRequest/index.js b/web/src/containers/VerificationEmailRequest/index.js index 7cdcc6231b..57795bd28e 100644 --- a/web/src/containers/VerificationEmailRequest/index.js +++ b/web/src/containers/VerificationEmailRequest/index.js @@ -16,12 +16,20 @@ import withConfig from 'components/ConfigProvider/withConfig'; import { openContactForm } from 'actions/appActions'; const BottomLink = () => ( - <div className={classnames('f-1', 'link_wrapper')}> - {STRINGS['VERIFICATION_EMAIL_REQUEST.NO_EMAIL']} - <Link to="/verify" className={classnames('blue-link')}> - {STRINGS['VERIFICATION_EMAIL_REQUEST.REQUEST_EMAIL']} - </Link> - </div> + <> + <div className={classnames('f-1', 'link_wrapper')}> + {STRINGS['SIGN_UP.HAVE_ACCOUNT']} + <Link to="/login" className={classnames('blue-link')}> + {STRINGS['SIGN_UP.GOTO_LOGIN']} + </Link> + </div> + <div className={classnames('f-1', 'link_wrapper')}> + {STRINGS['LOGIN.NO_ACCOUNT']} + <Link to="/signup" className={classnames('blue-link')}> + {STRINGS['LOGIN.CREATE_ACCOUNT']} + </Link> + </div> + </> ); class VerifyEmailRequest extends Component { @@ -113,8 +121,9 @@ class VerifyEmailRequest extends Component { 'login_container' )} > - {isMobile && <MobileBarBack onBackClick={this.onGoBack} />} - + {isMobile && !showContactForm && ( + <MobileBarBack onBackClick={this.onGoBack} /> + )} <div className={classnames( ...FLEX_CENTER_CLASSES, @@ -124,16 +133,6 @@ class VerifyEmailRequest extends Component { 'w-100' )} > - <IconTitle - iconId="EXCHANGE_LOGO" - iconPath={ICONS['EXCHANGE_LOGO']} - stringId="VERIFICATION_EMAIL_REQUEST.TITLE" - text={STRINGS['VERIFICATION_EMAIL_REQUEST.TITLE']} - textType="title" - underline={true} - imageWrapperClassName="auth_logo-wrapper" - className="w-100 holla-logo" - /> <div className={classnames( ...FLEX_CENTER_CLASSES, @@ -143,6 +142,23 @@ class VerifyEmailRequest extends Component { 'w-100' )} > + <IconTitle + iconId="EXCHANGE_LOGO" + iconPath={ICONS['EXCHANGE_LOGO']} + stringId="VERIFICATION_EMAIL_REQUEST.TITLE" + text={STRINGS['VERIFICATION_EMAIL_REQUEST.TITLE']} + textType="title" + underline={true} + imageWrapperClassName="auth_logo-wrapper" + className="w-100 holla-logo" + subtitle={STRINGS['VERIFICATION_EMAIL_REQUEST.SUBTITLE']} + actionProps={{ + text: STRINGS['VERIFICATION_EMAIL_REQUEST.SUPPORT'], + iconPath: ICONS['BLUE_QUESTION'], + onClick: openContactForm, + useSvg: true, + }} + /> <EmailRequestForm onSubmit={this.onSubmitEmailRequest} formFields={formFields} From c4d2aed6b926d7f39c11fbe302b28f6bb32ee6c2 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Fri, 16 Sep 2022 16:50:59 +0300 Subject: [PATCH 05/54] Onboarding, add way to navigate to login or signup --- web/src/containers/Signup/SignupSuccess.js | 65 ++++++++++++++++------ 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/web/src/containers/Signup/SignupSuccess.js b/web/src/containers/Signup/SignupSuccess.js index 44a30d4de0..529f63d3cd 100644 --- a/web/src/containers/Signup/SignupSuccess.js +++ b/web/src/containers/Signup/SignupSuccess.js @@ -3,28 +3,57 @@ import { Link } from 'react-router'; import { IconTitle } from 'components'; import STRINGS from 'config/localizedStrings'; import withConfig from 'components/ConfigProvider/withConfig'; +import classnames from 'classnames'; +import { FLEX_CENTER_CLASSES } from 'config/constants'; + +const BottomLink = () => ( + <> + <div className={classnames('f-1', 'link_wrapper')}> + {STRINGS['SIGN_UP.HAVE_ACCOUNT']} + <Link to="/login" className={classnames('blue-link')}> + {STRINGS['SIGN_UP.GOTO_LOGIN']} + </Link> + </div> + <div className={classnames('f-1', 'link_wrapper')}> + {STRINGS['LOGIN.NO_ACCOUNT']} + <Link to="/signup" className={classnames('blue-link')}> + {STRINGS['LOGIN.CREATE_ACCOUNT']} + </Link> + </div> + </> +); const SignupSuccess = ({ icons: ICONS, ...rest }) => { return ( - <div className="signup_success-wrapper d-flex justify-content-center align-items-center flex-column auth_wrapper"> - <IconTitle - iconId="CHECK" - iconPath={ICONS['CHECK']} - stringId="VERIFICATION_TEXTS.TITLE" - text={STRINGS['VERIFICATION_TEXTS.TITLE']} - textType="title" - className="w-100" - /> - <div className="signup_success-content"> - <p>{STRINGS['VERIFICATION_TEXTS.TEXT_1']}</p> - <p>{STRINGS['VERIFICATION_TEXTS.TEXT_2']}</p> - </div> - <div> - {STRINGS['SIGN_UP.NO_EMAIL']} - <Link to="/verify" className="blue-link"> - {STRINGS['SIGN_UP.REQUEST_EMAIL']} - </Link> + <div + className={classnames( + ...FLEX_CENTER_CLASSES, + 'flex-column', + 'f-1', + 'login_container' + )} + > + <div className="signup_success-wrapper d-flex justify-content-center align-items-center flex-column auth_wrapper"> + <IconTitle + iconId="CHECK" + iconPath={ICONS['CHECK']} + stringId="VERIFICATION_TEXTS.TITLE" + text={STRINGS['VERIFICATION_TEXTS.TITLE']} + textType="title" + className="w-100" + /> + <div className="signup_success-content"> + <p>{STRINGS['VERIFICATION_TEXTS.TEXT_1']}</p> + <p>{STRINGS['VERIFICATION_TEXTS.TEXT_2']}</p> + </div> + <div> + {STRINGS['SIGN_UP.NO_EMAIL']} + <Link to="/verify" className="blue-link"> + {STRINGS['SIGN_UP.REQUEST_EMAIL']} + </Link> + </div> </div> + <BottomLink /> </div> ); }; From d349597007e196ce59c28d84e839f318cccd59a6 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Fri, 16 Sep 2022 16:58:13 +0300 Subject: [PATCH 06/54] After resetting password --- web/src/containers/ResetPassword/ResetPasswordSuccess.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/containers/ResetPassword/ResetPasswordSuccess.js b/web/src/containers/ResetPassword/ResetPasswordSuccess.js index 19df63f5e5..966a750e39 100644 --- a/web/src/containers/ResetPassword/ResetPasswordSuccess.js +++ b/web/src/containers/ResetPassword/ResetPasswordSuccess.js @@ -31,7 +31,7 @@ const ResetPasswordSuccess = ({ {STRINGS['RESET_PASSWORD_SUCCESS.TEXT_1']} </div> )} - <Button label={label} onClick={onClick} className="button-margin" /> + <Button label={label} onClick={onClick} className="button-margin mt-5" /> </div> ); }; From b32ed70e821cd2f6dae129ae92ab43265edc1136 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Fri, 16 Sep 2022 17:18:51 +0300 Subject: [PATCH 07/54] Deposit and withdraws change with diagonal arrows --- web/public/assets/images/blue-deposit-icon.svg | 18 ++++++++++++++++++ web/public/assets/images/blue_withrow_icon.svg | 16 ++++++++++++++++ web/src/config/icons/dark.js | 2 ++ web/src/config/icons/light.js | 2 ++ web/src/containers/Wallet/AssetsBlock.js | 4 ++-- 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 web/public/assets/images/blue-deposit-icon.svg create mode 100644 web/public/assets/images/blue_withrow_icon.svg diff --git a/web/public/assets/images/blue-deposit-icon.svg b/web/public/assets/images/blue-deposit-icon.svg new file mode 100644 index 0000000000..669efbec69 --- /dev/null +++ b/web/public/assets/images/blue-deposit-icon.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"> +<style type="text/css"> + .icon-plus-1{fill:#0000FF;} + .st0{fill:#002BFF;} + .st1{fill:#FFFFFF;} +</style> +<circle id="XMLID_134_" class="icon-plus-1" cx="25" cy="25" r="25"/> +<path id="Path_3_00000016764327731827108580000010424901856094027934_" class="st1" d="M14.7,38.7c-0.9,0.9-2.3,0.9-3.2,0 + c-0.4-0.4-0.6-1-0.6-1.6l0-19.8c0-1.3,1-2.3,2.3-2.2s2.3,1,2.2,2.3l0,19.8C15.4,37.7,15.2,38.2,14.7,38.7L14.7,38.7z"/> +<path id="Path_3_00000047778029988004519910000017533062724939776692_" class="st1" d="M11.5,38.6c-0.9-0.9-0.9-2.3,0-3.2 + c0.4-0.4,1-0.6,1.6-0.6l19.8,0c1.3,0,2.3,1,2.2,2.3s-1,2.3-2.3,2.2l-19.8,0C12.5,39.3,11.9,39,11.5,38.6L11.5,38.6z"/> +<path id="Path_3_00000010272100705195573310000003847338887338401679_" class="st1" d="M13.1,39.3c-1.3,0-2.3-1.1-2.2-2.3 + c0-0.6,0.3-1.2,0.7-1.6l23.7-23.8c0.9-0.9,2.3-0.9,3.2,0c0.9,0.9,0.9,2.3,0,3.2L14.7,38.6C14.3,39.1,13.7,39.3,13.1,39.3L13.1,39.3z + "/> +</svg> diff --git a/web/public/assets/images/blue_withrow_icon.svg b/web/public/assets/images/blue_withrow_icon.svg new file mode 100644 index 0000000000..a7171332e5 --- /dev/null +++ b/web/public/assets/images/blue_withrow_icon.svg @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"> + <style type="text/css"> + .icon-plus-1{fill:#0000FF;} + .st0{fill:#002BFF;} + .st1{fill:#FFFFFF;} +</style> + <circle id="XMLID_134_" class="icon-plus-1" cx="25" cy="25" r="25" /> + <path id="Path_3_00000016764327731827108580000010424901856094027934_" class="st1" d="M35.3,11.6c0.9-0.9,2.3-0.9,3.2,0 + c0.4,0.4,0.6,1,0.6,1.6l0,19.8c0,1.3-1,2.3-2.3,2.2s-2.3-1-2.2-2.3l0-19.8C34.6,12.6,34.8,12.1,35.3,11.6L35.3,11.6z" /> + <path id="Path_3_00000047778029988004519910000017533062724939776692_" class="st1" d="M38.5,11.7c0.9,0.9,0.9,2.3,0,3.2 + c-0.4,0.4-1,0.6-1.6,0.6l-19.8,0c-1.3,0-2.3-1-2.2-2.3c0-1.3,1-2.3,2.3-2.2l19.8,0C37.5,11,38.1,11.2,38.5,11.7L38.5,11.7z" /> + <path id="Path_3_00000010272100705195573310000003847338887338401679_" class="st1" d="M36.9,11c1.3,0,2.3,1.1,2.2,2.3 + c0,0.6-0.3,1.2-0.7,1.6L14.7,38.7c-0.9,0.9-2.3,0.9-3.2,0c-0.9-0.9-0.9-2.3,0-3.2l23.7-23.7C35.7,11.2,36.3,11,36.9,11L36.9,11z" /> +</svg> \ No newline at end of file diff --git a/web/src/config/icons/dark.js b/web/src/config/icons/dark.js index 080620d4b1..c3613bd335 100644 --- a/web/src/config/icons/dark.js +++ b/web/src/config/icons/dark.js @@ -182,6 +182,8 @@ const nestedIcons = { SESSION_TIMED_OUT: '/assets/images/session-timed-out.svg', BLUE_EDIT: '/assets/images/blue-edit-exir-icon.svg', BLUE_PLUS: '/assets/images/max-plus-blue-icon.svg', + BLUE_DEPOSIT_ICON: '/assets/images/blue-deposit-icon.svg', + BLUE_WITHROW_ICON: '/assets/images/blue_withrow_icon.svg', BLUE_TIMER: '/assets/images/timer-icon.svg', NOTIFICATION_VERIFICATION_WARNING: '/assets/images/verification.svg', diff --git a/web/src/config/icons/light.js b/web/src/config/icons/light.js index 3a3b766872..63ab53b150 100644 --- a/web/src/config/icons/light.js +++ b/web/src/config/icons/light.js @@ -167,6 +167,8 @@ const nestedIcons = { SESSION_TIMED_OUT: '/assets/images/session-timed-out.svg', BLUE_EDIT: '/assets/images/blue-edit-exir-icon.svg', BLUE_PLUS: '/assets/images/max-plus-blue-icon.svg', + BLUE_DEPOSIT_ICON: '/assets/images/blue-deposit-icon.svg', + BLUE_WITHROW_ICON: '/assets/images/blue_withrow_icon.svg', BLUE_TIMER: '/assets/images/timer-icon.svg', NOTIFICATION_VERIFICATION_WARNING: '/assets/images/verification.svg', diff --git a/web/src/containers/Wallet/AssetsBlock.js b/web/src/containers/Wallet/AssetsBlock.js index 9b99c555b6..9b3a22d0be 100644 --- a/web/src/containers/Wallet/AssetsBlock.js +++ b/web/src/containers/Wallet/AssetsBlock.js @@ -301,7 +301,7 @@ const AssetsBlock = ({ stringId="WALLET_BUTTON_BASE_DEPOSIT" text={STRINGS['WALLET_BUTTON_BASE_DEPOSIT']} iconId="BLUE_PLUS" - iconPath={ICONS['BLUE_PLUS']} + iconPath={ICONS['BLUE_DEPOSIT_ICON']} onClick={() => navigate(`wallet/${key}/deposit`)} className="csv-action action-button-wrapper" showActionText={isMobile} @@ -311,7 +311,7 @@ const AssetsBlock = ({ stringId="WALLET_BUTTON_BASE_WITHDRAW" text={STRINGS['WALLET_BUTTON_BASE_WITHDRAW']} iconId="BLUE_PLUS" - iconPath={ICONS['BLUE_PLUS']} + iconPath={ICONS['BLUE_WITHROW_ICON']} onClick={() => navigate(`wallet/${key}/withdraw`)} className="csv-action action-button-wrapper" showActionText={isMobile} From 1ac2f4de282a4370093abe739c58f5f4e799a5a8 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Fri, 16 Sep 2022 17:48:47 +0300 Subject: [PATCH 08/54] History icon --- web/public/assets/images/clock.svg | 12 ++++++++++++ web/src/config/icons/static.js | 1 + web/src/containers/Wallet/MainWallet.js | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 web/public/assets/images/clock.svg diff --git a/web/public/assets/images/clock.svg b/web/public/assets/images/clock.svg new file mode 100644 index 0000000000..ed49f1a34a --- /dev/null +++ b/web/public/assets/images/clock.svg @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#FFFFFF;} +</style> +<path id="Path_3_00000049195749705309616170000002146436606352155561_" class="st0" d="M23.2,26.8c-0.9-0.9-0.9-2.3,0-3.2 + c0.4-0.4,1-0.7,1.6-0.7l18.5-0.1c1.3,0,2.3,1,2.3,2.3c0,1.3-1,2.3-2.3,2.3l-18.5,0.1C24.2,27.5,23.6,27.2,23.2,26.8L23.2,26.8z"/> +<path id="Path_3_00000141440866148849312550000016656160126446402465_" class="st0" d="M26.3,26.8c-0.9,0.9-2.3,0.9-3.2,0 + c-0.4-0.4-0.7-1-0.7-1.6l-0.2-13.8c0-1.3,1-2.3,2.3-2.3s2.3,1,2.3,2.3L27,25.1C27,25.7,26.7,26.3,26.3,26.8L26.3,26.8z"/> +</svg> diff --git a/web/src/config/icons/static.js b/web/src/config/icons/static.js index d3166c01d8..2ddc6e8dfb 100644 --- a/web/src/config/icons/static.js +++ b/web/src/config/icons/static.js @@ -144,6 +144,7 @@ const icons = { FIAT_PLUGIN: '/assets/images/fiat-plugin.svg', DOLLAR_GEAR: '/assets/images/single-dollar-gear.svg', SWITCH_ASSET_FOR_FEES: '/assets/images/switch-asset-for-fees.svg', + CLOCK: '/assets/images/clock.svg', }; export default icons; diff --git a/web/src/containers/Wallet/MainWallet.js b/web/src/containers/Wallet/MainWallet.js index e02e97f302..11ea2b6971 100644 --- a/web/src/containers/Wallet/MainWallet.js +++ b/web/src/containers/Wallet/MainWallet.js @@ -182,7 +182,7 @@ class Wallet extends Component { text: STRINGS['TRADE_HISTORY'], status: 'information', iconId: 'PAPER_CLIP', - iconPath: STATIC_ICONS['PAPER_CLIP'], + iconPath: STATIC_ICONS['CLOCK'], allowClick: true, className: isOpen ? 'paper-clip-icon' From c91987d644cece10c7b0c4e26f329c89ed219e52 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Fri, 16 Sep 2022 17:57:42 +0300 Subject: [PATCH 09/54] TRADE and EARN icon --- web/public/assets/images/earn.svg | 20 ++++++++++++++++++++ web/public/assets/images/trade.svg | 14 ++++++++++++++ web/src/config/icons/dark.js | 2 ++ web/src/config/icons/light.js | 2 ++ web/src/containers/Wallet/AssetsBlock.js | 8 ++++---- 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 web/public/assets/images/earn.svg create mode 100644 web/public/assets/images/trade.svg diff --git a/web/public/assets/images/earn.svg b/web/public/assets/images/earn.svg new file mode 100644 index 0000000000..2b4bdf18b6 --- /dev/null +++ b/web/public/assets/images/earn.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#FFFFFF;} + .icon-plus-1{fill:#0000FF;} +</style> +<circle id="XMLID_134_" class="icon-plus-1" cx="25" cy="25" r="25"/> +<g id="Group_1" transform="translate(-1288.505 -307.413)"> + <path id="Path_3" class="st0" d="M1296.1,352.1c-1.3,0-2.3-1-2.3-2.3c0-0.6,0.2-1.2,0.7-1.6l35-35c0.9-0.9,2.3-0.9,3.2,0 + c0.9,0.9,0.9,2.3,0,3.2l-35,35C1297.3,351.9,1296.7,352.1,1296.1,352.1L1296.1,352.1z"/> + <path id="Path_4" class="st0" d="M1301.4,328.7c-4.8,0-8.6-3.9-8.6-8.6c0-4.8,3.9-8.6,8.6-8.6c4.8,0,8.6,3.9,8.6,8.6 + c0,2.3-0.9,4.5-2.5,6.1C1305.9,327.8,1303.7,328.7,1301.4,328.7z M1301.4,316c-2.2,0-4.1,1.8-4.1,4.1c0,2.2,1.8,4.1,4.1,4.1 + c2.2,0,4.1-1.8,4.1-4.1c0-1.1-0.4-2.1-1.2-2.9C1303.5,316.4,1302.5,316,1301.4,316z"/> + <path id="Path_5" class="st0" d="M1325.9,353.2c-2.3,0-4.5-0.9-6.1-2.5l0,0c-3.4-3.4-3.4-8.8,0-12.2c3.4-3.4,8.8-3.4,12.2,0 + c3.4,3.4,3.4,8.8,0,12.2C1330.4,352.3,1328.2,353.2,1325.9,353.2z M1323,347.5c1.6,1.6,4.2,1.6,5.7,0c1.6-1.6,1.6-4.2,0-5.7 + c-1.6-1.6-4.2-1.6-5.7,0c-1.7,1.5-1.9,3.9-0.4,5.6C1322.7,347.4,1322.8,347.5,1323,347.5L1323,347.5z"/> +</g> +</svg> diff --git a/web/public/assets/images/trade.svg b/web/public/assets/images/trade.svg new file mode 100644 index 0000000000..a3dfa468a1 --- /dev/null +++ b/web/public/assets/images/trade.svg @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"> +<style type="text/css"> + .st0{fill:#FFFFFF;} + .icon-plus-1{fill:#0000FF;} +</style> +<circle id="XMLID_134_" class="icon-plus-1" cx="25" cy="25" r="25"/> +<path id="Union_1" class="st0" d="M4.9,36.6c-0.8-1.1-0.8-2.5,0-3.6l11.1-14.3c0.3-0.5,0.9-0.8,1.5-0.7c0.6-0.1,1.2,0.2,1.6,0.6 + l9.4,10.2l13.4-16.2c0.7-1,2.1-1.2,3-0.4c0.2,0.1,0.3,0.3,0.4,0.4c1,1.2,1,3,0,4.2l-14,16.9c-0.4,0.5-1.1,0.9-1.7,0.9 + c-0.1,0-0.2,0-0.3,0c-0.1,0-0.2,0-0.3,0c-0.5,0-1.1-0.2-1.4-0.6l-9.8-10.6L7.6,36.6c-0.3,0.4-0.8,0.7-1.4,0.7 + C5.7,37.3,5.2,37,4.9,36.6z"/> +</svg> diff --git a/web/src/config/icons/dark.js b/web/src/config/icons/dark.js index c3613bd335..7b6ad2c879 100644 --- a/web/src/config/icons/dark.js +++ b/web/src/config/icons/dark.js @@ -181,6 +181,8 @@ const nestedIcons = { BLUE_ARROW_RIGHT: '/assets/images/blue-arrow-right.svg', SESSION_TIMED_OUT: '/assets/images/session-timed-out.svg', BLUE_EDIT: '/assets/images/blue-edit-exir-icon.svg', + BLUE_TRADE_ICON: '/assets/images/trade.svg', + BLUE_EARN_ICON: '/assets/images/earn.svg', BLUE_PLUS: '/assets/images/max-plus-blue-icon.svg', BLUE_DEPOSIT_ICON: '/assets/images/blue-deposit-icon.svg', BLUE_WITHROW_ICON: '/assets/images/blue_withrow_icon.svg', diff --git a/web/src/config/icons/light.js b/web/src/config/icons/light.js index 63ab53b150..754d950158 100644 --- a/web/src/config/icons/light.js +++ b/web/src/config/icons/light.js @@ -168,6 +168,8 @@ const nestedIcons = { BLUE_EDIT: '/assets/images/blue-edit-exir-icon.svg', BLUE_PLUS: '/assets/images/max-plus-blue-icon.svg', BLUE_DEPOSIT_ICON: '/assets/images/blue-deposit-icon.svg', + BLUE_TRADE_ICON: '/assets/images/trade.svg', + BLUE_EARN_ICON: '/assets/images/earn.svg', BLUE_WITHROW_ICON: '/assets/images/blue_withrow_icon.svg', BLUE_TIMER: '/assets/images/timer-icon.svg', diff --git a/web/src/containers/Wallet/AssetsBlock.js b/web/src/containers/Wallet/AssetsBlock.js index 9b3a22d0be..560d6e9cc7 100644 --- a/web/src/containers/Wallet/AssetsBlock.js +++ b/web/src/containers/Wallet/AssetsBlock.js @@ -324,8 +324,8 @@ const AssetsBlock = ({ <ActionNotification stringId="TRADE_TAB_TRADE" text={STRINGS['TRADE_TAB_TRADE']} - iconId="BLUE_PLUS" - iconPath={ICONS['BLUE_PLUS']} + iconId="BLUE_TRADE_ICON" + iconPath={ICONS['BLUE_TRADE_ICON']} onClick={() => goToTrade(pair)} className="csv-action" showActionText={isMobile} @@ -338,8 +338,8 @@ const AssetsBlock = ({ <ActionNotification stringId="STAKE.EARN" text={STRINGS['STAKE.EARN']} - iconId="BLUE_PLUS" - iconPath={ICONS['BLUE_PLUS']} + iconId="BLUE_EARN_ICON" + iconPath={ICONS['BLUE_EARN_ICON']} onClick={() => navigate('/stake')} className="csv-action" showActionText={isMobile} From 59ed42c6a44da78625581c23c51ffcb8dffcb823 Mon Sep 17 00:00:00 2001 From: ram <ram@bitholla.com> Date: Fri, 16 Sep 2022 20:33:02 +0530 Subject: [PATCH 10/54] Changes for the common button component with mentioned behaviours --- web/src/components/AdminForm/hoc.js | 12 +++---- web/src/components/FormButton/Button.js | 31 +++++++++++++++++++ .../Admin/General/EmailVerificationForm.js | 13 ++++---- .../containers/Admin/General/FooterForm.js | 15 +++++---- .../containers/Admin/General/InterfaceForm.js | 10 ++++-- .../Admin/General/PublishSection.js | 16 +++++----- .../Admin/Settings/CustomizeEmailForm.js | 10 +++--- 7 files changed, 71 insertions(+), 36 deletions(-) create mode 100644 web/src/components/FormButton/Button.js diff --git a/web/src/components/AdminForm/hoc.js b/web/src/components/AdminForm/hoc.js index d82451e089..b31de35f46 100644 --- a/web/src/components/AdminForm/hoc.js +++ b/web/src/components/AdminForm/hoc.js @@ -3,6 +3,7 @@ import renderFields from './utils'; import { reduxForm, reset, getFormValues } from 'redux-form'; import { Button } from 'antd'; import { connect } from 'react-redux'; +import FormButton from 'components/FormButton/Button'; const Form = (name, className = '', allowPristine = false) => { const HocForm = ({ @@ -49,9 +50,9 @@ const Form = (name, className = '', allowPristine = false) => { {secondaryBtnTxt} </Button> ) : null} - <Button + <FormButton type={buttonType ? buttonType : 'primary'} - onClick={handleSubmit(onSubmit)} + handleSubmit={handleSubmit(onSubmit)} disabled={ disableAllFields || (allowPristine ? false : fields && pristine) || @@ -63,9 +64,8 @@ const Form = (name, className = '', allowPristine = false) => { size={small ? 'small' : 'large'} className={small ? `${buttonClass}` : `w-100 ${buttonClass}`} style={small ? { float: 'right' } : null} - > - {buttonText} - </Button> + buttonText={buttonText} + /> </form> ); }; @@ -78,7 +78,7 @@ const Form = (name, className = '', allowPristine = false) => { })(HocForm); const mapStateToProps = (state) => ({ - formValues: getFormValues(name)(state) + formValues: getFormValues(name)(state), }); return connect(mapStateToProps)(CommonHocForm); }; diff --git a/web/src/components/FormButton/Button.js b/web/src/components/FormButton/Button.js new file mode 100644 index 0000000000..871e9988e1 --- /dev/null +++ b/web/src/components/FormButton/Button.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { Button } from 'antd'; + +const FormButton = ({ + type = 'primary', + handleSubmit = () => {}, + disabled = true, + size, + className = '', + style = null, + buttonText = '', + htmlType = '', +}) => { + return ( + <div> + <Button + type={type} + onClick={handleSubmit} + disabled={disabled} + size={size} + className={className} + style={style} + htmlType={htmlType} + > + {buttonText} + </Button> + </div> + ); +}; + +export default FormButton; diff --git a/web/src/containers/Admin/General/EmailVerificationForm.js b/web/src/containers/Admin/General/EmailVerificationForm.js index c7be2202ec..ceddd9960e 100644 --- a/web/src/containers/Admin/General/EmailVerificationForm.js +++ b/web/src/containers/Admin/General/EmailVerificationForm.js @@ -1,7 +1,9 @@ import React, { useEffect, useState } from 'react'; -import { Button, Checkbox, Form } from 'antd'; +import { Checkbox, Form } from 'antd'; import { InfoCircleFilled } from '@ant-design/icons'; +import FormButton from 'components/FormButton/Button'; + const { Item } = Form; const EmailVerificationForm = ({ @@ -71,14 +73,13 @@ const EmailVerificationForm = ({ </div> </div> <div> - <Button + <FormButton type="primary" htmlType="submit" - className="green-btn minimal-btn" disabled={isDisable || buttonSubmitting} - > - Save - </Button> + className="green-btn minimal-btn" + buttonText="Save" + /> </div> </Form> </div> diff --git a/web/src/containers/Admin/General/FooterForm.js b/web/src/containers/Admin/General/FooterForm.js index a5ad37b2b3..9bafde762a 100644 --- a/web/src/containers/Admin/General/FooterForm.js +++ b/web/src/containers/Admin/General/FooterForm.js @@ -5,9 +5,10 @@ import { Button } from 'antd'; import _findLast from 'lodash/findLast'; import _findLastKey from 'lodash/findLastKey'; import isEqual from 'lodash.isequal'; +import debounce from 'lodash.debounce'; import renderFields from '../../../components/AdminForm/utils'; -import debounce from 'lodash.debounce'; +import FormButton from 'components/FormButton/Button'; class FormWrapper extends Component { componentDidMount() { @@ -114,16 +115,14 @@ class FormWrapper extends Component { {customFields ? this.renderCustomFields(fields) : renderFields(fields, getFieldDecorator, initialValues)} - <Button - block + <FormButton type="primary" + handleSubmit={handleSubmit(this.onSubmit)} htmlType="submit" - className="green-btn minimal-btn" - onClick={handleSubmit(this.onSubmit)} disabled={buttonSubmitting} - > - {buttonTxt} - </Button> + className="green-btn minimal-btn" + buttonText={buttonTxt} + /> </form> </div> ); diff --git a/web/src/containers/Admin/General/InterfaceForm.js b/web/src/containers/Admin/General/InterfaceForm.js index 46832cad84..e51fddcfb7 100644 --- a/web/src/containers/Admin/General/InterfaceForm.js +++ b/web/src/containers/Admin/General/InterfaceForm.js @@ -5,6 +5,7 @@ import classnames from 'classnames'; import _isEqual from 'lodash/isEqual'; import { STATIC_ICONS } from 'config/icons'; +import FormButton from 'components/FormButton/Button'; const { Item } = Form; @@ -264,9 +265,12 @@ const InterfaceForm = ({ </div> ) : null} <div> - <Button type="primary" htmlType="submit" disabled={isSubmit}> - Save - </Button> + <FormButton + type="primary" + htmlType="submit" + disabled={isSubmit} + buttonText="save" + /> </div> </Form> </div> diff --git a/web/src/containers/Admin/General/PublishSection.js b/web/src/containers/Admin/General/PublishSection.js index ebb2306292..92be29c659 100644 --- a/web/src/containers/Admin/General/PublishSection.js +++ b/web/src/containers/Admin/General/PublishSection.js @@ -1,5 +1,7 @@ import React from 'react'; -import { Button, Collapse } from 'antd'; +import { Collapse } from 'antd'; + +import FormButton from 'components/FormButton/Button'; const PublishSection = ({ title = '', @@ -54,17 +56,15 @@ const PublishSection = ({ ) : null} </Collapse> </div> - <Button + <FormButton type="primary" - className="green-btn minimal-btn" - loading={loadingButton && currentPublishType === currentkey} - onClick={() => handlePublish(currentkey)} + handleSubmit={() => handlePublish(currentkey)} disabled={ !isPublishDisable || (isPublishDisable && updatedKey !== currentkey) } - > - Publish - </Button> + className="green-btn minimal-btn" + buttonText="Publish" + /> </div> ); }; diff --git a/web/src/containers/Admin/Settings/CustomizeEmailForm.js b/web/src/containers/Admin/Settings/CustomizeEmailForm.js index 712a923835..d71792a2d2 100644 --- a/web/src/containers/Admin/Settings/CustomizeEmailForm.js +++ b/web/src/containers/Admin/Settings/CustomizeEmailForm.js @@ -7,6 +7,7 @@ import debounce from 'lodash.debounce'; import { updateEmailStrings } from '../General/action'; import { STATIC_ICONS } from 'config/icons'; +import FormButton from 'components/FormButton/Button'; const { TextArea } = Input; const { Option } = Select; @@ -383,14 +384,13 @@ const CustomizeEmailForm = ({ )} </div> </div> - <Button + <FormButton type="primary" - className="green-btn" htmlType="submit" disabled={buttonSubmitting} - > - Save - </Button> + className="green-btn" + buttonText="Save" + /> </Form> <Modal visible={isModalVisible} From 396630ea70775eed33d8f9ad698e291229a54c62 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Tue, 20 Sep 2022 05:50:39 +0300 Subject: [PATCH 11/54] Drop down arrow, flip it when active and flip it. --- web/src/components/AppBar/ThemeSwitcher.js | 8 +++++--- .../Form/TradeFormFields/DropDown.js | 8 +++++--- web/src/containers/Trade/components/Filters.js | 10 +++++++--- .../containers/Trade/components/Orderbook.js | 14 +++++++++++--- .../Trade/components/TradeHistory.js | 18 +++++++++++++----- 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/web/src/components/AppBar/ThemeSwitcher.js b/web/src/components/AppBar/ThemeSwitcher.js index ae7c765168..ffe66657f6 100644 --- a/web/src/components/AppBar/ThemeSwitcher.js +++ b/web/src/components/AppBar/ThemeSwitcher.js @@ -1,14 +1,15 @@ -import React from 'react'; +import React, { useState } from 'react'; import classnames from 'classnames'; import Image from 'components/Image'; import { FLEX_CENTER_CLASSES } from 'config/constants'; import withConfig from 'components/ConfigProvider/withConfig'; import { Select } from 'antd'; -import { CaretDownOutlined } from '@ant-design/icons'; +import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'; const { Option } = Select; const ThemeSwitcher = ({ selected, options = [], toggle, icons: ICONS }) => { + const [isOpen, setIsOpen] = useState(false); const handleClick = () => { const theme = options[0].value === selected ? options[1].value : options[0].value; @@ -72,7 +73,8 @@ const ThemeSwitcher = ({ selected, options = [], toggle, icons: ICONS }) => { size="small" onSelect={toggle} bordered={false} - suffixIcon={<CaretDownOutlined />} + onClick={() => setIsOpen((prev) => !prev)} + suffixIcon={isOpen ? <CaretUpOutlined /> : <CaretDownOutlined />} className="custom-select-input-style appbar elevated" dropdownClassName="custom-select-style select-option-wrapper" > diff --git a/web/src/components/Form/TradeFormFields/DropDown.js b/web/src/components/Form/TradeFormFields/DropDown.js index 579971265f..1ed7787b98 100644 --- a/web/src/components/Form/TradeFormFields/DropDown.js +++ b/web/src/components/Form/TradeFormFields/DropDown.js @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Select } from 'antd'; -import { CaretDownOutlined } from '@ant-design/icons'; +import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'; import STRINGS from 'config/localizedStrings'; const { Option } = Select; @@ -8,6 +8,7 @@ const { Option } = Select; // todo: add antd component to redux form const DropDown = (props) => { + const [isOpen, setIsOpen] = useState(false); const { input: { onChange, value }, options, @@ -22,7 +23,8 @@ const DropDown = (props) => { bordered={false} size="small" onChange={onChange} - suffixIcon={<CaretDownOutlined />} + onClick={setIsOpen((prev) => !prev)} + suffixIcon={isOpen ? <CaretUpOutlined /> : <CaretDownOutlined />} className="custom-select-input-style w-100 elevated" dropdownClassName="custom-select-style select-option-wrapper" > diff --git a/web/src/containers/Trade/components/Filters.js b/web/src/containers/Trade/components/Filters.js index b45bdd5a58..6213d51d98 100644 --- a/web/src/containers/Trade/components/Filters.js +++ b/web/src/containers/Trade/components/Filters.js @@ -1,12 +1,13 @@ -import React from 'react'; +import React, { useState } from 'react'; import { connect } from 'react-redux'; import { Select } from 'antd'; -import { CaretDownOutlined } from '@ant-design/icons'; +import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'; import STRINGS from 'config/localizedStrings'; const { Option } = Select; const Filters = ({ pairs, pair, onChange }) => { + const [isOpen, setIsOpen] = useState(false); return ( <div> <Select @@ -17,7 +18,10 @@ const Filters = ({ pairs, pair, onChange }) => { className="custom-select-input-style elevated" dropdownClassName="custom-select-style" bordered={false} - suffixIcon={<CaretDownOutlined />} + suffixIcon={isOpen ? <CaretUpOutlined /> : <CaretDownOutlined />} + onClick={() => { + setIsOpen((prev) => !prev); + }} value={pair} onChange={onChange} > diff --git a/web/src/containers/Trade/components/Orderbook.js b/web/src/containers/Trade/components/Orderbook.js index f4920ef821..982d4648f0 100644 --- a/web/src/containers/Trade/components/Orderbook.js +++ b/web/src/containers/Trade/components/Orderbook.js @@ -55,6 +55,7 @@ class Orderbook extends Component { priceDiff: 0, inProp: false, isAnimated: false, + isDropdownOpen: false, }; componentDidMount() { @@ -296,10 +297,17 @@ class Orderbook extends Component { bordered={false} defaultValue={false} size="small" + onClick={() => { + this.setState({ isDropdownOpend: !this.state.isDropdownOpen }); + }} suffixIcon={ - <CaretDownOutlined - onClick={() => this.dropdownVisibleChange(!isOpen)} - /> + this.isDropdownOpen ? ( + <CaretUpOutlined /> + ) : ( + <CaretDownOutlined + onClick={() => this.dropdownVisibleChange(!isOpen)} + /> + ) } value={isBase} onSelect={this.onSelect} diff --git a/web/src/containers/Trade/components/TradeHistory.js b/web/src/containers/Trade/components/TradeHistory.js index c04a916871..6e772f0225 100644 --- a/web/src/containers/Trade/components/TradeHistory.js +++ b/web/src/containers/Trade/components/TradeHistory.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { Component, useState } from 'react'; import classnames from 'classnames'; import { connect } from 'react-redux'; import { ReactSVG } from 'react-svg'; @@ -12,7 +12,7 @@ import { tradeHistorySelector } from '../utils'; import withConfig from 'components/ConfigProvider/withConfig'; import { calcPercentage } from 'utils/math'; import { Select } from 'antd'; -import { CaretDownOutlined } from '@ant-design/icons'; +import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'; import math from 'mathjs'; import { opacifyNumber } from 'helpers/opacify'; @@ -86,6 +86,7 @@ class TradeHistory extends Component { const { isBase, isOpen } = this.state; const { pairData } = this.props; const { pair_base_display, pair_2_display } = pairData; + const { isDropdownOpen, setIsDropdownOpen } = useState(false); return [ { @@ -126,10 +127,17 @@ class TradeHistory extends Component { bordered={false} defaultValue={false} size="small" + onClick={() => { + setIsDropdownOpen((prev) => !prev); + }} suffixIcon={ - <CaretDownOutlined - onClick={() => this.dropdownVisibleChange(!isOpen)} - /> + isDropdownOpen ? ( + <CaretUpOutlined /> + ) : ( + <CaretDownOutlined + onClick={() => this.dropdownVisibleChange(!isOpen)} + /> + ) } value={isBase} onSelect={this.onSelect} From 68a9af1f253d2766570a316aa01441e7721f73a1 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Tue, 20 Sep 2022 06:00:35 +0300 Subject: [PATCH 12/54] Add a hover effect on the coin area in wallet --- web/src/containers/Wallet/AssetsBlock.js | 2 +- web/src/containers/Wallet/_Wallet.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/web/src/containers/Wallet/AssetsBlock.js b/web/src/containers/Wallet/AssetsBlock.js index 560d6e9cc7..82992aee10 100644 --- a/web/src/containers/Wallet/AssetsBlock.js +++ b/web/src/containers/Wallet/AssetsBlock.js @@ -245,7 +245,7 @@ const AssetsBlock = ({ </td> <td className="td-name td-fit"> {sortedSearchResults && loading ? ( - <div className="d-flex align-items-center"> + <div className="d-flex align-items-center wallet-hover cursor-pointer"> <Link to={`/wallet/${key.toLowerCase()}`}> <Image iconId={icon_id} diff --git a/web/src/containers/Wallet/_Wallet.scss b/web/src/containers/Wallet/_Wallet.scss index 147710c275..7f0d7a527d 100644 --- a/web/src/containers/Wallet/_Wallet.scss +++ b/web/src/containers/Wallet/_Wallet.scss @@ -2,6 +2,10 @@ $wrapper-border: 1px solid $colors-main-black; $wrapper-button-margin: 2.5rem; $header-margin: 2rem; +.wallet-hover:hover { + opacity: 0.5; +} + .layout-mobile { .button-container { min-height: 4.5rem; From 829b864e66e825f934ea551788c2e01e4d46559e Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 20 Sep 2022 10:26:55 +0430 Subject: [PATCH 13/54] change for default name and short_name in manifest json --- web/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/index.js b/web/src/index.js index 30b4462b4c..fcabd49b29 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -252,7 +252,7 @@ const bootstrapApp = ( app: { remoteRoutes, plugins, - info: { name }, + constants: { api_name: name }, }, } = store.getState(); From 3b010d057f170e24b4341c30d82f2d72bc104c37 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Wed, 21 Sep 2022 00:58:06 +0900 Subject: [PATCH 14/54] app key is added for user settings --- server/constants.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/constants.js b/server/constants.js index b9c7965805..c48499c94e 100644 --- a/server/constants.js +++ b/server/constants.js @@ -302,7 +302,8 @@ exports.SETTING_KEYS = [ 'interface', 'audio', 'risk', - 'chat' + 'chat', + 'app' ]; exports.OMITTED_USER_FIELDS = [ From acab2c7705617ceeea8897065e73e5e63c9d8928 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Wed, 21 Sep 2022 01:00:08 +0900 Subject: [PATCH 15/54] version update --- server/api/swagger/swagger.yaml | 2 +- server/package.json | 2 +- version | 2 +- web/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/api/swagger/swagger.yaml b/server/api/swagger/swagger.yaml index 5d372506c5..877101e4d2 100644 --- a/server/api/swagger/swagger.yaml +++ b/server/api/swagger/swagger.yaml @@ -1,6 +1,6 @@ swagger: "2.0" info: - version: "2.4.2" + version: "2.4.3" title: HollaEx Kit host: api.hollaex.com basePath: /v2 diff --git a/server/package.json b/server/package.json index ec402c1f6f..6056dc4527 100644 --- a/server/package.json +++ b/server/package.json @@ -1,5 +1,5 @@ { - "version": "2.4.2", + "version": "2.4.3", "private": false, "description": "HollaEx Kit", "keywords": [ diff --git a/version b/version index acdc3f1b0b..6550da6970 100644 --- a/version +++ b/version @@ -1 +1 @@ -2.4.2 \ No newline at end of file +2.4.3 \ No newline at end of file diff --git a/web/package.json b/web/package.json index bcc101e34a..0aebc5b911 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "hollaex-kit", - "version": "2.4.2", + "version": "2.4.3", "private": true, "dependencies": { "@ant-design/compatible": "1.0.5", From 39783a6dda27e07a493de25b7f6d9e5c80f7f224 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Wed, 21 Sep 2022 16:42:22 +0900 Subject: [PATCH 16/54] removed files --- plugins/LICENSE | 21 -- plugins/test.js | 917 ------------------------------------------------ 2 files changed, 938 deletions(-) delete mode 100644 plugins/LICENSE delete mode 100644 plugins/test.js diff --git a/plugins/LICENSE b/plugins/LICENSE deleted file mode 100644 index dd6bdf83ca..0000000000 --- a/plugins/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2019 Paciolan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE -OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/plugins/test.js b/plugins/test.js deleted file mode 100644 index 3cffb46496..0000000000 --- a/plugins/test.js +++ /dev/null @@ -1,917 +0,0 @@ -'use strict'; - -const crypto = require('crypto'); - -const { - meta, - publicMeta, - toolsLib, - lodash, - moment, - app, - loggerPlugin, - expressValidator, - bluebird, - rp -} = this; - -const { - webhook_secret: { value: WEBHOOK_SECRET }, - client_secret: { value: CLIENT_SECRET }, - manual_review: { value: MANUAL_REVIEW } -} = meta; -const { - client_id: { value: CLIENT_ID }, - flow_id: { value: FLOW_ID } -} = publicMeta; - -const VERIFY_STATUS = { - EMPTY: 0, - PENDING: 1, - REJECTED: 2, - COMPLETED: 3 -}; - -const - MATI_API_URL_AUTH = 'https://api.getmati.com/oauth', - getDomainUrl = (path) => `${toolsLib.getDomain()}${path}`; - -const init = async () => { - if (!WEBHOOK_SECRET) { - throw new Error('webhook_secret required value'); - } - if (!CLIENT_SECRET) { - throw new Error('client_secret required value'); - } - if (!CLIENT_ID) { - throw new Error('client_id required value'); - } - if (!FLOW_ID) { - throw new Error('flow_id required value'); - } - if (typeof MANUAL_REVIEW !== 'boolean') { - throw new Error('manual_review invalid value'); - } -}; - -const convertGender = (gender) => { - return gender ? 'Female' : 'Male'; -}; - -const parseObjToList = (data) => { - const result = { - html: '', - text: '' - }; - - for (let field in data) { - if (!lodash.isNil(data[field])) { - if (field === 'gender') { - data[field] = convertGender(data[field]); - } - - if (toolsLib.isDatetime(data[field])) { - data[field] = moment(data[field]).format('YYYY/MM/DD'); - } - result.html += `<li>${lodash.startCase(field)}: ${data[field]}</li>`; - result.text += `${lodash.startCase(field)}: ${data[field]}\n`; - } - } - - return result; -}; - -const documentApprovedEmail = (email, data = {}) => { - const idData = parseObjToList(data); - - const html = ` - <div> - <p> - Dear ${email}, - </p> - <p> - Your uploaded KYC documents have been approved.<br> - You now have access to all exchange features that require identity verification. - </p> - <ul> - ${idData.html} - </ul> - <p> - To view your approved documents, visit your <a href=${getDomainUrl('/verification')}>Verification page</a>. - </p> - <p> - Regards,<br> - ${toolsLib.getKitConfig().api_name} team - </p> - </div> - `; - - const text = ` - Dear ${email}, - - Your uploaded KYC documents have been approved. - You now have access to all exchange features that require identity verification. - - ${idData.text} - - To view your approved documents, visit your Verification page. - - Regards, - ${toolsLib.getKitConfig().api_name} team - `; - - const subject = 'KYC Documents Approved'; - - return toolsLib.sendCustomEmail( - email, - subject, - toolsLib.emailHtmlBoilerplate(html), - { - bcc: 'default', - text - } - ); -}; - -const documentPendingEmail = (email) => { - const html = ` - <div> - <p> - Dear ${email}, - </p> - <p> - Your uploaded documents are currently being processed.<br> - We will notify you when your documents are approved or denied. - </p> - <p> - To view the status of your pending documents, visit your <a href=${getDomainUrl('/verification')}>Verification page</a>. - </p> - <p> - Regards,<br> - ${toolsLib.getKitConfig().api_name} team - </p> - </div> - `; - - const text = ` - Dear ${email}, - - Your uploaded documents are currently being processed. - We will notify you when your documents are approved or denied. - - To view the status of your pending documents, visit your Verification page. - - Regards, - ${toolsLib.getKitConfig().api_name} team - `; - - const subject = 'KYC Documents Pending'; - - return toolsLib.sendCustomEmail( - email, - subject, - toolsLib.emailHtmlBoilerplate(html), - { - bcc: 'default', - text - } - ); -}; - -const documentRejectedEmail = (email, reasons = {}) => { - const parsedReasons = parseObjToList(reasons); - - const html = ` - <div> - <p> - Dear ${email}, - </p> - <p> - Unfortunately, your uploaded KYC documents have been rejected.<br> - The reasons for your documents being rejected are listed below.<br> - </p> - <div> - ${parsedReasons.html} - </div> - <p> - If you feel these reasons are invalid, please feel free to reply to this email.<br> - Otherwise, please reupload valid documents in order to verify your identity. - </p> - <p> - Regards,<br> - ${toolsLib.getKitConfig().api_name} team - </p> - </div> - `; - - const text = ` - Dear ${email}, - - Unfortunately, your uploaded KYC documents have been rejected. - The reasons for your documents being rejected are listed below. - - ${parsedReasons.text} - - If you feel these reasons are invalid, please feel free to reply to this email. - Otherwise, please reupload valid documents in order to verify your identity. - - Regards, - ${toolsLib.getKitConfig().api_name} team - `; - - const subject = 'KYC Documents Rejected'; - - return toolsLib.sendCustomEmail( - email, - subject, - toolsLib.emailHtmlBoilerplate(html), - { - bcc: 'default', - text - } - ); -}; - -const documentExpiredEmail = (email) => { - const html = ` - <div> - <p> - Dear ${email}, - </p> - <p> - Your iDenfy document upload token as expired.<br> - You will no longer be able to use your token to upload your documents.<br> - To generate a new token, please go through the KYC process in your <a href=${getDomainUrl('/verification')}>Verification page</a>. - </p> - <p> - Regards,<br> - ${toolsLib.getKitConfig().api_name} team - </p> - </div> - `; - - const text = ` - Dear ${email}, - - Your iDenfy document upload token as expired. - You will no longer be able to use your token to upload your documents. - To generate a new token, please go through the KYC process in your Verification page. - - Regards, - ${toolsLib.getKitConfig().api_name} team - `; - - const subject = 'iDenfy Token Expired'; - - return toolsLib.sendCustomEmail( - email, - subject, - toolsLib.emailHtmlBoilerplate(html), - { - bcc: 'default', - text - } - ); -}; - -const adminAlertEmail = async (data = {}) => { - const { email, id } = data; - - const html = ` - <div> - <p> - Documents provided by user ${email} with ID ${id} have been automatically approved and are awaiting manual approval.<br> - <br> - You can manually approve or reject these documents through the <a href=${getDomainUrl(`/admin/user?id=${id}`)}>Operator Controls Panel</a>.<br> - Once reviewed, the user will be notified of the updated status. - </p> - </div> - `; - - const text = ` - Documents provided by user ${email} with ID ${id} have been automatically approved and are awaiting manual approval. - - You can manually approve or reject these documents through the Operator Controls Panel. - Once reviewed, the user will be notified of the updated status. - `; - - const subject = 'KYC Documents Awaiting Manual Review'; - - const kycOperators = await toolsLib.database.findAll('user', { - where: { - is_kyc: true - }, - attributes: ['email'], - raw: true - }); - - let cc = null; - - if (kycOperators.length > 0) { - cc = kycOperators.map((operator) => operator.email).join(','); - } - - return toolsLib.sendCustomEmail( - toolsLib.getKitSecrets().emails.audit, - subject, - toolsLib.emailHtmlBoilerplate(html), - { - cc, - text - } - ); -}; - -const getGender = (docSex) => { - if (docSex && docSex !== 'UNDEFINED') { - return docSex === 'F'; - } - - return false; -}; - -const generateUpdatedUserData = (status, data, eventName) => { - let result = {}; - if (eventName === 'verification_started' || eventName === 'verification_inputs_completed') { - result = { - id_data: { - status - } - }; - return result; - - } else if (eventName === 'verification_expired') { - result = { - id_data: { - status - } - }; - result.id_data.mati.resource = data.resource; - - return result; - - } else if (eventName === 'verification_updated' || eventName === 'verification_completed') { - bluebird.all([ - data.resource, - generateMatiToken() - ]) - .then(([resourceURL, responseToken]) => { - if (!responseToken) - throw new Error('Not authentication Mati'); - - loggerPlugin.verbose( - data.metadata.user_id, - 'GET /plugins/mati/admin/files request getMatiFiles', - responseToken - ); - responseToken = JSON.parse(responseToken); - return getMatiFiles(resourceURL, responseToken.access_token); - }) - .then((documentUser) => { - - result = { - full_name: '', - nationality: '', - gender: false, - dob: null, - id_data: { - status - } - }; - - loggerPlugin.verbose( - data.metadata.user_id, - 'GET /plugins/mati/admin/files response data', - documentUser - ); - - const { - fullName: { value: fullName }, - documentNumber: { value: documentNumber }, - dateOfBirt: { value: dateOfBirt }, - expirationDate: { value: expirationDate }, - documentType: { value: documentType }, - firstName: { value: firstName }, - issueCountry: { value: issueCountry }, - nationality: { value: nationality }, - personalNumber: { value: personalNumber }, - sex: { value: sex }, - surname: { value: surname } - } = documentUser.documents.fields; - - result.id_data.mati = documentUser.documents.data; - result.id_data.mati.resource = documentUser.resource; - if (documentType) { - result.id_data.type = documentType.toLowerCase(); - } - - if (documentNumber) { - result.id_data.number = documentNumber; - } - - if (expirationDate) { - result.id_data.expiration_date = moment(expirationDate).toISOString(); - } - - if (nationality) { - result.nationality = nationality; - } - - if (dateOfBirt) { - result.dob = moment(dateOfBirt).toISOString(); - } - - if (fullName) { - result.full_name = fullName; - } - if (sex) { - result.gender = getGender(sex); - } - return result; - }); - } -}; - -const generateMatiToken = async () => { - const method = 'POST'; - const headers = { - 'content-type': 'application/x-www-form-urlencoded', - 'Authorization': 'Basic ' + new Buffer.from(CLIENT_ID + ':' + CLIENT_SECRET, 'utf8').toString('base64') - }; - const form = { - 'grant_type': 'client_credentials' - }; - const option = { - headers, - method, - uri: MATI_API_URL_AUTH, - form - }; - - return rp(option); -}; - -const getMatiFiles = async (resource, accessToken) => { - - const method = 'GET'; - const headers = { - 'content-type': 'application/x-www-form-urlencoded', - 'Authorization': 'Bearer ' + accessToken - }; - const url = resource; - loggerPlugin.verbose( - resource, - accessToken, - 'getMatiFiles request' - ); - return rp({ - headers, - method, - url - }); -}; - -const verifyRequest = async (signature, secret, payloadBody) => { - let hash = crypto.createHmac('sha256', secret); - hash = hash.update(payloadBody).digest('hex'); - const isValid = crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(signature)); - - loggerPlugin.error( - 'MATI PLUGIN cannot verify notification request' - ); - - if (!isValid) { - throw new Error('Invalid request'); - } -}; - -init() - .then(() => { - app.post('/plugins/mati/notification', (req, res) => { - loggerPlugin.verbose( - req.uuid, - 'POST /plugins/mati/notification body URL webhook', - req.body - ); - - const signature = req.headers['x-signature']; - const data = req.body; - - verifyRequest(signature, WEBHOOK_SECRET, JSON.stringify(data)) - .then(() => { - if (!data.metadata || !data.metadata.user_id) { - throw new Error('Meta data user_id not given'); - } - - return toolsLib.database.findOne('user', { - where: { - id: data.metadata.user_id - }, - attributes: [ - 'id', - 'email', - 'network_id', - 'full_name', - 'gender', - 'nationality', - 'dob', - 'id_data' - ] - }); - }) - .then(async (user) => { - if (!user) { - throw new Error('User not found'); - } - - const { eventName } = data; - - let updateStatus; - - if (eventName === 'verification_started') { - updateStatus = VERIFY_STATUS.PENDING; - } else if (eventName === 'verification_inputs_completed') { - updateStatus = VERIFY_STATUS.PENDING; - } else if (eventName === 'verification_updated') { - if (MANUAL_REVIEW) { - updateStatus = VERIFY_STATUS.PENDING; - } else { - updateStatus = VERIFY_STATUS.COMPLETED; - } - } else if (eventName === 'verification_completed') { - if (MANUAL_REVIEW) { - updateStatus = VERIFY_STATUS.PENDING; - } else { - updateStatus = VERIFY_STATUS.COMPLETED; - } - } else if (eventName === 'verification_expired') { - updateStatus = VERIFY_STATUS.REJECTED; - } - - const previousStatus = user.id_data.status; - - loggerPlugin.verbose( - req.uuid, - 'POST /plugins/mati/notification status', - 'mati eventName', - eventName, - 'previous id data status:', - previousStatus, - 'updating status:', - updateStatus - ); - - if (updateStatus) { - const updateData = await generateUpdatedUserData(updateStatus, data, eventName); - - loggerPlugin.verbose( - req.uuid, - 'POST /plugins/mati/notification updated user', - updateData - ); - const updatedUser = await user.update(updateData); - - loggerPlugin.verbose( - req.uuid, - 'POST /plugins/mati/notification updated user', - updatedUser - ); - - try { - if (updateStatus === VERIFY_STATUS.PENDING && MANUAL_REVIEW) { - adminAlertEmail({ - email: user.email, - id: user.id - }); - } - } catch (err) { - loggerPlugin.error( - req.uuid, - 'POST /plugins/mati/notification error while sending manual review required email', - err.message - ); - } - - try { - if (updateStatus === VERIFY_STATUS.REJECTED) { - documentRejectedEmail( - user.email - ); - } else if (updateStatus === VERIFY_STATUS.PENDING) { - documentPendingEmail(user.email); - } else if (updateStatus === VERIFY_STATUS.COMPLETED) { - documentApprovedEmail(user.email, { - full_name: updatedUser.full_name ? updatedUser.full_name : null, - dob: updatedUser.dob, - gender: lodash.isBoolean(updatedUser.gender) ? updatedUser.gender : null, - nationality: updatedUser.nationality ? updatedUser.nationality : null, - ...lodash.omit(updatedUser.id_data, ['status', 'mati']) - }); - } - } catch (err) { - loggerPlugin.error( - req.uuid, - 'POST /plugins/mati/notification error while sending email', - err.message - ); - } - } - return res.json({ message: 'Success' }); - - }) - .catch((err) => { - loggerPlugin.error( - req.uuid, - 'POST /plugins/mati/notification err', - err - ); - return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); - }); - }); - - app.get('/plugins/mati/admin/files', [ - toolsLib.security.verifyBearerTokenExpressMiddleware(['admin', 'supervisor', 'support', 'kyc']), - expressValidator.checkSchema({ - user_id: { - in: ['query'], - errorMessage: 'must be an integer', - isInt: true, - optional: false - } - }) - ], (req, res) => { - const errors = expressValidator.validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - - loggerPlugin.verbose( - req.uuid, - 'GET /plugins/mati/admin/files auth', - req.auth.sub - ); - - const { user_id } = req.query; - toolsLib.user.getUserByKitId(user_id) - .then((user) => { - if (!user) { - throw new Error('User not found'); - } - - if ( - !user.id_data - || !user.id_data.mati - || !user.id_data.mati.resource - || user.id_data.status === VERIFY_STATUS.EMPTY - ) { - throw new Error('User does not have uploaded documents'); - } - loggerPlugin.verbose( - user_id, - 'GET /plugins/mati/admin/files request generateMatiToken' - ); - - return bluebird.all([ - user, - generateMatiToken() - ]); - }) - .then(([user, responseToken]) => { - if (!responseToken) - throw new Error('Not authentication Mati'); - loggerPlugin.verbose( - user_id, - 'GET /plugins/mati/admin/files request getMatiFiles', - responseToken - ); - responseToken = JSON.parse(responseToken); - return getMatiFiles(user.id_data.mati.resource, responseToken.access_token); - }) - .then((data) => { - - loggerPlugin.verbose( - user_id, - 'GET /plugins/mati/admin/files response data', - data - ); - - return res.json(data); - }) - .catch((err) => { - loggerPlugin.error( - req.uuid, - 'GET /plugins/mati/admin/files err', - err.message - ); - return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); - }); - }); - - app.get('/plugins/mati/admin/file1/:location', [], (req, res) => { - const { location } = req.params; - - generateMatiToken() - .then((responseToken) => { - if (!responseToken) - throw new Error('Not authentication Mati'); - responseToken = JSON.parse(responseToken); - return - const method = 'GET'; - const headers = { - 'Authorization': 'Bearer ' + responseToken - }; - const url = 'https://media.getmati.com/file?location='+location; - - return rp({ - headers, - method, - url - }) - }) - .then((data) => { - console.log(data, "data"); - res.contentType('image/jpeg'); - return res.send(data); - }) - .catch((err) => { - loggerPlugin.error( - req.uuid, - 'GET /plugins/mati/admin/file err', - err.message - ); - return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); - }); - }); - - app.post('/plugins/mati/verify', [ - toolsLib.security.verifyBearerTokenExpressMiddleware(['admin', 'kyc', 'support', 'supervisor']), - expressValidator.checkSchema({ - user_id: { - in: ['body'], - errorMessage: 'must be an integer', - isInt: true, - optional: false - } - }) - ], (req, res) => { - const errors = expressValidator.validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - - loggerPlugin.verbose( - req.uuid, - 'POST /plugins/mati/verify auth', - req.auth.sub - ); - - const { user_id } = req.body; - - toolsLib.user.getUserByKitId(user_id, false, false) - .then((user) => { - if (!user) { - throw new Error('User not found'); - } - - if ( - !user.id_data - || lodash.isNil(user.id_data.status) - || user.id_data.status === VERIFY_STATUS.EMPTY - ) { - throw new Error('User documents are not pending'); - } - - if (user.id_data.status === VERIFY_STATUS.COMPLETED) { - throw new Error('User documents are already verified'); - } - - return user.update({ - id_data: { - ...user.id_data, - status: VERIFY_STATUS.COMPLETED - } - }); - }) - .then((data) => { - try { - documentApprovedEmail(data.email, { - full_name: data.full_name ? data.full_name : null, - dob: data.dob, - gender: lodash.isBoolean(data.gender) ? data.gender : null, - nationality: data.nationality ? data.nationality : null, - ...lodash.omit(data.id_data, ['status', 'idenfy']) - }); - } catch (err) { - loggerPlugin.error( - req.uuid, - 'POST /plugins/mati/verify err while sending email', - err.message - ); - } - return res.json(lodash.pick(data, [ - 'id', - 'email', - 'full_name', - 'dob', - 'nationality', - 'gender', - 'id_data' - ])); - }) - .catch((err) => { - loggerPlugin.error( - req.uuid, - 'POST /plugins/mati/verify err', - err.message - ); - return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); - }); - }); - - app.post('/plugins/mati/revoke', [ - toolsLib.security.verifyBearerTokenExpressMiddleware(['admin', 'kyc', 'support', 'supervisor']), - expressValidator.checkSchema({ - user_id: { - in: ['body'], - errorMessage: 'must be an integer', - isInt: true, - optional: false - } - }) - ], (req, res) => { - const errors = expressValidator.validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - - loggerPlugin.verbose( - req.uuid, - 'POST /plugins/mati/revoke auth', - req.auth.sub - ); - - const user_id = req.body.user_id; - - toolsLib.user.getUserByKitId(user_id, false, false) - .then((user) => { - if (!user) { - throw new Error('User not found'); - } - - if ( - !user.id_data - || lodash.isNil(user.id_data.status) - || user.id_data.status === VERIFY_STATUS.EMPTY - ) { - throw new Error('User documents are not pending'); - } - - if (user.id_data.status === VERIFY_STATUS.REJECTED) { - throw new Error('User documents are already rejected'); - } - - return user.update({ - id_data: { - ...user.id_data, - status: VERIFY_STATUS.REJECTED - } - }); - }) - .then((data) => { - try { - documentRejectedEmail( - data.email - ); - } catch (err) { - loggerPlugin.error( - req.uuid, - 'POST /plugins/mati/revoke err while sending email', - err.message - ); - } - return res.json(lodash.pick(data, [ - 'id', - 'email', - 'full_name', - 'dob', - 'nationality', - 'gender', - 'id_data' - ])); - }) - .catch((err) => { - loggerPlugin.error( - req.uuid, - 'GET /plugins/mati/revoke err', - err.message - ); - return res.status(err.statusCode || 400).json({ message: toolsLib.errorMessageConverter(err) }); - }); - }); - }) - .catch((err) => { - loggerPlugin.error( - 'DOMINICAN EXCHANGE KYC PLUGIN err', - err.message - ); - }); \ No newline at end of file From a9639ea301a575c963dff2bb2279515c25ca7b76 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Wed, 21 Sep 2022 17:15:31 +0900 Subject: [PATCH 17/54] local dev plugin setup --- server/package.json | 3 +- server/plugins/dev.js | 256 ++++++++++++++++++------------------------ 2 files changed, 114 insertions(+), 145 deletions(-) diff --git a/server/package.json b/server/package.json index 6056dc4527..80aa579df2 100644 --- a/server/package.json +++ b/server/package.json @@ -89,7 +89,8 @@ "undomigrate": "sequelize db:migrate:undo:all", "migrate": "sequelize db:migrate", "start": "node app.js", - "test": "NODE_ENV=test nyc --reporter=html --reporter=text mocha --recursive --timeout 5000" + "test": "NODE_ENV=test nyc --reporter=html --reporter=text mocha --recursive --timeout 5000", + "dev:plugin": "docker exec -it server_hollaex-kit-server_1 node plugins/dev.js" }, "nyc": { "exclude": [ diff --git a/server/plugins/dev.js b/server/plugins/dev.js index b2b0655854..38a966f22f 100644 --- a/server/plugins/dev.js +++ b/server/plugins/dev.js @@ -1,152 +1,120 @@ - -/** - * Add your mock publicMeta and meta values in the object below - * In production, these values are stored in the configuration JSON file - - * Example mock configurations are included below -**/ - -this.configValues = { - // // ------------ CONFIG VALUES EXAMPLE START ------------ - - // publicMeta: { - // public_value: { - // type: 'string', - // description: 'Public meta value', - // required: false, - // value: 'i am public' - // } - // }, - // meta: { - // private_value: { - // type: 'string', - // description: 'Private meta value', - // required: true, - // value: 'i am private' - // } - // } - - // // ------------ CONFIG VALUES EXAMPLE END ------------ -}; - -const pluginScript = () => { - /** - * Add the plugin script here - * The script within this function should be in the script.js file for a plugin - - * An example of a plugin script is included below - **/ - - // // ------------ PLUGIN EXAMPLE START ------------ - - // const { app, loggerPlugin, toolsLib } = this.pluginLibraries; // this.pluginLibraries holds app, loggerPlugin, and toolsLib in the plugin script - // const { publicMeta, meta } = this.configValues; // this.configValues holds publicMeta and meta in the plugin script - - // const lodash = require('lodash'); - // const moment = require('moment'); - // const { public_value: { value: PUBLIC_VALUE } } = publicMeta; - // const { private_value: { value: PRIVATE_VALUE } } = meta; - - // // All endpoints for a plugin should follow the format: '/plugins/<PLUGIN_NAME>/...'. For this example, the plugin name is 'test' - // const HEALTH_ENDPOINT = '/plugins/test/health'; - // const CONFIG_VALUES_ENDPOINT = '/plugins/test/config-values'; - - // // We recommend creating an init function that checks for all required configuration values and all other requirements for this plugin to run - // const init = async () => { - // loggerPlugin.verbose( - // 'DEV PLUGIN initializing...' - // ); - - // if (!lodash.isString(PRIVATE_VALUE)) { - // throw new Error('Private Value must be configured for this plugin to run'); - // } - - // loggerPlugin.verbose( - // 'DEV PLUGIN initialized' - // ); - // }; - - // init() - // .then(() => { - // app.get(HEALTH_ENDPOINT, async (req, res) => { - // loggerPlugin.info( - // req.uuid, - // HEALTH_ENDPOINT - // ); - - // return res.json({ - // status: 'running', - // current_time: moment().toISOString(), - // exchange_name: toolsLib.getKitConfig().info.name - // }); - // }); - - // app.get(CONFIG_VALUES_ENDPOINT, async (req, res) => { - // loggerPlugin.info( - // req.uuid, - // CONFIG_VALUES_ENDPOINT - // ); - - // return res.json({ - // public_value: PUBLIC_VALUE, - // private_value: PRIVATE_VALUE - // }); - // }); - // }) - // .catch((err) => { - // // It's important to catch all errors in a script. If a thrown error is not caught, the plugin process will exit and continuously try to restart - // loggerPlugin.error( - // 'DEV PLUGIN initialization error', - // err.message - // ); - // }); - - // // ------------ PLUGIN EXAMPLE END ------------ -}; - - - - - - - - -// BELOW IS THE SCRIPT FOR RUNNING THE PLUGIN DEV ENVIRONMENT THAT IS NOT NECESSARY IN THE PLUGIN ITSELF +'use strict'; const { checkStatus } = require('../init'); +const express = require('express'); +const morgan = require('morgan'); +const PORT = process.env.PLUGIN_PORT || 10012; +const { logEntryRequest, stream, loggerPlugin } = require('../config/logger'); +const morganType = process.env.NODE_ENV === 'development' ? 'dev' : 'combined'; +const { domainMiddleware, helmetMiddleware } = require('../config/middleware'); +const cors = require('cors'); +const fs = require('fs'); +const path = require('path'); +const toolsLib = require('hollaex-tools-lib'); +const expressValidator = require('express-validator'); +const lodash = require('lodash'); +const npm = require('npm-programmatic'); +const _eval = require('eval'); +const rp = require('request-promise'); + +const getPluginConfig = () => { + return rp('http://host.docker.internal:8080/config.json'); +}; -const initializeDevPlugin = async () => { - await checkStatus(); - - const morgan = require('morgan'); - const { logEntryRequest, stream, loggerPlugin } = require('../config/logger'); - const { domainMiddleware, helmetMiddleware } = require('../config/middleware'); - const morganType = process.env.NODE_ENV === 'development' ? 'dev' : 'combined'; - const PORT = 10012; - const cors = require('cors'); - const toolsLib = require('hollaex-tools-lib'); - const express = require('express'); +let config, script; - const app = express(); - app.use(morgan(morganType, { stream })); - app.listen(PORT); - app.use(cors()); - app.use(express.urlencoded({ extended: true })); - app.use(express.json()); - app.use(logEntryRequest); - app.use(domainMiddleware); - helmetMiddleware(app); +const installLibrary = async (library) => { + const [name, version = 'latest'] = library.split('@'); + await npm.install([`${name}@${version}`], { + cwd: path.resolve(__dirname, '../'), + save: true, + output: true + }); - const pluginLibraries = { - app, - loggerPlugin, - toolsLib - }; + loggerPlugin.verbose( + 'plugins/index/installLibrary', + `${name} version ${version} installed` + ); - this.pluginLibraries = pluginLibraries; + const lib = require(name); + return lib; + }; -(async () => { - await initializeDevPlugin(); - pluginScript(); -})(); \ No newline at end of file +getPluginConfig() + .then((data) => { + data = JSON.parse(data); + config = data; + script = data.script; + return checkStatus(); + }) + .then(async () => { + const app = express(); + + app.use(morgan(morganType, { stream })); + app.listen(PORT); + app.use(cors()); + app.use(express.urlencoded({ extended: true })); + app.use(express.json()); + app.use(logEntryRequest); + app.use(domainMiddleware); + helmetMiddleware(app); + + const context = { + exports: exports, + require: require, + module: module, + toolsLib, + app, + loggerPlugin, + expressValidator, + pluginLibraries: { + app, + toolsLib, + loggerPlugin + }, + publicMeta: config.public_meta, + meta: config.meta, + configValues: { + publicMeta: config.public_meta, + meta: config.meta + }, + installedLibraries: {} + }; + + if (config.prescript && lodash.isArray(config.prescript.install) && !lodash.isEmpty(config.prescript.install)) { + loggerPlugin.verbose( + 'plugins/index/initialization', + `Installing packages for plugin ${config.name}` + ); + + for (const library of config.prescript.install) { + context.installedLibraries[library] = await installLibrary(library); + } + + loggerPlugin.verbose( + 'plugins/index/initialization', + `Plugin ${config.name} packages installed` + ); + } + + _eval(script, 'dev', context, true); + }) + .catch((err) => { + let message = 'Plugin Initialization failed'; + + if (err.message) { + message = err.message; + } + + if (err.statusCode && err.statusCode === 402) { + message = err.error.message; + } + + loggerPlugin.error( + '/plugins/index/initialization err', + message + ); + + setTimeout(() => { process.exit(1); }, 5000); + }); \ No newline at end of file From 140512dc189bc791bd9d458962d74c00884c51c2 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Wed, 21 Sep 2022 17:16:09 +0900 Subject: [PATCH 18/54] removed plugin eslint yml --- plugins/.eslintrc.yml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 plugins/.eslintrc.yml diff --git a/plugins/.eslintrc.yml b/plugins/.eslintrc.yml deleted file mode 100644 index 6ef13503d4..0000000000 --- a/plugins/.eslintrc.yml +++ /dev/null @@ -1,3 +0,0 @@ -extends: ["@paciolan/react"] -rules: - react/prop-types: off From 76f0e366b10939b4152e0c6585a6a2806efad0d2 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Wed, 21 Sep 2022 18:31:05 +0430 Subject: [PATCH 19/54] apps section functional version --- web/public/assets/images/all-apps.svg | 25 ++++ web/public/assets/images/apps.svg | 17 +++ web/public/assets/images/my-apps.svg | 15 ++ web/src/_common.scss | 4 + web/src/actions/appActions.js | 4 + web/src/components/AppBar/_AppBar.scss | 3 +- .../AppMenuSidebar/_AppMenuSidebar.scss | 3 +- web/src/config/icons/dark.js | 8 +- web/src/config/icons/static.js | 1 + web/src/config/lang/en.json | 24 +++- web/src/config/menu.js | 13 +- .../containers/Admin/General/InterfaceForm.js | 45 ++++++ web/src/containers/Admin/General/index.css | 16 +++ web/src/containers/App/App.js | 8 ++ web/src/containers/AppDetails/index.js | 29 +++- web/src/containers/Apps/All.js | 136 +++++++++++++++--- web/src/containers/Apps/ConfigureApps.js | 124 ++++++++++++++++ web/src/containers/Apps/User.js | 87 ++++++++--- web/src/containers/Apps/_Apps.scss | 19 +++ web/src/containers/Apps/index.js | 6 +- web/src/containers/Apps/utils.js | 16 +++ web/src/containers/_containers.scss | 1 + web/src/index.css | 28 +++- web/src/index.scss | 5 +- web/src/reducers/appReducer.js | 25 ++-- web/src/reducers/userReducer.js | 1 + web/src/utils/id.js | 2 + 27 files changed, 597 insertions(+), 68 deletions(-) create mode 100644 web/public/assets/images/all-apps.svg create mode 100644 web/public/assets/images/apps.svg create mode 100644 web/public/assets/images/my-apps.svg create mode 100644 web/src/containers/Apps/ConfigureApps.js create mode 100644 web/src/containers/Apps/_Apps.scss create mode 100644 web/src/containers/Apps/utils.js diff --git a/web/public/assets/images/all-apps.svg b/web/public/assets/images/all-apps.svg new file mode 100644 index 0000000000..7626228965 --- /dev/null +++ b/web/public/assets/images/all-apps.svg @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.2" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + x="0px" y="0px" viewBox="0 0 26.3 26.3" overflow="visible" xml:space="preserve"> +<g class="all-apps" id="Group_5258" transform="translate(-569.286 -408.426)"> + <path id="Path_4762" d="M575.6,425h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C576.1,424.8,575.9,425,575.6,425z"/> + <path id="Path_4762-2" d="M575.6,434.7h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C576.1,434.5,575.9,434.7,575.6,434.7z"/> + <path id="Path_4762-3" d="M585.3,415.3h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C585.8,415.1,585.6,415.3,585.3,415.3z"/> + <path id="Path_4762-4" d="M595.1,415.3h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C595.5,415.1,595.3,415.3,595.1,415.3z"/> + <path id="Path_4762-5" d="M585.3,425h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C585.8,424.8,585.6,425,585.3,425z"/> + <path id="Path_4762-6" d="M585.3,434.7h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C585.8,434.5,585.6,434.7,585.3,434.7z"/> + <path id="Path_4762-7" d="M595.1,425h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C595.5,424.8,595.3,425,595.1,425z"/> + <path id="Path_4762-8" d="M595.1,434.7h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C595.5,434.5,595.3,434.7,595.1,434.7z"/> + <path id="Path_4762-9" d="M575.6,415.3h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C576.1,415.1,575.9,415.3,575.6,415.3z"/> +</g> +</svg> diff --git a/web/public/assets/images/apps.svg b/web/public/assets/images/apps.svg new file mode 100644 index 0000000000..ea2feaba05 --- /dev/null +++ b/web/public/assets/images/apps.svg @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.2" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + x="0px" y="0px" viewBox="0 0 39.3 39.4" overflow="visible" xml:space="preserve"> +<g class="apps" id="Group_5256" transform="translate(8676.22 -1331)"> + <g id="Group_5253" transform="translate(-8676.22 1331)"> + <path id="Path_4762" d="M16,17.2H1.2C0.6,17.2,0,16.7,0,16V1.2C0,0.6,0.6,0,1.2,0H16c0.7,0,1.2,0.6,1.2,1.2l0,0V16 + C17.2,16.7,16.6,17.2,16,17.2z"/> + <path id="Path_4762-2" d="M16,39.4H1.2c-0.7,0-1.2-0.6-1.2-1.2V23.4c0-0.7,0.5-1.2,1.2-1.2H16 + c0.7,0,1.2,0.6,1.2,1.2l0,0v14.8C17.2,38.8,16.6,39.4,16,39.4z"/> + <path id="Path_4762-3" d="M38.1,17.2H23.4c-0.7,0-1.2-0.6-1.2-1.2V1.2c0-0.7,0.5-1.2,1.2-1.2h14.7 + c0.7,0,1.2,0.6,1.2,1.2l0,0V16C39.3,16.7,38.8,17.2,38.1,17.2z"/> + <path id="Path_4762-4" d="M38.1,39.4H23.4c-0.7,0-1.2-0.6-1.2-1.2V23.4c0-0.7,0.5-1.2,1.2-1.2h14.7 + c0.7,0,1.2,0.6,1.2,1.2l0,0v14.8C39.3,38.8,38.8,39.4,38.1,39.4z"/> + </g> +</g> +</svg> diff --git a/web/public/assets/images/my-apps.svg b/web/public/assets/images/my-apps.svg new file mode 100644 index 0000000000..0546dc9262 --- /dev/null +++ b/web/public/assets/images/my-apps.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.2" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + x="0px" y="0px" viewBox="0 0 26.3 26.3" overflow="visible" xml:space="preserve"> +<g class="my-apps" id="Group_5258" transform="translate(-569.286 -408.426)"> + <path id="Path_4762" d="M575.6,425h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C576.1,424.8,575.9,425,575.6,425z"/> + <path id="Path_4762-2" d="M575.6,434.7h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C576.1,434.5,575.9,434.7,575.6,434.7z"/> + <path id="Path_4762-3" d="M575.6,415.3h-5.9c-0.3,0-0.5-0.2-0.5-0.5v-5.9c0-0.3,0.2-0.5,0.5-0.5h5.9 + c0.3,0,0.5,0.2,0.5,0.5v5.9C576.1,415.1,575.9,415.3,575.6,415.3z"/> + <path id="Path_4762-4" d="M594.4,434.7h-14.2c-0.7,0-1.2-0.8-1.2-1.9v-22.5c0-1,0.5-1.9,1.2-1.9h14.2 + c0.7,0,1.2,0.8,1.2,1.9v22.5C595.5,433.9,595,434.7,594.4,434.7z"/> +</g> +</svg> diff --git a/web/src/_common.scss b/web/src/_common.scss index 6ec3dd9783..f236d80d59 100644 --- a/web/src/_common.scss +++ b/web/src/_common.scss @@ -337,3 +337,7 @@ table th { .inline-flex { display: inline-flex !important; } + +.no-wrap { + white-space: nowrap !important; +} diff --git a/web/src/actions/appActions.js b/web/src/actions/appActions.js index ff05682d16..46ea2f12ff 100644 --- a/web/src/actions/appActions.js +++ b/web/src/actions/appActions.js @@ -38,6 +38,7 @@ export const NOTIFICATIONS = { UNSTAKE: 'UNSTAKE', MOVE_XHT: 'MOVE_XHT', METAMASK_ERROR: 'METAMASK_ERROR', + CONFIGURE_APPS: 'CONFIGURE_APPS', }; export const CONTACT_FORM = 'CONTACT_FORM'; export const HELPFUL_RESOURCES_FORM = 'HELPFUL_RESOURCES_FORM'; @@ -376,6 +377,9 @@ export const openConnectViaDesktop = (data = {}) => export const openMetamaskError = (data = {}) => setNotification(NOTIFICATIONS.METAMASK_ERROR, data, true); +export const openConfigureApps = (onRemove) => + setNotification(NOTIFICATIONS.CONFIGURE_APPS, { onRemove }, true); + export const openRiskPortfolioOrderWarning = (data = {}) => setNotification(RISK_PORTFOLIO_ORDER_WARING, data, true); diff --git a/web/src/components/AppBar/_AppBar.scss b/web/src/components/AppBar/_AppBar.scss index a1571f7815..1d720cd114 100644 --- a/web/src/components/AppBar/_AppBar.scss +++ b/web/src/components/AppBar/_AppBar.scss @@ -371,7 +371,8 @@ $app-menu-width: calc(100vw - 40rem); .tab-history-st, .help-question, .tab-signout, - .tab-api0 { + .tab-api0, + .apps { fill: $colors-black; } } diff --git a/web/src/components/AppMenuSidebar/_AppMenuSidebar.scss b/web/src/components/AppMenuSidebar/_AppMenuSidebar.scss index 7f7f1fbfe8..fd9f0aa6b8 100644 --- a/web/src/components/AppMenuSidebar/_AppMenuSidebar.scss +++ b/web/src/components/AppMenuSidebar/_AppMenuSidebar.scss @@ -50,7 +50,8 @@ .help-question, .tab-signout, .tab-history-st, - .stake-page-icon { + .stake-page-icon, + .apps { fill: $base_top-bar-navigation_text !important; } } diff --git a/web/src/config/icons/dark.js b/web/src/config/icons/dark.js index 79a86fb7b2..5b993e3503 100644 --- a/web/src/config/icons/dark.js +++ b/web/src/config/icons/dark.js @@ -39,7 +39,7 @@ const nestedIcons = { SECURITY: '/assets/images/tab-security.svg', VERIFY: '/assets/images/tab-verify.svg', SETTING: '/assets/images/tab-setting.svg', - APPS: '/assets/images/tab-setting.svg', + APPS: '/assets/images/apps.svg', API: '/assets/images/tab-api.svg', STAKE: '/assets/images/stake-page-icon.svg', }, @@ -78,8 +78,10 @@ const nestedIcons = { }, APPS: { - ALL: '/assets/images/tab-setting.svg', - USER: '/assets/images/tab-setting.svg', + ALL: '/assets/images/all-apps.svg', + USER: '/assets/images/my-apps.svg', + CONFIGURE: '/assets/images/interface-settings-icon.svg', + REMOVE: '/assets/images/cancel-cross-active.svg', }, SECURITY: { diff --git a/web/src/config/icons/static.js b/web/src/config/icons/static.js index 9f50ac8efd..6cf9e39d16 100644 --- a/web/src/config/icons/static.js +++ b/web/src/config/icons/static.js @@ -71,6 +71,7 @@ const icons = { CANCEL_CROSS_ACTIVE: '/assets/images/cancel-cross-active.svg', VERIFICATION_ICON: '/assets/images/verification-green-tick.svg', CHAT_FEATURE_ICON: '/assets/images/chat-feature-icon.svg', + APPS_FEATURE_ICON: '/assets/images/apps.svg', HOME_PAGE_FEATURE_ICON: '/assets/images/home-page.svg', USER_EMAIL: '/assets/images/user-email.svg', USER_EMAIL_VERIFIED: '/assets/images/user-email-verified.svg', diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json index b9f1a85934..0c08f1a437 100644 --- a/web/src/config/lang/en.json +++ b/web/src/config/lang/en.json @@ -478,7 +478,8 @@ "ALL_APPS": { "TAB_TITLE": "All apps", "TITLE": "Exchange apps", - "SUBTITLE": "Get more functionality from your exchange account by simply selecting an app below and clicking Add button." + "SUBTITLE": "Get more functionality from your exchange account by simply selecting an app below and clicking Add button.", + "SEARCH_PLACEHOLDER": "Search apps..." }, "MY_APPS": { "TAB_TITLE": "My apps", @@ -489,11 +490,30 @@ "APP_NAME": "App name", "DESCRIPTION": "Description", "ACTION": "Action", - "VIEW_APP": "View app" + "CONFIGURE": "Configure", + "VIEW_APP": "View app", + "ADD": "Add", + "NOT_FOUND": "Can't find this app...", + "RETRY": "Try another search term" }, "APP_DETAILS": { "BACK_TO_APPS": "{0} to my apps", "BACK": "Back" + }, + "CONFIGURE": { + "TITLE": "Configure app", + "SUBTITLE": "Configure your app below:", + "REMOVE": "Remove app", + "TEXT": "If you are having issues with your app please contact us by clicking help below.", + "BACK": "BACK", + "HELP": "HELP" + }, + "REMOVE": { + "TITLE": "Remove app", + "SUBTITLE": "This will remove the app from your 'My apps' list.", + "TEXT": "Are you sure you want to remove this app?", + "BACK": "BACK", + "CONFIRM": "CONFIRM" } }, "TRANSACTION_HISTORY": { diff --git a/web/src/config/menu.js b/web/src/config/menu.js index 1d6c719d72..5c773a9d45 100644 --- a/web/src/config/menu.js +++ b/web/src/config/menu.js @@ -47,6 +47,13 @@ export const MENU_ITEMS = { hide_from_appbar: true, hide_from_bottom_nav: true, }, + { + id: 'apps', + path: '/apps', + icon_id: 'TAB_APPS', + string_id: 'ACCOUNTS.TAB_APPS', + hide_from_bottom_nav: true, + }, { id: 'chat', path: '/chat', @@ -92,12 +99,6 @@ export const MENU_ITEMS = { hide_from_appbar: true, hide_from_bottom_nav: true, }, - { - path: '/apps', - icon_id: 'TAB_APPS', - string_id: 'ACCOUNTS.TAB_APPS', - hide_from_bottom_nav: true, - }, ], bottom: [ { diff --git a/web/src/containers/Admin/General/InterfaceForm.js b/web/src/containers/Admin/General/InterfaceForm.js index 46832cad84..e53d0586ff 100644 --- a/web/src/containers/Admin/General/InterfaceForm.js +++ b/web/src/containers/Admin/General/InterfaceForm.js @@ -28,6 +28,7 @@ const InterfaceForm = ({ stake_page: !!values.stake_page, home_page: isUpgrade ? false : !!values.home_page, ultimate_fiat: !!values.ultimate_fiat, + apps: !!values.apps, }; handleSaveInterface(formValues); } @@ -50,6 +51,7 @@ const InterfaceForm = ({ if (isUpgrade) { initialValue.home_page = false; initialValue.chat = false; + initialValue.apps = false; } return ( <div className="general-wrapper"> @@ -239,6 +241,49 @@ const InterfaceForm = ({ </Checkbox> </Item> </div> + <div className={classnames({ 'disabled-area': isUpgrade })}> + <Item name="apps" valuePropName="checked"> + <Checkbox className="mt-3"> + <div className="d-flex align-items-center"> + <div className="feature-trade-box mr-1"> + <ReactSVG + src={STATIC_ICONS.APPS_FEATURE_ICON} + className="feature-apps-icon" + /> + </div> + <div className="ml-2 checkbox-txt"> + Apps + <div className="d-flex justify-content-between"> + <div className="small-text">(Apps ...)</div> + </div> + </div> + </div> + </Checkbox> + </Item> + </div> + {isUpgrade && ( + <div className="d-flex"> + <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> + <div> + <div className="font-weight-bold"> + Start your crypto culture + </div> + <div>Allow your users to socialize through chat</div> + </div> + <div className="ml-5 button-wrapper"> + <a + href="https://dash.bitholla.com/billing" + target="_blank" + rel="noopener noreferrer" + > + <Button type="primary" className="w-100"> + Upgrade Now + </Button> + </a> + </div> + </div> + </div> + )} </div> {isUpgrade ? ( <div className="d-flex"> diff --git a/web/src/containers/Admin/General/index.css b/web/src/containers/Admin/General/index.css index 8277affe30..2e4b963ad8 100644 --- a/web/src/containers/Admin/General/index.css +++ b/web/src/containers/Admin/General/index.css @@ -158,11 +158,27 @@ stroke: #808080; fill-opacity: 0.5; } +.interface-box .feature-apps-icon { + width: 42px; + margin: 4px 16px; + fill: #808080 !important; + fill-opacity: 0.5; +} +.feature-apps-icon .apps { + fill: #808080 !important; +} .interface-box .ant-checkbox-wrapper-checked .feature-icon, .interface-box .ant-checkbox-wrapper-checked .feature-chat-icon { stroke: #ffffff; fill-opacity: 1; } +.interface-box .ant-checkbox-wrapper-checked .feature-apps-icon { + fill: #ffffff !important; + fill-opacity: 1; +} +.feature-apps-icon .apps { + fill: #ffffff !important; +} .interface-box .checkbox-txt, .interface-box .small-text { color: #808080; diff --git a/web/src/containers/App/App.js b/web/src/containers/App/App.js index 9c03584f01..f087b80b33 100644 --- a/web/src/containers/App/App.js +++ b/web/src/containers/App/App.js @@ -64,6 +64,7 @@ import AppFooter from '../../components/AppFooter'; import OperatorControls from 'containers/OperatorControls'; import MarketSelector from 'components/AppBar/MarketSelector'; import ConnectViaDesktop from 'containers/Stake/components/ConnectViaDesktop'; +import ConfigureApps from 'containers/Apps/ConfigureApps'; import { getClasesForLanguage, @@ -511,6 +512,13 @@ class App extends Component { text={data} /> ); + case NOTIFICATIONS.CONFIGURE_APPS: + return ( + <ConfigureApps + onClose={this.onCloseDialog} + onRemove={data.onRemove} + /> + ); case CONNECT_VIA_DESKTOP: return <ConnectViaDesktop onClose={this.onCloseDialog} />; case RISK_PORTFOLIO_ORDER_WARING: diff --git a/web/src/containers/AppDetails/index.js b/web/src/containers/AppDetails/index.js index 692d18d72a..fa3886bd5d 100644 --- a/web/src/containers/AppDetails/index.js +++ b/web/src/containers/AppDetails/index.js @@ -1,17 +1,33 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { isMobile } from 'react-device-detect'; import { openContactForm } from 'actions/appActions'; -import { IconTitle, HeaderSection, EditWrapper } from 'components'; +import { IconTitle, HeaderSection, EditWrapper, SmartTarget } from 'components'; import STRINGS from 'config/localizedStrings'; import withConfig from 'components/ConfigProvider/withConfig'; +import { generateDynamicTarget } from 'utils/id'; +import { userAppsSelector } from 'containers/Apps/utils'; + +const Index = ({ openContactForm, icons: ICONS, router, userApps }) => { + const [mounted, setMounted] = useState(false); + const goBack = () => router.push('/apps'); -const Index = ({ openContactForm, icons: ICONS, router }) => { const { params: { app }, } = router; - const goBack = () => router.push('/apps'); + + if (!mounted) { + if (!app || userApps.map(({ name }) => name).includes(app)) { + goBack(); + } + } + + const id = generateDynamicTarget(app, 'app'); + + useEffect(() => { + setMounted(true); + }, []); return ( <div className="presentation_container apply_rtl settings_container"> @@ -42,11 +58,14 @@ const Index = ({ openContactForm, icons: ICONS, router }) => { </div> </div> </HeaderSection> + <SmartTarget id={id} /> </div> ); }; -const mapStateToProps = (state) => ({}); +const mapStateToProps = (state) => ({ + userApps: userAppsSelector(state), +}); const mapDispatchToProps = (dispatch) => ({ openContactForm: bindActionCreators(openContactForm, dispatch), diff --git a/web/src/containers/Apps/All.js b/web/src/containers/Apps/All.js index 17390d7489..261364bf06 100644 --- a/web/src/containers/Apps/All.js +++ b/web/src/containers/Apps/All.js @@ -1,17 +1,17 @@ -import React from 'react'; -import { IconTitle, EditWrapper, Table } from 'components'; +import React, { useState, useRef, useEffect } from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { Input } from 'antd'; +import debounce from 'lodash.debounce'; +import { SearchOutlined } from '@ant-design/icons'; +import { updateUserSettings, setUserData } from 'actions/userAction'; +import { IconTitle, EditWrapper, Table, Button, Image } from 'components'; import STRINGS from 'config/localizedStrings'; import withConfig from 'components/ConfigProvider/withConfig'; +import { unique } from 'utils/data'; +import { isEnabled, appsSelector } from './utils'; -const data = [ - { - id: 0, - name: 'Name of the app', - description: 'App description short sentence here', - }, -]; - -const generateHeaders = () => { +const generateHeaders = (addApp, isAdded) => { return [ { stringId: 'USER_APPS.TABLE.APP_NAME', @@ -25,16 +25,85 @@ const generateHeaders = () => { }, { label: '', - key: 'name', + renderCell: ({ name }, key) => ( + <td key={`${key}-${name}-app`} className="text-align-right"> + {isAdded(name) ? ( + <Image icon={''} iconId={''} wrapperClassName={''} /> + ) : ( + <Button + label={STRINGS['USER_APPS.TABLE.ADD']} + className="add-app-button" + onClick={() => addApp(name)} + /> + )} + </td> + ), }, ]; }; -const All = ({ icons: ICONS }) => { +const NoData = ({ onClick }) => ( + <div className="text-align-center"> + <div>{STRINGS['USER_APPS.TABLE.NOT_FOUND']}</div> + <div onClick={onClick} className="blue-link underline-text pointer"> + {STRINGS['USER_APPS.TABLE.RETRY']} + </div> + </div> +); + +const All = ({ + icons: ICONS, + apps, + settings: { apps: user_apps = [] }, + setUserData, +}) => { + const [search, setSearch] = useState(); + const [data, setData] = useState(apps); + + const inputRef = useRef(null); + + const addApp = (name) => { + // send add app request and show toast notification + const settings = { + apps: unique([...user_apps, name]), + }; + updateUserSettings(settings) + .then(({ data }) => setUserData(data)) + .catch((err) => console.log('error')); + }; + + const isAdded = (name) => { + return isEnabled(name, user_apps); + }; + + const retry = () => { + setSearch(''); + inputRef.current.focus({ + cursor: 'start', + }); + }; + + const onSearch = (search, apps) => { + if (search) { + const result = apps.filter(({ name }) => + name.toLowerCase().includes(search.toLowerCase()) + ); + setData(result); + } else { + setData(apps); + } + }; + + const debounced = useRef(debounce(onSearch, 1000)); + + useEffect(() => { + debounced.current(search, apps); + }, [search, apps]); + return ( <div> <div className="settings-form-wrapper"> - <div className="settings-form"> + <div className="settings-form apps-form"> <IconTitle stringId="USER_APPS.ALL_APPS.TITLE" text={STRINGS['USER_APPS.ALL_APPS.TITLE']} @@ -46,12 +115,30 @@ const All = ({ icons: ICONS }) => { {STRINGS['USER_APPS.ALL_APPS.SUBTITLE']} </EditWrapper> </div> + <div> + <Input + prefix={<SearchOutlined className="secondary-text" />} + placeholder={STRINGS['USER_APPS.ALL_APPS.SEARCH_PLACEHOLDER']} + value={search} + onChange={({ target: { value } }) => setSearch(value)} + style={{ + width: 200, + }} + bordered={false} + className="kit-divider" + ref={inputRef} + /> + </div> <Table + showHeaderNoData={true} rowClassName="pt-2 pb-2" - headers={generateHeaders()} + headers={generateHeaders(addApp, isAdded)} count={data.length} + pageSize={data.length} data={data} - rowKey={({ id }) => id} + rowKey={({ name }) => name} + displayPaginator={false} + {...(search ? { noData: <NoData onClick={retry} /> } : {})} /> </div> </div> @@ -59,4 +146,19 @@ const All = ({ icons: ICONS }) => { ); }; -export default withConfig(All); +const mapStateToProps = (state) => { + const { + user: { settings }, + } = state; + + return { + apps: appsSelector(state), + settings, + }; +}; + +const mapDispatchToProps = (dispatch) => ({ + setUserData: bindActionCreators(setUserData, dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(withConfig(All)); diff --git a/web/src/containers/Apps/ConfigureApps.js b/web/src/containers/Apps/ConfigureApps.js new file mode 100644 index 0000000000..d7204da43b --- /dev/null +++ b/web/src/containers/Apps/ConfigureApps.js @@ -0,0 +1,124 @@ +import React, { useState } from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { IconTitle, EditWrapper, Button, ActionNotification } from 'components'; +import STRINGS from 'config/localizedStrings'; +import withConfig from 'components/ConfigProvider/withConfig'; +import { openHelpdesk } from 'actions/appActions'; + +const ConfigureApps = ({ + onClose, + icons: ICONS, + openHelpdesk, + onRemove = () => {}, +}) => { + const [showRemove, setShowRemove] = useState(false); + const openNewForm = () => { + onClose(); + openHelpdesk({ category: 'bug' }); + }; + + return showRemove ? ( + <div className="help-wrapper"> + <IconTitle + iconId="APPS_REMOVE" + iconPath={ICONS['APPS_REMOVE']} + stringId="USER_APPS.REMOVE.TITLE" + text={STRINGS['USER_APPS.REMOVE.TITLE']} + textType="title" + underline={true} + className="w-100" + subtitle={STRINGS['USER_APPS.REMOVE.SUBTITLE']} + /> + <div> + <div className="my-5 mx-3"> + <div> + {STRINGS['USER_APPS.REMOVE.TEXT']} + <EditWrapper stringId="USER_APPS.REMOVE.TEXT" /> + </div> + </div> + + <div className="d-flex"> + <div className="w-50"> + <EditWrapper stringId="USER_APPS.REMOVE.BACK" /> + <Button + label={STRINGS['USER_APPS.REMOVE.BACK']} + onClick={() => setShowRemove(false)} + /> + </div> + <div className="separator" /> + <div className="w-50"> + <EditWrapper stringId="USER_APPS.REMOVE.CONFIRM" /> + <Button + label={STRINGS['USER_APPS.REMOVE.CONFIRM']} + onClick={onRemove} + /> + </div> + </div> + </div> + </div> + ) : ( + <div className="help-wrapper"> + <IconTitle + iconId="APPS_CONFIGURE" + iconPath={ICONS['APPS_CONFIGURE']} + stringId="USER_APPS.CONFIGURE.TITLE" + text={STRINGS['USER_APPS.CONFIGURE.TITLE']} + textType="title" + underline={true} + className="w-100" + subtitle={STRINGS['USER_APPS.CONFIGURE.SUBTITLE']} + /> + <div> + <div className="my-5 mx-3"> + <ActionNotification + stringId="USER_APPS.CONFIGURE.REMOVE" + text={STRINGS['USER_APPS.CONFIGURE.REMOVE']} + iconId="CANCEL_CROSS_ACTIVE" + iconPath={ICONS['CANCEL_CROSS_ACTIVE']} + onClick={() => setShowRemove(true)} + status="information" + textPosition="left" + className="remove-action" + /> + </div> + + <div className="my-5 mx-3"> + <div> + {STRINGS['USER_APPS.CONFIGURE.TEXT']} + <EditWrapper stringId="USER_APPS.CONFIGURE.TEXT" /> + </div> + </div> + + <div className="d-flex"> + <div className="w-50"> + <EditWrapper stringId="USER_APPS.CONFIGURE.BACK" /> + <Button + label={STRINGS['USER_APPS.CONFIGURE.BACK']} + onClick={onClose} + /> + </div> + <div className="separator" /> + <div className="w-50"> + <EditWrapper stringId="USER_APPS.CONFIGURE.HELP" /> + <Button + label={STRINGS['USER_APPS.CONFIGURE.HELP']} + onClick={openNewForm} + /> + </div> + </div> + </div> + </div> + ); +}; + +const mapStateToProps = () => ({}); + +const mapDispatchToProps = (dispatch) => ({ + openHelpdesk: bindActionCreators(openHelpdesk, dispatch), +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(withConfig(ConfigureApps)); diff --git a/web/src/containers/Apps/User.js b/web/src/containers/Apps/User.js index 075faf8667..4a118c4d32 100644 --- a/web/src/containers/Apps/User.js +++ b/web/src/containers/Apps/User.js @@ -1,18 +1,15 @@ import React from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import { IconTitle, EditWrapper, Table } from 'components'; +import { updateUserSettings, setUserData } from 'actions/userAction'; +import { openConfigureApps, closeNotification } from 'actions/appActions'; import STRINGS from 'config/localizedStrings'; import withConfig from 'components/ConfigProvider/withConfig'; import { withRouter } from 'react-router'; +import { userAppsSelector } from './utils'; -const data = [ - { - id: 0, - name: 'Name of the app', - description: 'App description short sentence here', - }, -]; - -const generateHeaders = (goToDetails) => { +const generateHeaders = (goToDetails, openConfigs) => { return [ { stringId: 'USER_APPS.TABLE.APP_NAME', @@ -24,13 +21,27 @@ const generateHeaders = (goToDetails) => { label: STRINGS['USER_APPS.TABLE.DESCRIPTION'], key: 'description', }, + { + stringId: 'USER_APPS.TABLE.CONFIGURE', + label: STRINGS['USER_APPS.TABLE.CONFIGURE'], + renderCell: ({ name }, key) => ( + <td key={`${key}-${name}-configure`}> + <span + className="blue-link underline-text pointer no-wrap" + onClick={() => openConfigs(name)} + > + {STRINGS['USER_APPS.TABLE.CONFIGURE']} + </span> + </td> + ), + }, { stringId: 'USER_APPS.TABLE.ACTION', label: STRINGS['USER_APPS.TABLE.ACTION'], - renderCell: ({ id, name }, key) => ( - <td key={`${key}-${id}-app`}> + renderCell: ({ name }, key) => ( + <td key={`${key}-${name}-action`}> <span - className="blue-link underline-text pointer" + className="blue-link underline-text pointer no-wrap" onClick={() => goToDetails(name)} > {STRINGS['USER_APPS.TABLE.VIEW_APP']} @@ -41,8 +52,29 @@ const generateHeaders = (goToDetails) => { ]; }; -const User = ({ icons: ICONS, router }) => { +const User = ({ + icons: ICONS, + router, + userApps: data, + settings: { apps = [] }, + setUserData, + openConfigureApps, + closeNotification, +}) => { const goToDetails = (name) => router.push(`apps/details/${name}`); + const onRemove = (name) => { + // send add app request and show toast notification + const settings = { + apps: apps.filter((app) => app !== name), + }; + updateUserSettings(settings) + .then(({ data }) => { + setUserData(data); + closeNotification(); + }) + .catch((err) => console.log('error')); + }; + const openConfigs = (name) => openConfigureApps(() => onRemove(name)); return ( <div> @@ -60,11 +92,14 @@ const User = ({ icons: ICONS, router }) => { </EditWrapper> </div> <Table + showHeaderNoData={true} rowClassName="pt-2 pb-2" - headers={generateHeaders(goToDetails)} + headers={generateHeaders(goToDetails, openConfigs)} count={data.length} + pageSize={data.length} data={data} - rowKey={({ id }) => id} + rowKey={({ name }) => name} + displayPaginator={false} /> </div> </div> @@ -72,4 +107,24 @@ const User = ({ icons: ICONS, router }) => { ); }; -export default withRouter(withConfig(User)); +const mapStateToProps = (state) => { + const { + user: { settings }, + } = state; + + return { + userApps: userAppsSelector(state), + settings, + }; +}; + +const mapDispatchToProps = (dispatch) => ({ + setUserData: bindActionCreators(setUserData, dispatch), + openConfigureApps: bindActionCreators(openConfigureApps, dispatch), + closeNotification: bindActionCreators(closeNotification, dispatch), +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(withRouter(withConfig(User))); diff --git a/web/src/containers/Apps/_Apps.scss b/web/src/containers/Apps/_Apps.scss new file mode 100644 index 0000000000..529bed33a3 --- /dev/null +++ b/web/src/containers/Apps/_Apps.scss @@ -0,0 +1,19 @@ +.add-app-button { + border-radius: 24px; + height: 24px !important; + min-width: 70px !important; + width: auto !important; + text-transform: none !important; +} + +.apps-form { + .ant-input { + color: $colors-main-black; + } +} + +.action_notification-wrapper { + &.remove-action { + position: relative !important; + } +} diff --git a/web/src/containers/Apps/index.js b/web/src/containers/Apps/index.js index f3d16e8cc0..1edabae983 100644 --- a/web/src/containers/Apps/index.js +++ b/web/src/containers/Apps/index.js @@ -18,7 +18,7 @@ import User from './User'; const Index = ({ icons: ICONS, openContactForm }) => { const [tabs, setTabs] = useState([]); - const [activeTab, setActiveTab] = useState(); + const [activeTab, setActiveTab] = useState(0); useEffect(() => { updateTabs(); @@ -66,8 +66,8 @@ const Index = ({ icons: ICONS, openContactForm }) => { stringId="ACCOUNTS.TAB_APPS" text={STRINGS['ACCOUNTS.TAB_APPS']} textType="title" - iconPath={ICONS['TAB_SETTING']} - iconId={STRINGS['ACCOUNTS.TAB_APPS']} + iconPath={ICONS['TAB_APPS']} + iconId="TAB_APPS" /> )} diff --git a/web/src/containers/Apps/utils.js b/web/src/containers/Apps/utils.js new file mode 100644 index 0000000000..df0e15103e --- /dev/null +++ b/web/src/containers/Apps/utils.js @@ -0,0 +1,16 @@ +import { createSelector } from 'reselect'; + +const getPlugins = (state) => state.app.plugins; +const getUserApps = (state) => state.user.settings.apps || []; +export const appsSelector = createSelector([getPlugins], (plugins) => + plugins.filter((type) => type === 'app') +); + +export const userAppsSelector = createSelector( + [getUserApps, appsSelector], + (user_apps, apps) => { + return apps.filter(({ name }) => user_apps.includes(name)); + } +); + +export const isEnabled = (app, apps) => apps.includes(app); diff --git a/web/src/containers/_containers.scss b/web/src/containers/_containers.scss index b3a47b0043..4b015bbec5 100644 --- a/web/src/containers/_containers.scss +++ b/web/src/containers/_containers.scss @@ -26,3 +26,4 @@ @import './ConfirmChangePassword/ConfirmChangePassword'; @import './StakeDetails/StakeDetails'; @import './Stake/Stake'; +@import './Apps/Apps'; diff --git a/web/src/index.css b/web/src/index.css index 40e14b0579..f5988d74c7 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -344,6 +344,9 @@ table th { .inline-flex { display: inline-flex !important; } +.no-wrap { + white-space: nowrap !important; } + .app_container { min-height: 100vh; background-color: var(--base_background); @@ -5396,6 +5399,19 @@ table th { .area-disabled { opacity: 0.5; } +.add-app-button { + border-radius: 24px; + height: 24px !important; + min-width: 70px !important; + width: auto !important; + text-transform: none !important; } + +.apps-form .ant-input { + color: var(--labels_important-active-labels-text-graphics); } + +.action_notification-wrapper.remove-action { + position: relative !important; } + .sidebar-row { min-height: 3rem; min-width: 10rem; } @@ -6017,7 +6033,8 @@ table th { .app_bar .app-bar-account-menu .app-bar-account-list-icon svg .tab-history-st, .app_bar .app-bar-account-menu .app-bar-account-list-icon svg .help-question, .app_bar .app-bar-account-menu .app-bar-account-list-icon svg .tab-signout, - .app_bar .app-bar-account-menu .app-bar-account-list-icon svg .tab-api0 { + .app_bar .app-bar-account-menu .app-bar-account-list-icon svg .tab-api0, + .app_bar .app-bar-account-menu .app-bar-account-list-icon svg .apps { fill: var(--labels_secondary-inactive-label-text-graphics); } .app_bar .app-bar-account-menu .app-bar-account-list-icon svg .account-active-1 { fill: var(--calculated_base_top-bar-navigation_text-inactive); } @@ -10770,6 +10787,7 @@ table th { .app-side-bar .list_active .tab-signout, .app-side-bar .list_active .tab-history-st, .app-side-bar .list_active .stake-page-icon, + .app-side-bar .list_active .apps, .app-side-bar .app-menu-bar-side_list:hover .tab-summary0, .app-side-bar .app-menu-bar-side_list:hover .tab-wallet0, .app-side-bar .app-menu-bar-side_list:hover .tab-security0, @@ -10779,7 +10797,8 @@ table th { .app-side-bar .app-menu-bar-side_list:hover .help-question, .app-side-bar .app-menu-bar-side_list:hover .tab-signout, .app-side-bar .app-menu-bar-side_list:hover .tab-history-st, - .app-side-bar .app-menu-bar-side_list:hover .stake-page-icon { + .app-side-bar .app-menu-bar-side_list:hover .stake-page-icon, + .app-side-bar .app-menu-bar-side_list:hover .apps { fill: var(--calculated_base_top-bar-navigation_text) !important; } .app-side-bar .list_active { @@ -11072,7 +11091,10 @@ svg .incoming-btc-01, svg .incoming-coin-01, svg .coin-btc-5, svg .stake-page-icon, -svg .fiat-kyc { +svg .fiat-kyc, +svg .all-apps, +svg .my-apps, +svg .apps { fill: var(--labels_secondary-inactive-label-text-graphics); } svg .account-inactive { diff --git a/web/src/index.scss b/web/src/index.scss index 441253dea7..4be3c6dac7 100644 --- a/web/src/index.scss +++ b/web/src/index.scss @@ -190,7 +190,10 @@ svg { .incoming-coin-01, .coin-btc-5, .stake-page-icon, - .fiat-kyc { + .fiat-kyc, + .all-apps, + .my-apps, + .apps { fill: $colors-black; } diff --git a/web/src/reducers/appReducer.js b/web/src/reducers/appReducer.js index 37f18fdb38..8241506288 100644 --- a/web/src/reducers/appReducer.js +++ b/web/src/reducers/appReducer.js @@ -448,15 +448,18 @@ const reducer = (state = INITIAL_STATE, { type, payload = {} }) => { } case SET_WEB_VIEWS: { const allWebViews = []; - payload.enabledPlugins.forEach(({ name, web_view = [] }) => { - if (web_view && web_view.length) { - const named_web_views = web_view.map((viewObj) => ({ - ...viewObj, - name, - })); - allWebViews.push(...named_web_views); + payload.enabledPlugins.forEach( + ({ name, web_view = [], type: plugin_type }) => { + if (web_view && web_view.length) { + const named_web_views = web_view.map((viewObj) => ({ + ...viewObj, + name, + plugin_type, + })); + allWebViews.push(...named_web_views); + } } - }); + ); const remoteRoutes = []; allWebViews.forEach(({ meta, name }) => { @@ -484,9 +487,11 @@ const reducer = (state = INITIAL_STATE, { type, payload = {} }) => { const CLUSTERED_WEB_VIEWS = {}; allWebViews.forEach((plugin) => { - const { target: staticTarget, meta, name } = plugin; + const { target: staticTarget, meta, name, plugin_type } = plugin; let target; - if (staticTarget) { + if (plugin_type === 'app') { + target = generateDynamicTarget(name, 'app'); + } else if (staticTarget) { target = staticTarget; } else if (meta) { const { diff --git a/web/src/reducers/userReducer.js b/web/src/reducers/userReducer.js index dd88c6e033..87c262f959 100644 --- a/web/src/reducers/userReducer.js +++ b/web/src/reducers/userReducer.js @@ -116,6 +116,7 @@ const INITIAL_STATE = { order_portfolio_percentage: 80, popup_warning: true, }, + apps: [], }, addressRequest: INITIAL_ADDRESS_OBJECT, limits: INITIAL_LIMIT_OBJECT, diff --git a/web/src/utils/id.js b/web/src/utils/id.js index e25c4c3b79..bc8a4e86df 100644 --- a/web/src/utils/id.js +++ b/web/src/utils/id.js @@ -10,6 +10,8 @@ export const generateDynamicTarget = ( const name = pluginName.toUpperCase(); const sub = subType.toUpperCase(); switch (type) { + case 'app': + return `APPLICATION__${name}`; case 'verification': return `REMOTE_VERIFICATION_TAB__${name}__${sub}`; case 'page': From d9dd67ee2247bb1cdb4023df764c7506d4f18608 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 18:44:43 +0300 Subject: [PATCH 20/54] Update check deposit status popup --- web/public/assets/images/search-blockchain.svg | 15 +++++++++++++++ web/src/components/CheckDeposit/index.js | 10 ++++------ web/src/config/icons/static.js | 1 + web/src/config/lang/ar.json | 1 + web/src/config/lang/en.json | 1 + web/src/config/lang/fa.json | 1 + web/src/config/lang/pt.json | 1 + web/src/config/lang/tr.json | 1 + web/src/index.scss | 4 ++++ 9 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 web/public/assets/images/search-blockchain.svg diff --git a/web/public/assets/images/search-blockchain.svg b/web/public/assets/images/search-blockchain.svg new file mode 100644 index 0000000000..6d9ebb1001 --- /dev/null +++ b/web/public/assets/images/search-blockchain.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 26.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 480 480" style="enable-background:new 0 0 480 480;" xml:space="preserve"> + <g> + <path d="M460.7,460.1l-55.6-64.9c18.8-21.9,26.6-51.2,21.1-79.5c-5.5-28.3-23.8-52.5-49.5-65.7c-25.7-13.2-56-13.8-82.2-1.7 + c-26.2,12.1-45.5,35.5-52.2,63.6c-6.7,28.1-0.2,57.7,17.7,80.3c17.9,22.6,45.2,35.8,74.1,35.7c21.2,0,41.8-7.2,58.4-20.5l55,64.1h0 + c1.4,2.1,3.6,3.5,6.1,3.8s5-0.4,6.9-2.1s3-4,3-6.5c0-2.5-1-4.9-2.9-6.6L460.7,460.1z M257.2,332.4c0.3-20.3,8.6-39.7,23.1-53.9 + s34.1-22.1,54.4-21.9c20.3,0.2,39.8,8.4,54,22.9c14.3,14.5,22.2,34,22.1,54.3c-0.1,20.3-8.2,39.8-22.6,54.1 + c-14.4,14.3-33.9,22.4-54.2,22.4c-20.5-0.2-40.1-8.5-54.5-23.1C265.1,372.7,257.1,352.9,257.2,332.4L257.2,332.4z" /> + <path d="M213.4,348.9L191.6,362V203.9l140-80.8v88.2c0,4.8,3.9,8.8,8.8,8.8s8.8-3.9,8.8-8.8v-107c0-3.1-1.7-6-4.4-7.6L187.2,5.9 + c-2.7-1.6-6-1.6-8.8,0L20.9,96.8c-2.7,1.6-4.4,4.5-4.4,7.6v182c0,3.1,1.7,6,4.4,7.6l157.5,90.7c2.7,1.6,6,1.6,8.8,0l35-20.8 + c3.6-2.6,4.7-7.6,2.4-11.5C222.4,348.6,217.5,347.1,213.4,348.9L213.4,348.9z M182.8,23.5l143.1,82.6l-143.1,82.6L39.7,106.1 + L182.8,23.5z M34.1,123.1l140,80.8V362l-140-80.9V123.1z" /> + </g> +</svg> \ No newline at end of file diff --git a/web/src/components/CheckDeposit/index.js b/web/src/components/CheckDeposit/index.js index b640cf01a2..11e048b2f8 100644 --- a/web/src/components/CheckDeposit/index.js +++ b/web/src/components/CheckDeposit/index.js @@ -94,17 +94,15 @@ const CheckDeposit = ({ <form className="check-deposit-modal-wrapper" onSubmit={handleSubmit}> <div className="d-flex justify-content-center align-items-center flex-column"> <img - src={STATIC_ICONS.SEARCH} + src={STATIC_ICONS.SEARCH_BLOCKCHAIN} alt="search" - className="search-icon mb-4" + className="search-icon mb-4 blockchain-search" /> <h2>{STRINGS['DEPOSIT_STATUS.CHECK_DEPOSIT_STATUS']}</h2> </div> <div className="inner-content"> - <span className="field-header"> - {STRINGS['DEPOSIT_STATUS.CHECK_DEPOSIT_STATUS']} - </span> - <div className="mb-5"> + <span>{STRINGS['DEPOSIT_STATUS.SEARCH_BLOCKCHAIN_FOR_DEPOSIT']}</span> + <div className="mb-5 field-header"> {STRINGS['DEPOSIT_STATUS.STATUS_DESCRIPTION']} </div> {renderFields(formFields)} diff --git a/web/src/config/icons/static.js b/web/src/config/icons/static.js index 2ddc6e8dfb..882d19f784 100644 --- a/web/src/config/icons/static.js +++ b/web/src/config/icons/static.js @@ -51,6 +51,7 @@ const icons = { DEPOSIT_TIERS_SECTION: '/assets/images/deposit-tier-section.svg', WITHDRAW_TIERS_SECTION: '/assets/images/withdraw-tier-section.svg', TAKER_TIERS_SECTION: '/assets/images/taker-tier-section.svg', + SEARCH_BLOCKCHAIN: '/assets/images/search-blockchain.svg', MAKER_TIERS_SECTION: '/assets/images/maker-tier-section.svg', LIMITS_SECTION_ICON: '/assets/images/limits-coin-tiers.svg', FEES_SECTION_ICON: '/assets/images/limits-pairs-tiers.svg', diff --git a/web/src/config/lang/ar.json b/web/src/config/lang/ar.json index ce82aa6e23..696daf18c1 100644 --- a/web/src/config/lang/ar.json +++ b/web/src/config/lang/ar.json @@ -1022,6 +1022,7 @@ "SEARCH": "بحث", "SEARCHING": "جاري البحث", "CHECK_DEPOSIT_STATUS": "تحقق من حالة الايداع", + "SEARCH_BLOCKCHAIN_FOR_DEPOSIT": "ابحث في blockchain عن الإيداع الخاص بك", "STATUS_DESCRIPTION": "يمكنك التحقق من حالة الإيداع الخاص بك عن طريق إضافة معرف المعاملة أدناه.", "TRANSACTION_ID": "معرف المعاملة ", "SEARCH_SUCCESS": "تم العثور على المعاملة!", diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json index 16c8285730..e49d11d4b3 100644 --- a/web/src/config/lang/en.json +++ b/web/src/config/lang/en.json @@ -1118,6 +1118,7 @@ "NEW": "New", "SEARCH_FIELD_LABEL": "Paste your transaction ID", "CHECK_DEPOSIT_STATUS": "Check deposit status", + "SEARCH_BLOCKCHAIN_FOR_DEPOSIT": "Search blockchain for your deposit", "STATUS_DESCRIPTION": "You can check the status of your deposit by passing the transaction ID (hash) below.", "TRANSACTION_ID": "Transaction ID (hash)", "SEARCH_SUCCESS": "Search complete", diff --git a/web/src/config/lang/fa.json b/web/src/config/lang/fa.json index bed5d40011..6c3ed78df0 100644 --- a/web/src/config/lang/fa.json +++ b/web/src/config/lang/fa.json @@ -1294,6 +1294,7 @@ "NEW": "New", "SEARCH_FIELD_LABEL": "Paste your transaction ID", "CHECK_DEPOSIT_STATUS": "Check deposit status", + "SEARCH_BLOCKCHAIN_FOR_DEPOSIT": "Search blockchain for your deposit", "STATUS_DESCRIPTION": "You can check the status of your deposit by passing the transaction ID (hash) below.", "TRANSACTION_ID": "Transaction ID (hash)", "SEARCH_SUCCESS": "Search complete", diff --git a/web/src/config/lang/pt.json b/web/src/config/lang/pt.json index 32f2fef6c6..bb3b5d5c44 100644 --- a/web/src/config/lang/pt.json +++ b/web/src/config/lang/pt.json @@ -1012,6 +1012,7 @@ "SEARCH": "PESQUISAR", "SEARCHING": "PESQUISANDO", "CHECK_DEPOSIT_STATUS": "Verificar o status do depósito", + "SEARCH_BLOCKCHAIN_FOR_DEPOSIT": "Pesquise blockchain para seu depósito", "STATUS_DESCRIPTION": "Você pode verificar o status do seu depósito passando o ID da transação (hash) abaixo.", "TRANSACTION_ID": "ID de transação (hash)", "SEARCH_SUCCESS": "Pesquisa finalizada", diff --git a/web/src/config/lang/tr.json b/web/src/config/lang/tr.json index 82e8f2705f..c802b69781 100644 --- a/web/src/config/lang/tr.json +++ b/web/src/config/lang/tr.json @@ -1180,6 +1180,7 @@ "NEW": "Yeni", "SEARCH_FIELD_LABEL": "İşlem ID'sini yapıştırın", "CHECK_DEPOSIT_STATUS": "Yatırım durumunu kontrol et", + "SEARCH_BLOCKCHAIN_FOR_DEPOSIT": "Depozitonuz için blockchain arayın", "STATUS_DESCRIPTION": "Aşağıya İşlem ID'nizi (hash) yapıştırarak, yatırım durumunuzu kontrol edebilirsiniz.", "TRANSACTION_ID": "İşlem ID (hash)", "SEARCH_SUCCESS": "Arama tamamlandı", diff --git a/web/src/index.scss b/web/src/index.scss index 6deb084243..c8f1a46854 100644 --- a/web/src/index.scss +++ b/web/src/index.scss @@ -97,6 +97,10 @@ body { } } +.blockchain-search { + filter: brightness(0) invert(0.8); +} + input, input:focus { outline: none; From 3a4c2fdfc728935c719ae632c8e31c92b288a90a Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 18:58:10 +0300 Subject: [PATCH 21/54] Percent movement in quick trade will flashes green --- web/src/components/QuickTrade/index.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/web/src/components/QuickTrade/index.js b/web/src/components/QuickTrade/index.js index dd4ddfd694..eea752aa11 100644 --- a/web/src/components/QuickTrade/index.js +++ b/web/src/components/QuickTrade/index.js @@ -193,6 +193,23 @@ class QuickTrade extends Component { isUseBroker = false; } const increment_unit = isUseBroker ? SIZE && SIZE.STEP : increment_size; + + const getClassnameForPriceDifferences = (priceDifferences) => { + if (priceDifference === 0) + return 'price-diff-none trade-tab-price_diff_none'; + if (priceDifference < 0) + return 'price-diff-down trade-tab-price_diff_down'; + return 'price-diff-up trade-tab-price_diff_up'; + }; + + const getClassnameForTickDifferences = (tickDifferences, state) => { + if (tickDifferences === 0) + return `glance-price-diff-none glance-trade-tab-price_diff_none ${state}`; + if (tickDifferences < 0) + return `glance-price-diff-down glance-trade-tab-price_diff_down ${state}`; + return `glance-price-diff-up glance-trade-tab-price_diff_up ${state}`; + }; + return ( <div className="quick_trade-container"> <div @@ -276,15 +293,12 @@ class QuickTrade extends Component { <Transition in={inProp} timeout={1000}> {(state) => ( <div className="d-flex f-size-22"> + {console.log(tickerDiff)} <div className={classnames( 'title-font', - priceDifference < 0 - ? 'price-diff-down trade-tab-price_diff_down' - : 'price-diff-up trade-tab-price_diff_up', - tickerDiff < 0 - ? `glance-price-diff-down glance-trade-tab-price_diff_down ${state}` - : `glance-price-diff-up glance-trade-tab-price_diff_up ${state}` + getClassnameForPriceDifferences(priceDifference), + getClassnameForTickDifferences(tickerDiff, state) )} > {priceDifferencePercent} From 0467bf986f04a66b9dbe25f45a5c58afd2e5fbe8 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 19:59:07 +0300 Subject: [PATCH 22/54] undo --- .../containers/Trade/components/TradeHistory.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/web/src/containers/Trade/components/TradeHistory.js b/web/src/containers/Trade/components/TradeHistory.js index 6e772f0225..fa2169e8c9 100644 --- a/web/src/containers/Trade/components/TradeHistory.js +++ b/web/src/containers/Trade/components/TradeHistory.js @@ -86,7 +86,6 @@ class TradeHistory extends Component { const { isBase, isOpen } = this.state; const { pairData } = this.props; const { pair_base_display, pair_2_display } = pairData; - const { isDropdownOpen, setIsDropdownOpen } = useState(false); return [ { @@ -127,17 +126,10 @@ class TradeHistory extends Component { bordered={false} defaultValue={false} size="small" - onClick={() => { - setIsDropdownOpen((prev) => !prev); - }} suffixIcon={ - isDropdownOpen ? ( - <CaretUpOutlined /> - ) : ( - <CaretDownOutlined - onClick={() => this.dropdownVisibleChange(!isOpen)} - /> - ) + <CaretDownOutlined + onClick={() => this.dropdownVisibleChange(!isOpen)} + /> } value={isBase} onSelect={this.onSelect} From 00d022d5bd7164b6ebc00c98b2270ae972f84b29 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 20:04:18 +0300 Subject: [PATCH 23/54] Bug Fix --- web/src/components/Form/TradeFormFields/DropDown.js | 4 +++- web/src/containers/Trade/components/TradeHistory.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/web/src/components/Form/TradeFormFields/DropDown.js b/web/src/components/Form/TradeFormFields/DropDown.js index 1ed7787b98..f90021cf57 100644 --- a/web/src/components/Form/TradeFormFields/DropDown.js +++ b/web/src/components/Form/TradeFormFields/DropDown.js @@ -23,7 +23,9 @@ const DropDown = (props) => { bordered={false} size="small" onChange={onChange} - onClick={setIsOpen((prev) => !prev)} + onClick={() => { + setIsOpen((prev) => !prev); + }} suffixIcon={isOpen ? <CaretUpOutlined /> : <CaretDownOutlined />} className="custom-select-input-style w-100 elevated" dropdownClassName="custom-select-style select-option-wrapper" diff --git a/web/src/containers/Trade/components/TradeHistory.js b/web/src/containers/Trade/components/TradeHistory.js index fa2169e8c9..7c37dc7eff 100644 --- a/web/src/containers/Trade/components/TradeHistory.js +++ b/web/src/containers/Trade/components/TradeHistory.js @@ -12,7 +12,7 @@ import { tradeHistorySelector } from '../utils'; import withConfig from 'components/ConfigProvider/withConfig'; import { calcPercentage } from 'utils/math'; import { Select } from 'antd'; -import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons'; +import { CaretDownOutlined } from '@ant-design/icons'; import math from 'mathjs'; import { opacifyNumber } from 'helpers/opacify'; From f9b5abff24ca641f901baace793f960d23d305dd Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 20:09:48 +0300 Subject: [PATCH 24/54] slider animation --- .../components/Form/TradeFormFields/_TradeFormFields.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/src/components/Form/TradeFormFields/_TradeFormFields.scss b/web/src/components/Form/TradeFormFields/_TradeFormFields.scss index f795c12dff..1fbaf70a85 100644 --- a/web/src/components/Form/TradeFormFields/_TradeFormFields.scss +++ b/web/src/components/Form/TradeFormFields/_TradeFormFields.scss @@ -97,6 +97,11 @@ $padding: 0.25rem; } .size-slider { + .ant-slider { + * { + transition: 0.1s; + } + } .ant-slider-with-marks { margin-bottom: 10px; } From 1fa6af49a303077854a4cd3f5f0609a82fb2a411 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 21:24:29 +0300 Subject: [PATCH 25/54] Clear order entry, should also clear amount slider --- .../components/Form/TradeFormFields/Slider.js | 18 +++++++++++++++--- .../containers/Trade/components/OrderEntry.js | 6 +++++- .../Trade/components/TradeHistory.js | 2 +- web/src/containers/Trade/index.js | 15 +++++++++++++++ web/src/index.css | 11 ++++++++++- web/src/utils/currency.js | 3 ++- 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/web/src/components/Form/TradeFormFields/Slider.js b/web/src/components/Form/TradeFormFields/Slider.js index 29c0deeb25..082d239ce6 100644 --- a/web/src/components/Form/TradeFormFields/Slider.js +++ b/web/src/components/Form/TradeFormFields/Slider.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { Slider } from 'antd'; // todo: connect antd slider to redux form @@ -31,8 +31,18 @@ const marks = { }, }; -const SizeSlider = (props) => { - const { onClick } = props; +const SizeSlider = ({ onClick, value, setRef }) => { + const [val, setVal] = useState(0); + + useEffect(() => { + if (setRef) { + setRef({ + reset: () => { + setVal(0); + }, + }); + } + }, [setRef]); return ( <div className="size-slider px-1 pb-2"> @@ -42,6 +52,8 @@ const SizeSlider = (props) => { defaultValue={0} tooltipVisible={false} onAfterChange={onClick} + value={val} + onChange={setVal} /> </div> ); diff --git a/web/src/containers/Trade/components/OrderEntry.js b/web/src/containers/Trade/components/OrderEntry.js index 02df75aba0..2ab1fed875 100644 --- a/web/src/containers/Trade/components/OrderEntry.js +++ b/web/src/containers/Trade/components/OrderEntry.js @@ -411,10 +411,12 @@ class OrderEntry extends Component { }; reset = () => { - const { change } = this.props; + const { change, resetSlider } = this.props; + this.setState({ sliderVal: 0 }); change(FORM_NAME, 'stop', ''); change(FORM_NAME, 'price', ''); change(FORM_NAME, 'size', ''); + resetSlider(); }; handleOrderBookChange = (name, value) => { @@ -568,6 +570,8 @@ class OrderEntry extends Component { name: 'size-slider', type: 'slider', onClick: this.setMax, + value: 0, + setRef: this.props.setSliderRef, }, postOnly: { name: 'post_only', diff --git a/web/src/containers/Trade/components/TradeHistory.js b/web/src/containers/Trade/components/TradeHistory.js index 7c37dc7eff..c04a916871 100644 --- a/web/src/containers/Trade/components/TradeHistory.js +++ b/web/src/containers/Trade/components/TradeHistory.js @@ -1,4 +1,4 @@ -import React, { Component, useState } from 'react'; +import React, { Component } from 'react'; import classnames from 'classnames'; import { connect } from 'react-redux'; import { ReactSVG } from 'react-svg'; diff --git a/web/src/containers/Trade/index.js b/web/src/containers/Trade/index.js index e464230f14..a0fe61ab11 100644 --- a/web/src/containers/Trade/index.js +++ b/web/src/containers/Trade/index.js @@ -358,6 +358,12 @@ class Trade extends PureComponent { } }; + setSliderRef = (sliderRef) => { + if (sliderRef) { + this.sliderRef = sliderRef; + } + }; + setActiveTab = (activeTab) => { const { setTradeTab } = this.props; setTradeTab(activeTab); @@ -429,6 +435,13 @@ class Trade extends PureComponent { }; }; + resetSlider = () => { + console.log(this.sliderRef); + if (this.sliderRef) { + this.sliderRef.reset(); + } + }; + subscribe = (pair) => { const { orderbookWs, wsInitialized } = this.state; if (orderbookWs && wsInitialized) { @@ -573,6 +586,8 @@ class Trade extends PureComponent { showPopup={settings.notification.popup_order_confirmation} setPriceRef={this.setPriceRef} setSizeRef={this.setSizeRef} + setSliderRef={this.setSliderRef} + resetSlider={this.resetSlider} /> </TradeBlock> </div> diff --git a/web/src/index.css b/web/src/index.css index 007ba8256e..6b6f188c8e 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -1543,6 +1543,9 @@ table th { .home_container .html_card_section .card-section-wrapper .card-section .header_txt { font-size: 14px; } } +.wallet-hover:hover { + opacity: 0.5; } + .layout-mobile .button-container { min-height: 4.5rem; } @@ -6023,7 +6026,7 @@ table th { .app_bar .opacity-1 { opacity: 1 !important; } .app_bar .app-bar-account-menu { - transition: .9s; + transition: 0.9s; opacity: 0; display: block; position: absolute; @@ -8168,6 +8171,9 @@ table th { .direction_rtl .trade_input-input-currency { left: 0; } +.size-slider .ant-slider * { + transition: 0.1s; } + .size-slider .ant-slider-with-marks { margin-bottom: 10px; } @@ -11047,6 +11053,9 @@ body { left: 0; top: calc(50% - 0.75rem); } +.blockchain-search { + filter: brightness(0) invert(0.8); } + input, input:focus { outline: none; diff --git a/web/src/utils/currency.js b/web/src/utils/currency.js index c96b9dd90d..a34d495b35 100644 --- a/web/src/utils/currency.js +++ b/web/src/utils/currency.js @@ -4,6 +4,7 @@ import store from 'store'; import STRINGS from '../config/localizedStrings'; import { BASE_CURRENCY, DEFAULT_COIN_DATA } from '../config/constants'; import { findPath, convertPathToPairNames } from './data'; +import { isNaN } from 'lodash'; export const BTC_FORMAT = '0,0.[0000]'; export const ETH_FORMAT = '0,0.[0000]'; @@ -31,7 +32,7 @@ export const AVERAGE_FORMAT = '3a'; // }; export const roundNumber = (number = 0, decimals = 4) => { - if (number === 0) { + if (number === 0 || number === Infinity || isNaN(number)) { return 0; } else if (decimals > 0) { const multipliedNumber = math.multiply( From 59ec671d687f5401884bc425d9a3ec1e551d3cdf Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 21:35:31 +0300 Subject: [PATCH 26/54] Hover feedback order entry --- .../Form/TradeFormFields/ChoiceSelector.js | 1 + .../Form/TradeFormFields/TabSelector.js | 12 +++++++++--- web/src/config/options.js | 16 ++++++++++++---- web/src/index.css | 3 +++ web/src/index.scss | 4 ++++ 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/web/src/components/Form/TradeFormFields/ChoiceSelector.js b/web/src/components/Form/TradeFormFields/ChoiceSelector.js index f998a129f2..1a1444c199 100644 --- a/web/src/components/Form/TradeFormFields/ChoiceSelector.js +++ b/web/src/components/Form/TradeFormFields/ChoiceSelector.js @@ -15,6 +15,7 @@ const ChoiceSelector = (props) => { 'justify-content-center', 'align-items-center', 'pointer', + option.value !== input.value ? option.className : '', 'holla-button-font', { active: option.value === input.value } )} diff --git a/web/src/components/Form/TradeFormFields/TabSelector.js b/web/src/components/Form/TradeFormFields/TabSelector.js index 61bfb88286..d5dd1a7a98 100644 --- a/web/src/components/Form/TradeFormFields/TabSelector.js +++ b/web/src/components/Form/TradeFormFields/TabSelector.js @@ -9,9 +9,15 @@ const TabSelector = (props) => { {options.map((option, index) => ( <div key={`type-${index}`} - className={classnames('text-uppercase', 'text-center', 'pointer', { - active: input.value === option.value, - })} + className={classnames( + 'text-uppercase', + 'text-center', + 'pointer', + input.value !== option.value ? option.className : '', + { + active: input.value === option.value, + } + )} onClick={() => input.onChange(option.value)} > {option.label} diff --git a/web/src/config/options.js b/web/src/config/options.js index 2f8a20783d..a76c00f3c2 100644 --- a/web/src/config/options.js +++ b/web/src/config/options.js @@ -1,13 +1,21 @@ import STRINGS from 'config/localizedStrings'; export const SIDES = [ - { value: 'buy', label: STRINGS['SIDES.BUY'] }, - { value: 'sell', label: STRINGS['SIDES.SELL'] }, + { value: 'buy', label: STRINGS['SIDES.BUY'], className: 'onHoverOpacity' }, + { value: 'sell', label: STRINGS['SIDES.SELL'], className: 'onHoverOpacity' }, ]; export const TYPES = [ - { value: 'market', label: STRINGS['TYPES.MARKET'] }, - { value: 'limit', label: STRINGS['TYPES.LIMIT'] }, + { + value: 'market', + label: STRINGS['TYPES.MARKET'], + className: 'onHoverOpacity', + }, + { + value: 'limit', + label: STRINGS['TYPES.LIMIT'], + className: 'onHoverOpacity', + }, ]; export const DEFAULT_TOGGLE_OPTIONS = [ diff --git a/web/src/index.css b/web/src/index.css index 6b6f188c8e..b47768323f 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -11061,6 +11061,9 @@ input:focus { outline: none; border: none; } +.onHoverOpacity:hover { + opacity: .5; } + input[type='number'] { -moz-appearance: textfield; appearance: textfield; } diff --git a/web/src/index.scss b/web/src/index.scss index c8f1a46854..39b8a5feef 100644 --- a/web/src/index.scss +++ b/web/src/index.scss @@ -107,6 +107,10 @@ input:focus { border: none; } +.onHoverOpacity:hover { + opacity: 0.5; +} + input[type='number'] { -moz-appearance: textfield; appearance: textfield; From 471182e97dd2870880496039d7dd8c7647b6e70c Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 22:04:16 +0300 Subject: [PATCH 27/54] =?UTF-8?q?Fill=20=E2=80=98no=20data=E2=80=99=20hist?= =?UTF-8?q?ory=20pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/package-lock.json | 2 +- .../assets/images/no-active-orders-01.svg | 11 +++++++++ .../assets/images/no-recent-deposits.svg | 9 ++++++++ .../assets/images/no-recent-trades-01.svg | 9 ++++++++ .../assets/images/no-recent-withdrawals.svg | 9 ++++++++ web/src/config/icons/static.js | 4 ++++ web/src/config/lang/ar.json | 1 + web/src/config/lang/de.json | 1 + web/src/config/lang/en.json | 4 ++++ web/src/config/lang/es.json | 1 + web/src/config/lang/fa.json | 1 + web/src/config/lang/fr.json | 1 + .../TransactionsHistory/HistoryDisplay.js | 1 + .../containers/TransactionsHistory/index.js | 23 +++++++++++++++++++ web/src/index.css | 2 +- 15 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 web/public/assets/images/no-active-orders-01.svg create mode 100644 web/public/assets/images/no-recent-deposits.svg create mode 100644 web/public/assets/images/no-recent-trades-01.svg create mode 100644 web/public/assets/images/no-recent-withdrawals.svg diff --git a/web/package-lock.json b/web/package-lock.json index 2d25043409..6bc6790c6f 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,6 +1,6 @@ { "name": "hollaex-kit", - "version": "2.4.0", + "version": "2.4.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/web/public/assets/images/no-active-orders-01.svg b/web/public/assets/images/no-active-orders-01.svg new file mode 100644 index 0000000000..a9b6cac8dc --- /dev/null +++ b/web/public/assets/images/no-active-orders-01.svg @@ -0,0 +1,11 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="42.439" height="42.446" viewBox="0 0 42.439 42.446"> + <g id="no-active-orders-01" opacity="0.55"> + <path id="Path_42" data-name="Path 42" d="M354.107,229.122h7.214a4.088,4.088,0,0,0,4.082-4.082V211.51a2.285,2.285,0,0,0-3.24-2.072l-.394.186-.178-.394a2.283,2.283,0,0,0-3.039-1.144l-.394.186-.178-.394a2.27,2.27,0,0,0-2.837-1.222l-.564.2v-7.074a2.294,2.294,0,0,0-.665-1.616,2.262,2.262,0,0,0-1.616-.665,2.3,2.3,0,0,0-1.616.665,2.262,2.262,0,0,0-.665,1.616v15.687l-2.42-2.42a2.262,2.262,0,0,0-1.616-.665,2.294,2.294,0,0,0-1.616.665,2.262,2.262,0,0,0-.665,1.616,2.3,2.3,0,0,0,.665,1.616l5.257,5.257a1.329,1.329,0,0,1,.387.936v2.567A4.112,4.112,0,0,0,354.107,229.122ZM345.053,215.6a1.323,1.323,0,0,1,1.871-1.871l3.232,3.232a.463.463,0,0,0,.518.1.48.48,0,0,0,.294-.441V199.781a1.316,1.316,0,0,1,.387-.936,1.329,1.329,0,0,1,.936-.387,1.316,1.316,0,0,1,.936.387,1.329,1.329,0,0,1,.387.936v14.435a.479.479,0,0,0,.959,0V208.8a1.33,1.33,0,1,1,2.66,0v5.412a.479.479,0,0,0,.959.015v-4.075a1.33,1.33,0,1,1,2.66,0v4.075a.479.479,0,0,0,.959-.015V211.51a1.33,1.33,0,1,1,2.66,0v13.53a3.138,3.138,0,0,1-3.131,3.131h-7.214a3.138,3.138,0,0,1-3.131-3.131v-2.567a2.3,2.3,0,0,0-.665-1.616Z" transform="translate(-322.964 -186.676)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_43" data-name="Path 43" d="M97.628,57.5H77.781A2.28,2.28,0,0,0,75.5,59.781v13.53a2.28,2.28,0,0,0,2.281,2.281H97.628a2.28,2.28,0,0,0,2.281-2.281V59.781A2.285,2.285,0,0,0,97.628,57.5ZM98.95,73.311a1.33,1.33,0,0,1-1.33,1.33H77.781a1.33,1.33,0,0,1-1.33-1.33V59.781a1.33,1.33,0,0,1,1.33-1.33H97.628a1.33,1.33,0,0,1,1.33,1.33v13.53Z" transform="translate(-75.5 -57.5)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_44" data-name="Path 44" d="M320.979,127.5a.482.482,0,0,0-.479.479V134.3a.479.479,0,1,0,.959,0v-6.317A.487.487,0,0,0,320.979,127.5Z" transform="translate(-301.558 -122.088)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_45" data-name="Path 45" d="M274.279,104.6a.482.482,0,0,0-.479.479V111.4a.479.479,0,1,0,.959,0v-6.317A.477.477,0,0,0,274.279,104.6Z" transform="translate(-258.468 -100.958)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_46" data-name="Path 46" d="M227.579,151.6a.482.482,0,0,0-.479.479V158.4a.479.479,0,1,0,.959,0v-6.317A.477.477,0,0,0,227.579,151.6Z" transform="translate(-215.379 -144.325)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_47" data-name="Path 47" d="M180.979,104.6a.482.482,0,0,0-.479.479V111.4a.479.479,0,0,0,.959,0v-6.317A.482.482,0,0,0,180.979,104.6Z" transform="translate(-172.382 -100.958)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_48" data-name="Path 48" d="M134.779,127.5a.482.482,0,0,0-.479.479V134.3a.479.479,0,0,0,.959,0v-6.317A.482.482,0,0,0,134.779,127.5Z" transform="translate(-129.754 -122.088)" fill="#fff" fill-rule="evenodd"/> + </g> +</svg> diff --git a/web/public/assets/images/no-recent-deposits.svg b/web/public/assets/images/no-recent-deposits.svg new file mode 100644 index 0000000000..9eba8e665f --- /dev/null +++ b/web/public/assets/images/no-recent-deposits.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="31.263" height="40.277" viewBox="0 0 31.263 40.277"> + <g id="Group_7" data-name="Group 7" transform="translate(-1098 -418)"> + <g id="no-recent-trades-01" transform="translate(313.475 90.003)" opacity="0.55"> + <path id="Path_49" data-name="Path 49" d="M795.493,361.953h6.966a4.044,4.044,0,0,0,2.327-.727l8.922-6.177a4.829,4.829,0,0,0,2.08-3.974,2.019,2.019,0,0,0-1.129-1.809h0a2.02,2.02,0,0,0-2.118.209l-7.492,5.76-.155-.626a2.284,2.284,0,0,0-2.219-1.724h-7.94a4.075,4.075,0,0,0-3.44,1.879l-6.409,10a2.3,2.3,0,0,0-.085,2.327,2.274,2.274,0,0,0,2,1.183h2.319a2.273,2.273,0,0,0,1.856-.959l3.433-4.8A1.327,1.327,0,0,1,795.493,361.953Zm-1.856,0-3.433,4.809a1.329,1.329,0,0,1-1.082.557H786.8a1.326,1.326,0,0,1-1.121-2.042l6.409-9.989a3.107,3.107,0,0,1,2.636-1.438h7.948a1.315,1.315,0,0,1,1.307,1.137l.031.263-.07.294.008.008-.008-.008v.015a1.334,1.334,0,0,1-1.268.943h-5.412a.479.479,0,1,0,0,.959h5.7a2.3,2.3,0,0,0,1.392-.472l8.76-6.742a1.064,1.064,0,0,1,1.709.843h0a3.893,3.893,0,0,1-1.67,3.193l-8.922,6.177a3.133,3.133,0,0,1-1.786.557h-6.964A2.22,2.22,0,0,0,793.637,361.953Z" fill="#fff" fill-rule="evenodd"/> + </g> + <path id="Path_54" data-name="Path 54" d="M806.161,349H791.023a2.934,2.934,0,0,1-2.93-2.932V330.928a2.934,2.934,0,0,1,2.93-2.931h15.138a2.935,2.935,0,0,1,2.932,2.931v15.137A2.936,2.936,0,0,1,806.161,349Zm-15.138-20a1.933,1.933,0,0,0-1.93,1.931v15.137a1.933,1.933,0,0,0,1.93,1.932h15.138a1.934,1.934,0,0,0,1.932-1.932V330.928A1.933,1.933,0,0,0,806.161,329Z" transform="translate(313.475 90.003)" fill="#fff" opacity="0.55"/> + <path id="Path_55" data-name="Path 55" d="M803.113,333.976a.5.5,0,0,0-.707,0l-7.481,7.481v-5.363a.5.5,0,0,0-1,0v6.571a.5.5,0,0,0,.309.461.505.505,0,0,0,.191.039h6.57a.5.5,0,0,0,0-1h-5.363l7.481-7.482A.5.5,0,0,0,803.113,333.976Z" transform="translate(313.475 90.003)" fill="#fff" opacity="0.55"/> + </g> +</svg> diff --git a/web/public/assets/images/no-recent-trades-01.svg b/web/public/assets/images/no-recent-trades-01.svg new file mode 100644 index 0000000000..7fa67e65d9 --- /dev/null +++ b/web/public/assets/images/no-recent-trades-01.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="33.423" height="42.445" viewBox="0 0 33.423 42.445"> + <g id="no-recent-trades-01" opacity="0.55"> + <path id="Path_49" data-name="Path 49" d="M172.811,368.915h6.966a4.046,4.046,0,0,0,2.327-.727l8.922-6.177a4.828,4.828,0,0,0,2.08-3.974,2.017,2.017,0,0,0-1.129-1.809h0a2.021,2.021,0,0,0-2.118.209l-7.492,5.76-.155-.626a2.283,2.283,0,0,0-2.219-1.724h-7.94a4.077,4.077,0,0,0-3.44,1.879l-6.409,10a2.3,2.3,0,0,0-.085,2.327,2.275,2.275,0,0,0,2,1.183h2.319a2.273,2.273,0,0,0,1.856-.959l3.433-4.8A1.326,1.326,0,0,1,172.811,368.915Zm-1.856,0-3.433,4.809a1.327,1.327,0,0,1-1.082.557h-2.319A1.326,1.326,0,0,1,163,372.239l6.409-9.989a3.109,3.109,0,0,1,2.636-1.438h7.948a1.314,1.314,0,0,1,1.307,1.137l.031.263-.07.294.008.008-.008-.008v.015a1.332,1.332,0,0,1-1.268.943h-5.412a.479.479,0,1,0,0,.959h5.7a2.307,2.307,0,0,0,1.392-.472l8.76-6.742a1.064,1.064,0,0,1,1.709.843h0a3.891,3.891,0,0,1-1.67,3.193l-8.922,6.177a3.13,3.13,0,0,1-1.786.557H172.8A2.223,2.223,0,0,0,170.955,368.915Z" transform="translate(-159.683 -332.786)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_50" data-name="Path 50" d="M147.268,76.862a11.182,11.182,0,0,0,5.141,1.237,11.3,11.3,0,1,0-11.3-11.3,11.182,11.182,0,0,0,1.237,5.141l.139.278-7.917,7.925a2.262,2.262,0,0,0-.665,1.616,2.294,2.294,0,0,0,.665,1.616l1.276,1.276a2.262,2.262,0,0,0,1.616.665,2.294,2.294,0,0,0,1.616-.665h0l7.917-7.932Zm-8.876,7.113a1.316,1.316,0,0,1-.936.387h0a1.316,1.316,0,0,1-.935-.387L135.245,82.7a1.334,1.334,0,0,1-.387-.943,1.316,1.316,0,0,1,.387-.936L143,73.066l.294.4c.008.008.015.023.023.031a.169.169,0,0,0,.031.039c.031.046.07.093.1.139l.008.008c.062.077.124.162.193.24l.1.124c.054.07.116.139.17.2s.1.108.147.162a1.189,1.189,0,0,1,.131.147c.039.046.085.085.124.131l.2.2c.046.046.093.085.139.131s.093.085.139.131l.216.193c.039.039.085.07.124.108l.015.015.139.116c.07.054.131.108.2.162.054.046.116.085.17.131a.168.168,0,0,1,.039.031c.008.008.023.015.031.023l.4.294Zm8.474-8.443c-.085-.054-.17-.108-.255-.17l-.031-.023c-.07-.046-.139-.1-.209-.147l-.07-.046c-.062-.046-.124-.093-.178-.139l-.062-.046-.232-.186-.031-.031c-.062-.054-.131-.108-.193-.162-.023-.015-.039-.039-.062-.054l-.008-.008c-.054-.046-.1-.093-.155-.139l-.015-.015a.357.357,0,0,1-.054-.054c-.062-.062-.131-.124-.193-.186l-.031-.031c-.062-.062-.124-.124-.186-.193-.015-.023-.039-.039-.054-.062l-.015-.015c-.046-.046-.093-.1-.131-.147a.7.7,0,0,0-.07-.077l-.155-.178-.039-.046a2.515,2.515,0,0,1-.178-.224.235.235,0,0,1-.039-.054l-.015-.023c-.039-.054-.085-.108-.124-.17-.015-.023-.039-.054-.054-.077-.046-.062-.093-.131-.139-.193l-.031-.046c-.054-.085-.108-.162-.162-.247l-.039-.062c-.039-.07-.085-.131-.124-.2a10.359,10.359,0,1,1,3.6,3.6c-.077-.046-.147-.093-.224-.139Z" transform="translate(-133.9 -55.5)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_51" data-name="Path 51" d="M277.465,202.288v-5.165l1.894,1.894a.476.476,0,0,0,.673,0,.467.467,0,0,0,.139-.34.48.48,0,0,0-.139-.34l-2.706-2.706a.241.241,0,0,0-.07-.054l-.015-.008a.481.481,0,0,0-.2-.07h-.108a.416.416,0,0,0-.2.07c-.008.008-.015.008-.023.015a.431.431,0,0,0-.062.046l-2.706,2.706a.476.476,0,1,0,.673.673l1.894-1.894v5.165a.482.482,0,0,0,.479.479A.475.475,0,0,0,277.465,202.288Z" transform="translate(-262.984 -184.676)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_52" data-name="Path 52" d="M337.9,105.949a.475.475,0,0,0,.34-.812l-2.706-2.706a.447.447,0,0,0-.193-.116h-.008a.336.336,0,0,0-.039-.008h-.015a.666.666,0,0,0-.124-.008h-.015a.07.07,0,0,0-.039.008l-.015.008c-.008,0-.015.008-.031.008l-.015.008c-.008,0-.015.008-.031.008l-.015.008c-.008.008-.015.008-.031.015l-.015.008c-.008.008-.015.008-.023.015l-.015.008c-.008.008-.015.015-.023.015l-.039.039-2.706,2.706a.467.467,0,0,0-.139.34.48.48,0,0,0,.139.34.467.467,0,0,0,.34.139h0a.48.48,0,0,0,.34-.139h0l1.894-1.894v5.141a.479.479,0,1,0,.959,0v-5.165l1.894,1.894A.45.45,0,0,0,337.9,105.949Z" transform="translate(-316.684 -98.682)" fill="#fff" fill-rule="evenodd"/> + <path id="Path_53" data-name="Path 53" d="M396.632,198.926a.467.467,0,0,0,.139-.34.48.48,0,0,0-.139-.34l-2.706-2.706a.136.136,0,0,0-.039-.031.507.507,0,0,0-.294-.108h-.016a.463.463,0,0,0-.325.139l-.015.015-2.7,2.7a.476.476,0,0,0,.673.673l1.894-1.894V202.2a.479.479,0,0,0,.959,0v-5.165l1.894,1.894A.476.476,0,0,0,396.632,198.926Z" transform="translate(-370.569 -184.584)" fill="#fff" fill-rule="evenodd"/> + </g> +</svg> diff --git a/web/public/assets/images/no-recent-withdrawals.svg b/web/public/assets/images/no-recent-withdrawals.svg new file mode 100644 index 0000000000..20dd61cc5a --- /dev/null +++ b/web/public/assets/images/no-recent-withdrawals.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="31.262" height="40.277" viewBox="0 0 31.262 40.277"> + <g id="Group_5" data-name="Group 5" transform="translate(-884.428 -327.997)"> + <g id="no-recent-trades-01" opacity="0.55"> + <path id="Path_49" data-name="Path 49" d="M895.4,361.953h6.966a4.044,4.044,0,0,0,2.327-.727l8.922-6.177a4.829,4.829,0,0,0,2.08-3.974,2.018,2.018,0,0,0-1.129-1.809h0a2.02,2.02,0,0,0-2.118.209l-7.492,5.76-.155-.626a2.284,2.284,0,0,0-2.219-1.724h-7.94a4.075,4.075,0,0,0-3.44,1.879l-6.409,10a2.3,2.3,0,0,0-.085,2.327,2.273,2.273,0,0,0,2,1.183h2.319a2.273,2.273,0,0,0,1.856-.959l3.433-4.8A1.326,1.326,0,0,1,895.4,361.953Zm-1.856,0-3.433,4.809a1.329,1.329,0,0,1-1.082.557h-2.319a1.326,1.326,0,0,1-1.121-2.042l6.409-9.989a3.107,3.107,0,0,1,2.636-1.438h7.948a1.315,1.315,0,0,1,1.307,1.137l.031.263-.07.294.008.008-.008-.008v.015a1.334,1.334,0,0,1-1.268.943h-5.412a.479.479,0,1,0,0,.959h5.7a2.3,2.3,0,0,0,1.392-.472l8.76-6.742a1.064,1.064,0,0,1,1.709.843h0a3.893,3.893,0,0,1-1.67,3.193l-8.922,6.177a3.133,3.133,0,0,1-1.786.557h-6.964A2.22,2.22,0,0,0,893.54,361.953Z" fill="#fff" fill-rule="evenodd"/> + </g> + <path id="Path_56" data-name="Path 56" d="M906.064,349H890.927a2.936,2.936,0,0,1-2.932-2.932V330.928A2.935,2.935,0,0,1,890.927,328h15.137a2.934,2.934,0,0,1,2.931,2.931v15.137A2.934,2.934,0,0,1,906.064,349Zm-15.137-20a1.933,1.933,0,0,0-1.932,1.931v15.137A1.934,1.934,0,0,0,890.927,348h15.137a1.934,1.934,0,0,0,1.931-1.932V330.928A1.933,1.933,0,0,0,906.064,329Z" fill="#fff" opacity="0.55"/> + <path id="Path_57" data-name="Path 57" d="M903.125,334.138a.5.5,0,0,0-.271-.27.487.487,0,0,0-.191-.039h-6.57a.5.5,0,0,0,0,1h5.363l-7.481,7.482a.5.5,0,1,0,.707.707l7.481-7.482V340.9a.5.5,0,0,0,1,0v-6.571A.5.5,0,0,0,903.125,334.138Z" fill="#fff" opacity="0.55"/> + </g> +</svg> diff --git a/web/src/config/icons/static.js b/web/src/config/icons/static.js index 882d19f784..648c0f6aec 100644 --- a/web/src/config/icons/static.js +++ b/web/src/config/icons/static.js @@ -52,6 +52,10 @@ const icons = { WITHDRAW_TIERS_SECTION: '/assets/images/withdraw-tier-section.svg', TAKER_TIERS_SECTION: '/assets/images/taker-tier-section.svg', SEARCH_BLOCKCHAIN: '/assets/images/search-blockchain.svg', + NO_ACTIVE_ORDERS: '/assets/images/no-active-orders-01.svg', + NO_ACTIVE_TRADES: '/assets/images/no-recent-trades-01.svg', + NO_ACTIVE_DEPOSITS: '/assets/images/no-recent-deposits.svg', + NO_ACTIVE_WITHDRAWALS: '/assets/images/no-recent-withdrawals.svg', MAKER_TIERS_SECTION: '/assets/images/maker-tier-section.svg', LIMITS_SECTION_ICON: '/assets/images/limits-coin-tiers.svg', FEES_SECTION_ICON: '/assets/images/limits-pairs-tiers.svg', diff --git a/web/src/config/lang/ar.json b/web/src/config/lang/ar.json index 696daf18c1..491673b07f 100644 --- a/web/src/config/lang/ar.json +++ b/web/src/config/lang/ar.json @@ -23,6 +23,7 @@ "HELPFUL_RESOURCES_TEXT": "مصادر مفيدة", "HELP_TELEGRAM_TEXT": "تحقق من وثائق API المفتوحة:", "HELP_TELEGRAM_LINK": "https://apidocs.hollaex.com", + "NO_ACTIVE_ORDERS": "No orders detected. Place your orders on the Pro or Quick trade page", "NEED_HELP_TEXT": "تحتاج لمساعدة؟", "HELP_TEXT": "مساعدة", "SUCCESS_TEXT": "نجاح", diff --git a/web/src/config/lang/de.json b/web/src/config/lang/de.json index 85cb51fe53..e0e4adc0e9 100644 --- a/web/src/config/lang/de.json +++ b/web/src/config/lang/de.json @@ -7,6 +7,7 @@ "CANCEL_WITHDRAWAL": "Auszahlung abbrechen", "CANCEL_WITHDRAWAL_POPUP_CONFIRM": "Möchten Sie Ihre ausstehende Auszahlung stornieren?:", "TIMESTAMP_FORMAT": "YYYY/MM/DD HH:mm:ss", + "NO_ACTIVE_ORDERS": "No orders detected. Place your orders on the Pro or Quick trade page", "HOUR_FORMAT": "HH:mm:ss", "LOGIN_TEXT": "Login", "SIGN_IN": "Anmelden", diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json index e49d11d4b3..47a3e7d708 100644 --- a/web/src/config/lang/en.json +++ b/web/src/config/lang/en.json @@ -7,6 +7,10 @@ "CANCEL_WITHDRAWAL": "Cancel Withdrawal", "CANCEL_WITHDRAWAL_POPUP_CONFIRM": "Do you want to cancel your pending withdrawal of:", "TIMESTAMP_FORMAT": "YYYY/MM/DD HH:mm:ss", + "NO_ACTIVE_ORDERS": "No orders detected. Place your orders on the Pro or Quick trade page", + "NO_ACTIVE_TRADES": "Looks like there aren't any trades yet", + "NO_ACTIVE_DEPOSITS": "Looks like there aren't any deposits yet.", + "NO_ACTIVE_WITHDRAWALS": "Looks like there aren't any withdrawals yet", "HOUR_FORMAT": "HH:mm:ss", "LOGIN_TEXT": "Login", "SIGN_IN": "Sign In", diff --git a/web/src/config/lang/es.json b/web/src/config/lang/es.json index ef62aa021d..9f3a2db1aa 100644 --- a/web/src/config/lang/es.json +++ b/web/src/config/lang/es.json @@ -6,6 +6,7 @@ "CANCEL_BASE_WITHDRAWAL": "Cancelar {0} Retiro", "CANCEL_WITHDRAWAL": "Cancelar Retiro", "CANCEL_WITHDRAWAL_POPUP_CONFIRM": "Quiere cancelar su retiro pendiente de:", + "NO_ACTIVE_ORDERS": "No orders detected. Place your orders on the Pro or Quick trade page", "TIMESTAMP_FORMAT": "YYYY/MM/DD HH:mm:ss", "HOUR_FORMAT": "HH:mm:ss", "LOGIN_TEXT": "Iniciar Sesión", diff --git a/web/src/config/lang/fa.json b/web/src/config/lang/fa.json index 6c3ed78df0..980cf62fc3 100644 --- a/web/src/config/lang/fa.json +++ b/web/src/config/lang/fa.json @@ -36,6 +36,7 @@ "GO_TRADE": "معامله رو شروع کن", "VIEW_INFO": "مشاهده صفحه اطلاعات", "APPLY_HERE": "اعمال تغییرات", + "NO_ACTIVE_ORDERS": "No orders detected. Place your orders on the Pro or Quick trade page", "HOME": { "SECTION_1_TITLE": "به HollaEx kit خوش آمدید", "SECTION_1_TEXT_1": "با خیالی آسوده اکسچنج تبادل دارایی های دیجیتال خود را بسازید و جزو آینده بازارهای مالی جهان شوید.", diff --git a/web/src/config/lang/fr.json b/web/src/config/lang/fr.json index fac0aa8ea3..93d8d6e2f3 100644 --- a/web/src/config/lang/fr.json +++ b/web/src/config/lang/fr.json @@ -11,6 +11,7 @@ "LOGIN_TEXT": "Connexion", "SIGN_IN": "S'identifier", "SIGNUP_TEXT": "S'enregistrer", + "NO_ACTIVE_ORDERS": "No orders detected. Place your orders on the Pro or Quick trade page", "REGISTER_TEXT": "S'inscrire", "ACCOUNT_TEXT": "Compte", "CLOSE_TEXT": "Fermer", diff --git a/web/src/containers/TransactionsHistory/HistoryDisplay.js b/web/src/containers/TransactionsHistory/HistoryDisplay.js index ea4ce076b8..f2fa5aee9e 100644 --- a/web/src/containers/TransactionsHistory/HistoryDisplay.js +++ b/web/src/containers/TransactionsHistory/HistoryDisplay.js @@ -115,6 +115,7 @@ const HistoryDisplay = (props) => { title={title} handleNext={handleNext} jumpToPage={jumpToPage} + noData={props.noData} /> )} <Dialog diff --git a/web/src/containers/TransactionsHistory/index.js b/web/src/containers/TransactionsHistory/index.js index c0ca4ea300..6fabc049b1 100644 --- a/web/src/containers/TransactionsHistory/index.js +++ b/web/src/containers/TransactionsHistory/index.js @@ -44,6 +44,8 @@ import { import STRINGS from 'config/localizedStrings'; import withConfig from 'components/ConfigProvider/withConfig'; +import { STATIC_ICONS } from 'config/icons'; +import { Image } from 'hollaex-web-lib'; const GROUP_CLASSES = [...FLEX_CENTER_CLASSES, 'flex-column']; @@ -419,6 +421,21 @@ class TransactionsHistory extends Component { withIcon: true, }; + const prepareNoData = (tab) => { + return ( + <div className="d-flex flex-column align-items-center"> + <Image + iconId={tab} + icon={STATIC_ICONS[tab]} + alt={tab} + width="40px" + height="40px" + /> + <span>{STRINGS[tab]}</span> + </div> + ); + }; + switch (activeTab) { case 1: props.stringId = 'ORDER_HISTORY'; @@ -431,6 +448,7 @@ class TransactionsHistory extends Component { props.jumpToPage = jumpToPage; props.handleDownload = () => downloadUserOrders(temp); props.filters = filters.orders; + props.noData = prepareNoData('NO_ACTIVE_ORDERS'); break; case 0: props.stringId = 'TRANSACTION_HISTORY.TITLE_TRADES'; @@ -443,6 +461,8 @@ class TransactionsHistory extends Component { props.jumpToPage = jumpToPage; props.handleDownload = () => downloadUserTrades(temp); props.filters = filters.trades; + props.noData = prepareNoData('NO_ACTIVE_TRADES'); + break; case 2: props.stringId = 'TRANSACTION_HISTORY.TITLE_DEPOSITS'; @@ -454,6 +474,8 @@ class TransactionsHistory extends Component { props.jumpToPage = jumpToPage; props.handleDownload = () => downloadUserDeposit(temp); props.filters = filters.deposits; + props.noData = prepareNoData('NO_ACTIVE_DEPOSITS'); + break; case 3: props.stringId = 'TRANSACTION_HISTORY.TITLE_WITHDRAWALS'; @@ -465,6 +487,7 @@ class TransactionsHistory extends Component { props.jumpToPage = jumpToPage; props.handleDownload = () => downloadUserWithdrawal(temp); props.filters = filters.withdrawals; + props.noData = prepareNoData('NO_ACTIVE_WITHDRAWALS'); break; default: return <div />; diff --git a/web/src/index.css b/web/src/index.css index b47768323f..7d6b25cf6b 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -11062,7 +11062,7 @@ input:focus { border: none; } .onHoverOpacity:hover { - opacity: .5; } + opacity: 0.5; } input[type='number'] { -moz-appearance: textfield; From 0954523eba77c32e183324f77e4fcb49dff5a5c4 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Wed, 21 Sep 2022 22:25:48 +0300 Subject: [PATCH 28/54] In cases where there is no movement, draw a line. --- web/src/components/QuickTrade/index.js | 2 +- .../containers/TradeTabs/components/SparkLine.js | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/web/src/components/QuickTrade/index.js b/web/src/components/QuickTrade/index.js index eea752aa11..76efadace1 100644 --- a/web/src/components/QuickTrade/index.js +++ b/web/src/components/QuickTrade/index.js @@ -293,7 +293,6 @@ class QuickTrade extends Component { <Transition in={inProp} timeout={1000}> {(state) => ( <div className="d-flex f-size-22"> - {console.log(tickerDiff)} <div className={classnames( 'title-font', @@ -315,6 +314,7 @@ class QuickTrade extends Component { containerProps={{ style: { height: '100%', width: '100%' }, }} + renderDefaultLine /> </div> <div className="d-flex pb-35"> diff --git a/web/src/containers/TradeTabs/components/SparkLine.js b/web/src/containers/TradeTabs/components/SparkLine.js index 9443f260d1..ddf4bd2d12 100644 --- a/web/src/containers/TradeTabs/components/SparkLine.js +++ b/web/src/containers/TradeTabs/components/SparkLine.js @@ -7,7 +7,6 @@ class SparkLine extends Component { constructor(props) { super(props); const { data: { close = [], open = 0 } = {} } = this.props; - this.state = { chartOptions: { tooltip: { @@ -60,7 +59,10 @@ class SparkLine extends Component { } componentWillReceiveProps(nextProps) { - const { data } = this.props; + const { data, renderDefaultLine } = this.props; + if (data?.close?.length === 1 && renderDefaultLine) { + data.close.push(data.close[0]); + } if (JSON.stringify(data) !== JSON.stringify(nextProps.data)) { this.setState((prevState) => ({ ...prevState, @@ -69,8 +71,12 @@ class SparkLine extends Component { series: [ { ...prevState.chartOptions.series, - name: _get(nextProps, 'data.name') ? _get(nextProps, 'data.name') : _get(prevState, 'chartOptions.series.name'), - type: _get(nextProps, 'data.type') ? _get(nextProps, 'data.type') : _get(prevState, 'chartOptions.series.type'), + name: _get(nextProps, 'data.name') + ? _get(nextProps, 'data.name') + : _get(prevState, 'chartOptions.series.name'), + type: _get(nextProps, 'data.type') + ? _get(nextProps, 'data.type') + : _get(prevState, 'chartOptions.series.type'), data: nextProps.data.close, threshold: nextProps.data.open, }, From 128c91f4e803debdc9353a2b07164491041c3dc5 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Thu, 22 Sep 2022 17:54:40 +0300 Subject: [PATCH 29/54] OTP Button fix --- web/src/components/Button/CheckboxButton.js | 13 ++++-- web/src/containers/UserSecurity/OTP.js | 43 ++++++++++++------- .../UserSecurity/_UserSecurity.scss | 13 ++++++ web/src/index.css | 10 +++++ 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/web/src/components/Button/CheckboxButton.js b/web/src/components/Button/CheckboxButton.js index 336cf8d42a..d8fc3a5e41 100644 --- a/web/src/components/Button/CheckboxButton.js +++ b/web/src/components/Button/CheckboxButton.js @@ -3,10 +3,16 @@ import classnames from 'classnames'; import { EditWrapper } from 'components'; import Image from 'components/Image'; -const renderCheckboxImage = (checked, ICONS = {}) => ( +const renderCheckboxImage = (checked, ICONS = {}, customCheckIcon) => ( <Image iconId={checked ? 'SUCCESS_BLACK' : 'SECURE'} - icon={checked ? ICONS['SUCCESS_BLACK'] : ICONS['SECURE']} + icon={ + checked + ? customCheckIcon + ? ICONS[customCheckIcon] + : ICONS['SUCCESS_BLACK'] + : ICONS['SECURE'] + } wrapperClassName="checkbutton-input-wrapper--image" /> ); @@ -27,6 +33,7 @@ const CheckboxButton = ({ loading = false, children, icons, + customCheckIcon = '', }) => ( <div className="checkbutton-wrapper"> <div @@ -43,7 +50,7 @@ const CheckboxButton = ({ {loading ? ( <div className="checkbutton-input-wrapper--loader" /> ) : ( - renderCheckboxImage(checked, icons) + renderCheckboxImage(checked, icons, customCheckIcon) )} <span className="checkbutton-input-wrapper--label"> <EditWrapper stringId={stringId}>{label}</EditWrapper> diff --git a/web/src/containers/UserSecurity/OTP.js b/web/src/containers/UserSecurity/OTP.js index de8d059ca0..6608c6bccd 100644 --- a/web/src/containers/UserSecurity/OTP.js +++ b/web/src/containers/UserSecurity/OTP.js @@ -3,6 +3,7 @@ import { CheckboxButton, IconTitle, EditWrapper } from 'components'; import QRCode from 'qrcode.react'; import OTPForm from './OTPForm'; import STRINGS from 'config/localizedStrings'; +import { Image } from 'hollaex-web-lib'; export const renderOTPForm = ( secret, @@ -86,20 +87,32 @@ export const OTP = ({ </div> )} </div> - <CheckboxButton - stringId="ACCOUNT_SECURITY.OTP.CONTENT.ENABLE,ACCOUNT_SECURITY.OTP.CONTENT.DISABLE" - label={ - STRINGS[ - `ACCOUNT_SECURITY.OTP.CONTENT.${otp_enabled ? 'DISABLE' : 'ENABLE'}` - ] - } - onClick={requestOTP} - disabled={data.requesting} - loading={data.requesting} - checked={otp_enabled} - icons={icons} - > - {children} - </CheckboxButton> + <div className="d-flex w-100 justify-content-center align-items-center mt-5"> + <CheckboxButton + stringId="ACCOUNT_SECURITY.OTP.CONTENT.ENABLE,ACCOUNT_SECURITY.OTP.CONTENT.DISABLE" + label={ + STRINGS[ + `ACCOUNT_SECURITY.OTP.CONTENT.${otp_enabled ? 'DISABLE' : 'ENABLE'}` + ] + } + onClick={requestOTP} + disabled={data.requesting} + loading={data.requesting} + checked={otp_enabled} + icons={icons} + customCheckIcon="SECURE" + > + {children} + </CheckboxButton> + {otp_enabled && ( + <Image + iconId={'SUCCESS_BLACK'} + icon={icons['SUCCESS_BLACK']} + wrapperClassName="OTP_Success ml-2" + width="20px" + height="20px" + /> + )} + </div> </div> ); diff --git a/web/src/containers/UserSecurity/_UserSecurity.scss b/web/src/containers/UserSecurity/_UserSecurity.scss index 103238bb4d..d45e8798cd 100644 --- a/web/src/containers/UserSecurity/_UserSecurity.scss +++ b/web/src/containers/UserSecurity/_UserSecurity.scss @@ -11,6 +11,15 @@ } } +.OTP_Success { + width: 30px; + height: 30px; + svg { + width: 30px; + height: 30px; + } +} + .otp_form-wrapper { display: flex; flex-direction: column; @@ -215,6 +224,10 @@ $padding-input: 4rem; flex-direction: row; align-items: center; } + + .checkbutton-input-wrapper { + margin-top: 0px !important; + } } .layout-mobile { diff --git a/web/src/index.css b/web/src/index.css index daad3b4292..d73be2273b 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -870,6 +870,13 @@ table th { .user_security-wrapper > *:not(:last-child) { margin-bottom: 2rem; } +.OTP_Success { + width: 30px; + height: 30px; } + .OTP_Success svg { + width: 30px; + height: 30px; } + .otp_form-wrapper { display: flex; flex-direction: column; @@ -1003,6 +1010,9 @@ table th { flex-direction: row; align-items: center; } +.user-security-container .checkbutton-input-wrapper { + margin-top: 0px !important; } + .layout-mobile .user_security-wrapper .warning_text { font-size: 13px !important; } From 04935dcc2692f9a3f22430da61e2ef91f98b9251 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Thu, 22 Sep 2022 18:42:56 +0300 Subject: [PATCH 30/54] Refresh buttons added into history --- web/public/assets/icons/refresh-icon.svg | 1 + web/src/actions/walletActions.js | 1 - web/src/config/icons/static.js | 1 + .../TransactionsHistory/HistoryDisplay.js | 13 ++++++++++- .../_TransactionsHistory.scss | 23 ++++++++++++++++++- .../containers/TransactionsHistory/index.js | 6 +++-- web/src/index.css | 16 ++++++++++++- 7 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 web/public/assets/icons/refresh-icon.svg diff --git a/web/public/assets/icons/refresh-icon.svg b/web/public/assets/icons/refresh-icon.svg new file mode 100644 index 0000000000..1502e06685 --- /dev/null +++ b/web/public/assets/icons/refresh-icon.svg @@ -0,0 +1 @@ +<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" width="30px" height="30px"><path d="M 15 3 C 12.031398 3 9.3028202 4.0834384 7.2070312 5.875 A 1.0001 1.0001 0 1 0 8.5058594 7.3945312 C 10.25407 5.9000929 12.516602 5 15 5 C 20.19656 5 24.450989 8.9379267 24.951172 14 L 22 14 L 26 20 L 30 14 L 26.949219 14 C 26.437925 7.8516588 21.277839 3 15 3 z M 4 10 L 0 16 L 3.0507812 16 C 3.562075 22.148341 8.7221607 27 15 27 C 17.968602 27 20.69718 25.916562 22.792969 24.125 A 1.0001 1.0001 0 1 0 21.494141 22.605469 C 19.74593 24.099907 17.483398 25 15 25 C 9.80344 25 5.5490109 21.062074 5.0488281 16 L 8 16 L 4 10 z"/></svg> \ No newline at end of file diff --git a/web/src/actions/walletActions.js b/web/src/actions/walletActions.js index 3fbae0b81d..042a7b5451 100644 --- a/web/src/actions/walletActions.js +++ b/web/src/actions/walletActions.js @@ -221,7 +221,6 @@ export const getOrdersHistory = ({ dataParams.open = open; } const query = querystring.stringify(dataParams); - return (dispatch) => { dispatch({ type: ACTION_KEYS.ORDER_HISTORY_PENDING, payload: { page } }); axios diff --git a/web/src/config/icons/static.js b/web/src/config/icons/static.js index 2d983ead1c..18aa3a14af 100644 --- a/web/src/config/icons/static.js +++ b/web/src/config/icons/static.js @@ -48,6 +48,7 @@ const icons = { HELP_FOOTER_POPUP: '/assets/images/terms_of_service_and_privacy_policy-tooltip.png', HELP_REFERRAL_BADGE_POPUP: '/assets/images/help-popup-footer.png', + REFRESH: '/assets/icons/refresh-icon.svg', DEPOSIT_TIERS_SECTION: '/assets/images/deposit-tier-section.svg', WITHDRAW_TIERS_SECTION: '/assets/images/withdraw-tier-section.svg', TAKER_TIERS_SECTION: '/assets/images/taker-tier-section.svg', diff --git a/web/src/containers/TransactionsHistory/HistoryDisplay.js b/web/src/containers/TransactionsHistory/HistoryDisplay.js index f2fa5aee9e..23553b1c26 100644 --- a/web/src/containers/TransactionsHistory/HistoryDisplay.js +++ b/web/src/containers/TransactionsHistory/HistoryDisplay.js @@ -29,6 +29,7 @@ const HistoryDisplay = (props) => { handleNext, jumpToPage, handleDownload, + refetchData, icons: ICONS, activeTab, } = props; @@ -81,7 +82,7 @@ const HistoryDisplay = (props) => { text={STRINGS['TRANSACTION_HISTORY.TEXT_DOWNLOAD']} iconId="DATA" iconPath={ICONS['DATA']} - className="csv-action" + className="download-history" onClick={handleDownload} /> </div> @@ -96,6 +97,16 @@ const HistoryDisplay = (props) => { onClick={openDialog} /> ) : null} + <div className="download-icon"> + <ActionNotification + stringId="RESFRESH" + text={STRINGS['REFRESH']} + iconId="REFRESH" + iconPath={STATIC_ICONS['REFRESH']} + className="refresh-history" + onClick={refetchData} + /> + </div> </div> )} {filters} diff --git a/web/src/containers/TransactionsHistory/_TransactionsHistory.scss b/web/src/containers/TransactionsHistory/_TransactionsHistory.scss index c8d4890bb4..2625a7f300 100644 --- a/web/src/containers/TransactionsHistory/_TransactionsHistory.scss +++ b/web/src/containers/TransactionsHistory/_TransactionsHistory.scss @@ -159,8 +159,29 @@ } } .check-deposit-txt { - right: 150px !important; + right: 230px !important; + & svg { + padding-right: 0.3rem; + box-sizing: border-box; + border-right: 1px solid $trade-fill-indicator-text; + height: 100%; + } + } + + .download-history { + right: 85px !important; + & svg { + padding-right: 0.1rem; + box-sizing: content-box; + border-right: 1px solid $trade-fill-indicator-text; + height: 100%; + } } + + .refresh-history { + right: 10px !important; + } + .loader_wrapper { top: 0; left: 0; diff --git a/web/src/containers/TransactionsHistory/index.js b/web/src/containers/TransactionsHistory/index.js index 6fabc049b1..b0e052bcc6 100644 --- a/web/src/containers/TransactionsHistory/index.js +++ b/web/src/containers/TransactionsHistory/index.js @@ -449,6 +449,7 @@ class TransactionsHistory extends Component { props.handleDownload = () => downloadUserOrders(temp); props.filters = filters.orders; props.noData = prepareNoData('NO_ACTIVE_ORDERS'); + props.refetchData = () => this.requestData(activeTab); break; case 0: props.stringId = 'TRANSACTION_HISTORY.TITLE_TRADES'; @@ -462,7 +463,7 @@ class TransactionsHistory extends Component { props.handleDownload = () => downloadUserTrades(temp); props.filters = filters.trades; props.noData = prepareNoData('NO_ACTIVE_TRADES'); - + props.refetchData = () => this.requestData(activeTab); break; case 2: props.stringId = 'TRANSACTION_HISTORY.TITLE_DEPOSITS'; @@ -475,7 +476,7 @@ class TransactionsHistory extends Component { props.handleDownload = () => downloadUserDeposit(temp); props.filters = filters.deposits; props.noData = prepareNoData('NO_ACTIVE_DEPOSITS'); - + props.refetchData = () => this.requestData(activeTab); break; case 3: props.stringId = 'TRANSACTION_HISTORY.TITLE_WITHDRAWALS'; @@ -488,6 +489,7 @@ class TransactionsHistory extends Component { props.handleDownload = () => downloadUserWithdrawal(temp); props.filters = filters.withdrawals; props.noData = prepareNoData('NO_ACTIVE_WITHDRAWALS'); + props.refetchData = () => this.requestData(activeTab); break; default: return <div />; diff --git a/web/src/index.css b/web/src/index.css index d73be2273b..7e4f34c1f7 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -2226,7 +2226,21 @@ table th { border-radius: 20px; margin-right: 10px; } .history_block-wrapper .check-deposit-txt { - right: 150px !important; } + right: 230px !important; } + .history_block-wrapper .check-deposit-txt svg { + padding-right: .3rem; + box-sizing: border-box; + border-right: 1px solid var(--labels_secondary-inactive-label-text-graphics); + height: 100%; } + .history_block-wrapper .download-history { + right: 85px !important; } + .history_block-wrapper .download-history svg { + padding-right: .1rem; + box-sizing: content-box; + border-right: 1px solid var(--labels_secondary-inactive-label-text-graphics); + height: 100%; } + .history_block-wrapper .refresh-history { + right: 10px !important; } .history_block-wrapper .loader_wrapper { top: 0; left: 0; } From bcfb2eeacb34db50ae23bce19a421fb778d3e9c7 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Thu, 22 Sep 2022 19:05:55 +0300 Subject: [PATCH 31/54] Add symbol in the fields for order entry --- web/src/components/Form/TradeFormFields/InputField.js | 2 +- web/src/containers/Trade/components/OrderEntry.js | 7 ++----- web/src/index.css | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/web/src/components/Form/TradeFormFields/InputField.js b/web/src/components/Form/TradeFormFields/InputField.js index f577e73ce1..b291b32207 100644 --- a/web/src/components/Form/TradeFormFields/InputField.js +++ b/web/src/components/Form/TradeFormFields/InputField.js @@ -21,7 +21,7 @@ const InputField = (props) => { > <input ref={setRef} {...input} {...rest} /> {currency && ( - <div className="trade_input-input-currency d-flex justify-content-center align-items-center"> + <div className="trade_input-input-currency d-flex justify-content-center align-items-center mr-2"> {currency} </div> )} diff --git a/web/src/containers/Trade/components/OrderEntry.js b/web/src/containers/Trade/components/OrderEntry.js index 2ab1fed875..b3cdd0d3f0 100644 --- a/web/src/containers/Trade/components/OrderEntry.js +++ b/web/src/containers/Trade/components/OrderEntry.js @@ -451,9 +451,6 @@ class OrderEntry extends Component { side = 'buy', } = props; - const { display_name } = coins[pair] || DEFAULT_COIN_DATA; - const { display_name: buy_display_name } = - coins[buyingPair] || DEFAULT_COIN_DATA; const { initialValues: { order_type }, } = this.state; @@ -528,7 +525,7 @@ class OrderEntry extends Component { maxValue(max_price), step(increment_price), ], - currency: buy_display_name, + currency: pair_2_display, setRef: this.props.setPriceRef, }, size: { @@ -563,7 +560,7 @@ class OrderEntry extends Component { min: min_size, max: max_size, validate: [required, minValue(min_size), maxValue(max_size)], - currency: display_name, + currency: pair_base_display, setRef: this.props.setSizeRef, }, slider: { diff --git a/web/src/index.css b/web/src/index.css index 7e4f34c1f7..10d97c9681 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -2228,14 +2228,14 @@ table th { .history_block-wrapper .check-deposit-txt { right: 230px !important; } .history_block-wrapper .check-deposit-txt svg { - padding-right: .3rem; + padding-right: 0.3rem; box-sizing: border-box; border-right: 1px solid var(--labels_secondary-inactive-label-text-graphics); height: 100%; } .history_block-wrapper .download-history { right: 85px !important; } .history_block-wrapper .download-history svg { - padding-right: .1rem; + padding-right: 0.1rem; box-sizing: content-box; border-right: 1px solid var(--labels_secondary-inactive-label-text-graphics); height: 100%; } From 5dacaf189200e8d28c2dc986acb49851d039bd7c Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Thu, 22 Sep 2022 19:18:32 +0300 Subject: [PATCH 32/54] In drop down, keep the currently selected --- .../Form/FormFields/DropdownField.js | 18 ++++++++++++++++++ .../Form/FormFields/_DropdownField.scss | 4 ++++ web/src/index.css | 3 +++ 3 files changed, 25 insertions(+) diff --git a/web/src/components/Form/FormFields/DropdownField.js b/web/src/components/Form/FormFields/DropdownField.js index ce020c3f0c..381152686e 100644 --- a/web/src/components/Form/FormFields/DropdownField.js +++ b/web/src/components/Form/FormFields/DropdownField.js @@ -102,6 +102,20 @@ class DropdownField extends Component { </div> ); + renderOptionWhenOpen = (option, index) => ( + <div + id={`${this.props.input.name}-${option.value}-${index}`} + key={`${this.props.input.name}-${option.value}-${index}`} + onClick={this.onSelectOption(option)} + className={classnames('dropdown-option-open', { + pointer: !this.props.disabled, + })} + > + {this.renderIcon(option)} + {option.label} + </div> + ); + renderOptions = (options) => ( <div className={classnames('dropdown-options-wrapper')}> {options.length > 0 @@ -195,6 +209,10 @@ class DropdownField extends Component { </div> )} </div> + {isOpen && + selectedItem && + !autocomplete && + this.renderOptionWhenOpen(selectedItem)} {isOpen && this.renderOptions(filteredOptions)} </FieldWrapper> ); diff --git a/web/src/components/Form/FormFields/_DropdownField.scss b/web/src/components/Form/FormFields/_DropdownField.scss index a7aa1e391d..30b0765c72 100644 --- a/web/src/components/Form/FormFields/_DropdownField.scss +++ b/web/src/components/Form/FormFields/_DropdownField.scss @@ -15,6 +15,10 @@ $dropdown-option--padding: 0.25rem; } } +.dropdown-option-open { + margin: 0px !important; +} + .disabled { .field-children { color: $colors-deactivate; diff --git a/web/src/index.css b/web/src/index.css index 10d97c9681..94cbff9043 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -7707,6 +7707,9 @@ table th { cursor: not-allowed; color: var(--labels_secondary-inactive-label-text-graphics); } +.dropdown-option-open { + margin: 0px !important; } + .disabled .field-children { color: var(--labels_secondary-inactive-label-text-graphics); } .disabled .field-children .dropdown-triangle:after { From 7db9e3c389a54d3aa9b957c85e9407042564e8e8 Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Thu, 22 Sep 2022 19:29:21 +0300 Subject: [PATCH 33/54] Inconsistent capital letters in theme drop down --- web/src/components/AppBar/ThemeSwitcher.js | 2 +- web/src/components/AppBar/_AppBar.scss | 3 +++ web/src/index.css | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/web/src/components/AppBar/ThemeSwitcher.js b/web/src/components/AppBar/ThemeSwitcher.js index ffe66657f6..46e76dba25 100644 --- a/web/src/components/AppBar/ThemeSwitcher.js +++ b/web/src/components/AppBar/ThemeSwitcher.js @@ -79,7 +79,7 @@ const ThemeSwitcher = ({ selected, options = [], toggle, icons: ICONS }) => { dropdownClassName="custom-select-style select-option-wrapper" > {options.map(({ value }) => ( - <Option value={value} key={value}> + <Option value={value} key={value} className="capitalize"> {value} </Option> ))} diff --git a/web/src/components/AppBar/_AppBar.scss b/web/src/components/AppBar/_AppBar.scss index fe837b6872..883a16dd2b 100644 --- a/web/src/components/AppBar/_AppBar.scss +++ b/web/src/components/AppBar/_AppBar.scss @@ -513,6 +513,9 @@ $app-menu-width: calc(100vw - 40rem); font-size: 11px; } } +.capitalize { + text-transform: capitalize; +} .home_app_bar { position: relative; diff --git a/web/src/index.css b/web/src/index.css index 94cbff9043..d5642b068c 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -6207,6 +6207,9 @@ table th { cursor: pointer; font-size: 11px; } +.capitalize { + text-transform: capitalize; } + .home_app_bar { position: relative; width: 100%; From 69504622e8a64f2c3de4509e5465bf122315e124 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Mon, 26 Sep 2022 20:11:20 +0900 Subject: [PATCH 34/54] min coin length set to 2 --- server/api/swagger/swagger.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api/swagger/swagger.yaml b/server/api/swagger/swagger.yaml index 877101e4d2..c35eecd4eb 100644 --- a/server/api/swagger/swagger.yaml +++ b/server/api/swagger/swagger.yaml @@ -1613,7 +1613,7 @@ paths: in: query required: true type: string - minLength: 3 + minLength: 2 maxLength: 15 - name: network in: query From 8836c4b899c6eaabf01c5b24e061cc1caeed1b62 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 04:50:44 +0330 Subject: [PATCH 35/54] admin features section refinements --- .../containers/Admin/General/InterfaceForm.js | 341 ++++++++++-------- web/src/containers/Admin/General/index.css | 4 + 2 files changed, 190 insertions(+), 155 deletions(-) diff --git a/web/src/containers/Admin/General/InterfaceForm.js b/web/src/containers/Admin/General/InterfaceForm.js index 34e92eb2a4..ad6192217d 100644 --- a/web/src/containers/Admin/General/InterfaceForm.js +++ b/web/src/containers/Admin/General/InterfaceForm.js @@ -131,184 +131,215 @@ const InterfaceForm = ({ </Checkbox> </Item> - <div className={classnames({ 'disabled-area': isFiatUpgrade })}> - <Item name="ultimate_fiat" valuePropName="checked"> - <Checkbox className="mt-3"> - <div className="d-flex align-items-center"> - <div className="feature-trade-box mr-1"> - <ReactSVG - src={STATIC_ICONS.MPESA_ICON} - className="d-flex feature-icon justify-content-center mr-2 mt-3 ml-1 pl-1" - beforeInjection={(svg) => { - svg.setAttribute('style', 'width: 60px'); - }} - /> + <div className="d-flex"> + <div + className={classnames('interface-item', { + 'disabled-area': isFiatUpgrade, + })} + > + <Item name="ultimate_fiat" valuePropName="checked"> + <Checkbox className="mt-3"> + <div className="d-flex align-items-center"> + <div className="feature-trade-box mr-1"> + <ReactSVG + src={STATIC_ICONS.MPESA_ICON} + className="d-flex feature-icon justify-content-center mr-2 mt-3 ml-1 pl-1" + beforeInjection={(svg) => { + svg.setAttribute('style', 'width: 60px'); + }} + /> + </div> + <div className="ml-2 checkbox-txt"> + Fiat Controls + <div className="small-text"> + (On & off ramping and tracking for fiat assets) + </div> + </div> </div> - <div className="ml-2 checkbox-txt"> - Ultimate fiat - <div className="small-text">(Ultimate fiat ...)</div> + </Checkbox> + </Item> + </div> + {isFiatUpgrade && ( + <div className="d-flex"> + <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> + <div> + <div className="font-weight-bold"> + Powerful fiat ramping + </div> + <div>Cash in and out with fiat ramps</div> </div> - </div> - </Checkbox> - </Item> - </div> - {isFiatUpgrade ? ( - <div className="d-flex"> - <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> - <div> - <div className="font-weight-bold"> - Make a good first impression + <div className="ml-5 button-wrapper"> + <a + href="https://dash.bitholla.com/billing" + target="_blank" + rel="noopener noreferrer" + > + <Button type="primary" className="w-100"> + Upgrade Now + </Button> + </a> </div> - <div>Add a customizable landing page</div> - </div> - <div className="ml-5 button-wrapper"> - <a - href="https://dash.bitholla.com/billing" - target="_blank" - rel="noopener noreferrer" - > - <Button type="primary" className="w-100"> - Upgrade Now - </Button> - </a> </div> </div> - </div> - ) : null} - <div className={classnames({ 'disabled-area': isUpgrade })}> - <Item name="chat" valuePropName="checked"> - <Checkbox className="mt-3"> - <div className="d-flex align-items-center"> - <div className="feature-trade-box mr-1"> - <ReactSVG - src={STATIC_ICONS.CHAT_FEATURE_ICON} - className="feature-chat-icon" - /> - </div> - <div className="ml-2 checkbox-txt"> - Chat system - <div className="d-flex justify-content-between"> - <div className="small-text"> - (Usernames, text and emoji communication) + )} + </div> + + <div className="d-flex"> + <div + className={classnames('interface-item', { + 'disabled-area': isUpgrade, + })} + > + <Item name="chat" valuePropName="checked"> + <Checkbox className="mt-3"> + <div className="d-flex align-items-center"> + <div className="feature-trade-box mr-1"> + <ReactSVG + src={STATIC_ICONS.CHAT_FEATURE_ICON} + className="feature-chat-icon" + /> + </div> + <div className="ml-2 checkbox-txt"> + Chat system + <div className="d-flex justify-content-between"> + <div className="small-text"> + (Usernames, text and emoji communication) + </div> </div> </div> </div> - </div> - </Checkbox> - </Item> - </div> - {isUpgrade ? ( - <div className="d-flex"> - <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> - <div> - <div className="font-weight-bold"> - Start your crypto culture - </div> - <div>Allow your users to socialize through chat</div> - </div> - <div className="ml-5 button-wrapper"> - <a - href="https://dash.bitholla.com/billing" - target="_blank" - rel="noopener noreferrer" - > - <Button type="primary" className="w-100"> - Upgrade Now - </Button> - </a> - </div> - </div> + </Checkbox> + </Item> </div> - ) : null} - <div className={classnames({ 'disabled-area': isUpgrade })}> - <Item name="home_page" valuePropName="checked"> - <Checkbox className="mt-3"> - <div className="d-flex align-items-center"> - <div className="feature-trade-box mr-1"> - <ReactSVG - src={STATIC_ICONS.HOME_PAGE_FEATURE_ICON} - className="feature-chat-icon" - /> - </div> - <div className="ml-2 checkbox-txt"> - Homepage - <div className="d-flex justify-content-between"> - <div className="small-text"> - (This will be the first page seen on your domain) - </div> + {isUpgrade && ( + <div className="d-flex"> + <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> + <div> + <div className="font-weight-bold"> + Start your crypto culture </div> + <div>Allow your users to socialize through chat</div> + </div> + <div className="ml-5 button-wrapper"> + <a + href="https://dash.bitholla.com/billing" + target="_blank" + rel="noopener noreferrer" + > + <Button type="primary" className="w-100"> + Upgrade Now + </Button> + </a> </div> </div> - </Checkbox> - </Item> + </div> + )} </div> - <div className={classnames({ 'disabled-area': isUpgrade })}> - <Item name="apps" valuePropName="checked"> - <Checkbox className="mt-3"> - <div className="d-flex align-items-center"> - <div className="feature-trade-box mr-1"> - <ReactSVG - src={STATIC_ICONS.APPS_FEATURE_ICON} - className="feature-apps-icon" - /> + + <div className="d-flex"> + <div + className={classnames('interface-item', { + 'disabled-area': isUpgrade, + })} + > + <Item name="home_page" valuePropName="checked"> + <Checkbox className="mt-3"> + <div className="d-flex align-items-center"> + <div className="feature-trade-box mr-1"> + <ReactSVG + src={STATIC_ICONS.HOME_PAGE_FEATURE_ICON} + className="feature-chat-icon" + /> + </div> + <div className="ml-2 checkbox-txt"> + Homepage + <div className="d-flex justify-content-between"> + <div className="small-text"> + (This will be the first page seen on your domain) + </div> + </div> + </div> </div> - <div className="ml-2 checkbox-txt"> - Apps - <div className="d-flex justify-content-between"> - <div className="small-text">(Apps ...)</div> + </Checkbox> + </Item> + </div> + {isUpgrade && ( + <div className="d-flex"> + <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> + <div> + <div className="font-weight-bold"> + Make a good first impression </div> + <div>Add a customizable landing page</div> </div> - </div> - </Checkbox> - </Item> - </div> - {isUpgrade && ( - <div className="d-flex"> - <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> - <div> - <div className="font-weight-bold"> - Start your crypto culture + <div className="ml-5 button-wrapper"> + <a + href="https://dash.bitholla.com/billing" + target="_blank" + rel="noopener noreferrer" + > + <Button type="primary" className="w-100"> + Upgrade Now + </Button> + </a> </div> - <div>Allow your users to socialize through chat</div> - </div> - <div className="ml-5 button-wrapper"> - <a - href="https://dash.bitholla.com/billing" - target="_blank" - rel="noopener noreferrer" - > - <Button type="primary" className="w-100"> - Upgrade Now - </Button> - </a> </div> </div> - </div> - )} - </div> - {isUpgrade ? ( + )} + </div> + <div className="d-flex"> - <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> - <div> - <div className="font-weight-bold"> - Make a good first impression + <div + className={classnames('interface-item', { + 'disabled-area': isUpgrade, + })} + > + <Item name="apps" valuePropName="checked"> + <Checkbox className="mt-3"> + <div className="d-flex align-items-center"> + <div className="feature-trade-box mr-1"> + <ReactSVG + src={STATIC_ICONS.APPS_FEATURE_ICON} + className="feature-apps-icon" + /> + </div> + <div className="ml-2 checkbox-txt"> + Apps + <div className="d-flex justify-content-between"> + <div className="small-text"> + (Give your users extra exchange applications) + </div> + </div> + </div> + </div> + </Checkbox> + </Item> + </div> + {isUpgrade && ( + <div className="d-flex"> + <div className="d-flex align-items-center justify-content-between upgrade-section mt-2 mb-5"> + <div> + <div className="font-weight-bold"> + First exchange app store + </div> + <div>Add more exchange functionality</div> + </div> + <div className="ml-5 button-wrapper"> + <a + href="https://dash.bitholla.com/billing" + target="_blank" + rel="noopener noreferrer" + > + <Button type="primary" className="w-100"> + Upgrade Now + </Button> + </a> + </div> </div> - <div>Add a customizable landing page</div> </div> - <div className="ml-5 button-wrapper"> - <a - href="https://dash.bitholla.com/billing" - target="_blank" - rel="noopener noreferrer" - > - <Button type="primary" className="w-100"> - Upgrade Now - </Button> - </a> - </div> - </div> + )} </div> - ) : null} + </div> <div> <FormButton type="primary" diff --git a/web/src/containers/Admin/General/index.css b/web/src/containers/Admin/General/index.css index 2e4b963ad8..c0359d7b4d 100644 --- a/web/src/containers/Admin/General/index.css +++ b/web/src/containers/Admin/General/index.css @@ -365,6 +365,10 @@ h2, pointer-events: none; } +.general-wrapper .interface-item { + min-width: 418px; +} + .general-wrapper .description a { text-decoration: underline !important; } From abed1333b153bcbd4697211888be874d446de376 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 06:04:35 +0330 Subject: [PATCH 36/54] apps section refinements --- web/src/config/lang/en.json | 6 +++++- web/src/containers/Apps/All.js | 30 ++++++++++++++++++++++++------ web/src/containers/Apps/User.js | 2 +- web/src/containers/Apps/_Apps.scss | 4 ++++ web/src/containers/Apps/index.js | 2 +- web/src/index.css | 3 +++ 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json index de36bb180a..017d4f1cc3 100644 --- a/web/src/config/lang/en.json +++ b/web/src/config/lang/en.json @@ -485,7 +485,11 @@ "TAB_TITLE": "All apps", "TITLE": "Exchange apps", "SUBTITLE": "Get more functionality from your exchange account by simply selecting an app below and clicking Add button.", - "SEARCH_PLACEHOLDER": "Search apps..." + "SEARCH_PLACEHOLDER": "Search apps...", + "ADD": { + "SUCCESSFUL": "You've successfully added a new app!", + "FAILED": "Something went wrong" + } }, "MY_APPS": { "TAB_TITLE": "My apps", diff --git a/web/src/containers/Apps/All.js b/web/src/containers/Apps/All.js index 261364bf06..6448083705 100644 --- a/web/src/containers/Apps/All.js +++ b/web/src/containers/Apps/All.js @@ -5,13 +5,14 @@ import { Input } from 'antd'; import debounce from 'lodash.debounce'; import { SearchOutlined } from '@ant-design/icons'; import { updateUserSettings, setUserData } from 'actions/userAction'; +import { setSnackNotification } from 'actions/appActions'; import { IconTitle, EditWrapper, Table, Button, Image } from 'components'; import STRINGS from 'config/localizedStrings'; import withConfig from 'components/ConfigProvider/withConfig'; import { unique } from 'utils/data'; import { isEnabled, appsSelector } from './utils'; -const generateHeaders = (addApp, isAdded) => { +const generateHeaders = (addApp, isAdded, ICONS) => { return [ { stringId: 'USER_APPS.TABLE.APP_NAME', @@ -28,7 +29,11 @@ const generateHeaders = (addApp, isAdded) => { renderCell: ({ name }, key) => ( <td key={`${key}-${name}-app`} className="text-align-right"> {isAdded(name) ? ( - <Image icon={''} iconId={''} wrapperClassName={''} /> + <Image + icon={ICONS['GREEN_CHECK']} + iconId={'GREEN_CHECK'} + wrapperClassName={'apps-table-check'} + /> ) : ( <Button label={STRINGS['USER_APPS.TABLE.ADD']} @@ -56,6 +61,8 @@ const All = ({ apps, settings: { apps: user_apps = [] }, setUserData, + setActiveTab, + setSnackNotification, }) => { const [search, setSearch] = useState(); const [data, setData] = useState(apps); @@ -68,8 +75,18 @@ const All = ({ apps: unique([...user_apps, name]), }; updateUserSettings(settings) - .then(({ data }) => setUserData(data)) - .catch((err) => console.log('error')); + .then(({ data }) => { + setUserData(data); + setActiveTab(1); + setSnackNotification({ + content: STRINGS['USER_APPS.ALL_APPS.ADD.SUCCESSFUL'], + }); + }) + .catch(() => { + setSnackNotification({ + content: STRINGS['USER_APPS.ALL_APPS.ADD.FAILED'], + }); + }); }; const isAdded = (name) => { @@ -110,7 +127,7 @@ const All = ({ textType="title" iconPath={ICONS['APPS_ALL']} /> - <div> + <div className="py-4"> <EditWrapper stringId="USER_APPS.ALL_APPS.SUBTITLE"> {STRINGS['USER_APPS.ALL_APPS.SUBTITLE']} </EditWrapper> @@ -132,7 +149,7 @@ const All = ({ <Table showHeaderNoData={true} rowClassName="pt-2 pb-2" - headers={generateHeaders(addApp, isAdded)} + headers={generateHeaders(addApp, isAdded, ICONS)} count={data.length} pageSize={data.length} data={data} @@ -159,6 +176,7 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => ({ setUserData: bindActionCreators(setUserData, dispatch), + setSnackNotification: bindActionCreators(setSnackNotification, dispatch), }); export default connect(mapStateToProps, mapDispatchToProps)(withConfig(All)); diff --git a/web/src/containers/Apps/User.js b/web/src/containers/Apps/User.js index 4a118c4d32..81e4fc4626 100644 --- a/web/src/containers/Apps/User.js +++ b/web/src/containers/Apps/User.js @@ -86,7 +86,7 @@ const User = ({ textType="title" iconPath={ICONS['APPS_USER']} /> - <div> + <div className="py-4"> <EditWrapper stringId="USER_APPS.MY_APPS.SUBTITLE"> {STRINGS['USER_APPS.MY_APPS.SUBTITLE']} </EditWrapper> diff --git a/web/src/containers/Apps/_Apps.scss b/web/src/containers/Apps/_Apps.scss index 529bed33a3..031c5603d8 100644 --- a/web/src/containers/Apps/_Apps.scss +++ b/web/src/containers/Apps/_Apps.scss @@ -17,3 +17,7 @@ position: relative !important; } } + +.apps-table-check { + width: 10px !important; +} diff --git a/web/src/containers/Apps/index.js b/web/src/containers/Apps/index.js index 1edabae983..765a84d0f0 100644 --- a/web/src/containers/Apps/index.js +++ b/web/src/containers/Apps/index.js @@ -35,7 +35,7 @@ const Index = ({ icons: ICONS, openContactForm }) => { ) : ( <div>{STRINGS['USER_APPS.ALL_APPS.TAB_TITLE']}</div> ), - content: <All />, + content: <All setActiveTab={setActiveTab} />, }, { title: isMobile ? ( diff --git a/web/src/index.css b/web/src/index.css index d5642b068c..0d8caf4051 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -5473,6 +5473,9 @@ table th { .action_notification-wrapper.remove-action { position: relative !important; } +.apps-table-check { + width: 10px !important; } + .sidebar-row { min-height: 3rem; min-width: 10rem; } From 62b1ede6925e4d79cbe88536d05ea222c1449ca5 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 06:07:07 +0330 Subject: [PATCH 37/54] fix for snack notification scrolling issue --- web/src/components/SnackNotification/_SnackNotification.scss | 5 +++-- web/src/index.css | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/web/src/components/SnackNotification/_SnackNotification.scss b/web/src/components/SnackNotification/_SnackNotification.scss index a16cc69593..29eedbadba 100644 --- a/web/src/components/SnackNotification/_SnackNotification.scss +++ b/web/src/components/SnackNotification/_SnackNotification.scss @@ -7,9 +7,10 @@ height: 3.5rem; left: calc(50vw - 10rem); padding: 0.3rem 0.5rem !important; - position: absolute; + position: fixed; + min-width: 20rem; + max-width: 30rem; // top: 1rem; - width: 20rem; z-index: 9999; -webkit-box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.4); -moz-box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.4); diff --git a/web/src/index.css b/web/src/index.css index 0d8caf4051..bd518b91a6 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -10370,8 +10370,9 @@ table th { height: 3.5rem; left: calc(50vw - 10rem); padding: 0.3rem 0.5rem !important; - position: absolute; - width: 20rem; + position: fixed; + min-width: 20rem; + max-width: 30rem; z-index: 9999; -webkit-box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.4); -moz-box-shadow: 2px 2px 3px 2px rgba(0, 0, 0, 0.4); From 65259a26f4ce850f5d73bee4be8c8daacd51dbf4 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 06:27:35 +0330 Subject: [PATCH 38/54] fix for table component row key issue --- web/src/components/Table/TableBody.js | 2 ++ web/src/components/Table/index.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/web/src/components/Table/TableBody.js b/web/src/components/Table/TableBody.js index 45572d8247..443d49b457 100644 --- a/web/src/components/Table/TableBody.js +++ b/web/src/components/Table/TableBody.js @@ -82,6 +82,7 @@ const TableBody = ({ cancelDelayData, expandable, cssTransitionClassName, + rowKey, }) => ( <tbody className={classnames('table_body-wrapper', { @@ -113,6 +114,7 @@ const TableBody = ({ <Fragment> {data.map((row, rowIndex) => ( <TableRow + key={rowKey(row)} headers={headers} cancelDelayData={cancelDelayData} expandable={expandable} diff --git a/web/src/components/Table/index.js b/web/src/components/Table/index.js index fb7c61edce..2c59fa7e1f 100644 --- a/web/src/components/Table/index.js +++ b/web/src/components/Table/index.js @@ -105,6 +105,7 @@ class Table extends Component { className, expandable, cssTransitionClassName, + rowKey, } = this.props; const count = this.props.count || this.props.data.length; @@ -153,6 +154,7 @@ class Table extends Component { withIcon={withIcon} expandable={expandable} cssTransitionClassName={cssTransitionClassName} + rowKey={rowKey} /> </table> </div> @@ -190,6 +192,7 @@ Table.defaultProps = { rowExpandable: () => false, }, cssTransitionClassName: '', + rowKey: ({ id }) => id, }; export default Table; From b33b894dcbe36cd2a1344a71615c330164866f3c Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 06:28:16 +0330 Subject: [PATCH 39/54] fix for apps section search results issue --- web/src/containers/Apps/All.js | 3 +-- web/src/containers/Apps/User.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/web/src/containers/Apps/All.js b/web/src/containers/Apps/All.js index 6448083705..dde8de9773 100644 --- a/web/src/containers/Apps/All.js +++ b/web/src/containers/Apps/All.js @@ -150,8 +150,7 @@ const All = ({ showHeaderNoData={true} rowClassName="pt-2 pb-2" headers={generateHeaders(addApp, isAdded, ICONS)} - count={data.length} - pageSize={data.length} + showAll={true} data={data} rowKey={({ name }) => name} displayPaginator={false} diff --git a/web/src/containers/Apps/User.js b/web/src/containers/Apps/User.js index 81e4fc4626..62159421a8 100644 --- a/web/src/containers/Apps/User.js +++ b/web/src/containers/Apps/User.js @@ -95,8 +95,7 @@ const User = ({ showHeaderNoData={true} rowClassName="pt-2 pb-2" headers={generateHeaders(goToDetails, openConfigs)} - count={data.length} - pageSize={data.length} + showAll={true} data={data} rowKey={({ name }) => name} displayPaginator={false} From 2fde7e7b0b4d654753b7c2d60ef3b66ace5e3001 Mon Sep 17 00:00:00 2001 From: sahlabadi <sahlabadi2002@gmail.com> Date: Tue, 27 Sep 2022 11:39:58 +0800 Subject: [PATCH 40/54] precondition of testing fix, Audio cues --- test/Cypress/cypress/integration/Gherkin/pre/pre.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Cypress/cypress/integration/Gherkin/pre/pre.js b/test/Cypress/cypress/integration/Gherkin/pre/pre.js index b3ba2d222e..b17df16b67 100644 --- a/test/Cypress/cypress/integration/Gherkin/pre/pre.js +++ b/test/Cypress/cypress/integration/Gherkin/pre/pre.js @@ -69,7 +69,7 @@ And ('Show pop up when order has partially filled is off',()=>{ And ('All Audio cues is off',()=>{ cy.get('.tab_controller-tabs > :nth-child(2) > div').as('Interface').click() - cy.contains('Play Audio Cue').click() + cy.contains('Audio Cues').click() cy.get('.toggle-wrapper-all > :nth-child(1) > :nth-child(1) > .field-content > .field-children > .justify-content-between > .toggle_button-wrapper > .toggle-content > .toggle-action_button') .invoke('text') .then(text => { @@ -124,8 +124,8 @@ And ('chatbox is off',()=>{ And ('XHTT spread in market is less than 0.001',()=>{ cy.get('.top-box-menu').click() cy.contains('Pro trade').click() - cy.contains('XHTT/USDT').click() - cy.get('.app_bar-currency-txt').should('have.text', 'XHTT/USDT:') + cy.contains('XHT/USDT').click() + cy.get('.app_bar-currency-txt').should('have.text', 'XHT/USDT:') cy.get('.trade_orderbook-asks > :nth-child(1) > .d-flex > .trade_orderbook-cell-price') .should('be.visible') cy.log('check lowest aks exist and click on the price will send the price') From 9638587d767b3039bb9c0ecef95c3082251e4fa1 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 07:23:51 +0330 Subject: [PATCH 41/54] apps input clear button --- web/src/containers/Apps/All.js | 1 + web/src/containers/Apps/_Apps.scss | 3 +++ web/src/index.css | 3 +++ 3 files changed, 7 insertions(+) diff --git a/web/src/containers/Apps/All.js b/web/src/containers/Apps/All.js index dde8de9773..ba1d2d1d8f 100644 --- a/web/src/containers/Apps/All.js +++ b/web/src/containers/Apps/All.js @@ -134,6 +134,7 @@ const All = ({ </div> <div> <Input + allowClear prefix={<SearchOutlined className="secondary-text" />} placeholder={STRINGS['USER_APPS.ALL_APPS.SEARCH_PLACEHOLDER']} value={search} diff --git a/web/src/containers/Apps/_Apps.scss b/web/src/containers/Apps/_Apps.scss index 031c5603d8..4174315c2c 100644 --- a/web/src/containers/Apps/_Apps.scss +++ b/web/src/containers/Apps/_Apps.scss @@ -10,6 +10,9 @@ .ant-input { color: $colors-main-black; } + .ant-input-clear-icon { + color: $colors-black; + } } .action_notification-wrapper { diff --git a/web/src/index.css b/web/src/index.css index bd518b91a6..94c8f8d4e6 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -5470,6 +5470,9 @@ table th { .apps-form .ant-input { color: var(--labels_important-active-labels-text-graphics); } +.apps-form .ant-input-clear-icon { + color: var(--labels_secondary-inactive-label-text-graphics); } + .action_notification-wrapper.remove-action { position: relative !important; } From 112e87279ff675283613574edec0981d9d0a99ef Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 07:53:23 +0330 Subject: [PATCH 42/54] user reducer and actions updates --- web/src/containers/Apps/All.js | 2 +- web/src/containers/Apps/User.js | 2 +- web/src/utils/utils.js | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/web/src/containers/Apps/All.js b/web/src/containers/Apps/All.js index ba1d2d1d8f..66c4996195 100644 --- a/web/src/containers/Apps/All.js +++ b/web/src/containers/Apps/All.js @@ -72,7 +72,7 @@ const All = ({ const addApp = (name) => { // send add app request and show toast notification const settings = { - apps: unique([...user_apps, name]), + app: unique([...user_apps, name]), }; updateUserSettings(settings) .then(({ data }) => { diff --git a/web/src/containers/Apps/User.js b/web/src/containers/Apps/User.js index 62159421a8..65a4aeb619 100644 --- a/web/src/containers/Apps/User.js +++ b/web/src/containers/Apps/User.js @@ -65,7 +65,7 @@ const User = ({ const onRemove = (name) => { // send add app request and show toast notification const settings = { - apps: apps.filter((app) => app !== name), + app: apps.filter((app) => app !== name), }; updateUserSettings(settings) .then(({ data }) => { diff --git a/web/src/utils/utils.js b/web/src/utils/utils.js index d662a57c43..8fe84658f2 100644 --- a/web/src/utils/utils.js +++ b/web/src/utils/utils.js @@ -104,6 +104,9 @@ export const constructSettings = (state = {}, settings) => { if (settings.language) { settingsData.language = settings.language; } + if (settings.app) { + settingsData.apps = settings.app; + } // ToDo: need to these code after end point update. if ( From 7b072f221b36aae8044991c00390390e79f5cb14 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 08:02:33 +0330 Subject: [PATCH 43/54] apps section minor design improvement --- web/src/containers/Apps/All.js | 11 +++++++++-- web/src/containers/Apps/User.js | 4 ++-- web/src/containers/Apps/_Apps.scss | 2 +- web/src/index.css | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/web/src/containers/Apps/All.js b/web/src/containers/Apps/All.js index 66c4996195..7dcc699a09 100644 --- a/web/src/containers/Apps/All.js +++ b/web/src/containers/Apps/All.js @@ -27,7 +27,7 @@ const generateHeaders = (addApp, isAdded, ICONS) => { { label: '', renderCell: ({ name }, key) => ( - <td key={`${key}-${name}-app`} className="text-align-right"> + <td key={`${key}-${name}-app`} className="text-align-center"> {isAdded(name) ? ( <Image icon={ICONS['GREEN_CHECK']} @@ -70,10 +70,10 @@ const All = ({ const inputRef = useRef(null); const addApp = (name) => { - // send add app request and show toast notification const settings = { app: unique([...user_apps, name]), }; + updateUserSettings(settings) .then(({ data }) => { setUserData(data); @@ -81,6 +81,13 @@ const All = ({ setSnackNotification({ content: STRINGS['USER_APPS.ALL_APPS.ADD.SUCCESSFUL'], }); + if (window) { + window.scroll({ + top: 0, + left: 0, + behavior: 'smooth', + }); + } }) .catch(() => { setSnackNotification({ diff --git a/web/src/containers/Apps/User.js b/web/src/containers/Apps/User.js index 65a4aeb619..fbf7f87d79 100644 --- a/web/src/containers/Apps/User.js +++ b/web/src/containers/Apps/User.js @@ -62,11 +62,12 @@ const User = ({ closeNotification, }) => { const goToDetails = (name) => router.push(`apps/details/${name}`); + const openConfigs = (name) => openConfigureApps(() => onRemove(name)); const onRemove = (name) => { - // send add app request and show toast notification const settings = { app: apps.filter((app) => app !== name), }; + updateUserSettings(settings) .then(({ data }) => { setUserData(data); @@ -74,7 +75,6 @@ const User = ({ }) .catch((err) => console.log('error')); }; - const openConfigs = (name) => openConfigureApps(() => onRemove(name)); return ( <div> diff --git a/web/src/containers/Apps/_Apps.scss b/web/src/containers/Apps/_Apps.scss index 4174315c2c..a32acfa386 100644 --- a/web/src/containers/Apps/_Apps.scss +++ b/web/src/containers/Apps/_Apps.scss @@ -22,5 +22,5 @@ } .apps-table-check { - width: 10px !important; + width: 2rem !important; } diff --git a/web/src/index.css b/web/src/index.css index 94c8f8d4e6..a4de90f08d 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -5477,7 +5477,7 @@ table th { position: relative !important; } .apps-table-check { - width: 10px !important; } + width: 2rem !important; } .sidebar-row { min-height: 3rem; From aeadaaf6f7289aae49e9248274205573e5d788d2 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 27 Sep 2022 10:40:23 +0330 Subject: [PATCH 44/54] fix for apps selector issue --- web/src/containers/Apps/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/containers/Apps/utils.js b/web/src/containers/Apps/utils.js index df0e15103e..170fb47529 100644 --- a/web/src/containers/Apps/utils.js +++ b/web/src/containers/Apps/utils.js @@ -3,7 +3,7 @@ import { createSelector } from 'reselect'; const getPlugins = (state) => state.app.plugins; const getUserApps = (state) => state.user.settings.apps || []; export const appsSelector = createSelector([getPlugins], (plugins) => - plugins.filter((type) => type === 'app') + plugins.filter(({ type }) => type === 'app') ); export const userAppsSelector = createSelector( From e37f04da958392756a96766e4ad49208dea21c90 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Sat, 1 Oct 2022 12:40:16 +0900 Subject: [PATCH 45/54] get user using id instead of email --- server/api/controllers/user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/api/controllers/user.js b/server/api/controllers/user.js index 13e63238b6..2f4294ea29 100644 --- a/server/api/controllers/user.js +++ b/server/api/controllers/user.js @@ -505,9 +505,9 @@ const resetPassword = (req, res) => { const getUser = (req, res) => { loggerUser.debug(req.uuid, 'controllers/user/getUser', req.auth.sub); - const email = req.auth.sub.email; + const id = req.auth.sub.id; - toolsLib.user.getUserByEmail(email, true, true, { + toolsLib.user.getUserByKitId(id, true, true, { additionalHeaders: { 'x-forwarded-for': req.headers['x-forwarded-for'] } From 84860e855e4022693e2355e9b1aa57cc131c3425 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Mon, 3 Oct 2022 00:46:42 +0900 Subject: [PATCH 46/54] fiat withdrawal email confirmation flow --- server/api/controllers/withdrawal.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/server/api/controllers/withdrawal.js b/server/api/controllers/withdrawal.js index 2a184dd53f..021739c0cd 100644 --- a/server/api/controllers/withdrawal.js +++ b/server/api/controllers/withdrawal.js @@ -121,7 +121,24 @@ const performWithdrawal = (req, res) => { }), withdrawal ]); + } else if (toolsLib.getKitCoin(withdrawal.currency).type === 'fiat') { + // burn the asset + return all([ + toolsLib.wallet.burnAssetByKitId( + withdrawal.user_id, + withdrawal.currency, + withdrawal.amount, + { + transactionId: withdrawal.transaction_id, + address: withdrawal.address, + status: false, + fee: withdrawal.fee + } + ), + withdrawal + ]); } else { + // blockchain type to sent to the network return all([ toolsLib.wallet.performWithdrawal( withdrawal.user_id, From bd41034ce630a04f176bc032cecd01eee1ac4488 Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Mon, 3 Oct 2022 00:47:20 +0900 Subject: [PATCH 47/54] withdrawal request flow improvement to accomodate fiat withdrawal --- server/utils/hollaex-tools-lib/tools/wallet.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/server/utils/hollaex-tools-lib/tools/wallet.js b/server/utils/hollaex-tools-lib/tools/wallet.js index a250c50b7e..05154dfe09 100644 --- a/server/utils/hollaex-tools-lib/tools/wallet.js +++ b/server/utils/hollaex-tools-lib/tools/wallet.js @@ -195,9 +195,15 @@ async function validateWithdrawal(user, address, amount, currency, network = nul const sendRequestWithdrawalEmail = (user_id, address, amount, currency, opts = { network: null, otpCode: null, + fee: null, + fee_coin: null, + skipValidate: false, // should be used with care if set to true ip: null, domain: null }) => { + let fee = opts.fee; + let fee_coin = opts.fee_coin; + return verifyOtpBeforeAction(user_id, opts.otpCode) .then((validOtp) => { if (!validOtp) { @@ -206,7 +212,12 @@ const sendRequestWithdrawalEmail = (user_id, address, amount, currency, opts = { return getUserByKitId(user_id); }) .then(async (user) => { - const { fee, fee_coin } = await validateWithdrawal(user, address, amount, currency, opts.network); + if (!opts.skipValidate) { + const withdrawal = await validateWithdrawal(user, address, amount, currency, opts.network); + fee = withdrawal.fee; + fee_coin = withdrawal.fee_coin; + } + return withdrawalRequestEmail( user, @@ -230,7 +241,7 @@ const sendRequestWithdrawalEmail = (user_id, address, amount, currency, opts = { const withdrawalRequestEmail = (user, data, domain, ip) => { data.timestamp = Date.now(); let stringData = JSON.stringify(data); - const token = crypto.randomBytes(60).toString('hex'); + const token = data.transaction_id || crypto.randomBytes(60).toString('hex'); return client.hsetAsync(WITHDRAWALS_REQUEST_KEY, token, stringData) .then(() => { From a8e06cef9e9c06d617ff63a5989d4ac4986e8d9a Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Mon, 3 Oct 2022 03:02:43 +0300 Subject: [PATCH 48/54] FEE Preview fix --- web/src/containers/Withdraw/ReviewModalContent.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/containers/Withdraw/ReviewModalContent.js b/web/src/containers/Withdraw/ReviewModalContent.js index 194efd3ebc..092f897111 100644 --- a/web/src/containers/Withdraw/ReviewModalContent.js +++ b/web/src/containers/Withdraw/ReviewModalContent.js @@ -49,7 +49,7 @@ const ReviewModalContent = ({ const fee_type = data.fee_type ? data.fee_type : ''; const isPercentage = fee_type === 'percentage'; const hasDifferentFeeCoin = - !isPercentage && fee_coin && fee_coin !== currency; + !isPercentage && !!fee_coin && fee_coin !== currency; let min_fee; let max_fee; @@ -76,7 +76,7 @@ const ReviewModalContent = ({ const feePrice = math.number(math.multiply(fee, price)); - const totalTransaction = hasDifferentFeeCoin + const totalTransaction = !!hasDifferentFeeCoin ? math.number(math.fraction(data.amount)) : math.number(math.add(math.fraction(data.amount), fee)); @@ -89,7 +89,7 @@ const ReviewModalContent = ({ const { display_name: fee_coin_display } = coins[fee_coin] || DEFAULT_COIN_DATA; - const withdrawFeeMessage = hasDifferentFeeCoin + const withdrawFeeMessage = !!hasDifferentFeeCoin ? STRINGS.formatString( STRINGS['WITHDRAW_PAGE.MESSAGE_FEE_COIN'], STRINGS.formatString(CURRENCY_PRICE_FORMAT, fee, fee_coin_display) From f606b0bea6d31ab3f7797eaa0e7d0c1c4774e46e Mon Sep 17 00:00:00 2001 From: Tayfun Yaltur <tayfunyaltur@gmail.com> Date: Mon, 3 Oct 2022 03:26:06 +0300 Subject: [PATCH 49/54] 2FA, change password modal fix --- web/src/containers/UserSecurity/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/src/containers/UserSecurity/index.js b/web/src/containers/UserSecurity/index.js index c2b19ce4e5..17d2ff0d09 100644 --- a/web/src/containers/UserSecurity/index.js +++ b/web/src/containers/UserSecurity/index.js @@ -386,6 +386,9 @@ class UserVerification extends Component { if (otp_enabled) { this.setState({ dialogIsOpen: true, + modalText: + STRINGS['ACCOUNT_SECURITY.CHANGE_PASSWORD.DIALOG.EMAIL_CONFIRMATION'], + stringId: 'ACCOUNT_SECURITY.CHANGE_PASSWORD.DIALOG.EMAIL_CONFIRMATION', updatedPassword: { old_password: values.old_password, new_password: values.new_password, From a224557b9c52b00d3265f89c4407b0d234d4f4cd Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 4 Oct 2022 12:39:05 +0330 Subject: [PATCH 50/54] minor app details refinements --- web/src/config/lang/en.json | 3 ++- web/src/containers/AppDetails/index.js | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/web/src/config/lang/en.json b/web/src/config/lang/en.json index 017d4f1cc3..0fccda8b04 100644 --- a/web/src/config/lang/en.json +++ b/web/src/config/lang/en.json @@ -507,7 +507,8 @@ "RETRY": "Try another search term" }, "APP_DETAILS": { - "BACK_TO_APPS": "{0} to my apps", + "BACK_PLACEHOLDER": "{0} {1}", + "BACK_TO_APPS": "to my apps", "BACK": "Back" }, "CONFIGURE": { diff --git a/web/src/containers/AppDetails/index.js b/web/src/containers/AppDetails/index.js index fa3886bd5d..2d167d759f 100644 --- a/web/src/containers/AppDetails/index.js +++ b/web/src/containers/AppDetails/index.js @@ -18,7 +18,7 @@ const Index = ({ openContactForm, icons: ICONS, router, userApps }) => { } = router; if (!mounted) { - if (!app || userApps.map(({ name }) => name).includes(app)) { + if (!app || !userApps.map(({ name }) => name).includes(app)) { goBack(); } } @@ -46,12 +46,15 @@ const Index = ({ openContactForm, icons: ICONS, router, userApps }) => { <div> <EditWrapper stringId="USER_APPS.APP_DETAILS.BACK_TO_APPS,USER_APPS.APP_DETAILS.BACK"> {STRINGS.formatString( - STRINGS['USER_APPS.APP_DETAILS.BACK_TO_APPS'], + STRINGS['USER_APPS.APP_DETAILS.BACK_PLACEHOLDER'], <span className="blue-link underline-text pointer" onClick={goBack} > {STRINGS['USER_APPS.APP_DETAILS.BACK']} + </span>, + <span className="px-1"> + {STRINGS['USER_APPS.APP_DETAILS.BACK_TO_APPS']} </span> )} </EditWrapper> From d97caa6b5ec2b74167048af66368db70de1fa31a Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Tue, 4 Oct 2022 12:40:36 +0330 Subject: [PATCH 51/54] admin apps initial commit --- web/src/containers/Admin/AppWrapper/index.js | 20 ++- web/src/containers/Admin/Apps/index.css | 43 ++++++ web/src/containers/Admin/Apps/index.js | 135 +++++++++++++++++++ web/src/containers/Admin/Apps/utils.js | 7 + web/src/containers/Admin/Plugins/index.js | 26 +++- web/src/containers/AppDetails/index.js | 2 +- web/src/containers/index.js | 1 + web/src/reducers/appReducer.js | 9 +- web/src/routes.js | 6 + web/src/utils/id.js | 2 +- 10 files changed, 240 insertions(+), 11 deletions(-) create mode 100644 web/src/containers/Admin/Apps/index.css create mode 100644 web/src/containers/Admin/Apps/index.js create mode 100644 web/src/containers/Admin/Apps/utils.js diff --git a/web/src/containers/Admin/AppWrapper/index.js b/web/src/containers/Admin/AppWrapper/index.js index 82a11fb2d7..5fb57807e5 100644 --- a/web/src/containers/Admin/AppWrapper/index.js +++ b/web/src/containers/Admin/AppWrapper/index.js @@ -426,6 +426,8 @@ class AppWrapper extends React.Component { return 'Markets'; } else if (location.pathname.includes('/admin/plugins')) { return 'Plugins'; + } else if (location.pathname.includes('/admin/apps')) { + return 'Apps'; } else if (location.pathname.includes('/admin/tiers')) { return 'Tiers'; } else if (location.pathname.includes('/admin/roles')) { @@ -549,7 +551,12 @@ class AppWrapper extends React.Component { }; render() { - const { children, router, user } = this.props; + const { + children, + router, + user, + constants: { features }, + } = this.props; const logout = () => { removeToken(); router.replace('/login'); @@ -576,6 +583,17 @@ class AppWrapper extends React.Component { } }); + if (features.apps) { + pathNames = [ + ...pathNames, + { + path: '/admin/apps', + label: 'Apps', + routeKey: 'apps', + }, + ]; + } + if (!isLoaded) return null; if (!isLoggedIn()) { router.replace('/login'); diff --git a/web/src/containers/Admin/Apps/index.css b/web/src/containers/Admin/Apps/index.css new file mode 100644 index 0000000000..6ec015a74f --- /dev/null +++ b/web/src/containers/Admin/Apps/index.css @@ -0,0 +1,43 @@ +.apps-list-container { + color: #ffffff; + margin: 0rem auto; + padding: 2rem 0rem; +} + +.apps-list-container .apps-icon { + height: 5rem; + margin: 0rem 1rem 0rem 0.5rem; + width: 4rem; +} + +.apps-list-container .apps-icon .apps { + fill: transparent !important; + stroke: #ffffff !important; +} + +.apps-list-container .small-font { + font-size: 9px; + font-weight: bold; +} + +.apps-list-container .apps-text { + width: 45rem; +} + +.apps-list-container .apps-title { + font-size: 18px; + font-weight: bold; +} + +.apps-list-container .anchor { + text-decoration: underline; + cursor: pointer; +} + +.apps-list-container .ant-breadcrumb-link { + cursor: pointer; +} + +.apps-list-container .ant-breadcrumb-link span:hover { + color: var(--admin_panel_main_font); +} diff --git a/web/src/containers/Admin/Apps/index.js b/web/src/containers/Admin/Apps/index.js new file mode 100644 index 0000000000..588f4765f5 --- /dev/null +++ b/web/src/containers/Admin/Apps/index.js @@ -0,0 +1,135 @@ +import React, { useState, useEffect, Fragment } from 'react'; +import { connect } from 'react-redux'; +import { ReactSVG } from 'react-svg'; +import { STATIC_ICONS } from 'config/icons'; +import { Table, Breadcrumb, Button } from 'antd'; +import { appsSelector } from './utils'; +import { SmartTarget } from 'components'; +import { generateDynamicTarget } from 'utils/id'; + +import './index.css'; + +const { Item } = Breadcrumb; + +const generateHeaders = (configure, viewApp) => { + return [ + { + title: 'App name', + key: 'name', + dataIndex: 'name', + }, + { + title: 'Description', + key: 'description', + dataIndex: 'description', + }, + { + title: 'Config', + key: '', + dataIndex: '', + render: (_, { name }, key) => ( + <td key={`${key}-${name}-configure`}> + <span + className="underline-text pointer no-wrap" + onClick={() => configure(name)} + > + Config + </span> + </td> + ), + }, + { + title: 'App details', + key: '', + dataIndex: '', + render: (_, { name }, key) => ( + <td key={`${key}-${name}-view`}> + <span + className="underline-text pointer no-wrap" + onClick={() => viewApp(name)} + > + View App + </span> + </td> + ), + }, + ]; +}; + +const Index = ({ router, apps }) => { + const [app, setApp] = useState(); + const [id, setId] = useState(); + + const back = () => setApp(); + const configure = (app) => router.push(`/admin/plugins?plugin=${app}`); + const goToPlugins = () => router.push('/admin/plugins'); + + useEffect(() => { + setId(generateDynamicTarget(app, 'app', 'admin')); + }, [app]); + + return ( + <div className="app_container-content admin-user-container admin-user-content apps-list-container"> + {app ? ( + <Fragment> + <Breadcrumb> + <Item> + <span onClick={back}>Apps</span> + </Item> + <Item>{app}</Item> + </Breadcrumb> + <SmartTarget id={id} onBack={back} /> + </Fragment> + ) : ( + <Fragment> + <div className="d-flex align-items-center"> + <div> + <ReactSVG + src={STATIC_ICONS.APPS_FEATURE_ICON} + className="apps-icon" + /> + </div> + <div className="apps-text"> + <div className="apps-title">Active apps</div> + <div> + <span> + Below is a list of exchange applications that were activated + from the{' '} + </span> + <span className="anchor" onClick={goToPlugins}> + plugins page. + </span> + <span> + {' '} + These apps are active and visible to your users and provide + extra functionality. + </span> + </div> + </div> + </div> + + <div className="pt-3 pb-5 text-align-right"> + <Button type="primary" className="green-btn" onClick={goToPlugins}> + Add plugin app + </Button> + </div> + + <Table + className="blue-admin-table" + dataSource={apps} + columns={generateHeaders(configure, setApp)} + pagination={false} + /> + </Fragment> + )} + </div> + ); +}; + +const mapStateToProps = (state) => { + return { + apps: appsSelector(state), + }; +}; + +export default connect(mapStateToProps)(Index); diff --git a/web/src/containers/Admin/Apps/utils.js b/web/src/containers/Admin/Apps/utils.js new file mode 100644 index 0000000000..77dc4cf936 --- /dev/null +++ b/web/src/containers/Admin/Apps/utils.js @@ -0,0 +1,7 @@ +import { createSelector } from 'reselect'; + +const getPlugins = (state) => state.app.plugins; + +export const appsSelector = createSelector([getPlugins], (plugins) => + plugins.filter(({ type }) => type === 'app') +); diff --git a/web/src/containers/Admin/Plugins/index.js b/web/src/containers/Admin/Plugins/index.js index e0711e0b7e..187da49255 100644 --- a/web/src/containers/Admin/Plugins/index.js +++ b/web/src/containers/Admin/Plugins/index.js @@ -18,6 +18,11 @@ const { Item } = Breadcrumb; class Plugins extends Component { constructor(props) { super(props); + const { + router: { + location: { query: { plugin } = {} }, + }, + } = this.props; this.state = { activeTab: '', loading: false, @@ -32,7 +37,7 @@ class Plugins extends Component { isVisible: false, isRemovePlugin: false, removePluginName: '', - tabKey: 'explore', + tabKey: plugin ? 'my_plugin' : 'explore', pluginCards: [], processing: false, }; @@ -75,7 +80,20 @@ class Plugins extends Component { return requestMyPlugins(params) .then((res) => { if (res && res.data) { - this.setState({ myPlugins: res.data }); + const { + router, + router: { + location: { pathname, query: { plugin } = {} }, + }, + } = this.props; + this.setState({ myPlugins: res.data }, () => { + const pluginData = res.data.find(({ name }) => name === plugin); + if (pluginData) { + this.handleOpenPlugin(pluginData); + this.handleBreadcrumb(); + router.push(pathname); + } + }); } }) .catch((err) => { @@ -183,7 +201,7 @@ class Plugins extends Component { if (plugin_type === 'add_plugin' && !isConfigure) { this.setState({ type: 'configure', - isConfigure: true + isConfigure: true, }); } } else { @@ -200,7 +218,7 @@ class Plugins extends Component { selectedPlugin: {}, type: '', isConfigure: false, - tabKey: 'explore' + tabKey: 'explore', }); }; diff --git a/web/src/containers/AppDetails/index.js b/web/src/containers/AppDetails/index.js index 2d167d759f..19c89ec537 100644 --- a/web/src/containers/AppDetails/index.js +++ b/web/src/containers/AppDetails/index.js @@ -23,7 +23,7 @@ const Index = ({ openContactForm, icons: ICONS, router, userApps }) => { } } - const id = generateDynamicTarget(app, 'app'); + const id = generateDynamicTarget(app, 'app', 'kit'); useEffect(() => { setMounted(true); diff --git a/web/src/containers/index.js b/web/src/containers/index.js index 33cd4d5027..202c8176ec 100644 --- a/web/src/containers/index.js +++ b/web/src/containers/index.js @@ -66,3 +66,4 @@ export { default as Roles } from './Admin/Roles'; export { default as Resources } from './Admin/Resources'; export { default as Pairs } from './Admin/Trades'; export { default as Fiatmarkets } from './Admin/Fiat'; +export { default as AdminApps } from './Admin/Apps'; diff --git a/web/src/reducers/appReducer.js b/web/src/reducers/appReducer.js index 8241506288..28d7302d53 100644 --- a/web/src/reducers/appReducer.js +++ b/web/src/reducers/appReducer.js @@ -489,9 +489,7 @@ const reducer = (state = INITIAL_STATE, { type, payload = {} }) => { allWebViews.forEach((plugin) => { const { target: staticTarget, meta, name, plugin_type } = plugin; let target; - if (plugin_type === 'app') { - target = generateDynamicTarget(name, 'app'); - } else if (staticTarget) { + if (staticTarget) { target = staticTarget; } else if (meta) { const { @@ -502,7 +500,10 @@ const reducer = (state = INITIAL_STATE, { type, payload = {} }) => { type, currency, } = meta; - if (is_page) { + + if (plugin_type === 'app') { + target = generateDynamicTarget(name, 'app', type); + } else if (is_page) { target = generateDynamicTarget(name, 'page'); } else if (is_verification_tab && type) { target = generateDynamicTarget(name, 'verification', type); diff --git a/web/src/routes.js b/web/src/routes.js index 9b7adbfd1e..509c4c1f74 100644 --- a/web/src/routes.js +++ b/web/src/routes.js @@ -58,6 +58,7 @@ import { Resources, Pairs, Fiatmarkets, + AdminApps, } from './containers'; import chat from './containers/Admin/Chat'; @@ -544,6 +545,11 @@ export const generateRoutes = (routes = []) => { name="Admin plugins" component={withAdminProps(Plugins, 'plugins')} /> + <Route + path="/admin/apps" + name="Admin apps" + component={withAdminProps(AdminApps, 'apps')} + /> {/* <Route path="/admin/plugins/:services" name="Admin plugins" diff --git a/web/src/utils/id.js b/web/src/utils/id.js index bc8a4e86df..29f0bbba7a 100644 --- a/web/src/utils/id.js +++ b/web/src/utils/id.js @@ -11,7 +11,7 @@ export const generateDynamicTarget = ( const sub = subType.toUpperCase(); switch (type) { case 'app': - return `APPLICATION__${name}`; + return `APPLICATION__${name}__${sub}`; case 'verification': return `REMOTE_VERIFICATION_TAB__${name}__${sub}`; case 'page': From a8277c7f3ee3037c5730c0f38d5f7d6c758e8fca Mon Sep 17 00:00:00 2001 From: Ali Beikverdi <ali@bitholla.com> Date: Tue, 4 Oct 2022 23:19:36 +0900 Subject: [PATCH 52/54] chart edge case for decimal point scaling --- web/src/actions/chartAction.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/src/actions/chartAction.js b/web/src/actions/chartAction.js index 204412996b..a87ccb56e7 100644 --- a/web/src/actions/chartAction.js +++ b/web/src/actions/chartAction.js @@ -28,6 +28,7 @@ export const getChartSymbol = (symbol, tickSize, api_name = '') => { let count = getDecimals(tickSize); pricescale = math.pow(10, count); } + if (pricescale === 0) pricescale = 1; // return axios({ // url: `/udf/symbols?symbol=${symbol}`, // method: 'GET' From f5a6e4e8a14e501ebd606e969e01d99e45de80e8 Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Wed, 5 Oct 2022 06:42:17 +0330 Subject: [PATCH 53/54] fix for booting image issue --- web/src/helpers/boot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/helpers/boot.js b/web/src/helpers/boot.js index b6ba92e09b..3f3970f6e1 100644 --- a/web/src/helpers/boot.js +++ b/web/src/helpers/boot.js @@ -16,7 +16,7 @@ const getLoadingImage = () => { export const setLoadingImage = ({ icons }) => { const theme = localStorage.getItem('theme'); getLoadingImage().src = - icons[theme]['EXCHANGE_LOADER'] || + (icons[theme] && icons[theme]['EXCHANGE_LOADER']) || icons[defaultIconsKey]['EXCHANGE_LOADER']; }; From 8d054d5c504ef223b39f64128ad639e32dd1d6cc Mon Sep 17 00:00:00 2001 From: Amir Hossein Salar <ah.salar@gmail.com> Date: Wed, 5 Oct 2022 07:57:54 +0330 Subject: [PATCH 54/54] fix for input group parsing warning --- web/src/components/QuickTrade/InputGroup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/QuickTrade/InputGroup.js b/web/src/components/QuickTrade/InputGroup.js index a1ab564f06..6d985a3a77 100644 --- a/web/src/components/QuickTrade/InputGroup.js +++ b/web/src/components/QuickTrade/InputGroup.js @@ -159,7 +159,7 @@ class InputGroup extends React.PureComponent { placeholder={STRINGS['AMOUNT']} style={isOpen ? { display: 'none' } : { width: '67%' }} className="input-group__input" - value={`${inputValue}`} + value={inputValue || ''} onChange={this.onChangeEvent} bordered={false} step={limits.MIN}