diff --git a/package-lock.json b/package-lock.json index 7be7848e..b3100fc4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -139,6 +139,11 @@ "react-is": "^16.6.3" } }, + "@types/clipboard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.1.tgz", + "integrity": "sha512-gJJX9Jjdt3bIAePQRRjYWG20dIhAgEqonguyHxXuqALxsoDsDLimihqrSg8fXgVTJ4KZCzkfglKtwsh/8dLfbA==" + }, "@types/history": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.2.tgz", @@ -437,6 +442,14 @@ "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", "dev": true }, + "add-dom-event-listener": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz", + "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==", + "requires": { + "object-assign": "4.x" + } + }, "ajv": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", @@ -655,9 +668,9 @@ } }, "aws-sdk": { - "version": "2.418.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.418.0.tgz", - "integrity": "sha512-15aCtqqCsiyMW+CDwo6Fq3V5jDzpgb5//aPMosL+5FQnQu65t2GiLidcIPx4fWvsYpRiE/i4enz3a0Kqtt2acQ==", + "version": "2.448.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.448.0.tgz", + "integrity": "sha512-RMmdxP0VgI8eq7SehOHINULL6BL84wy9jOngQwJnxCPT/3/5jUuexKjzeFpdXTS4+dVToqj8q9THAbqzuXZ9dQ==", "requires": { "buffer": "4.9.1", "events": "1.1.1", @@ -1880,6 +1893,11 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, + "big-integer": { + "version": "1.6.43", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.43.tgz", + "integrity": "sha512-9dULc9jsKmXl0Aeunug8wbF+58n+hQoFjqClN7WeZwGLh0XJUWyJJ9Ee+Ep+Ql/J9fRsTVaeThp8MhiCCrY0Jg==" + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -1900,29 +1918,22 @@ "file-uri-to-path": "1.0.0" } }, - "bip32": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-1.0.2.tgz", - "integrity": "sha512-kedLYj8yvYzND+EfzeoMSlGiN7ImiRBF/MClJSZPkMfcU+OQO7ZpL5L/Yg+TunebBZIHhunstiQF//KLKSF5rg==", - "requires": { - "bs58check": "^2.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "tiny-secp256k1": "^1.0.0", - "typeforce": "^1.11.5", - "wif": "^2.0.6" - } - }, "bip39": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.5.0.tgz", - "integrity": "sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.1.tgz", + "integrity": "sha512-h1mxBCpocHoZ6eUWNwh13bSXCZYy/wknSAvs1se3XDOTeerHU3jA8E4PIoPr8YMY3kdDSCpM1HypJmDS+C7U2Q==", "requires": { + "@types/node": "11.11.6", "create-hash": "^1.1.0", "pbkdf2": "^3.0.9", - "randombytes": "^2.0.1", - "safe-buffer": "^5.0.1", - "unorm": "^1.3.3" + "randombytes": "^2.0.1" + }, + "dependencies": { + "@types/node": { + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" + } } }, "bl": { @@ -1948,7 +1959,8 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true }, "body-parser": { "version": "1.18.3", @@ -2045,7 +2057,8 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true }, "browserify-aes": { "version": "1.2.0", @@ -2375,6 +2388,16 @@ } } }, + "clipboard": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -2461,12 +2484,25 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "component-classes": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz", + "integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=", + "requires": { + "component-indexof": "0.0.3" + } + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", "dev": true }, + "component-indexof": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz", + "integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ=" + }, "compressible": { "version": "2.0.16", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz", @@ -2515,30 +2551,31 @@ "dev": true }, "conseiljs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/conseiljs/-/conseiljs-0.2.1.tgz", - "integrity": "sha512-vM5OufwGPsYxtfP94MlVM2gWpf1PU2gAPVpAzopq+XYKa4XeLwmTBLREQZyFatUvQ5Qa9faY3V1QJ2p7xskaQQ==", + "version": "git+https://github.com/Cryptonomic/ConseilJS.git#a39441ce0fbb7a3458e4271f75557ffb94892a2d", + "from": "git+https://github.com/Cryptonomic/ConseilJS.git#a39441ce0fbb7a3458e4271f75557ffb94892a2d", "requires": { "@ledgerhq/hw-transport": "4.24.0", "@ledgerhq/hw-transport-node-hid": "4.24.0", - "aws-sdk": "^2.417.0", + "aws-sdk": "^2.447.0", "babel-runtime": "6.26.0", - "base-n": "git://github.com/yourcodesucks/base-n.git", + "base-n": "git://github.com/yourcodesucks/base-n.git#9d983f475c7396fbdc2fcbbc35b4821f0deeaa25", "basil-tezos-ledger": "0.0.1", - "bip32": "^1.0.0", - "bip39": "^2.5.0", + "big-integer": "^1.6.43", + "bip39": "^3.0.1", "blakejs": "^1.1.0", "bs58check": "^2.1.2", "https": "^1.0.0", "libsodium-wrappers-sumo": "0.7.4", - "node-fetch": "^2.3.0", + "moo": "^0.5.0", + "nearley": "^2.16.0", + "node-fetch": "^2.5.0", "zxcvbn": "^4.4.2" }, "dependencies": { "node-fetch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", - "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz", + "integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw==" } } }, @@ -2702,6 +2739,15 @@ "randomfill": "^1.0.3" } }, + "css-animation": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.5.0.tgz", + "integrity": "sha512-hWYoWiOZ7Vr20etzLh3kpWgtC454tW5vn4I6rLANDgpzNSkO7UfOqyCEeaoBSG9CYWQpRkFWTWbWW8o3uZrNLw==", + "requires": { + "babel-runtime": "6.x", + "component-classes": "^1.2.5" + } + }, "css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -2836,6 +2882,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -2950,6 +2997,11 @@ "rimraf": "^2.2.8" } }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -3014,6 +3066,11 @@ "randombytes": "^2.0.0" } }, + "discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=" + }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -3039,6 +3096,11 @@ "buffer-indexof": "^1.0.0" } }, + "dom-align": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.8.2.tgz", + "integrity": "sha512-17vInOylbB7H4qua7QRsmQT05FFTZemO8BhnOPgF9BPqjAPDyQr/9V8fmJbn05vQ31m2gu3EJSSYN2u94szUZg==" + }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -3133,6 +3195,7 @@ "version": "6.4.1", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "dev": true, "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -3806,8 +3869,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -3828,14 +3890,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3850,20 +3910,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -3980,8 +4037,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -3993,7 +4049,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4008,7 +4063,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4016,14 +4070,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4042,7 +4094,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4123,8 +4174,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4136,7 +4186,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4222,8 +4271,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -4259,7 +4307,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4279,7 +4326,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4323,14 +4369,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -4478,6 +4522,14 @@ } } }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "requires": { + "delegate": "^3.1.2" + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -4569,6 +4621,7 @@ "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" @@ -4606,6 +4659,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -5377,6 +5431,11 @@ "css-vendor": "^0.3.8" } }, + "keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -5443,6 +5502,31 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -5674,12 +5758,14 @@ "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==" + "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": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true }, "minimatch": { "version": "3.0.4", @@ -5782,6 +5868,19 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" }, + "moment-timezone": { + "version": "0.5.25", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.25.tgz", + "integrity": "sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==", + "requires": { + "moment": ">= 2.9.0" + } + }, + "moo": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.0.tgz", + "integrity": "sha512-AMv6iqhTEd5vT/cQlH6cammKS5ekyHhyqTRKi5zKMWl1RTyFnQ3ohPSBNSm8ySe2wlxSKwDonr9D5ZT44mdO3g==" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -5799,7 +5898,8 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "multicast-dns": { "version": "6.2.3", @@ -5846,14 +5946,53 @@ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" }, + "nearley": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", + "requires": { + "commander": "^2.19.0", + "moo": "^0.4.3", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6", + "semver": "^5.4.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + }, + "moo": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz", + "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==" + } + } + }, "needle": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", - "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.1.tgz", + "integrity": "sha512-CaLXV3W8Vnbps8ZANqDGz7j4x7Yj1LW4TWF/TQuDfj7Cfx4nAPTvw98qgTevtto1oHDrh3pQkaODbqupXlsWTg==", "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "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==" + } } }, "negotiator": { @@ -5890,9 +6029,9 @@ } }, "node-abi": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.1.tgz", - "integrity": "sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.8.0.tgz", + "integrity": "sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==", "requires": { "semver": "^5.4.1" } @@ -5913,13 +6052,20 @@ "dev": true }, "node-hid": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.7.tgz", - "integrity": "sha512-s6x8dU9/9+yKyeNw5xvU9FvQ1QGazVrDIG08/bixxCVQw98jfeFyz51C0T9/0KzKAYMOXMtElYvPIKmtY7eizw==", + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-0.7.8.tgz", + "integrity": "sha512-79Z9hw/pqIDp0kxvb353ivGgslo4i0hYQTcCqfRFxIJSO2gF9VtPla5uQY/9jTcDlON5O5YaqxbdH+8bs+m+1Q==", "requires": { - "bindings": "^1.4.0", - "nan": "^2.12.1", - "prebuild-install": "^5.2.4" + "bindings": "^1.5.0", + "nan": "^2.13.2", + "prebuild-install": "^5.3.0" + }, + "dependencies": { + "nan": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", + "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" + } } }, "node-libs-browser": { @@ -6388,6 +6534,11 @@ "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=" + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -6510,9 +6661,9 @@ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" }, "prebuild-install": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.2.4.tgz", - "integrity": "sha512-CG3JnpTZXdmr92GW4zbcba4jkDha6uHraJ7hW4Fn8j0mExxwOKK20hqho8ZuBDCKYCHYIkFM1P2jhtG+KpP4fg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz", + "integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==", "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -6661,6 +6812,28 @@ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", "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" + } + }, + "railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=" + }, + "randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "requires": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + } + }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", @@ -6719,6 +6892,64 @@ "strip-json-comments": "~2.0.1" } }, + "rc-align": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-2.4.5.tgz", + "integrity": "sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw==", + "requires": { + "babel-runtime": "^6.26.0", + "dom-align": "^1.7.0", + "prop-types": "^15.5.8", + "rc-util": "^4.0.4" + } + }, + "rc-animate": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-2.8.2.tgz", + "integrity": "sha512-JUKpst+OSDFQjqhhZliBcmO3Fie1SeiIxsEhS7PbZVz/UjCC8uDtp31+NRxidxy3BnfXbbfZdtG9mNWIDqIfTw==", + "requires": { + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "css-animation": "^1.3.2", + "prop-types": "15.x", + "raf": "^3.4.0", + "react-lifecycles-compat": "^3.0.4" + } + }, + "rc-tooltip": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-3.7.3.tgz", + "integrity": "sha512-dE2ibukxxkrde7wH9W8ozHKUO4aQnPZ6qBHtrTH9LoO836PjDdiaWO73fgPB05VfJs9FbZdmGPVEbXCeOP99Ww==", + "requires": { + "babel-runtime": "6.x", + "prop-types": "^15.5.8", + "rc-trigger": "^2.2.2" + } + }, + "rc-trigger": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-2.6.2.tgz", + "integrity": "sha512-op4xCu95/gdHVaysyxxiYxbY+Z+UcIBSUY9nQfLqm1FlitdtnAN+owD5iMPfnnsRXntgcQ5+RdYKNUFQT5DjzA==", + "requires": { + "babel-runtime": "6.x", + "classnames": "^2.2.6", + "prop-types": "15.x", + "rc-align": "^2.4.0", + "rc-animate": "2.x", + "rc-util": "^4.4.0" + } + }, + "rc-util": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.6.0.tgz", + "integrity": "sha512-rbgrzm1/i8mgfwOI4t1CwWK7wGe+OwX+dNa7PVMgxZYPBADGh86eD4OcJO1UKGeajIMDUUKMluaZxvgraQIOmw==", + "requires": { + "add-dom-event-listener": "^1.1.0", + "babel-runtime": "6.x", + "prop-types": "^15.5.10", + "shallowequal": "^0.2.2" + } + }, "react": { "version": "16.8.5", "resolved": "https://registry.npmjs.org/react/-/react-16.8.5.tgz", @@ -6730,6 +6961,16 @@ "scheduler": "^0.13.5" } }, + "react-clipboard.js": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/react-clipboard.js/-/react-clipboard.js-2.0.7.tgz", + "integrity": "sha512-KDjKTFL4Yumr6yq8/uM8+Ptk7m8YJLFRz1ie6u1hk8BC64ThTrzVqh3t6zJw11alEtwLvOgieF7YDm3JpxhZTQ==", + "requires": { + "@types/clipboard": "^2.0.1", + "clipboard": "^2.0.0", + "prop-types": "^15.5.0" + } + }, "react-dom": { "version": "16.8.5", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.5.tgz", @@ -6761,6 +7002,11 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-moment": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/react-moment/-/react-moment-0.9.2.tgz", + "integrity": "sha512-jpKIEvcEOTSa4RXWTjDlvja7sN+ee5Gyk5ZKa704FZxE01OxmKIpq9GUliqTrAgdDYJJUQsnqQamczn0TN+DTg==" + }, "react-redux": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.1.tgz", @@ -6814,6 +7060,71 @@ "resolved": "https://registry.npmjs.org/react-router-redux/-/react-router-redux-4.0.8.tgz", "integrity": "sha1-InQDWWtRUeGCN32rg1tdRfD4BU4=" }, + "react-swipeable-views": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/react-swipeable-views/-/react-swipeable-views-0.13.1.tgz", + "integrity": "sha512-zZIRBD+HFO0P5z3TCkDMsSG/Sc3LXGGtojO+dEAGxsPvZjc3ji4Z/oOcLjZ4ozl0xIlLQJZ89o1rR82H/MDBHw==", + "requires": { + "@babel/runtime": "7.0.0", + "dom-helpers": "^3.2.1", + "prop-types": "^15.5.4", + "react-swipeable-views-core": "^0.13.1", + "react-swipeable-views-utils": "^0.13.1", + "warning": "^4.0.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", + "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + } + } + }, + "react-swipeable-views-core": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/react-swipeable-views-core/-/react-swipeable-views-core-0.13.1.tgz", + "integrity": "sha512-EP8sCvvD7VDiZLglPt9icMuMNu8qLRLk0ab/fB1HXv7lX8ClnwF3UMCM0ZrN3sguSY7CsX3LevducGGsT1VcDg==", + "requires": { + "@babel/runtime": "7.0.0", + "warning": "^4.0.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", + "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + } + } + }, + "react-swipeable-views-utils": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/react-swipeable-views-utils/-/react-swipeable-views-utils-0.13.1.tgz", + "integrity": "sha512-r5eyPIIHnlvILvFHXGnASDXa3RwC6X2YevegA2II5fhzYqwQRpJ81+lnzknNg5hiIN6ucXc5vrkqRRjabAhMpA==", + "requires": { + "@babel/runtime": "7.0.0", + "fbjs": "^0.8.4", + "keycode": "^2.1.7", + "prop-types": "^15.6.0", + "react-event-listener": "^0.6.0", + "react-swipeable-views-core": "^0.13.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", + "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + } + } + }, "react-transition-group": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz", @@ -7063,8 +7374,7 @@ "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 + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, "rimraf": { "version": "2.6.3", @@ -7135,6 +7445,11 @@ "ajv-keywords": "^3.1.0" } }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -7265,6 +7580,14 @@ "safe-buffer": "^5.0.1" } }, + "shallowequal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz", + "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=", + "requires": { + "lodash.keys": "^3.1.2" + } + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -7976,17 +8299,10 @@ "setimmediate": "^1.0.4" } }, - "tiny-secp256k1": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.0.1.tgz", - "integrity": "sha512-Wz2kMPWtCI5XBftFeF3bUL8uz2+VlasniKwOkRPjvL7h1QVd9rbhrve/HWUu747kJKzVf1XHonzcdM4Ut8fvww==", - "requires": { - "bindings": "^1.3.0", - "bn.js": "^4.11.8", - "create-hmac": "^1.1.7", - "elliptic": "^6.4.0", - "nan": "^2.10.0" - } + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" }, "to-arraybuffer": { "version": "1.0.1", @@ -8094,11 +8410,6 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, - "typeforce": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", - "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" - }, "typescript": { "version": "3.3.4000", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.4000.tgz", @@ -8180,11 +8491,6 @@ "imurmurhash": "^0.1.4" } }, - "unorm": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.5.0.tgz", - "integrity": "sha512-sMfSWoiRaXXeDZSXC+YRZ23H4xchQpwxjpw1tmfR+kgbBCaOgln4NI0LXejJIhnBuKINrB3WRn+ZI8IWssirVw==" - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -8801,14 +9107,6 @@ "string-width": "^1.0.2 || 2" } }, - "wif": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", - "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", - "requires": { - "bs58check": "<3.0.0" - } - }, "worker-farm": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", diff --git a/package.json b/package.json index 9a400155..1f7cc727 100755 --- a/package.json +++ b/package.json @@ -46,13 +46,18 @@ "dependencies": { "@material-ui/core": "^3.8.3", "@material-ui/icons": "^3.0.1", - "conseiljs": "^0.2.1", + "conseiljs": "git+https://github.com/Cryptonomic/ConseilJS.git#a39441ce0fbb7a3458e4271f75557ffb94892a2d", "moment": "^2.23.0", + "moment-timezone": "^0.5.25", + "rc-tooltip": "^3.7.3", "react": "^16.8.5", + "react-clipboard.js": "^2.0.7", "react-dom": "^16.8.5", + "react-moment": "^0.9.2", "react-redux": "^5.0.7", "react-router-dom": "^4.2.2", "react-router-redux": "^4.0.8", + "react-swipeable-views": "^0.13.1", "redux": "^4.0.0", "redux-devtools-extension": "^2.13.7", "redux-thunk": "^2.3.0", diff --git a/resources/fonts/ArronaxIcons/arronax.eot b/resources/fonts/ArronaxIcons/arronax.eot new file mode 100755 index 00000000..32e9592f Binary files /dev/null and b/resources/fonts/ArronaxIcons/arronax.eot differ diff --git a/resources/fonts/ArronaxIcons/arronax.svg b/resources/fonts/ArronaxIcons/arronax.svg new file mode 100755 index 00000000..0c28d703 --- /dev/null +++ b/resources/fonts/ArronaxIcons/arronax.svg @@ -0,0 +1,28 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/fonts/ArronaxIcons/arronax.ttf b/resources/fonts/ArronaxIcons/arronax.ttf new file mode 100755 index 00000000..cd9824d5 Binary files /dev/null and b/resources/fonts/ArronaxIcons/arronax.ttf differ diff --git a/resources/fonts/ArronaxIcons/arronax.woff b/resources/fonts/ArronaxIcons/arronax.woff new file mode 100755 index 00000000..77c59a1c Binary files /dev/null and b/resources/fonts/ArronaxIcons/arronax.woff differ diff --git a/resources/fonts/TezosIcons/Tezos-icons.eot b/resources/fonts/TezosIcons/Tezos-icons.eot deleted file mode 100755 index ff9a5f66..00000000 Binary files a/resources/fonts/TezosIcons/Tezos-icons.eot and /dev/null differ diff --git a/resources/fonts/TezosIcons/Tezos-icons.svg b/resources/fonts/TezosIcons/Tezos-icons.svg deleted file mode 100755 index 0bcab169..00000000 --- a/resources/fonts/TezosIcons/Tezos-icons.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - -Generated by IcoMoon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/resources/fonts/TezosIcons/Tezos-icons.ttf b/resources/fonts/TezosIcons/Tezos-icons.ttf deleted file mode 100755 index e469a087..00000000 Binary files a/resources/fonts/TezosIcons/Tezos-icons.ttf and /dev/null differ diff --git a/resources/fonts/TezosIcons/Tezos-icons.woff b/resources/fonts/TezosIcons/Tezos-icons.woff deleted file mode 100755 index 0572d00d..00000000 Binary files a/resources/fonts/TezosIcons/Tezos-icons.woff and /dev/null differ diff --git a/src/assets/sadOctopus.svg b/src/assets/sadOctopus.svg new file mode 100644 index 00000000..5a015da3 --- /dev/null +++ b/src/assets/sadOctopus.svg @@ -0,0 +1,20 @@ + + + + AF65BAF4-159C-48B4-ABFC-0594343B712F@1.00x + Created with sketchtool. + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/TezosIcon/index.tsx b/src/components/ArronaxIcon/index.tsx similarity index 59% rename from src/components/TezosIcon/index.tsx rename to src/components/ArronaxIcon/index.tsx index d17a722f..0a2f1fa3 100644 --- a/src/components/TezosIcon/index.tsx +++ b/src/components/ArronaxIcon/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import styled from 'styled-components'; const Icon = styled.span` - font-family: 'Tezos-icons' !important; + font-family: 'Arronax-icons' !important; font-size: ${({ size }) => size}; color: ${({ color}) => color}; speak: none; @@ -28,105 +28,67 @@ const getIconByName = iconName => { const toUnicode = unicode => String.fromCharCode(parseInt(unicode, 16)); switch (iconName) { - case 'icon-new-window': { - return toUnicode('e916'); - } - case 'icon-star': { - return toUnicode('e910'); - } - case 'icon-broadcast': { - return toUnicode('e911'); - } - case 'arrow-left': { + case 'icon-delete': { return toUnicode('e900'); } - case 'arrow-right': { + case 'icon-octopus-logo': { + return toUnicode('e901'); + } + case 'icon-tz': { return toUnicode('e902'); } - - case 'checkmark': { + case 'icon-sort-ascending': { return toUnicode('e903'); } - - case 'checkmark-outline': { + case 'icon-sort-descending': { return toUnicode('e904'); } - - case 'help': { + case 'icon-reorder': { return toUnicode('e905'); } - - case 'manager': { + case 'icon-close': { return toUnicode('e906'); } - - case 'smart-address': { + case 'icon-reset': { return toUnicode('e907'); } - - case 'tezos': { + case 'icon-add': { return toUnicode('e908'); } - - case 'warning': { + case 'icon-next': { return toUnicode('e909'); } - - case 'logout': { + case 'icon-previous': { return toUnicode('e90a'); } - - case 'settings': { + case 'icon-search-left': { return toUnicode('e90b'); - } - - case 'checkmark2': { + } + case 'icon-search-right': { + return toUnicode('e90c'); + } + case 'icon-down-caret': { + return toUnicode('e90d'); + } + case 'icon-columns': { return toUnicode('e90e'); } - - case 'send': { + case 'icon-filter': { return toUnicode('e90f'); } - - case 'star': { + case 'icon-question': { return toUnicode('e910'); } - - case 'broadcast': { + case 'icon-export': { return toUnicode('e911'); } - - case 'view-show': { - return toUnicode('e912'); - } - - case 'view-hide': { - return toUnicode('e913'); - } - - case 'change': { - return toUnicode('e914'); - } - - case 'receive': { - return toUnicode('e915'); - } - - case 'new-window': { - return toUnicode('e916'); - } - - case 'info': { - return toUnicode('e917'); - } - default: { console.error(`${iconName} No such icon in Tezos icons font`); } } }; -const TezosIcon = (props: Props) => { +const ArronaxIcon = (props: Props) => { const { iconName, size, color, className, onClick } = props; return ( @@ -135,4 +97,4 @@ const TezosIcon = (props: Props) => { ); }; -export default TezosIcon; +export default ArronaxIcon; diff --git a/src/components/ColumnItem/index.tsx b/src/components/ColumnItem/index.tsx new file mode 100755 index 00000000..df049c20 --- /dev/null +++ b/src/components/ColumnItem/index.tsx @@ -0,0 +1,61 @@ +import * as React from 'react'; +import styled from 'styled-components'; +import { withStyles } from '@material-ui/core/styles'; +import Checkbox from '@material-ui/core/Checkbox'; +import ArronaxIcon from '../ArronaxIcon'; + +const Container = styled.div` + display: flex; + height: 51px; + width: 372px; + align-items: center; + padding: 0 28px 0 10px; + &:hover { + background: rgba(101, 200, 206, 0.13); + } +`; + +const DraggableIcon = styled(ArronaxIcon)` + margin-left: auto; + opacity: 0.4; +`; + +const styles = { + checkbox: { + '&$checked': { + color: '#56c2d9', + }, + }, + checked: {}, +}; + +interface Props { + isChecked?: boolean; + name: string; + classes: any; + onClick: () => void; +} + +const ColumnItem: React.StatelessComponent = (props) => { + const { isChecked, name, classes, onClick } = props; + return ( + + + {name} + {/* {isChecked && } */} + + ); +}; + +ColumnItem.defaultProps = { + isChecked: false +} + +export default withStyles(styles)(ColumnItem); diff --git a/src/components/ColumnsDisplay/index.tsx b/src/components/ColumnsDisplay/index.tsx deleted file mode 100644 index df125bd4..00000000 --- a/src/components/ColumnsDisplay/index.tsx +++ /dev/null @@ -1,360 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; -import { withStyles } from '@material-ui/core/styles'; -import Checkbox from '@material-ui/core/Checkbox'; -import ListItemText from '@material-ui/core/ListItemText'; -import Button from '@material-ui/core/Button'; -import Menu from '@material-ui/core/Menu'; -import MenuItem from '@material-ui/core/MenuItem'; -import DragIcon from '@material-ui/icons/DragHandle'; -import KeyboardArrowDown from '@material-ui/icons/KeyboardArrowDown'; - -const Container = styled.div` - display: flex; - border: 1px solid #d8d8d8; - border-radius: 5px; - margin-right: 5px; - margin-left: 5px; -`; - -const ButtonShell = styled(Button)` - position: relative; - width: 140px; - height: 52px; - border: 1px solid #d8d8d8; - border-radius: 5px; - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - font-weight: 400 !important; - cursor: pointer; -`; - -const NestedTitle = styled.div` - cursor: default; - flex-shrink: 0; - outline: none; - margin-top: 15px; - margin-bottom: 12px; - margin-left: 31px; - color: #9b9b9b; - font-family: Roboto-Medium; - font-size: 16px; - font-weight: 500; - height: 19px; - letter-spacing: 0; - width: 333px; -`; - -const DraggableIcon = styled(DragIcon)` - float: right; - margin-left: 25px; - color: #d8d8d8; -`; - -const ButtonContainer = styled.span` - flex-shrink: 0; - display: flex; - float: right; - margin: 4px 20px 15px 10px !important; -`; - -const ArrowIcon = styled(KeyboardArrowDown)` - color: #56c2d9; - margin-left: 7px; -`; - -const MenuContainer = styled.div` - height: 100%; - display: flex; - flex-direction: column; - flex-wrap: nowrap; -`; - -const MenuContents = styled.div` - height: 390px; - flex: 1; - outline: none; - overflow: auto; - min-height: 1.25em; - padding-top: 10px; -`; - -const SubmitButton = styled(Button)` - display: flex; - background: #56c2d9 !important; - border-radius: 5px 5px 5px 5px; - height: 42px; - width: 113px; - color: #ffffff !important; - font-family: Roboto-Bold; - font-size: 20px; - font-weight: bold; - letter-spacing: 2.43px; - text-align: center; - width: 113px; -`; -const CancelButton = styled(Button)` - display: flex; - color: #56c2d9 !important; - border-radius: 5px 5px 5px 5px; - height: 42px; - width: 113px; - font-family: Roboto-Bold; - font-size: 20px; - font-weight: bold; - letter-spacing: 2.43px; - text-align: center; - width: 113px; - margin-right: 6px !important; -`; - -const HR = styled.hr` - border-color: #d8d8d8 !important; - border-style: solid !important; - margin-top: 0px; - outline: none; -`; - -const FadeOut = styled.span` - position: absolute; - width: 100%; - height: 20px; -`; - -const FadeTop = styled(FadeOut)` - margin-top: -20px; - background-image: linear-gradient( - to top, - rgba(255, 255, 255, 0.7) 0%, - rgba(255, 255, 255, 1) 80% - ); - z-index: 10; -`; - -const FadeBottom = styled.div` - overflow: visible; - pointer-events: none; - outline: none; - position: absolute; - width: 100%; - margin-top: -55px; - padding-top: 10px; - height: 55px; - background-image: linear-gradient( - to bottom, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0.8) 50% - ); - z-index: 10; -`; - -const styles = { - menuItem: { - '&&&': { - backgroundColor: 'transparent', - }, - }, - removeSelector: { - '&&&': { - cursor: 'default', - }, - }, - checkbox: { - '&$checked': { - color: '#56c2d9', - }, - }, - checked: {}, -}; - -interface SelectedColumnsData { - cardinality: null | number; - dataType: string; - displayName: string; - entity: string; - keyType: string; - name: string; -} - -type Props = { - selectedColumns: any; - selectedEntity: string; - attributes: any; - classes: any; - submitValues: () => void; - setColumns: (columns: object[]) => void; -}; - -type States = { - selected: object[]; - anchorEl: boolean; - fadeBottom: boolean; -}; - -class ColumnDisplay extends React.Component { - state = { - selected: [], - anchorEl: null, - fadeBottom: true, - }; - - componentDidMount() { - const { selectedColumns, selectedEntity } = this.props; - this.setState({ - selected: [...selectedColumns[selectedEntity]], - }); - } - - componentDidUpdate(prevProps: Props) { - const { selectedColumns, selectedEntity } = this.props; - if ( - prevProps.selectedColumns[selectedEntity] !== - selectedColumns[selectedEntity] || - selectedEntity !== prevProps.selectedEntity - ) { - this.setState({ - selected: [...selectedColumns[selectedEntity]], - }); - } - } - - handleSubmit = async event => { - const { selected } = this.state; - const { setColumns, submitValues } = this.props; - event.preventDefault(); - await this.setState({ anchorEl: null }); - await setColumns(selected); - await submitValues(); - }; - - handleChange = (name: SelectedColumnsData) => event => { - const { selected } = this.state; - const positionInArray = selected.findIndex( - selected => selected.name === name.name - ); - if (positionInArray === -1 && selected.length <= 5) { - this.setState({ - selected: [...selected, name], - }); - } else if (positionInArray > -1 && selected.length <= 6) { - selected.splice(positionInArray, 1); - this.setState({ - selected: [...selected], - }); - } - }; - - cancelChange = () => { - const { selectedColumns, selectedEntity } = this.props; - this.setState({ - selected: [...selectedColumns[selectedEntity]], - anchorEl: null, - }); - }; - - handleClick = event => { - this.setState({ anchorEl: event.currentTarget }); - }; - - handleScroll = event => { - const bottom = - event.target.scrollHeight - event.target.scrollTop === - event.target.clientHeight; - if (bottom) { - this.setState({ fadeBottom: false }); - } else { - this.setState({ fadeBottom: true }); - } - }; - - render() { - const { selectedEntity, classes, attributes } = this.props; - const { anchorEl, fadeBottom, selected } = this.state; - let tab; - switch (selectedEntity) { - case 'blocks': - tab = 'blocks'; - break; - case 'operations': - tab = 'operations'; - break; - case 'accounts': - tab = 'accounts'; - break; - } - const selectedName = selected.map(selected => { - return selected.name; - }); - - return ( - - - - Columns ({selected.length}) - - - - - Select Up to 6 Columns to Display - - - {attributes.map((name, index) => ( - = 6 && - selectedName.indexOf(name.name) === -1 - ? classes.removeSelector - : null - } - classes={{ root: classes.menuItem }} - onClick={this.handleChange(name)} - key={index} - value={name.name} - > - = 6 && - selectedName.indexOf(name.name) === -1 - ? classes.removeSelector - : null - } - classes={{ - root: classes.checkbox, - checked: classes.checked, - }} - disableRipple={true} - checked={selectedName.indexOf(name.name) > -1} - /> - - - - ))} - - {fadeBottom && } -
{' '} - - Cancel - - Done - - -
-
-
-
- ); - } -} - -export default withStyles(styles)(ColumnDisplay); diff --git a/src/components/ColumnsPanel/index.tsx b/src/components/ColumnsPanel/index.tsx new file mode 100644 index 00000000..8d47793a --- /dev/null +++ b/src/components/ColumnsPanel/index.tsx @@ -0,0 +1,207 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import styled from 'styled-components'; +import ArronaxIcon from '../ArronaxIcon'; +import ColumnItem from '../ColumnItem'; + +import { + getColumns, + getAttributes, + getEntity +} from '../../reducers/app/selectors'; +import { + setColumnsAction +} from '../../reducers/app/actions'; +import { resetColumns } from '../../reducers/app/thunks'; + +const Container = styled.div` + width: ${({ count }) => count*372 + 'px' }; + margin: auto; + max-width: 100%; +`; + +const MainContainer = styled.div` + box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.05); + background-color: white; + max-width: 100%; + overflow-x: auto; +`; + +const ColumnsContainer = styled.div` + display: flex; + flex-direction: column; + flex-wrap: wrap; + max-height: 510px; +`; + +const HeaderTxt = styled.div` + color: #4a4a4a; + font-size: 20px; + margin-bottom: 14px; +`; + +const Title = styled.div` + font-size: 16px; + line-height: 19px; + padding: 13px 25px; + color: rgb(155, 155, 155); + font-weight: 400; +`; + +const RefreshIcon = styled(ArronaxIcon)` + margin-right: 12px; +`; + +const ButtonContainer = styled.div` + display: flex; + padding: 25px; + justify-content: flex-end; +`; + +const RunButton = styled.div` + cursor: pointer; + margin-left: 40px; + color: white; + background: #56c2d9; + border-radius: 9px; + font-size: 20px; + font-weight: 700; + height: 60px; + width: 158px; + display: flex; + align-items: center; + justify-content: center; +`; + +const ResetButton = styled.div` + color: #56c2d9; + font-size: 20px; + font-weight: 700; + cursor: pointer; + display: flex; + align-items: center; +`; + +type Props = { + selectedColumns: any[]; + selectedEntity: string; + attributes: any; + onSubmit: () => void; + setColumns: (entity: string, columns: object[]) => void; + onResetColumns: () => void; +}; + +type States = { + selected: object[]; +}; + +class ColumnsPanel extends React.Component { + state = { + selected: [], + prevPropsSelected: [] + }; + + static getDerivedStateFromProps(props, state) { + if (props.selectedColumns !== state.prevPropsSelected) { + return { + prevPropsSelected: props.selectedColumns, + selected: props.selectedColumns + }; + } + return null; + } + + handleSubmit = async () => { + const { selected } = this.state; + const { selectedEntity, setColumns, onSubmit } = this.props; + await setColumns(selectedEntity, selected); + await onSubmit(); + }; + + handleChange = (attribute) => { + const { selected } = this.state; + const positionInArray = selected.findIndex( + column => column.name === attribute.name + ); + if (positionInArray === -1) { + this.setState({ + selected: [...selected, attribute], + }); + } else { + selected.splice(positionInArray, 1); + this.setState({ + selected: [...selected], + }); + } + }; + + cancelChange = () => { + const { onResetColumns } = this.props; + onResetColumns(); + }; + + render() { + const { attributes } = this.props; + const { selected } = this.state; + const columnsCount = Math.ceil(attributes.length / 10); + return ( + + Columns + + Select Columns to Display + + {selected.map((attribute, index) => ( + this.handleChange(attribute)} + /> + ))} + {attributes.sort((a, b) => (a.displayName.toLowerCase() < b.displayName.toLowerCase()) ? -1 : 1).map((attribute, index) => { + const pos = selected.findIndex(item => item.name === attribute.name); + if (pos !== -1) { + return null; + } + return ( + this.handleChange(attribute)} + /> + ); + })} + + + + + + Reset + + + Apply + + + + ); + } +} + +const mapStateToProps = state => ({ + selectedColumns: getColumns(state), + attributes: getAttributes(state), + selectedEntity: getEntity(state), +}); + +const mapDispatchToProps = dispatch => ({ + setColumns: (entity: string, columns: object[]) => + dispatch(setColumnsAction(entity, columns)), + onResetColumns: () => + dispatch(resetColumns()) +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ColumnsPanel); + diff --git a/src/components/CustomPaginator/index.tsx b/src/components/CustomPaginator/index.tsx index 1e1c4310..3a0d8fa9 100755 --- a/src/components/CustomPaginator/index.tsx +++ b/src/components/CustomPaginator/index.tsx @@ -6,11 +6,15 @@ import MenuItem from '@material-ui/core/MenuItem'; import ArrowDropDown from '@material-ui/icons/KeyboardArrowDown'; import LeftChevronIcon from '@material-ui/icons/ChevronLeft'; import RightChevronIcon from '@material-ui/icons/ChevronRight'; +import IconButton from '@material-ui/core/IconButton'; +import Tooltip from 'rc-tooltip'; +import ArronaxIcon from '../ArronaxIcon'; +import 'rc-tooltip/assets/bootstrap_white.css'; const Container = styled.div` position: absolute; right: 30px; - top: -50px; + top: 225px; height: 52px; display: flex; align-items: center; @@ -64,7 +68,14 @@ const MainTxtWrapper = styled.div` color: #4a4a4a; font-size: 16px; letter-spacing: 1.95px; - margin: 0 13px 0 2px; + margin: 0 5px 0 2px; +`; + +const LimitTxt = styled.div` + color: #4a4a4a; + font-size: 16px; + letter-spacing: 1.95px; + margin: 0; `; const ButtonWrapper = styled.div` @@ -79,6 +90,9 @@ const ButtonWrapper = styled.div` cursor: ${({ isActive }) => (isActive ? 'pointer' : 'default')}; pointer-events: ${({ isActive }) => (isActive ? 'auto' : 'none')}; border-radius: ${({ isNext }) => (isNext ? '0 5px 5px 0' : '5px 0 0 5px')}; + &:hover { + border-color: rgb(180, 231, 242); + } `; const LeftIconWrapper = styled(LeftChevronIcon)` @@ -93,6 +107,26 @@ const RightIconWrapper = styled(RightChevronIcon)` } `; +const TooltipButton = styled(IconButton)` + &&& { + padding: 5px; + margin-right: 14px; + } +`; + +const TooltipContainer = styled.div` + width: 344px; + font-size: 16px; + line-height: 24px; + font-weight: 500; + color: rgb(155, 155, 155); + background: white; +`; + +const ExportTxt = styled.span` + color: #56c2d9; +`; + const getList = (pageCount, balance, rowsPerPage) => { let items = []; for (let i = 0; i < pageCount - 1; i++) { @@ -121,15 +155,24 @@ const getList = (pageCount, balance, rowsPerPage) => { return items; }; +const getLimitTooltip = (onExportCsv) => { + return ( + + Queries on Arronax are limited to 5000 results. Export to CSV to get the full result set. + + ); +} + interface Props { rowsPerPage: number; page: number; totalNumber: number; onChangePage(page: number): void; + onExportCsv: () => void; } const CustomPaginator: React.StatelessComponent = props => { - const { page, totalNumber, onChangePage, rowsPerPage } = props; + const { page, totalNumber, onChangePage, rowsPerPage, onExportCsv } = props; const pageCount = Math.ceil(totalNumber / rowsPerPage); const balance = totalNumber % rowsPerPage; return ( @@ -144,6 +187,23 @@ const CustomPaginator: React.StatelessComponent = props => { of {totalNumber} + {totalNumber >= 5000 && ( + + limit + + + + + + + )} onChangePage(page - 1)} diff --git a/src/components/CustomTableRow/index.tsx b/src/components/CustomTableRow/index.tsx index 2245b33c..35a33d48 100755 --- a/src/components/CustomTableRow/index.tsx +++ b/src/components/CustomTableRow/index.tsx @@ -1,9 +1,14 @@ import * as React from 'react'; -import * as moment from 'moment'; import styled from 'styled-components'; +import Moment from 'react-moment'; +import 'moment-timezone'; import TableCell from '@material-ui/core/TableCell'; import TableRow from '@material-ui/core/TableRow'; import Circle from '@material-ui/icons/FiberManualRecord'; +import ContentCopy from '@material-ui/icons/FileCopyOutlined'; +import Clipboard from 'react-clipboard.js'; +import { getShortColumn } from '../../utils/general'; +import { AttributeDefinition } from '../../types'; const TableRowWrapper = styled(TableRow)` &&& { @@ -14,11 +19,11 @@ const TableRowWrapper = styled(TableRow)` `; const StyledCircle1 = styled(Circle)` - color: rgb(255, 155, 213); + color: ${({ newcolor }) => newcolor}; `; const StyledCircle2 = styled(Circle)` - color: rgb(215, 195, 113); + color: ${({ newcolor }) => newcolor}; margin-left: -4px; margin-right: 7px; `; @@ -35,106 +40,125 @@ const StyledCell = styled(TableCell)` const SpanContainer = styled.span` display: flex; + align-items: center; `; -const ExplorerLink = styled.a` - text-decoration: none; - color: #10ade4; +const CopyIcon = styled(ContentCopy)` + &&& { + color: #a6dfe2; + font-size: 20px; + } +`; + +const ClipboardWrapper = styled(Clipboard)` + border: none; + background: transparent; + outline: none !important; + cursor: pointer; `; + +const LinkDiv = styled.div` + color: #56c2d9; + cursor: pointer; + text-decoration: underline; +`; + +const DefaultAttributeNames = [ + 'predecessor', + 'hash', + 'block_id', + 'block_hash', + 'operation_group_hash', + 'delegate', + 'protocol', + 'context', + 'operations_hash', + 'signature' +]; + +const PrimaryKeyList = { + blocks: ['hash', 'level'], + accounts: ['account_id'], + operations: ['operation_group_hash'] +}; + interface Props { - entity: string; item: any; selectedColumns: any[]; network: string; + platform: string; + selectedEntity: string, + onClickPrimaryKey: (key, value) => void; +} + +const formatValueForPrimary = (entity, name, shortValue, value, onClickPrimaryKey) => { + if (PrimaryKeyList[entity].includes(name)) { + return onClickPrimaryKey(name, value)}>{shortValue}; + } else if (entity === 'accounts' && name === 'manager') { // TODO: resolve via metadata + return onClickPrimaryKey('account_id', value)}>{shortValue}; + } else if (entity === 'blocks' && name === 'predecessor') { // TODO: resolve via metadata + return onClickPrimaryKey('hash', value)}>{shortValue}; + } + return shortValue; } -export const displayType = (network, shortenedItem, item, name) => { - if (name === 'account_id' || name === 'manager') { +const formatValueForDisplay = ( + platform: string, + network: string, + entity: string, + value: any, + attribute: AttributeDefinition, + onClickPrimaryKey: (key, value) => void +) => { + const { name, dataFormat, dataType} = attribute; + if (dataType === 'Boolean') { + const svalue = value.toString(); + return svalue.charAt(0).toUpperCase() + svalue.slice(1); + } else if (dataType === 'DateTime') { + if (!dataFormat) { + return value; + } + return ( + + {value} + + ) + } else if (name === 'account_id' || name === 'manager') { + let colors = Buffer.from(Buffer.from(value.substring(3, 6) + value.slice(-3), 'utf8').map(b => Math.floor((b - 48) * 255)/74)).toString('hex'); return ( - - - - {shortenedItem[name]} - + + + {formatValueForPrimary(entity, name, getShortColumn(value), value, onClickPrimaryKey)} + + + ); - } else if ( - name === 'predecessor' || - name === 'hash' || - name === 'block_id' || - name === 'block_hash' || - name === 'operation_group_hash' || - name === 'delegate' - ) { + } else if (DefaultAttributeNames.includes(name)) { return ( - - {shortenedItem[name]} - + {formatValueForPrimary(entity, name, getShortColumn(value), value, onClickPrimaryKey)} + + + ); - } else if ( - name === 'protocol' || - name === 'context' || - name === 'operations_hash' || - name === 'signature' - ) { - return shortenedItem[name]; } else { - return item[name]; + return formatValueForPrimary(entity, name, value, value, onClickPrimaryKey); } }; const CustomTableRow: React.StatelessComponent = props => { - const { selectedColumns, item, network } = props; - const shortenedItem = { ...item }; - let itemsArray = Object.keys(shortenedItem); - itemsArray.forEach(hash => { - if (item[hash] === null) { - return; - } else if ( - hash.toLowerCase().includes('hash') || - hash.toLowerCase().includes('predecessor') || - hash.toLowerCase().includes('account_id') || - hash.toLowerCase().includes('block_id') || - hash.toLowerCase() === 'manager' || - hash.toLowerCase().includes('protocol') || - hash.toLowerCase().includes('block_hash') || - hash.toLowerCase() === 'delegate' || - hash.toLowerCase().includes('operation_group_hash') || - hash.toLowerCase().includes('context') || - hash.toLowerCase().includes('signature') - ) { - const hashRepresentation = item[hash]; - const firstHalf = hashRepresentation.substring(0, 6); - const secondHalf = hashRepresentation.substring( - hashRepresentation.length - 6, - hashRepresentation.length - ); - const newHash = `${firstHalf}...${secondHalf}`; - shortenedItem[hash] = newHash; - } - return shortenedItem[hash]; - }); + const { selectedColumns, item, network, platform, selectedEntity, onClickPrimaryKey } = props; return ( {selectedColumns.map((column, index) => { return ( - {column.name === 'timestamp' ? ( - moment(item[column.name]).format('dd MM YYYY h:mm:ss a') - ) : ( - - {displayType(network, shortenedItem, item, column.name)} - - )} + + {formatValueForDisplay(platform, network, selectedEntity, item[column.name], column, onClickPrimaryKey)} + ); })} diff --git a/src/components/EntityModal/index.tsx b/src/components/EntityModal/index.tsx new file mode 100755 index 00000000..be8a23ce --- /dev/null +++ b/src/components/EntityModal/index.tsx @@ -0,0 +1,175 @@ +import * as React from 'react'; +import styled from 'styled-components'; +import Modal from '@material-ui/core/Modal'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import Moment from 'react-moment'; +import 'moment-timezone'; +import ArronaxIcon from '../ArronaxIcon'; + +const ModalWrapper = styled(Modal)``; + +const ScrollContainer = styled.div` + width: 100%; + height: 100%; + overflow-y: auto; + padding: 77px 0; +`; + +const ModalContainer = styled.div` + background-color: #ffffff; + outline: none; + position: relative; + padding: 27px 30px 30px 30px; + margin: 0 auto; + width: 798px; + min-height: 100%; +`; + +const ListContainer = styled.div` + width: 100%; +`; + +const CloseIcon = styled(ArronaxIcon)` + cursor: pointer; + position: absolute; + top: 30px; + right: 30px; +`; + +const ModalTitle = styled.div` + padding: 0 0 19px 0; + font-size: 24px; + line-height: 28px; + font-weight: 400; + color: #9b9b9b; +`; + +const RowContainer = styled.div` + display: flex; + padding: 15px 0; + font-size: 16px; + line-height: 19px; + border-bottom: 1px solid #dcdcdc; + letter-spacing: 0.23px; + color: rgb(74, 74, 74); +`; + +const TitleTxt = styled.div` + width: 198px; + font-weight: 400; +`; + +const ContentTxt = styled.div` + font-weight: 300; + word-break: break-word; + flex: 1; +`; + +const LoadingContainer = styled.div` + position: absolute; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.3); + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 100; +`; + +export const ButtonContainer = styled.div` + display: flex; + padding: 15px; + justify-content: flex-end; +`; + +export const CloseButton = styled.div` + color: #56c2d9; + font-size: 20px; + font-weight: 700; + cursor: pointer; + display: flex; + align-items: center; +`; + +const TITLE = { + blocks: 'Block', + opperations: 'Operation', + accounts: 'Account' +}; + +type Props = { + selectedEntity: string, + open: boolean, + item: any; + attributes: any[]; + isLoading: boolean, + onClose: () => void +}; + +class EntityModal extends React.Component { + + onClickModal = (event) => { + event.stopPropagation(); + } + render() { + const { + selectedEntity, + open, + item, + attributes, + isLoading, + onClose, + } = this.props; + return ( + + + this.onClickModal(event)}> + + {TITLE[selectedEntity]} Details + {!isLoading && ( + + {attributes.map((column, index) => { + const { displayName, dataType, dataFormat, name } = column; + let value = item[name]; + if (!value) { + return null; + } + if (dataType === 'DateTime' && dataFormat) { + value = ( + + {value} + + ); + } + return ( + + {displayName} + {value} + + ); + })} + + + Close + + + + )} + {isLoading && ( + + + + )} + + + + + ); + } +}; + +export default EntityModal; diff --git a/src/components/FilterItem/index.tsx b/src/components/FilterItem/index.tsx deleted file mode 100755 index 12ea765e..00000000 --- a/src/components/FilterItem/index.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; -import FormControl from '@material-ui/core/FormControl'; -import TextField from '@material-ui/core/TextField'; -import FormHelperText from '@material-ui/core/FormHelperText'; - -const Container = styled(FormControl)` - width: 100%; -`; - -const TextFieldWrapper = styled(TextField)` - &&& { - font-size: 16px; - font-weight: 300; - margin: 0; - - input { - padding: 10px; - } - } -}`; -const LabelWrapper = styled(FormHelperText)` - &&& { - color: rgba(0, 0, 0, 0.38); - font-size: 14px; - } -}`; - -interface Props { - label: string; - value?: any; - type: string; - onChange: (value: string, type: string) => void; -} - -const FilterItem: React.StatelessComponent = (props) => { - const {value, label, type, onChange} = props; - let realValue = ''; - if (type === 'limit') { - realValue = value; - } else { - value.forEach((item, index) => { - if (index === 0) { - realValue = item; - } else { - realValue += ', ' + item; - } - }) - } - return ( - - {label} - onChange(event.target.value, type)} - /> - - ); -}; -FilterItem.defaultProps = { - value: [] -} - -export default FilterItem; diff --git a/src/components/FilterPanel/index.tsx b/src/components/FilterPanel/index.tsx index 811b207c..86534efa 100644 --- a/src/components/FilterPanel/index.tsx +++ b/src/components/FilterPanel/index.tsx @@ -1,91 +1,43 @@ import * as React from 'react'; import { connect } from 'react-redux'; -import styled from 'styled-components'; -import PlusIcon from '@material-ui/icons/Add'; -import DeleteIcon from '@material-ui/icons/DeleteOutline'; import IconButton from '@material-ui/core/IconButton'; +import { ConseilOperator } from 'conseiljs'; +import ArronaxIcon from 'components/ArronaxIcon'; import { fetchValues } from '../../reducers/app/thunks'; import { getAvailableValues, getSelectedFilters, getOperators, + getAttributes, + getEntity } from '../../reducers/app/selectors'; import { - setSelectedValuesAction, - removeValueAction, addFilterAction, removeFilterAction, changeFilterAction, + removeAllFiltersAction } from '../../reducers/app/actions'; import FilterSelect from '../FilterSelect'; import ValueSelect from '../ValueSelect'; import ValueInput from '../ValueInput'; +import { Filter } from '../../types'; -const Container = styled.div` - width: 100%; - background: #fbfbfb; - border: 1px solid #ededed; - border-radius: 3px; -`; - -const FilterItemContainer = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - padding: 18px 24px 0 30px; -`; - -const FilterItemGr = styled.div` - border-radius: 5px; - border: 1px solid #ecedef; - display: flex; -`; - -const AddFilterFooter = styled.div` - width: 100%; - height: ${({ isFilters }) => (isFilters ? '67px' : '93px')}; - display: flex; - align-items: center; - padding-left: 24px; - border-top: ${({ isFilters }) => (isFilters ? '1px solid #ECEDEF' : 'none')}; - margin-top: ${({ isFilters }) => (isFilters ? '18px' : '0')}; -`; - -const AddFilterButton = styled.div` - color: #56c2d9; - font-size: 18px; - font-weight: bold; - cursor: pointer; - display: flex; - align-items: center; - opacity: ${({ isDisabled }) => (isDisabled ? 0.5 : 1)}; - pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'initial')}; -`; - -const PlusIconWrapper = styled(PlusIcon)` - &&& { - color: #56c2d9; - font-size: 27px; - } -`; - -const DeleteIconWrapper = styled(DeleteIcon)` - &&& { - color: #d8d8d8; - font-size: 37px; - } -`; - -const FilterExpTxt = styled.div` - color: #9b9b9b; - font-size: 18px; - margin-left: 21px; -`; - -const HR = styled.div` - width: 1px; - background-color: #ecedef; -`; +import { + Container, + HeaderTxt, + MainContainer, + FilterItemContainer, + FilterItemGr, + AddFilterFooter, + AddFilterButton, + PlusIconWrapper, + FilterExpTxt, + HR, + RefreshIcon, + ButtonContainer, + RunButton, + ResetButton +} from './style'; const attrTabValue = { blocks: 'block', @@ -93,143 +45,102 @@ const attrTabValue = { accounts: 'account', }; -interface Filter { - name: string; - operator: string; -} +const CARDINALITY_NUMBER = 15; type Props = { - selectedValues: object[]; - availableValues: object[]; + availableValues: object; selectedEntity: string; attributes: any[]; filters: Array; operators: any; - filterInputState: object; - setFilterInputState: ( - value: string, - filterName: string, - filterOperator: string - ) => void; - removeValue: (value: object) => void; - setSelectedValues: (value: object) => void; + swipeRef: any; fetchValues: (value: string) => void; addFilter: (entity: string) => void; removeFilter: (entity: string, index: number) => void; changeFilter: (entity: string, filter: object, index: number) => void; + removeAllFilters: (entity: string) => void; + onSubmit: () => void; }; -type States = { - value: string; -}; - -class FilterPanel extends React.Component { - state = { - value: '', - }; - - onAddFilter = () => { - const { addFilter, selectedEntity } = this.props; - addFilter(selectedEntity); +class FilterPanel extends React.Component { + onAddFilter = async () => { + const { addFilter, selectedEntity, swipeRef } = this.props; + await addFilter(selectedEntity); + swipeRef.updateHeight(); }; - onRemoveFilter = (index, filter) => { + onRemoveFilter = (index) => { const { removeFilter, selectedEntity, - removeValue, - selectedValues, - filterInputState, - setFilterInputState, } = this.props; - const itemToRemove = filterInputState[selectedEntity].find( - value => Object.keys(value).toString() === filter.name - ); - if (itemToRemove) { - setFilterInputState( - null, - Object.keys(itemToRemove).toString(), - filter.operator - ); - } - selectedValues.forEach(val => { - const valueToRemove = Object.keys(val).toString(); - if (valueToRemove === filter.name) { - removeValue(val); - } - }); removeFilter(selectedEntity, index); }; - onFilterNameChange = (val, index) => { + onFilterNameChange = (attr, index) => { const { - filters, selectedEntity, changeFilter, - attributes, fetchValues, + availableValues, + operators } = this.props; - const cards = attributes.map(attr => { - if (attr.cardinality < 15 && attr.cardinality !== null) { - return attr.name; - } - }); - if (cards.includes(val)) { - fetchValues(val); + const isLowCardinality = attr.cardinality < CARDINALITY_NUMBER && attr.cardinality !== null; + if (isLowCardinality && !availableValues[attr.name]) { + fetchValues(attr.name); + } + let operatorType = 'dateTime'; + if (attr.dataType === 'Int' || attr.dataType === 'Decimal') { + operatorType = 'numeric'; + } else if (attr.dataType === 'String') { + operatorType = 'string'; + } else if (attr.dataType === 'Boolean') { + operatorType = 'boolean'; } - const selectedFilter: any = filters[index]; - selectedFilter.name = val; + const selectedFilter = { + name: attr.name, + isLowCardinality, + operatorType, + operator: operators[operatorType][0].name, + values: [''] + }; changeFilter(selectedEntity, selectedFilter, index); }; - onFilterOperatorChange = (val, index) => { + onFilterOperatorChange = (operator, index) => { const { filters, selectedEntity, changeFilter, - filterInputState, - setFilterInputState, } = this.props; - const selectedFilter: any = filters[index]; - const findInput = filterInputState[selectedEntity].find( - filter => Object.keys(filter).toString() === selectedFilter.name - ); - // Check to see if input value for this attribute is populated and clear if so - if (findInput) { - setFilterInputState( - null, - Object.keys(findInput).toString(), - selectedFilter.operator - ); - } - selectedFilter.operator = val; - changeFilter(selectedEntity, selectedFilter, index); - }; - onFilterAttributeChange = (val, index) => { - const { filters, selectedEntity, changeFilter } = this.props; - const selectedFilter: any = filters[index]; - selectedFilter.attribute = val; + const selectedFilter = { + ...filters[index], + operator: operator.name, + values: [''] + }; changeFilter(selectedEntity, selectedFilter, index); }; - onValueChange = val => { - const { setSelectedValues } = this.props; - setSelectedValues(val); - }; + onFilterValueChange = (value, index, pos) => { + const { + filters, + selectedEntity, + changeFilter + } = this.props; - handleInputChange = (value, filter, filterOperator) => { - const { setFilterInputState } = this.props; - this.setState({ value: value }); - setFilterInputState(value, filter, filterOperator); + const selectedFilter: Filter = {...filters[index]}; + selectedFilter.values[pos] = value; + changeFilter(selectedEntity, selectedFilter, index); }; - handleBetweenInputChange = (value, filter, filterOperator) => { - const { setFilterInputState } = this.props; - this.setState({ value: value }); - const betweenValue = `-${value}`; - setFilterInputState(betweenValue, filter, filterOperator); + onResetFilters = () => { + const { + removeAllFilters, + selectedEntity + } = this.props; + removeAllFilters(selectedEntity); }; render() { @@ -238,148 +149,112 @@ class FilterPanel extends React.Component { attributes, filters, operators, - selectedValues, availableValues, - filterInputState, + onSubmit } = this.props; - const { value } = this.state; const entityName = attrTabValue[selectedEntity]; - const cards = []; - attributes.forEach(attr => { - if (attr.cardinality < 15 && attr.cardinality !== null) { - cards.push(attr.name); - } - }); - - const numericDataTypes = attributes.map(attr => { - if (attr.dataType === 'Int' || attr.dataType === 'Decimal') { - return attr.name; - } - }); - const stringDataTypes = attributes.map(attr => { - if (attr.dataType === 'String') { - return attr.name; - } - }); - const booleanDataTypes = attributes.map(attr => { - if (attr.dataType === 'Boolean') { - return attr.name; - } - }); - const disableAddFilter = - (filters.length > 0 && - filters.length !== - filterInputState[selectedEntity].length + selectedValues.length) || - (filters.length > 0 && - filters.length === - filterInputState[selectedEntity].length + selectedValues.length && - selectedValues.length !== filters.length && - value === ''); + const filterLength = filters.length; + let disableAddFilter = true; + const lastFilter: any = filterLength > 0 ? filters[filterLength - 1] : {}; + if (filterLength === 0) { + disableAddFilter = false; + } else if (lastFilter.operator === ConseilOperator.ISNULL || lastFilter.operator === 'isnotnull') { + disableAddFilter = false; + } else if(lastFilter.operator === ConseilOperator.BETWEEN || lastFilter.operator === ConseilOperator.IN) { + disableAddFilter = lastFilter.values.length !== 2; + } else if (lastFilter.values[0]) { + disableAddFilter = false; + } return ( - {filters.map((filter: any, index) => { - let newAttributes = []; - attributes.forEach((attr: any) => { - if (attr.name === filter.name) { - newAttributes.push(attr); - } - const index = filters.findIndex( - (item: any) => item.name === attr.name - ); - if (index < 0) { - newAttributes.push(attr); - } - }); - return ( - - - this.onFilterNameChange(val, index)} - /> - {filter.name &&
} - {filter.name && ( + Filter + + {filters.map((filter: Filter, index) => { + const newAttributes = attributes.filter((attr: any) => { + if (attr.name === filter.name) { + return true; + } + const pos = filters.findIndex( + (item: any) => item.name === attr.name + ); + return pos === -1; + }); + + return ( + + - this.onFilterOperatorChange(event, index) - } + value={filter.name} + placeholder={`Select ${entityName} Attribute`} + items={newAttributes} + onChange={attr => this.onFilterNameChange(attr, index)} /> - )} - {filter.operator &&
} - {(filter.operator && filter.operator === 'EQ') || - (filter.operator === 'NOTEQ' && - cards.includes(filter.name) && ( + {filter.name &&
} + {filter.name && ( + + this.onFilterOperatorChange(operator, index) + } + /> + )} + {filter.operator &&
} + {filter.operator && (filter.operator === ConseilOperator.EQ || filter.operator === 'noteq') && + filter.isLowCardinality && ( this.onValueChange(value)} + placeholder='Select Value' + selectedValue={filter.values[0]} + values={availableValues[filter.name]} + onChange={value => this.onFilterValueChange(value, index, 0)} /> - ))} - {filter.operator && !cards.includes(filter.name) && ( - - this.handleInputChange( - value, - filter.name, - filter.operator - ) - } - onBetweenInputChange={value => - this.handleBetweenInputChange( - value, - filter.name, - filter.operator - ) - } - /> - )} -
- this.onRemoveFilter(index, filter)} - > - - -
- ); - })} + )} + {filter.operator && !filter.isLowCardinality && ( + this.onFilterValueChange(value, index, pos)} + /> + )} +
+ this.onRemoveFilter(index)} + > + + +
+ ); + })} - 0}> - - - Add Filter - - {filters.length == 0 && ( - - You can filter by all {entityName} attributes and more. - - )} - + 0}> + + + Add Filter + + {filters.length == 0 && ( + + You can filter by all {entityName} attributes and more. + + )} + + + + + + Reset + + + Run + +
); } @@ -389,18 +264,19 @@ const mapStateToProps = state => ({ filters: getSelectedFilters(state), availableValues: getAvailableValues(state), operators: getOperators(state), + attributes: getAttributes(state), + selectedEntity: getEntity(state) }); const mapDispatchToProps = dispatch => ({ fetchValues: (value: string) => dispatch(fetchValues(value)), - removeValue: (value: object) => dispatch(removeValueAction(value)), - setSelectedValues: (value: object) => - dispatch(setSelectedValuesAction(value)), addFilter: (entity: string) => dispatch(addFilterAction(entity)), removeFilter: (entity: string, index: number) => dispatch(removeFilterAction(entity, index)), changeFilter: (entity: string, filter: object, index: number) => dispatch(changeFilterAction(entity, filter, index)), + removeAllFilters: (selectedEntity: string) => + dispatch(removeAllFiltersAction(selectedEntity)), }); export default connect( diff --git a/src/components/FilterPanel/style.ts b/src/components/FilterPanel/style.ts new file mode 100644 index 00000000..9ec7d7a7 --- /dev/null +++ b/src/components/FilterPanel/style.ts @@ -0,0 +1,107 @@ + +import styled from 'styled-components'; +import PlusIcon from '@material-ui/icons/Add'; +import ArronaxIcon from 'components/ArronaxIcon'; + +export const Container = styled.div` + width: 100%; +`; + +export const HeaderTxt = styled.div` + color: #4a4a4a; + font-size: 20px; + margin-bottom: 14px; +`; + +export const MainContainer = styled.div` + width: 100%; + background: #fbfbfb; + border: 1px solid #ededed; + border-radius: 3px; +`; + +export const FilterItemContainer = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + padding: 18px 24px 0 30px; +`; + +export const FilterItemGr = styled.div` + border-radius: 5px; + border: 1px solid #ecedef; + display: flex; +`; + +export const AddFilterFooter = styled.div` + width: 100%; + height: ${({ isFilters }) => (isFilters ? '67px' : '93px')}; + display: flex; + align-items: center; + padding-left: 24px; + border-top: ${({ isFilters }) => (isFilters ? '1px solid #ECEDEF' : 'none')}; + margin-top: ${({ isFilters }) => (isFilters ? '18px' : '0')}; +`; + +export const AddFilterButton = styled.div` + color: #56c2d9; + font-size: 18px; + font-weight: bold; + cursor: pointer; + display: flex; + align-items: center; + opacity: ${({ isDisabled }) => (isDisabled ? 0.5 : 1)}; + pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'initial')}; +`; + +export const PlusIconWrapper = styled(PlusIcon)` + &&& { + color: #56c2d9; + font-size: 27px; + } +`; + +export const FilterExpTxt = styled.div` + color: #9b9b9b; + font-size: 18px; + margin-left: 21px; +`; + +export const HR = styled.div` + width: 1px; + background-color: #ecedef; +`; + +export const RefreshIcon = styled(ArronaxIcon)` + margin-right: 12px; +`; + +export const ButtonContainer = styled.div` + display: flex; + padding: 25px; + justify-content: flex-end; +`; + +export const RunButton = styled.div` + cursor: pointer; + margin-left: 40px; + color: white; + background: #56c2d9; + border-radius: 9px; + font-size: 20px; + font-weight: 700; + height: 60px; + width: 158px; + display: flex; + align-items: center; + justify-content: center; +`; + +export const ResetButton = styled.div` + color: #56c2d9; + font-size: 20px; + font-weight: 700; + cursor: pointer; + display: flex; + align-items: center; +`; \ No newline at end of file diff --git a/src/components/FilterSelect/index.tsx b/src/components/FilterSelect/index.tsx index 23a75fe9..a83414c8 100755 --- a/src/components/FilterSelect/index.tsx +++ b/src/components/FilterSelect/index.tsx @@ -16,7 +16,7 @@ const ButtonShell = styled(Button)` font-size: 18px; cursor: pointer; color: ${({ isactive }) => (isactive ? '#4A4A4A' : '#9b9b9b')}; - text-transform: capitalize; + text-transform: ${({ iscapital }) => (iscapital ? 'capitalize' : 'initial')};; } `; @@ -107,7 +107,7 @@ interface Props { value: string; items: Array; placeholder?: string; - onChange: (value: string) => void; + onChange: (item: object) => void; } type States = { @@ -132,17 +132,9 @@ class FilterSelect extends React.Component { } } - componentDidUpdate(prevProps) { - const { onChange } = this.props; - if (prevProps.placeholder === 'Select Operator' && prevProps.value === '') { - const equalsOperator = Object.values(prevProps.items)[0]; - onChange(equalsOperator['name']); - } - } - handleChange = item => { const { onChange } = this.props; - onChange(item.name); + onChange(item); this.setState({ anchorEl: null }); }; @@ -181,6 +173,7 @@ class FilterSelect extends React.Component { aria-haspopup="true" isactive={value} onClick={this.handleClick} + iscapital={placeholder !== 'Select Operator'? 1 : 0} > {menuTitle} diff --git a/src/components/FilterTool/index.tsx b/src/components/FilterTool/index.tsx deleted file mode 100755 index 9e826ee6..00000000 --- a/src/components/FilterTool/index.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import * as React from 'react'; -import styled from 'styled-components'; -import TezosIcon from 'components/TezosIcon'; - -const Container = styled.div` - position: relative; - width: 107px; - height: 52px; - border: 1px solid #56c2d9; - border-radius: 5px; - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - color: #56c2d9; - cursor: pointer; -`; - -const FilterIconWrapper = styled(TezosIcon)` - display: inline-block; - transform: rotate(90deg); - margin-right: 11px; -`; - -const FilterMark = styled.div` - position: absolute; - width: 24px; - height: 24px; - background: #56c2d9; - box-shadow: 0 0 4px 0 rgba(0, 0, 0, 1); - border-radius: 12px; - color: #ffffff; - font-size: 13px; - letter-spacing: 0.2px; - font-weight: 500; - display: flex; - align-items: center; - justify-content: center; - right: -9px; - top: -9px; -`; - -interface Props { - value: number; - onCollapse: () => void; -} - -const FilterTool: React.StatelessComponent = props => { - const { value, onCollapse } = props; - return ( - - - Filter - {value > 0 && {value}} - - ); -}; - -FilterTool.defaultProps = { - value: 0, -}; - -export default FilterTool; diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index af6c4b0f..6a699e69 100755 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -10,7 +10,7 @@ import ArrowDropDown from '@material-ui/icons/KeyboardArrowDown'; import InputBase from '@material-ui/core/InputBase'; import IconButton from '@material-ui/core/IconButton'; import SearchIcon from '@material-ui/icons/Search'; -import TezosIcon from '../TezosIcon'; +import ArronaxIcon from '../ArronaxIcon'; import getConfigs from '../../utils/getconfig'; const configs = getConfigs(); @@ -163,7 +163,7 @@ const Header: React.StatelessComponent = props => { ARRONAX - + = props => { ))} - - - - - - - ); }; diff --git a/src/components/SettingsPanel/index.tsx b/src/components/SettingsPanel/index.tsx index 4e11132b..19e815aa 100755 --- a/src/components/SettingsPanel/index.tsx +++ b/src/components/SettingsPanel/index.tsx @@ -2,70 +2,16 @@ import * as React from 'react'; import styled from 'styled-components'; import Collapse from '@material-ui/core/Collapse'; import CloseIcon from '@material-ui/icons/CloseOutlined'; -import ColumnsDisplay from '../ColumnsDisplay'; +import SwipeableViews from 'react-swipeable-views'; import FilterPanel from '../FilterPanel'; -import RefreshIcon from '@material-ui/icons/Refresh'; +import ColumnsPanel from '../ColumnsPanel'; +import { ToolType } from '../../types'; const Container = styled.div` position: relative; - padding: 50px 77px 50px 50px; - background: #ecedef; -`; - -const QueryContainer = styled.div` - display: flex; -`; - -const ButtonsContainer = styled.div` - display: flex; - width: 100%; - align-items: center; - justify-content: flex-end; -`; - -const RunButton = styled.div` - cursor: pointer; - margin-left: 40px; - color: white; - background: #56c2d9; - border-radius: 9px 9px 9px 9px; - font-size: 18px; - height: 47px; - width: 125px; - display: flex; - align-items: center; - justify-content: center; -`; - -const ResetButton = styled.div` - color: #56c2d9; - font-size: 18px; - font-weight: bold; - cursor: pointer; - display: flex; - align-items: center; -`; - -const FilterTxt = styled.div` - color: #4a4a4a; - font-size: 20px; - margin-bottom: 14px; -`; - -const DisplayTxt = styled(FilterTxt)` - margin-top: 20px; -`; - -const DisplayContainer = styled.div` - align-items: center; - padding-left: 24px; - padding-right: 24px; - height: 93px; - background: white; - border: 1px solid #ededed; - border-radius: 3px; - display: flex; - flex-grow: row; + padding: 40px 77px 12px 50px; + background: rgb(236, 237, 239); + box-shadow: inset 0px 1px 3px 0px rgba(0, 0, 0, 0.5); `; const CloseIconContainer = styled.div` @@ -83,73 +29,45 @@ const CloseIconWrapper = styled(CloseIcon)` `; interface Props { - selectedColumns: any; - isCollapse: boolean; - filterInputState: object; - selectedEntity: string; - attributes: object[]; - selectedValues: object[]; - setColumns: (columns: object[]) => void; - submitValues: () => void; - setFilterInputState: ( - value: string, - filterName: string, - filterOperator: string - ) => void; + isCollapsed: boolean; + selectedTool: string; + onSubmit: () => void; onClose: () => void; - resetValues: () => void; } -const SettingsPanel: React.StatelessComponent = props => { - const { - isCollapse, - onClose, - selectedColumns, - resetValues, - submitValues, - filterInputState, - setFilterInputState, - selectedEntity, - attributes, - setColumns, - selectedValues, - } = props; - return ( - - - - - - Filter - - Display - - - - - - - - {' '}Reset - - Run - - - - - ); +class SettingsPanel extends React.Component { + swipeableActions = null; + componentDidMount() { + this.swipeableActions.updateHeight(); + } + render() { + const { + isCollapsed, + selectedTool, + onClose, + onSubmit + } = this.props; + const activeIndex = selectedTool === ToolType.FILTER ? 0 : 1; + return ( + + + + + + { + this.swipeableActions = actions; + }} + animateHeight + > + + + + + + ); + } }; export default SettingsPanel; diff --git a/src/components/Toolbar/index.tsx b/src/components/Toolbar/index.tsx new file mode 100755 index 00000000..36b9add2 --- /dev/null +++ b/src/components/Toolbar/index.tsx @@ -0,0 +1,137 @@ +import * as React from 'react'; +import styled from 'styled-components'; +import ArronaxIcon from '../ArronaxIcon'; +import { ToolType } from '../../types'; + +const Container = styled.div` + position: relative; + width: 100%; + height: 77px; + padding: 25px 30px 0 30px; +`; + +const ToolItem = styled.div` + height: 52px; + border: 1px solid rgb(220, 220, 220); + display: flex; + align-items: center; + font-size: 18px; + font-weight: 500; + color: rgb(74, 74, 74); + cursor: pointer; + position: absolute; + top: 25px; + z-index: 1; + &:hover { + border-color: rgb(180, 231, 242); + color: rgb(86, 194, 217); + z-index: 4; + span { + color: rgb(86, 194, 217); + } + } + &:after { + content: ''; + width: 100%; + height: 6px; + background: transparent; + position: absolute; + bottom: 0; + left: 0; + } +`; + +const FilterTool = styled(ToolItem)` + width: 126px; + border-radius: 5px 0px 0px 5px; + padding-left: 13px; + left: 30px; + color: ${({ isactive }) => (isactive ? 'rgb(86, 194, 217)' : 'rgb(74, 74, 74)')}; + span { + color: ${({ isactive }) => (isactive ? 'rgb(86, 194, 217)' : 'rgb(74, 74, 74)')}; + } + &:after { + background: ${({ isactive }) => (isactive ? 'rgb(166, 223, 226)' : 'transparent')}; + } +`; + +const ColumnsTool = styled(ToolItem)` + width: 153px; + left: 155px; + padding-left: 12px; + color: ${({ isactive }) => (isactive ? 'rgb(86, 194, 217)' : 'rgb(74, 74, 74)')}; + span { + color: ${({ isactive }) => (isactive ? 'rgb(86, 194, 217)' : 'rgb(74, 74, 74)')}; + } + &:after { + background: ${({ isactive }) => (isactive ? 'rgb(166, 223, 226)' : 'transparent')}; + } +`; + +const ExportTool = styled(ToolItem)` + width: 149px; + border-radius: 0px 5px 5px 0px; + left: 307px; + padding-left: 18px; + &:after { + background: ${({ isactive }) => (isactive ? 'rgb(166, 223, 226)' : 'transparent')}; + } +`; + +const FilterIcon = styled(ArronaxIcon)` + display: inline-block; + margin-right: 11px; +`; + +const ExportIcon = styled(ArronaxIcon)` + display: inline-block; + margin-right: 6px; +`; + +const ColumnIcon = styled(ArronaxIcon)` + display: inline-block; + margin-right: 8px; +`; + + +interface Props { + isCollapsed: boolean; + selectedTool: string; + filterCount: number; + columnsCount: number; + onChangeTool: (tool: string) => void; + onExportCsv: () => void; +} + +const Toolbar: React.StatelessComponent = props => { + const { isCollapsed, selectedTool, filterCount, columnsCount, onChangeTool, onExportCsv } = props; + return ( + + onChangeTool(ToolType.FILTER)} + > + + Filter ({filterCount}) + + onChangeTool(ToolType.COLUMN)} + > + Columns ({columnsCount}) + + + + Export CSV + + + ); +}; + +Toolbar.defaultProps = { + filterCount: 0, + columnsCount: 0, + isCollapsed: false +}; + +export default Toolbar; diff --git a/src/components/ValueInput/index.tsx b/src/components/ValueInput/index.tsx index 506aaa78..307b40a0 100644 --- a/src/components/ValueInput/index.tsx +++ b/src/components/ValueInput/index.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import styled from 'styled-components'; import TextField from '@material-ui/core/TextField'; +import { ConseilOperator } from 'conseiljs'; const Container = styled.div``; @@ -32,63 +33,32 @@ const TextInput = styled(TextField)` line-height: 17px; width: 150px; `; - -interface Filter { - name: string; - operator: string; -} - interface Props { - filter: Filter; - inputProps?: object; + operator: string; InputProps?: object; - value: string; - filterInputState: object; - selectedEntity: string; - onInputChange: (value: string) => void; - onBetweenInputChange: (value: string) => void; + values: Array; + onChange: (value: string, index: number) => void; } -class ValueInput extends React.Component { - handleInputChange = value => { - const { onInputChange } = this.props; - onInputChange(value); - }; - - handleBetweenChange = value => { - const { onBetweenInputChange } = this.props; - onBetweenInputChange(value); - }; - - render() { +const ValueInput: React.StatelessComponent = props => { const { InputProps, - inputProps, - filter, - filterInputState, - selectedEntity, - } = this.props; + operator, + values, + onChange + } = props; let input; - // Find state value that matches this filter - const findStateValue = filterInputState[selectedEntity].find( - value => Object.keys(value).toString() === filter.name - ); - const currentStateValue = findStateValue - ? Object.values(findStateValue).toString() - : ''; // Render specific input type based on operators - if (filter.operator === 'BETWEEN' || filter.operator === 'IN') { - const splitValues = currentStateValue.split('-'); + if (operator === ConseilOperator.BETWEEN || operator === ConseilOperator.IN) { input = ( this.handleInputChange(event.target.value)} + placeholder='Insert Value' + onChange={event => onChange(event.target.value, 0)} />
@@ -96,36 +66,30 @@ class ValueInput extends React.Component {
this.handleBetweenChange(event.target.value)} + placeholder='Insert Value' + onChange={event => onChange(event.target.value, 1)} />
); - } else if ( - filter.operator === 'ISNULL' || - filter.operator === 'ISNOTNULL' - ) { + } else if (operator === ConseilOperator.ISNULL || operator === 'isnotnull') { input = null; } else { input = ( this.handleInputChange(event.target.value)} + placeholder='Insert Value' + onChange={event => onChange(event.target.value, 0)} /> ); } return {input}; - } } export default ValueInput; diff --git a/src/components/ValueSelect/index.tsx b/src/components/ValueSelect/index.tsx index 0f8e4046..e6779603 100644 --- a/src/components/ValueSelect/index.tsx +++ b/src/components/ValueSelect/index.tsx @@ -4,14 +4,10 @@ import Button from '@material-ui/core/Button'; import Menu from '@material-ui/core/Menu'; import MenuItem from '@material-ui/core/MenuItem'; import KeyboardArrowDown from '@material-ui/icons/KeyboardArrowDown'; +import { convertValue } from '../../utils/general'; const Container = styled.div``; -const HR = styled.div` - width: 1px; - background-color: #ecedef; -`; - const ButtonShell = styled(Button)` &&& { height: 52px; @@ -75,9 +71,8 @@ const MainMenuItem = styled(MenuItem)` `; interface Props { - filter: any; - selectedValues: any; - availableValues: Array; + selectedValue: string; + values: Array; placeholder?: string; onChange: (value: object) => void; } @@ -87,14 +82,17 @@ type States = { }; class ValueSelect extends React.Component { + static defaultProps = { + values: [], + selectedValue: '' + }; state = { anchorEl: null, }; handleChange = value => { - const { onChange, filter } = this.props; - const newValue = { [filter.toString()]: value }; - onChange(newValue); + const { onChange } = this.props; + onChange(value); this.setState({ anchorEl: null }); }; @@ -108,42 +106,15 @@ class ValueSelect extends React.Component { render() { const { anchorEl } = this.state; - const { availableValues, selectedValues, placeholder, filter } = this.props; - let newValue = []; - - selectedValues.forEach(val => { - if (val[filter.toString()] !== undefined) { - newValue.push(val[filter.toString()]); - } - }); - let valuesAvailable = []; - availableValues.forEach(item => { - if (Object.keys(item) == filter) { - if (item[filter.toString()] !== null) { - const items = item[filter.toString()].replace(/(^|_)./g, s => - s - .split('_') - .map(s => s.charAt(0).toUpperCase() + s.substring(1)) - .join(' ') - ); - valuesAvailable.push(items); - } else if (item.toString() === null) { - valuesAvailable.push('Null'); - } - } - }); - const selectedItem: any = valuesAvailable.find( - (item: any) => item == newValue[0] - ); - const menuTitle = - selectedValues && selectedItem !== undefined ? selectedItem : placeholder; + const { values, selectedValue, placeholder } = this.props; + const menuTitle = selectedValue ? selectedValue : placeholder; return ( {menuTitle} @@ -164,13 +135,13 @@ class ValueSelect extends React.Component { > {placeholder} - {valuesAvailable.map((value: any, index) => ( + {values.map((value, index) => ( this.handleChange(value)} key={index} - selected={value === newValue[0]} + selected={value === selectedValue} > - {value} + {convertValue(value)} ))} diff --git a/src/containers/App/index.tsx b/src/containers/App/index.tsx index 03b771c7..79e75285 100644 --- a/src/containers/App/index.tsx +++ b/src/containers/App/index.tsx @@ -5,35 +5,34 @@ import Tabs from '@material-ui/core/Tabs'; import Tab from '@material-ui/core/Tab'; import CircularProgress from '@material-ui/core/CircularProgress'; import { - getAttributes, getLoading, getNetwork, getEntity, getItems, - getColumns, getIsFullLoaded, - getSelectedValues, - getSelectedFilters, getFilterCount, + getColumns } from '../../reducers/app/selectors'; import { changeNetwork, initLoad, submitQuery, + exportCsvData } from '../../reducers/app/thunks'; import { - setSelectedValuesAction, - setColumnsAction, setTabAction, - removeValueAction, removeAllFiltersAction, } from '../../reducers/app/actions'; import Header from 'components/Header'; -import FilterTool from 'components/FilterTool'; import SettingsPanel from 'components/SettingsPanel'; import Footer from 'components/Footer'; +import Toolbar from 'components/Toolbar'; import CustomTable from '../CustomTable'; +import { ToolType } from '../../types'; + +import * as octopusSrc from 'assets/sadOctopus.svg'; + const Container = styled.div` padding: 50px 0; min-height: calc(100vh - 405px); @@ -45,7 +44,7 @@ const MainContainer = styled.div` `; const LoadingContainer = styled.div` - position: absolute; + position: fixed; display: flex; align-items: center; justify-content: center; @@ -53,14 +52,8 @@ const LoadingContainer = styled.div` top: 0; left: 0; width: 100%; - height: 100%; -`; - -const FilterHeader = styled.div` - display: flex; - align-items: center; - opacity: ${({ isDark }) => (isDark ? 0.74 : 1)}; - padding: 25px 30px 0 30px; + height: 100vh; + z-index: 100; `; const TabsWrapper = styled(Tabs)` @@ -76,7 +69,6 @@ const TabsWrapper = styled(Tabs)` const TabContainer = styled.div` padding: 0px 30px; - position: relative; width: 100%; `; @@ -96,6 +88,66 @@ const FilterExTxt = styled.span` margin-left: 21px; `; +const NoResultContainer = styled.div` + width: 100%; + padding-top: 67px; + display: flex; + justify-content: center; +`; + +const OctopusImg = styled.img` + height: 183px; + width: 169px; +`; + +const NoResultContent = styled.div` + margin-left: 38px; + padding-top: 16px; +`; + +const NoResultTxt = styled.div` + color: rgb(42, 57, 115); + font-size: 28px; + font-weight: 500; + line-height: 30px; +`; + +const TryTxt = styled.div` + color: rgb(155, 155, 155); + font-size: 18px; + font-weight: 500; + line-height: 21px; + margin-top: 8px; +`; + +const ButtonContainer = styled.div` + display: flex; + margin-top: 24px; +`; + +const CustomButton = styled.div` + cursor: pointer; + border-radius: 9px; + height: 42px; + width: 158px; + font-size: 16px; + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; +`; + +const ClearButton = styled(CustomButton)` + border: 2px solid rgb(0, 196, 220); + color: rgb(0, 196, 220); +`; + +const TryButton = styled(CustomButton)` + color: white; + background: rgb(86, 194, 217); + margin-left: 22px; +`; + const tabsArray = [ { value: 'blocks', @@ -114,38 +166,30 @@ const tabsArray = [ export interface Props { isLoading: boolean; network: string; - selectedValues: object[]; selectedEntity: string; items: object[]; - attributes: object[]; - selectedColumns: any[]; isFullLoaded: boolean; - selectedFilters: object[]; filterCount: number; - setColumns: (entity: string, columns: object[]) => void; - removeValue: (value: object) => void; + selectedColumns: any[]; removeAllFilters: (entity: string) => void; changeNetwork(network: string): void; changeTab: (type: string) => void; initLoad: () => void; - fetchItems: (type: string) => void; - setSelectedValues: (type: object[]) => void; submitQuery: () => void; + exportCsvData: ()=> void } export interface States { - isFilterCollapse: boolean; - filterInputState: any; - selectedDisplayColumns: object[]; + isSettingCollapsed: boolean; + selectedTool: string } class Arronax extends React.Component { constructor(props: Props) { super(props); this.state = { - isFilterCollapse: false, - filterInputState: { blocks: [], operations: [], accounts: [] }, - selectedDisplayColumns: [], + isSettingCollapsed: false, + selectedTool: ToolType.FILTER }; } @@ -154,32 +198,6 @@ class Arronax extends React.Component { initLoad(); } - componentDidUpdate(prevProps: Props) { - const { filterInputState } = this.state; - const { selectedColumns, selectedEntity, selectedFilters } = this.props; - const currentFilters = selectedFilters.map(filter => - Object.values(filter)[0].toString() - ); - // Remove any value from state that doesn't match Redux's selected filters state - filterInputState[selectedEntity].forEach(filter => { - const stateFilter = Object.keys(filter).toString(); - if (!currentFilters.includes(stateFilter)) { - const index = filterInputState[selectedEntity].indexOf(stateFilter); - filterInputState[selectedEntity].splice(index, 1); - this.setState({ filterInputState: filterInputState }); - } - }); - if ( - prevProps.selectedColumns[selectedEntity] !== - selectedColumns[selectedEntity] || - selectedEntity !== prevProps.selectedEntity - ) { - this.setState({ - selectedDisplayColumns: [...selectedColumns[selectedEntity]], - }); - } - } - onChangeNetwork = event => { const { changeNetwork } = this.props; changeNetwork(event.target.value); @@ -191,146 +209,55 @@ class Arronax extends React.Component { await changeTab(value); }; - onFilterCollapse = () => { - const { isFilterCollapse } = this.state; - this.setState({ isFilterCollapse: !isFilterCollapse }); + onChangeTool = async (tool: string) => { + const { isSettingCollapsed, selectedTool } = this.state; + if (isSettingCollapsed && selectedTool !== tool) { + this.setState({ selectedTool: tool }); + } else if (!isSettingCollapsed && selectedTool !== tool) { + this.setState({ isSettingCollapsed: !isSettingCollapsed, selectedTool: tool }); + } else { + this.setState({ isSettingCollapsed: !isSettingCollapsed }); + } + } + + onSettingCollapse = () => { + const { isSettingCollapsed } = this.state; + this.setState({ isSettingCollapsed: !isSettingCollapsed }); }; onCloseFilter = () => { - this.setState({ isFilterCollapse: false }); + this.setState({ isSettingCollapsed: false }); }; - resetValues = () => { + onResetFilters = () => { const { - selectedValues, - removeValue, removeAllFilters, - selectedEntity, - selectedFilters, + selectedEntity } = this.props; - const { filterInputState } = this.state; - filterInputState[selectedEntity] = []; - this.setState({ filterInputState: filterInputState }); removeAllFilters(selectedEntity); - // Remove selected values for this particular entity - selectedValues.forEach(value => { - selectedFilters.forEach(filter => { - const currentValue = Object.keys(value).toString(); - const currentFilter = Object.values(filter)[0].toString(); - if (currentValue === currentFilter) { - removeValue(value); - } - }); - }); }; - submitValues = async () => { + onSubmit = async () => { + const { submitQuery } = this.props; + this.onCloseFilter(); + await submitQuery(); + }; + + onClearFilter = async () => { const { - setSelectedValues, - submitQuery, + removeAllFilters, selectedEntity, - setColumns, + submitQuery } = this.props; - const { filterInputState, selectedDisplayColumns } = this.state; - // Set columns in Redux state - await setColumns(selectedEntity, selectedDisplayColumns); - // Loop through each value in state and set the value in Redux's state - await filterInputState[selectedEntity].forEach(val => { - setSelectedValues(val); - }); - // Submit the query to ConseilJS + await removeAllFilters(selectedEntity); await submitQuery(); - }; + } - setFilterInputState = (val, filterName, filterOperator) => { - const { filterInputState } = this.state; - const { selectedEntity } = this.props; - const filterState = [...filterInputState[selectedEntity]]; - let filterCheck = []; - filterInputState[selectedEntity].forEach(filter => { - filterCheck.push(Object.keys(filter).toString()); - }); - // Remove the value from state by sending in a NULL value - if (val === null) { - const itemToRemove = filterState.find( - val => Object.keys(val).toString() === filterName - ); - const index = filterState.indexOf(itemToRemove); - filterState.splice(index, 1); - filterInputState[selectedEntity] = filterState; - this.setState({ filterInputState: filterInputState }); - } else if ( - filterCheck.includes(filterName) && - filterOperator !== 'BETWEEN' - ) { - const index = filterCheck.indexOf(filterName); - filterState.splice(index, 1); - const newState = [...filterState, { [filterName]: val }]; - filterInputState[selectedEntity] = newState; - this.setState({ filterInputState: filterInputState }); - } else if ( - filterCheck.includes(filterName) && - filterOperator === 'BETWEEN' - ) { - const currentValueObject = filterState.find( - val => Object.keys(val).toString() === filterName - ); - const currentValue = Object.values(currentValueObject).toString(); - if (!currentValue.includes('-')) { - if (val.includes('-')) { - const index = filterCheck.indexOf(filterName); - filterState.splice(index, 1); - const newState = [ - ...filterState, - { [filterName]: `${currentValue}${val}` }, - ]; - filterInputState[selectedEntity] = newState; - this.setState({ filterInputState: filterInputState }); - } else if (!val.includes('-')) { - const index = filterCheck.indexOf(filterName); - filterState.splice(index, 1); - const newState = [...filterState, { [filterName]: val }]; - filterInputState[selectedEntity] = newState; - this.setState({ filterInputState: filterInputState }); - } - } else if (currentValue.includes('-')) { - if (val.includes('-')) { - const value = Object.values(currentValue); - const dashIndex = value.indexOf('-'); - const firstHalf = value.slice(0, dashIndex).join(''); - const secondHalf = val; - const finalValue = firstHalf + secondHalf; - const index = filterCheck.indexOf(filterName); - filterState.splice(index, 1); - const newState = [...filterState, { [filterName]: finalValue }]; - filterInputState[selectedEntity] = newState; - this.setState({ filterInputState: filterInputState }); - } else if (!val.includes('-')) { - const value = Object.values(currentValue); - const dashIndex = value.indexOf('-'); - const secondHalf = value.slice(dashIndex).join(''); - const firstHalf = val; - const finalValue = firstHalf + secondHalf; - const index = filterCheck.indexOf(filterName); - filterState.splice(index, 1); - const newState = [...filterState, { [filterName]: finalValue }]; - filterInputState[selectedEntity] = newState; - this.setState({ filterInputState: filterInputState }); - } - } - } else { - const newValues = [ - ...filterInputState[selectedEntity], - { [filterName]: val }, - ]; - filterInputState[selectedEntity] = newValues; - this.setState({ filterInputState: filterInputState }); - } - }; + onExportCsv = async () => { + const { exportCsvData } = this.props; + exportCsvData(); + } - setSelectedColumns = (columns: object[]) => { - this.setState({ selectedDisplayColumns: columns }); - }; render() { const { @@ -338,13 +265,11 @@ class Arronax extends React.Component { network, selectedEntity, items, - selectedColumns, isFullLoaded, - attributes, filterCount, - selectedValues, + selectedColumns } = this.props; - const { isFilterCollapse, filterInputState } = this.state; + const { isSettingCollapsed, selectedTool } = this.state; const isRealLoading = isLoading || (!isFullLoaded && items.length === 0); return ( @@ -366,35 +291,35 @@ class Arronax extends React.Component { /> ))} + - - - - e.g. What blocks were baked by Foundation Baker 1 in the past 24 - hours? - - - + {items.length > 0 && } + {items.length === 0 && ( + + + + Sorry, your filters returned no results. + Try a different filter combination. + + Clear Filters + Try Again + + + + )}