diff --git a/package-lock.json b/package-lock.json index 87fc998..f6ef3ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1129,6 +1129,12 @@ "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", @@ -1243,6 +1249,12 @@ "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", "dev": true }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, "ansi-align": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", @@ -1383,6 +1395,22 @@ "default-require-extensions": "^1.0.0" } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1585,6 +1613,12 @@ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true + }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", @@ -3159,6 +3193,15 @@ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, "bluebird": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", @@ -4388,6 +4431,12 @@ "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", "dev": true }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -5254,6 +5303,15 @@ "pify": "^2.0.0", "pinkie-promise": "^2.0.0" } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -5263,6 +5321,12 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -5978,6 +6042,17 @@ "object-assign": "^4.0.1", "object-hash": "^1.1.4", "rimraf": "^2.6.1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "eslint-module-utils": { @@ -6774,6 +6849,17 @@ "flatted": "^2.0.0", "rimraf": "2.6.3", "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flatted": { @@ -7492,6 +7578,29 @@ } } }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -7504,6 +7613,53 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, "generic-names": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-1.0.3.tgz", @@ -7628,6 +7784,15 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -7756,6 +7921,17 @@ "slash": "^3.0.0" } }, + "globule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz", + "integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -7936,6 +8112,12 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -8414,6 +8596,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true + }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -8994,6 +9182,15 @@ "requires": { "ms": "^2.1.1" } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -10718,6 +10915,12 @@ } } }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -10750,8 +10953,7 @@ "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true + "dev": true }, "nanomatch": { "version": "1.2.13", @@ -10837,6 +11039,52 @@ "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", "dev": true }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "dev": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -10921,6 +11169,92 @@ "semver": "^6.3.0" } }, + "node-sass": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", + "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", + "dev": true, + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -10977,6 +11311,18 @@ "path-key": "^3.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, "nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", @@ -11270,6 +11616,16 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "p-finally": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", @@ -14160,6 +14516,12 @@ "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", "dev": true }, + "react-moment": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/react-moment/-/react-moment-0.9.7.tgz", + "integrity": "sha512-ifzUrUGF6KRsUN2pRG5k56kO0mJBr8kRkWb0wNvtFIsBIxOuPxhUpL1YlXwpbQCbHq23hUu6A0VEk64HsFxk9g==", + "dev": true + }, "react-scripts": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.5.tgz", @@ -14564,6 +14926,17 @@ "graceful-fs": "^4.1.2", "rimraf": "~2.6.2", "write": "^0.2.1" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "fs-extra": { @@ -15702,9 +16075,9 @@ } }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", "dev": true, "requires": { "glob": "^7.1.3" @@ -15958,6 +16331,18 @@ } } }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" + } + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -16018,6 +16403,27 @@ } } }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -16704,6 +17110,15 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "dev": true }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", @@ -17025,6 +17440,17 @@ "integrity": "sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==", "dev": true }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "dev": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -17409,6 +17835,15 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "dev": true, + "requires": { + "glob": "^7.1.2" + } + }, "tslib": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", @@ -18299,6 +18734,17 @@ "p-map": "^1.1.1", "pify": "^3.0.0", "rimraf": "^2.2.8" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "find-up": { @@ -18490,6 +18936,17 @@ "klaw": "^1.0.0", "path-is-absolute": "^1.0.0", "rimraf": "^2.2.8" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "jsonfile": { @@ -18591,6 +19048,48 @@ "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", diff --git a/package.json b/package.json index e12e6a7..5bbc5af 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,10 @@ "npm": ">=5" }, "scripts": { + "clean": "rimraf dist/", "test": "cross-env CI=1 react-scripts test --env=jsdom", "test:watch": "react-scripts test --env=jsdom", - "build": "rollup -c", + "build": "npm run clean && rollup -c", "start": "rollup -c -w", "prepare": "npm run build", "predeploy": "cd example && npm install && npm run build", @@ -27,12 +28,11 @@ "peerDependencies": { "prop-types": "^15.5.4", "react": "^15.0.0 || ^16.0.0", - "react-dom": "^15.0.0 || ^16.0.0" + "react-dom": "^15.0.0 || ^16.0.0", + "nr1": "" }, "devDependencies": { "@newrelic/eslint-plugin-newrelic": "^0.3.0", - "eslint": "^6.6.0", - "prettier": "^1.19.1", "@semantic-release/changelog": "^3.0.5", "@semantic-release/git": "^7.0.18", "@svgr/rollup": "^2.4.1", @@ -43,10 +43,16 @@ "babel-preset-react": "^6.24.1", "babel-preset-stage-0": "^6.24.1", "cross-env": "^5.1.4", + "eslint": "^6.6.0", "gh-pages": "^1.2.0", + "node-sass": "^4.13.0", + "prettier": "^1.19.1", "react": "^16.4.1", "react-dom": "^16.4.1", "react-scripts": "^1.1.4", + "react-moment": "^0.9.7", + "moment": "^2.24.0", + "rimraf": "^3.0.0", "rollup": "^0.64.1", "rollup-plugin-babel": "^3.0.7", "rollup-plugin-commonjs": "^9.1.3", @@ -57,5 +63,6 @@ }, "files": [ "dist" - ] + ], + "dependencies": {} } diff --git a/rollup.config.js b/rollup.config.js index 63dcd7b..33971f8 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -8,7 +8,34 @@ import svgr from '@svgr/rollup'; import pkg from './package.json'; -export default { +const glob = require('glob'); + +/* + * Generate an instance for each "config" + */ +function getPlugins() { + return [ + external(), + postcss({ + extract: true, + modules: true, + use: ['sass'] + }), + url(), + svgr(), + babel({ + exclude: 'node_modules/**', + plugins: ['external-helpers'] + }), + resolve(), + commonjs() + ]; +} + +/* + * Base Config + */ +const baseConfig = { input: 'src/index.js', output: [ { @@ -22,18 +49,48 @@ export default { sourcemap: true } ], - plugins: [ - external(), - postcss({ - modules: true - }), - url(), - svgr(), - babel({ - exclude: 'node_modules/**', - plugins: ['external-helpers'] - }), - resolve(), - commonjs() - ] + plugins: getPlugins() }; + +const allConfigs = []; +allConfigs.push(baseConfig); + +/* + * Build a rollup config for every component + * + * https://github.com/egoist/rollup-plugin-postcss/issues/160 + * + * Generate a CSS output for each component so we can selectively pull in per-component styles + * + * The downside to this approach is the JS code is output twice. Once because we're exporting it + * for easy import, and once for the css file generation. + * + * rollup-plugin-postcss is only good at consolidating css output, and does not seem actively maintained + * We would need to fork it, and allow for per css input file output + */ + +const modularStyles = false; // Leaving here for future evaluation, but not currently in use + +if (modularStyles) { + const componentEntryPoints = glob.sync('./src/components/*/index.js'); + componentEntryPoints.forEach(entryPoint => { + const outputs = baseConfig.output; + const plugins = getPlugins(); + const outputPath = entryPoint + .replace('src/', 'dist/') + .replace('/index.js', ''); + + const config = { + ...baseConfig, + input: entryPoint, + output: outputs.map(outputDest => { + return { ...outputDest, file: outputPath }; + }), + plugins + }; + + allConfigs.push(config); + }); +} + +export default allConfigs; diff --git a/src/components/AccountDropdown/README.md b/src/components/AccountDropdown/README.md new file mode 100644 index 0000000..6df67d4 --- /dev/null +++ b/src/components/AccountDropdown/README.md @@ -0,0 +1,53 @@ +# AccountDropdown + +## Description + +Applications (Nerdpacks) developed in New Relic One are limited (for security purposes) to data in the account they are installed (subscribed) to and hierarchically to any child accounts. + +Often the goal is to limit the view by a given account to ensure accurate context. + +This component provides a common interface for choosing an account with a callback (`onSelect`) that allows for integration into the rest of your application. + +## Installation + +1. Install nr1-community + +```bash + npm i nr1-community +``` + +2. Install peer dependencies + +```bash + npm i moment react-moment +``` + +3. Import styles + +Add: + +```scss +@import '~nr1-community/dist/components/AccountDropdown.css'; +``` + +to your `styles.scss` + +## Usage + +```jsx +import { AccountDropdown } from 'nr1-community'; + +render () { + +} +``` + +## Props + +```jsx + onSelect: PropTypes.func, + urlState: PropTypes.object, + className: PropTypes.string, + style: PropTypes.object, + title: PropTypes.string +``` diff --git a/src/components/AccountDropdown/index.js b/src/components/AccountDropdown/index.js new file mode 100644 index 0000000..5f77409 --- /dev/null +++ b/src/components/AccountDropdown/index.js @@ -0,0 +1,176 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + navigation, + UserStorageQuery, + UserStorageMutation, + AccountsQuery, + Dropdown, + DropdownItem, + Spinner +} from 'nr1'; + +import styles from './styles.scss'; + +const collection = 'nr1-community:AccountDropdown'; +const documentId = 'default-account'; + +export class AccountDropdown extends React.Component { + static propTypes = { + onSelect: PropTypes.func, + urlState: PropTypes.object, + className: PropTypes.string, + style: PropTypes.object, + title: PropTypes.string + }; + + static defaultProps = { + title: 'Select account...' + }; + + constructor(props) { + super(props); + + this.state = { + accounts: null, + defaultAccount: undefined, + selected: null + }; + + this.select = this.select.bind(this); + } + + async componentDidMount() { + await Promise.all([this.loadAccounts(), this.loadDefaultAccount()]); + + this.setState(state => { + if (this.props.urlState && this.props.urlState.account) { + const account = this.state.accounts.find( + account => account.id === this.props.urlState.account + ); + if (account) { + return { + selectedFromUrlState: true, + selected: account + }; + } + } + + if (state.selected === null && state.defaultAccount && state.accounts) { + const account = this.state.accounts.find( + account => account.id === this.state.defaultAccount + ); + if (account) { + return { + selected: account + }; + } + } + + return null; + }); + } + + async componentDidUpdate(prevProps, prevState) { + const prevAccount = prevState.selected; + const account = this.state.selected; + + if (account && (!prevAccount || account.id !== prevAccount.id)) { + this.props.onSelect(account); + + if (!this.state.selectedFromUrlState) { + if (this.state.selected.id !== this.state.defaultAccount) { + this.updateDefaultAccount(this.state.selected); + } + + if ( + this.props.urlState && + this.state.selected.id !== this.props.urlState.account + ) { + navigation.setUrlState({ + account: this.state.selected.id + }); + } + } + } + } + + async loadDefaultAccount() { + const result = await UserStorageQuery.query({ collection, documentId }); + const id = + ((((result.data || {}).actor || {}).nerdStorage || {}).document || {}) + .id || null; + this.setState(() => ({ + defaultAccount: id + })); + } + + async loadAccounts() { + // eslint-disable-next-line no-unused-vars + const { loading, data, errors } = await AccountsQuery.query(); + + if (!data) { + // TO DO + } + + if (errors) { + // TO DO + } + + this.setState({ + accounts: data + }); + } + + async updateDefaultAccount(account) { + await UserStorageMutation.mutate({ + actionType: UserStorageMutation.ACTION_TYPE.WRITE_DOCUMENT, + collection, + documentId, + document: { id: account.id } + }); + + this.setState({ + defaultAccount: account.id + }); + } + + select(account) { + this.setState(state => { + if (!state.selected || state.selected.id !== account.id) { + return { + selectedFromUrlState: false, + selected: account + }; + } + + return {}; + }); + } + + render() { + // eslint-disable-next-line no-unused-vars + const { className, style, title } = this.props; + const { accounts, defaultAccount, selected } = this.state; + + if (!accounts || defaultAccount === undefined) { + return ; + } + + const items = accounts.map(account => ( + this.select(account)}> + {account.name} + + )); + + return ( + + {items} + + ); + } +} diff --git a/src/components/AccountDropdown/styles.scss b/src/components/AccountDropdown/styles.scss new file mode 100644 index 0000000..5d24a17 --- /dev/null +++ b/src/components/AccountDropdown/styles.scss @@ -0,0 +1,3 @@ +.big { + min-height: 150px; +} diff --git a/src/components/EventStream/categories.js b/src/components/EventStream/categories.js new file mode 100644 index 0000000..cca1b46 --- /dev/null +++ b/src/components/EventStream/categories.js @@ -0,0 +1,79 @@ +import { Icon } from 'nr1'; + +export default class EventCategories { + static CONTENT = { + class: 'timeline-item-type-content', + icon: Icon.TYPE.DOCUMENTS__DOCUMENTS__NOTES, + label: 'Content', + color: '#9C5400' + }; + + static HEARTBEAT = { + class: '', + icon: null, + label: 'Heartbeat', + color: '#222222' + }; + + static ADS = { + class: 'timeline-item-type-ad', + icon: Icon.TYPE.INTERFACE__OPERATIONS__SHOW, + label: 'Advertising', + color: '#007e8a' + }; + + static ERROR = { + class: 'timeline-item-type-error', + icon: Icon.TYPE.HARDWARE_AND_SOFTWARE__SOFTWARE__APPLICATION__S_ERROR, + label: 'Errors', + color: '#bf0015' + }; + + static BUFFER = { + class: '', + icon: null, + label: 'Buffer', + color: '#22222' + }; + + static GENERAL = { + class: 'timeline-item-type-general', + icon: null, + label: 'General', + color: '#22222' + }; + + static EXTERNAL = { + class: '', + icon: null, + label: 'External Calls', + color: '#22222' + }; + + static setCategory(eventType, event) { + if (eventType === 'PageAction') { + switch (event.actionName) { + case 'CONTENT_REQUEST': + case 'DOWNLOAD': + case 'CONTENT_START': + case 'CONTENT_PAUSE': + case 'CONTENT_END': + return EventCategories.CONTENT; + case 'CONTENT_HEARTBEAT': + return EventCategories.HEARTBEAT; + case 'AD_REQUEST': + case 'AD_START': + case 'AD_QUARTILE': + case 'AD_END': + return EventCategories.ADS; + case 'CONTENT_BUFFER_START': + case 'CONTENT_BUFFER_END': + return EventCategories.BUFFER; + case 'CONTENT_ERROR': + return EventCategories.ERROR; + default: + return EventCategories.GENERAL; + } + } + } +} diff --git a/src/components/EventStream/index.js b/src/components/EventStream/index.js new file mode 100644 index 0000000..18d7beb --- /dev/null +++ b/src/components/EventStream/index.js @@ -0,0 +1,160 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { NrqlQuery, Spinner, Button, Icon, Stack, StackItem } from 'nr1'; +import Moment from 'react-moment'; +import EventCategories from './categories'; + +import styles from './styles.scss'; + +export class EventStream extends React.Component { + static propTypes = { + accountId: PropTypes.number, + session: PropTypes.object, + eventType: PropTypes.string, + durationInMinutes: PropTypes.number + }; + + constructor(props) { + super(props); + this.state = { + expandedTimelineItem: null + }; + this.handleTimelineItemClick = this.handleTimelineItemClick.bind(this); + } + + handleTimelineItemClick(e) { + e.preventDefault(); + const timelineItemId = e.currentTarget.getAttribute( + 'data-timeline-item-id' + ); + if (timelineItemId === this.state.expandedTimelineItem) { + this.setState(() => ({ + expandedTimelineItem: null + })); + } else { + this.setState(() => ({ + expandedTimelineItem: timelineItemId + })); + } + } + + _buildStreamTimeline(event) { + let timeline = Object.keys(event); + timeline = timeline.sort(); + const data = []; + // console.log(timeline) + timeline.forEach((attr, i) => { + if (event[attr]) { + data.push( +
  • + {attr} + {event[attr]} +
  • + ); + } + }); + return data; + } + + _buildStream(pageAction, data) { + const sessionEvents = []; + data[0].data.forEach((event, i) => { + const sessionCategory = EventCategories.setCategory(pageAction, event); + const date = new Date(event.timestamp); + const open = + this.state.expandedTimelineItem === i ? 'timeline-item-expanded' : ''; + const streamTimeline = this._buildStreamTimeline(event); + + sessionEvents.push( +
    +
    + + + + + + +
    +
    +
    +
    +
    + +
    +
    + {sessionCategory.label} +
    +
    +
    +
      + {streamTimeline} +
    +
    +
    +
    + ); + }); + return sessionEvents; + } + + render() { + const { accountId, session, eventType, durationInMinutes } = this.props; + const query = `SELECT * from ${eventType} WHERE session = '${session}' ORDER BY timestamp ASC LIMIT 1000 since ${durationInMinutes} minutes ago`; + + return ( +
    + {session ? ( + + {({ data, error, loading }) => { + if (loading) return ; + if (error) return 'ERROR'; + + const stream = this._buildStream(eventType, data); + return ( +
    {stream}
    + ); + }} +
    + ) : ( + + +

    + Select a session to review a timeline +

    +
    + +

    + When you select a session (in the column on the left) you will + be able to review a visual timeline for it here. +

    +
    +
    + )} +
    + ); + } +} diff --git a/src/components/EventStream/styles.scss b/src/components/EventStream/styles.scss new file mode 100644 index 0000000..43c66a3 --- /dev/null +++ b/src/components/EventStream/styles.scss @@ -0,0 +1,264 @@ +.timeline-container { + background-color: #fff; +} + +.timeline-item { + display: flex; + margin-bottom: 12px; + + &:hover .timeline-item-dot:after { + background-color: #464e4e; + } + + &:hover .timeline-timestamp-date { + color: #000d0d; + } + + &:hover .timeline-timestamp-time { + color: #464e4e; + } + + &:first-child .timeline-item-dot:before { + top: 0; + } + + &:last-child { + margin-bottom: 0; + + .timeline-item-dot:before { + bottom: 0; + } + } +} + +.timeline-item-expanded .timeline-item-contents-container { + display: block; + border-top: 1px solid #e3e4e4; +} + +.timeline-item-symbol:after { + background-color: #e4ffe3; +} + +.timeline-item-type-ad .timeline-item-symbol:after { + background-color: #edffff; +} + +.timeline-item-type-content .timeline-item-symbol:after { + background-color: #fff4d1; +} + +.timeline-item-type-error .timeline-item-symbol:after { + background-color: #fcf2f3; +} + +.timeline-item-type-buffer .timeline-item-symbol:after { + background-color: #fcf2f3; +} + +.timeline-item-type-general .timeline-item-symbol-icon { + display: none; +} + +.timeline-item-type-general .timeline-item-symbol:after { + background-color: #d0f0ff; +} + +.timeline-item-type-general .timeline-item-symbol:before { + content: ''; + display: block; + width: 10px; + height: 10px; + border: 1px solid #003555; + border-radius: 100%; + position: relative; + z-index: 10; +} + +.timeline-timestamp-date { + display: block; + font-size: 14px; + color: #464e4e; + margin-bottom: 1px; +} + +.timeline-item-timestamp { + text-align: right; + min-width: 75px; + color: #8e9494; + font-size: 12px; +} + +.timeline-item-dot { + padding: 0 25px 0 14px; + position: relative; + + &:after { + width: 7px; + height: 7px; + background-color: #b9bdbd; + border-radius: 100%; + box-shadow: 0 0 0 3px #fff; + position: absolute; + content: ''; + display: block; + top: 17px; + } + + &:before { + content: ''; + display: block; + width: 1px; + background-color: #d5d7d7; + position: absolute; + left: 17px; + top: -16px; + bottom: -16px; + } +} + +.timeline-item-contents { + height: 300px; + overflow: scroll; +} + +.timeline-item-contents-container { + display: none; + box-shadow: inset 0 10px 3px -5px rgba(0, 0, 0, 0.005), + inset 0 2px 0 rgba(0, 0, 0, 0.03); + background-color: #fafbfb; + border-radius: 0 0 3px 3px; +} + +.timeline-item-contents-item { + min-height: 30px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #edeeee; + padding: 0 8px; + + .key { + margin-right: 8px; + font-weight: 600; + color: #464e4e; + } + + .value { + text-align: right; + color: #464e4e; + overflow-wrap: break-word; + word-break: break-all; + max-width: 80%; + padding: 8px 0; + } + + &:last-child { + border-bottom: none; + } + + &:hover { + background-color: #f4f5f5; + cursor: default; + } +} + +.timeline-item-body { + width: 100%; + border: 1px solid #d5d7d7; + border-radius: 3px; + height: 38px; + position: relative; + background-color: #fff; + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02); + transition: 0.05s all ease-in-out; + + &:hover { + cursor: pointer; + transform: translateY(-1px); + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02), 0 4px 6px 0px rgba(0, 0, 0, 0.05); + border-color: #b9bdbd; + } + + &:hover:before { + border-right: 7px solid #b9bdbd; + } + + &:active { + cursor: pointer; + transform: translateY(1px); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.02); + } +} + +.timeline-item-body-header { + display: flex; + height: 38px; +} + +.timeline-item-title { + flex-grow: 1; + display: flex; + align-items: center; + padding-left: 10px; + font-size: 14px; + color: #464e4e; +} + +.timeline-item-symbol { + width: 36px; + display: flex; + justify-content: center; + align-items: center; + border-right: 1px dotted #b9bdbd; + + &:after { + content: ''; + display: block; + width: 23px; + height: 23px; + background-color: rgba(0, 0, 0, 0.1); + border-radius: 5px; + position: absolute; + z-index: 0; + } +} + +.timeline-item-symbol-icon { + position: relative; + z-index: 10; +} + +.timeline-item-body:after { + position: absolute; + content: ''; + display: block; + width: 0; + height: 0; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 7px solid #fff; + top: 13px; + left: -7px; +} + +.timeline-item-body::before { + position: absolute; + content: ''; + display: block; + width: 0; + height: 0; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 7px solid #c4c4c4; + top: 13px; + left: -8px; +} + +.timeline-item-expanded .timeline-item-body { + height: auto; +} + +.timeline-item-expanded .timeline-item-dropdown-arrow { + transform: rotate(180deg); +} \ No newline at end of file diff --git a/src/components/Example/Example.js b/src/components/Example/Example.js deleted file mode 100644 index 883f579..0000000 --- a/src/components/Example/Example.js +++ /dev/null @@ -1,16 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; - -import styles from './styles.css'; - -export default class Example extends Component { - static propTypes = { - text: PropTypes.string - }; - - render() { - const { text } = this.props; - - return
    Example Component: {text}
    ; - } -} diff --git a/src/components/Example/index.js b/src/components/Example/index.js deleted file mode 100644 index 80c34b2..0000000 --- a/src/components/Example/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Example'; diff --git a/src/components/Example/styles.css b/src/components/Example/styles.css deleted file mode 100644 index 44c1f06..0000000 --- a/src/components/Example/styles.css +++ /dev/null @@ -1,8 +0,0 @@ -/* add css styles here (optional) */ - -.test { - display: inline-block; - margin: 2em auto; - border: 2px solid #000; - font-size: 2em; -} diff --git a/src/components/index.js b/src/components/index.js index 5415efe..ac6ede8 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1 +1,2 @@ -export { default as Example } from './Example'; +export { EventStream } from './EventStream'; +export { AccountDropdown } from './AccountDropdown'; diff --git a/src/index.js b/src/index.js index 07635cb..590a7f4 100644 --- a/src/index.js +++ b/src/index.js @@ -1 +1,2 @@ export * from './components'; +export * from './utils'; diff --git a/src/utils/bytes-to-size.js b/src/utils/bytes-to-size.js new file mode 100644 index 0000000..eac4d9c --- /dev/null +++ b/src/utils/bytes-to-size.js @@ -0,0 +1,7 @@ +export default function bytesToSize(bytes) { + const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; + if (bytes === 0 || !bytes) return '0 B'; + const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10); + if (i === 0) return `${bytes.toFixed(1)} ${sizes[i]}`; + return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`; +} diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 0000000..a74e386 --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,2 @@ +export { default as bytesToSize } from './bytes-to-size'; +export { default as timeRangeToNrql } from './timerange-to-nrql'; diff --git a/src/utils/timerange-to-nrql.js b/src/utils/timerange-to-nrql.js new file mode 100644 index 0000000..28c93cb --- /dev/null +++ b/src/utils/timerange-to-nrql.js @@ -0,0 +1,20 @@ +const MINUTE = 60000; +const HOUR = 60 * MINUTE; +const DAY = 24 * HOUR; + +export default function timePickerNrql(props) { + if (!props || !props.launcherUrlState) return 'SINCE 30 minutes ago'; + const { timeRange } = props.launcherUrlState; + if (!timeRange) { + return 'SINCE 30 minutes ago'; + } + if (timeRange.beginTime && timeRange.endTime) { + return `SINCE ${timeRange.beginTime} UNTIL ${timeRange.endTime}`; + } else if (timeRange.duration <= HOUR) { + return `SINCE ${timeRange.duration / MINUTE} MINUTES AGO`; + } else if (timeRange.duration <= DAY) { + return `SINCE ${timeRange.duration / HOUR} HOURS AGO`; + } else { + return `SINCE ${timeRange.duration / DAY} DAYS AGO`; + } +}