webui: revamp the bug list

Michael Muré created

Change summary

webui/package-lock.json | 505 +++++++++++++++++++++++++-----------------
webui/package.json      |   4 
webui/public/index.html |  18 
webui/src/App.js        |  41 +-
webui/src/Bug.js        |  28 +-
webui/src/BugPage.js    |  29 +-
webui/src/BugSummary.js | 114 ++++++---
webui/src/Comment.js    |  27 +-
webui/src/ListPage.js   |  47 ++-
webui/src/index.js      |  20 
10 files changed, 485 insertions(+), 348 deletions(-)

Detailed changes

webui/package-lock.json 🔗

@@ -4,6 +4,65 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "@babel/runtime": {
+      "version": "7.0.0-beta.42",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.42.tgz",
+      "integrity": "sha512-iOGRzUoONLOtmCvjUsZv3mZzgCT6ljHQY5fr1qG1QIiJQwtM7zbPWGGpa3QWETq+UqwWyJnoi5XZDZRwZDFciQ==",
+      "requires": {
+        "core-js": "^2.5.3",
+        "regenerator-runtime": "^0.11.1"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "2.5.7",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
+          "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
+        }
+      }
+    },
+    "@material-ui/core": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-1.5.0.tgz",
+      "integrity": "sha512-beqrCT2QTw+R9DLc+V2W2GGr/jU87L2eVTrL1kU2qfnkRz+LwJHL6YCyh0gUFgZig4ywDCIQiaMMs0/3rU3qDw==",
+      "requires": {
+        "@babel/runtime": "7.0.0-beta.42",
+        "@types/jss": "^9.5.3",
+        "@types/react-transition-group": "^2.0.8",
+        "brcast": "^3.0.1",
+        "classnames": "^2.2.5",
+        "csstype": "^2.5.2",
+        "debounce": "^1.1.0",
+        "deepmerge": "^2.0.1",
+        "dom-helpers": "^3.2.1",
+        "hoist-non-react-statics": "^2.5.0",
+        "is-plain-object": "^2.0.4",
+        "jss": "^9.3.3",
+        "jss-camel-case": "^6.0.0",
+        "jss-default-unit": "^8.0.2",
+        "jss-global": "^3.0.0",
+        "jss-nested": "^6.0.1",
+        "jss-props-sort": "^6.0.0",
+        "jss-vendor-prefixer": "^7.0.0",
+        "keycode": "^2.1.9",
+        "normalize-scroll-left": "^0.1.2",
+        "popper.js": "^1.14.1",
+        "prop-types": "^15.6.0",
+        "react-event-listener": "^0.6.2",
+        "react-jss": "^8.1.0",
+        "react-transition-group": "^2.2.1",
+        "recompose": "^0.28.0",
+        "warning": "^4.0.1"
+      }
+    },
+    "@material-ui/icons": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-2.0.2.tgz",
+      "integrity": "sha512-Ct3PijJRPACnorgdr93QUKn5o6ixfVKTmy9yLyUpeYQgkaBpkaS60qKaQnSQ3ayA+BeFJQOHOHfGfCYGqBPVBg==",
+      "requires": {
+        "@babel/runtime": "7.0.0-beta.42",
+        "recompose": "^0.28.0"
+      }
+    },
     "@types/async": {
       "version": "2.0.49",
       "resolved": "https://registry.npmjs.org/@types/async/-/async-2.0.49.tgz",
@@ -15,6 +74,40 @@
       "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.12.6.tgz",
       "integrity": "sha512-wXAVyLfkG1UMkKOdMijVWFky39+OD/41KftzqfX1Oejd0Gm6dOIKjCihSVECg6X7PHjftxXmfOKA/d1H79ZfvQ=="
     },
+    "@types/jss": {
+      "version": "9.5.4",
+      "resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.4.tgz",
+      "integrity": "sha512-FAZoCrLjEb0GUgDP1I20748eIwyshM38cXJMFJ7hW2XbtSEo8RrSebgAH3jdXF4FV4NKzyD0TvXlf2MDE8yGrA==",
+      "requires": {
+        "csstype": "^2.0.0",
+        "indefinite-observable": "^1.0.1"
+      }
+    },
+    "@types/prop-types": {
+      "version": "15.5.5",
+      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz",
+      "integrity": "sha512-mOrlCEdwX3seT3n0AXNt4KNPAZZxcsABUHwBgFXOt+nvFUXkxCAO6UBJHPrDxWEa2KDMil86355fjo8jbZ+K0Q==",
+      "requires": {
+        "@types/react": "*"
+      }
+    },
+    "@types/react": {
+      "version": "16.4.9",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.9.tgz",
+      "integrity": "sha512-hG3/RD7baE2bY3N9hRodZbl9qcpG38njeQcbLZvOFOUqDShk7dtAEq5vH2HHf/GYHw4mc3m7zuIVgLnAlTVAnA==",
+      "requires": {
+        "@types/prop-types": "*",
+        "csstype": "^2.2.0"
+      }
+    },
+    "@types/react-transition-group": {
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.0.13.tgz",
+      "integrity": "sha512-A3DV2+aU1P2/wD4r2Lz3lKTV8hFjUslWmT18gGhBdMtZ6FVOAJV7HyZA7dt+Kc+pa1jjevLBhHj344Gnh8yo1g==",
+      "requires": {
+        "@types/react": "*"
+      }
+    },
     "@types/zen-observable": {
       "version": "0.5.4",
       "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.5.4.tgz",
@@ -30,7 +123,7 @@
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
       "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
       "requires": {
-        "mime-types": "2.1.18",
+        "mime-types": "~2.1.18",
         "negotiator": "0.6.1"
       }
     },
@@ -44,7 +137,7 @@
       "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz",
       "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=",
       "requires": {
-        "acorn": "4.0.13"
+        "acorn": "^4.0.3"
       },
       "dependencies": {
         "acorn": {
@@ -59,7 +152,7 @@
       "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz",
       "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=",
       "requires": {
-        "acorn": "4.0.13"
+        "acorn": "^4.0.4"
       },
       "dependencies": {
         "acorn": {
@@ -74,7 +167,7 @@
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
       "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
       "requires": {
-        "acorn": "3.3.0"
+        "acorn": "^3.0.4"
       },
       "dependencies": {
         "acorn": {
@@ -94,10 +187,10 @@
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
       "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
       "requires": {
-        "co": "4.6.0",
-        "fast-deep-equal": "1.1.0",
-        "fast-json-stable-stringify": "2.0.0",
-        "json-schema-traverse": "0.3.1"
+        "co": "^4.6.0",
+        "fast-deep-equal": "^1.0.0",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.3.0"
       }
     },
     "ajv-keywords": {
@@ -110,9 +203,9 @@
       "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
       "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
       "requires": {
-        "kind-of": "3.2.2",
-        "longest": "1.0.1",
-        "repeat-string": "1.6.1"
+        "kind-of": "^3.0.2",
+        "longest": "^1.0.1",
+        "repeat-string": "^1.5.2"
       },
       "dependencies": {
         "kind-of": {
@@ -120,7 +213,7 @@
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
-            "is-buffer": "1.1.6"
+            "is-buffer": "^1.1.5"
           }
         }
       }
@@ -140,7 +233,7 @@
       "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
       "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
       "requires": {
-        "string-width": "2.1.1"
+        "string-width": "^2.0.0"
       }
     },
     "ansi-escapes": {
@@ -163,7 +256,7 @@
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
       "requires": {
-        "color-convert": "1.9.2"
+        "color-convert": "^1.9.0"
       }
     },
     "anymatch": {
@@ -171,8 +264,8 @@
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
       "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
       "requires": {
-        "micromatch": "2.3.11",
-        "normalize-path": "2.1.1"
+        "micromatch": "^2.1.5",
+        "normalize-path": "^2.0.0"
       },
       "dependencies": {
         "arr-diff": {
@@ -180,7 +273,7 @@
           "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
           "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
           "requires": {
-            "arr-flatten": "1.1.0"
+            "arr-flatten": "^1.0.1"
           }
         },
         "array-unique": {
@@ -193,9 +286,9 @@
           "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
           "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
           "requires": {
-            "expand-range": "1.8.2",
-            "preserve": "0.2.0",
-            "repeat-element": "1.1.2"
+            "expand-range": "^1.8.1",
+            "preserve": "^0.2.0",
+            "repeat-element": "^1.1.2"
           }
         },
         "expand-brackets": {
@@ -203,7 +296,7 @@
           "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
           "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
           "requires": {
-            "is-posix-bracket": "0.1.1"
+            "is-posix-bracket": "^0.1.0"
           }
         },
         "extglob": {
@@ -211,7 +304,7 @@
           "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
           "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
           "requires": {
-            "is-extglob": "1.0.0"
+            "is-extglob": "^1.0.0"
           }
         },
         "kind-of": {
@@ -219,7 +312,7 @@
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
           "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
           "requires": {
-            "is-buffer": "1.1.6"
+            "is-buffer": "^1.1.5"
           }
         },
         "micromatch": {
@@ -227,19 +320,19 @@
           "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
           "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
           "requires": {
-            "arr-diff": "2.0.0",
-            "array-unique": "0.2.1",
-            "braces": "1.8.5",
-            "expand-brackets": "0.1.5",
-            "extglob": "0.3.2",
-            "filename-regex": "2.0.1",
-            "is-extglob": "1.0.0",
-            "is-glob": "2.0.1",
-            "kind-of": "3.2.2",
-            "normalize-path": "2.1.1",
-            "object.omit": "2.0.1",
-            "parse-glob": "3.0.4",
-            "regex-cache": "0.4.4"
+            "arr-diff": "^2.0.0",
+            "array-unique": "^0.2.1",
+            "braces": "^1.8.2",
+            "expand-brackets": "^0.1.4",
+            "extglob": "^0.3.1",
+            "filename-regex": "^2.0.0",
+            "is-extglob": "^1.0.0",
+            "is-glob": "^2.0.1",
+            "kind-of": "^3.0.2",
+            "normalize-path": "^2.0.1",
+            "object.omit": "^2.0.0",
+            "parse-glob": "^3.0.4",
+            "regex-cache": "^0.4.2"
           }
         }
       }
@@ -249,14 +342,14 @@
       "resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.10.tgz",
       "integrity": "sha512-Bevaab5xqmOuxVmn8DV+7suoKP/ADX8NKzvfZhD3LgbP72MzpFXxulnP5/xSIBKn08mZvloeYGYdQkoxa7q3/Q==",
       "requires": {
-        "apollo-cache": "1.1.12",
-        "apollo-cache-inmemory": "1.2.5",
-        "apollo-client": "2.3.5",
-        "apollo-link": "1.2.2",
-        "apollo-link-error": "1.1.0",
-        "apollo-link-http": "1.5.4",
-        "apollo-link-state": "0.4.1",
-        "graphql-tag": "2.9.2"
+        "apollo-cache": "^1.1.12",
+        "apollo-cache-inmemory": "^1.2.5",
+        "apollo-client": "^2.3.5",
+        "apollo-link": "^1.0.6",
+        "apollo-link-error": "^1.0.3",
+        "apollo-link-http": "^1.3.1",
+        "apollo-link-state": "^0.4.0",
+        "graphql-tag": "^2.4.2"
       }
     },
     "apollo-cache": {
@@ -264,7 +357,7 @@
       "resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.12.tgz",
       "integrity": "sha512-D0BPiHvJ6vIrXRh6P4mwlxuUOvODGuJxJq+zIjP8fADIqwjYtH3U3d/PY8dQ2fn4bDbvIAWBUkADBuJLpLIIpg==",
       "requires": {
-        "apollo-utilities": "1.0.16"
+        "apollo-utilities": "^1.0.16"
       }
     },
     "apollo-cache-inmemory": {
@@ -272,9 +365,9 @@
       "resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.5.tgz",
       "integrity": "sha512-D9KIT4bq7ORm0BVXjSIxU09SvTUunWKxM63Lvr81hR83I7B7RRM3uFBDUV9VG8rlIGkD+1obBNlW2ycerFV8wQ==",
       "requires": {
-        "apollo-cache": "1.1.12",
-        "apollo-utilities": "1.0.16",
-        "graphql-anywhere": "4.1.14"
+        "apollo-cache": "^1.1.12",
+        "apollo-utilities": "^1.0.16",
+        "graphql-anywhere": "^4.1.14"
       }
     },
     "apollo-client": {
@@ -283,13 +376,13 @@
       "integrity": "sha512-FYg+Mj/HWSaO/ZllT5JnyHGUhkFhZ+UOdEvJd/DYKjxHNPal/d3jyXtG947r4IhUqPmmxXsAXNwvJGPieBKJGg==",
       "requires": {
         "@types/async": "2.0.49",
-        "@types/zen-observable": "0.5.4",
-        "apollo-cache": "1.1.12",
-        "apollo-link": "1.2.2",
-        "apollo-link-dedup": "1.0.9",
-        "apollo-utilities": "1.0.16",
-        "symbol-observable": "1.2.0",
-        "zen-observable": "0.8.8"
+        "@types/zen-observable": "^0.5.3",
+        "apollo-cache": "^1.1.12",
+        "apollo-link": "^1.0.0",
+        "apollo-link-dedup": "^1.0.0",
+        "apollo-utilities": "^1.0.16",
+        "symbol-observable": "^1.0.2",
+        "zen-observable": "^0.8.0"
       }
     },
     "apollo-link": {
@@ -298,8 +391,8 @@
       "integrity": "sha512-Uk/BC09dm61DZRDSu52nGq0nFhq7mcBPTjy5EEH1eunJndtCaNXQhQz/BjkI2NdrfGI+B+i5he6YSoRBhYizdw==",
       "requires": {
         "@types/graphql": "0.12.6",
-        "apollo-utilities": "1.0.16",
-        "zen-observable-ts": "0.8.9"
+        "apollo-utilities": "^1.0.0",
+        "zen-observable-ts": "^0.8.9"
       }
     },
     "apollo-link-dedup": {
@@ -307,7 +400,7 @@
       "resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.9.tgz",
       "integrity": "sha512-RbuEKpmSHVMtoREMPh2wUFTeh65q+0XPVeqgaOP/rGEAfvLyOMvX0vT2nVaejMohoMxuUnfZwpldXaDFWnlVbg==",
       "requires": {
-        "apollo-link": "1.2.2"
+        "apollo-link": "^1.2.2"
       }
     },
     "apollo-link-error": {
@@ -315,7 +408,7 @@
       "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.0.tgz",
       "integrity": "sha512-4Vu/IUn6Kn6+Fthym4iuqypCKcLdwTg3MaCvtLdaLbt9X2hNCq3y8mv6vuWIlAY51X8wKhCgYghQSOs5R/embQ==",
       "requires": {
-        "apollo-link": "1.2.2"
+        "apollo-link": "^1.2.2"
       }
     },
     "apollo-link-http": {
@@ -323,8 +416,8 @@
       "resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.4.tgz",
       "integrity": "sha512-e9Ng3HfnW00Mh3TI6DhNRfozmzQOtKgdi+qUAsHBOEcTP0PTAmb+9XpeyEEOueLyO0GXhB92HUCIhzrWMXgwyg==",
       "requires": {
-        "apollo-link": "1.2.2",
-        "apollo-link-http-common": "0.2.4"
+        "apollo-link": "^1.2.2",
+        "apollo-link-http-common": "^0.2.4"
       }
     },
     "apollo-link-http-common": {
@@ -332,7 +425,7 @@
       "resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.4.tgz",
       "integrity": "sha512-4j6o6WoXuSPen9xh4NBaX8/vL98X1xY2cYzUEK1F8SzvHe2oFONfxJBTekwU8hnvapcuq8Qh9Uct+gelu8T10g==",
       "requires": {
-        "apollo-link": "1.2.2"
+        "apollo-link": "^1.2.2"
       }
     },
     "apollo-link-state": {
@@ -340,8 +433,8 @@
       "resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.1.tgz",
       "integrity": "sha512-69/til4ENfl/Fvf7br2xSsLSBcxcXPbOHVNkzLLejvUZickl93HLO4/fO+uvoBi4dCYRgN17Zr8FwI41ueRx0g==",
       "requires": {
-        "apollo-utilities": "1.0.16",
-        "graphql-anywhere": "4.1.14"
+        "apollo-utilities": "^1.0.8",
+        "graphql-anywhere": "^4.1.0-alpha.0"
       }
     },
     "apollo-utilities": {
@@ -349,7 +442,7 @@
       "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.16.tgz",
       "integrity": "sha512-5oKnElKqkV920KRbitiyISLeG63tUGAyNdotg58bQSX9Omr+smoNDTIRMRLbyIdKOYLaw3LpDaRepOPqljj0NQ==",
       "requires": {
-        "fast-json-stable-stringify": "2.0.0"
+        "fast-json-stable-stringify": "^2.0.0"
       }
     },
     "append-transform": {
@@ -357,7 +450,7 @@
       "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
       "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
       "requires": {
-        "default-require-extensions": "2.0.0"
+        "default-require-extensions": "^2.0.0"
       }
     },
     "argparse": {
@@ -365,7 +458,7 @@
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
       "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
       "requires": {
-        "sprintf-js": "1.0.3"
+        "sprintf-js": "~1.0.2"
       }
     },
     "aria-query": {
@@ -374,7 +467,7 @@
       "integrity": "sha1-Jsu1r/ZBRLCoJb4YRuCxbPoAsR4=",
       "requires": {
         "ast-types-flow": "0.0.7",
-        "commander": "2.16.0"
+        "commander": "^2.11.0"
       }
     },
     "arr-diff": {
@@ -417,8 +510,8 @@
       "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
       "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
       "requires": {
-        "define-properties": "1.1.2",
-        "es-abstract": "1.12.0"
+        "define-properties": "^1.1.2",
+        "es-abstract": "^1.7.0"
       }
     },
     "array-map": {
@@ -436,7 +529,7 @@
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
       "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
       "requires": {
-        "array-uniq": "1.0.3"
+        "array-uniq": "^1.0.1"
       }
     },
     "array-uniq": {
@@ -469,9 +562,9 @@
       "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
       "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
       "requires": {
-        "bn.js": "4.11.8",
-        "inherits": "2.0.3",
-        "minimalistic-assert": "1.0.1"
+        "bn.js": "^4.0.0",
+        "inherits": "^2.0.1",
+        "minimalistic-assert": "^1.0.0"
       }
     },
     "assert": {
@@ -517,7 +610,7 @@
       "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
       "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
       "requires": {
-        "lodash": "4.17.10"
+        "lodash": "^4.17.10"
       }
     },
     "async-each": {
@@ -540,12 +633,12 @@
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.1.6.tgz",
       "integrity": "sha512-C9yv/UF3X+eJTi/zvfxuyfxmLibYrntpF3qoJYrMeQwgUJOZrZvpJiMG2FMQ3qnhWtF/be4pYONBBw95ZGe3vA==",
       "requires": {
-        "browserslist": "2.11.3",
-        "caniuse-lite": "1.0.30000865",
-        "normalize-range": "0.1.2",
-        "num2fraction": "1.2.2",
-        "postcss": "6.0.23",
-        "postcss-value-parser": "3.3.0"
+        "browserslist": "^2.5.1",
+        "caniuse-lite": "^1.0.30000748",
+        "normalize-range": "^0.1.2",
+        "num2fraction": "^1.2.2",
+        "postcss": "^6.0.13",
+        "postcss-value-parser": "^3.2.3"
       }
     },
     "aws-sign2": {
@@ -571,9 +664,9 @@
       "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
       "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
       "requires": {
-        "chalk": "1.1.3",
-        "esutils": "2.0.2",
-        "js-tokens": "3.0.2"
+        "chalk": "^1.1.3",
+        "esutils": "^2.0.2",
+        "js-tokens": "^3.0.2"
       },
       "dependencies": {
         "js-tokens": {
@@ -588,25 +681,25 @@
       "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
       "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
       "requires": {
-        "babel-code-frame": "6.26.0",
-        "babel-generator": "6.26.1",
-        "babel-helpers": "6.24.1",
-        "babel-messages": "6.23.0",
-        "babel-register": "6.26.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0",
-        "babylon": "6.18.0",
-        "convert-source-map": "1.5.1",
-        "debug": "2.6.9",
-        "json5": "0.5.1",
-        "lodash": "4.17.10",
-        "minimatch": "3.0.4",
-        "path-is-absolute": "1.0.1",
-        "private": "0.1.8",
-        "slash": "1.0.0",
-        "source-map": "0.5.7"
+        "babel-code-frame": "^6.26.0",
+        "babel-generator": "^6.26.0",
+        "babel-helpers": "^6.24.1",
+        "babel-messages": "^6.23.0",
+        "babel-register": "^6.26.0",
+        "babel-runtime": "^6.26.0",
+        "babel-template": "^6.26.0",
+        "babel-traverse": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "babylon": "^6.18.0",
+        "convert-source-map": "^1.5.0",
+        "debug": "^2.6.8",
+        "json5": "^0.5.1",
+        "lodash": "^4.17.4",
+        "minimatch": "^3.0.4",
+        "path-is-absolute": "^1.0.1",
+        "private": "^0.1.7",
+        "slash": "^1.0.0",
+        "source-map": "^0.5.6"
       },
       "dependencies": {
         "source-map": {
@@ -621,10 +714,10 @@
       "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz",
       "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=",
       "requires": {
-        "babel-code-frame": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0",
-        "babylon": "6.18.0"
+        "babel-code-frame": "^6.22.0",
+        "babel-traverse": "^6.23.1",
+        "babel-types": "^6.23.0",
+        "babylon": "^6.17.0"
       }
     },
     "babel-generator": {
@@ -632,14 +725,14 @@
       "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
       "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
       "requires": {
-        "babel-messages": "6.23.0",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
-        "detect-indent": "4.0.0",
-        "jsesc": "1.3.0",
-        "lodash": "4.17.10",
-        "source-map": "0.5.7",
-        "trim-right": "1.0.1"
+        "babel-messages": "^6.23.0",
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "detect-indent": "^4.0.0",
+        "jsesc": "^1.3.0",
+        "lodash": "^4.17.4",
+        "source-map": "^0.5.7",
+        "trim-right": "^1.0.1"
       },
       "dependencies": {
         "source-map": {
@@ -654,9 +747,9 @@
       "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
       "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
       "requires": {
-        "babel-helper-explode-assignable-expression": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-helper-explode-assignable-expression": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-builder-react-jsx": {
@@ -664,9 +757,9 @@
       "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz",
       "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
-        "esutils": "2.0.2"
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "esutils": "^2.0.2"
       }
     },
     "babel-helper-call-delegate": {
@@ -674,10 +767,10 @@
       "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
       "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
       "requires": {
-        "babel-helper-hoist-variables": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-helper-hoist-variables": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-define-map": {
@@ -685,10 +778,10 @@
       "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
       "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
       "requires": {
-        "babel-helper-function-name": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
-        "lodash": "4.17.10"
+        "babel-helper-function-name": "^6.24.1",
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "lodash": "^4.17.4"
       }
     },
     "babel-helper-explode-assignable-expression": {
@@ -696,9 +789,9 @@
       "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
       "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-runtime": "^6.22.0",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-function-name": {
@@ -706,11 +799,11 @@
       "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
       "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
       "requires": {
-        "babel-helper-get-function-arity": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-helper-get-function-arity": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-get-function-arity": {
@@ -718,8 +811,8 @@
       "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
       "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-hoist-variables": {
@@ -727,8 +820,8 @@
       "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
       "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-optimise-call-expression": {
@@ -736,8 +829,8 @@
       "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
       "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-regex": {
@@ -745,9 +838,9 @@
       "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
       "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0",
-        "lodash": "4.17.10"
+        "babel-runtime": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "lodash": "^4.17.4"
       }
     },
     "babel-helper-remap-async-to-generator": {
@@ -755,11 +848,11 @@
       "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
       "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
       "requires": {
-        "babel-helper-function-name": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-helper-function-name": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helper-replace-supers": {
@@ -767,12 +860,12 @@
       "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
       "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
       "requires": {
-        "babel-helper-optimise-call-expression": "6.24.1",
-        "babel-messages": "6.23.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-helper-optimise-call-expression": "^6.24.1",
+        "babel-messages": "^6.23.0",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-helpers": {
@@ -780,8 +873,8 @@
       "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
       "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
       }
     },
     "babel-jest": {
@@ -789,9 +882,9 @@
       "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz",
       "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=",
       "requires": {
-        "babel-core": "6.26.0",
-        "babel-plugin-istanbul": "4.1.6",
-        "babel-preset-jest": "20.0.3"
+        "babel-core": "^6.0.0",
+        "babel-plugin-istanbul": "^4.0.0",
+        "babel-preset-jest": "^20.0.3"
       }
     },
     "babel-loader": {
@@ -799,9 +892,9 @@
       "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.2.tgz",
       "integrity": "sha512-jRwlFbINAeyDStqK6Dd5YuY0k5YuzQUvlz2ZamuXrXmxav3pNqe9vfJ402+2G+OmlJSXxCOpB6Uz0INM7RQe2A==",
       "requires": {
-        "find-cache-dir": "1.0.0",
-        "loader-utils": "1.1.0",
-        "mkdirp": "0.5.1"
+        "find-cache-dir": "^1.0.0",
+        "loader-utils": "^1.0.2",
+        "mkdirp": "^0.5.1"
       }
     },
     "babel-messages": {
@@ -809,7 +902,7 @@
       "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
       "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
       "requires": {
-        "babel-runtime": "6.26.0"
+        "babel-runtime": "^6.22.0"
       }
     },
     "babel-plugin-check-es2015-constants": {
@@ -817,7 +910,7 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
       "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
       "requires": {
-        "babel-runtime": "6.26.0"
+        "babel-runtime": "^6.22.0"
       }
     },
     "babel-plugin-dynamic-import-node": {
@@ -825,9 +918,9 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.1.0.tgz",
       "integrity": "sha512-tTfZbM9Ecwj3GK50mnPrUpinTwA4xXmDiQGCk/aBYbvl1+X8YqldK86wZ1owVJ4u3mrKbRlXMma80J18qwiaTQ==",
       "requires": {
-        "babel-plugin-syntax-dynamic-import": "6.18.0",
-        "babel-template": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-plugin-syntax-dynamic-import": "^6.18.0",
+        "babel-template": "^6.26.0",
+        "babel-types": "^6.26.0"
       }
     },
     "babel-plugin-istanbul": {
@@ -835,10 +928,10 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
       "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==",
       "requires": {
-        "babel-plugin-syntax-object-rest-spread": "6.13.0",
-        "find-up": "2.1.0",
-        "istanbul-lib-instrument": "1.10.1",
-        "test-exclude": "4.2.1"
+        "babel-plugin-syntax-object-rest-spread": "^6.13.0",
+        "find-up": "^2.1.0",
+        "istanbul-lib-instrument": "^1.10.1",
+        "test-exclude": "^4.2.1"
       }
     },
     "babel-plugin-jest-hoist": {
@@ -891,9 +984,9 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
       "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
       "requires": {
-        "babel-helper-remap-async-to-generator": "6.24.1",
-        "babel-plugin-syntax-async-functions": "6.13.0",
-        "babel-runtime": "6.26.0"
+        "babel-helper-remap-async-to-generator": "^6.24.1",
+        "babel-plugin-syntax-async-functions": "^6.8.0",
+        "babel-runtime": "^6.22.0"
       }
     },
     "babel-plugin-transform-class-properties": {
@@ -901,10 +994,10 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
       "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
       "requires": {
-        "babel-helper-function-name": "6.24.1",
-        "babel-plugin-syntax-class-properties": "6.13.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
+        "babel-helper-function-name": "^6.24.1",
+        "babel-plugin-syntax-class-properties": "^6.8.0",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
       }
     },
     "babel-plugin-transform-es2015-arrow-functions": {
@@ -912,7 +1005,7 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
       "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
       "requires": {
-        "babel-runtime": "6.26.0"
+        "babel-runtime": "^6.22.0"
       }
     },
     "babel-plugin-transform-es2015-block-scoped-functions": {
@@ -920,7 +1013,7 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
       "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
       "requires": {
-        "babel-runtime": "6.26.0"
+        "babel-runtime": "^6.22.0"
       }
     },
     "babel-plugin-transform-es2015-block-scoping": {
@@ -928,11 +1021,11 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
       "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0",
-        "lodash": "4.17.10"
+        "babel-runtime": "^6.26.0",
+        "babel-template": "^6.26.0",
+        "babel-traverse": "^6.26.0",
+        "babel-types": "^6.26.0",
+        "lodash": "^4.17.4"
       }
     },
     "babel-plugin-transform-es2015-classes": {
@@ -940,15 +1033,15 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
       "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
       "requires": {
-        "babel-helper-define-map": "6.26.0",
-        "babel-helper-function-name": "6.24.1",
-        "babel-helper-optimise-call-expression": "6.24.1",
-        "babel-helper-replace-supers": "6.24.1",
-        "babel-messages": "6.23.0",
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0",
-        "babel-traverse": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-helper-define-map": "^6.24.1",
+        "babel-helper-function-name": "^6.24.1",
+        "babel-helper-optimise-call-expression": "^6.24.1",
+        "babel-helper-replace-supers": "^6.24.1",
+        "babel-messages": "^6.23.0",
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1",
+        "babel-traverse": "^6.24.1",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-plugin-transform-es2015-computed-properties": {
@@ -956,8 +1049,8 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
       "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-template": "6.26.0"
+        "babel-runtime": "^6.22.0",
+        "babel-template": "^6.24.1"
       }
     },
     "babel-plugin-transform-es2015-destructuring": {
@@ -965,7 +1058,7 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
       "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
       "requires": {
-        "babel-runtime": "6.26.0"
+        "babel-runtime": "^6.22.0"
       }
     },
     "babel-plugin-transform-es2015-duplicate-keys": {
@@ -973,8 +1066,8 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
       "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
       "requires": {
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-plugin-transform-es2015-for-of": {
@@ -982,7 +1075,7 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
       "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
       "requires": {
-        "babel-runtime": "6.26.0"
+        "babel-runtime": "^6.22.0"
       }
     },
     "babel-plugin-transform-es2015-function-name": {
@@ -990,9 +1083,9 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
       "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
       "requires": {
-        "babel-helper-function-name": "6.24.1",
-        "babel-runtime": "6.26.0",
-        "babel-types": "6.26.0"
+        "babel-helper-function-name": "^6.24.1",
+        "babel-runtime": "^6.22.0",
+        "babel-types": "^6.24.1"
       }
     },
     "babel-plugin-transform-es2015-literals": {

webui/package.json 🔗

@@ -3,9 +3,11 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
-    "@material-ui/core": "^1.4.0",
+    "@material-ui/core": "^1.4.2",
+    "@material-ui/icons": "^2.0.2",
     "apollo-boost": "^0.1.10",
     "graphql": "^0.13.2",
+    "moment": "^2.22.2",
     "react": "^16.4.1",
     "react-apollo": "^2.1.9",
     "react-dom": "^16.4.1",

webui/public/index.html 🔗

@@ -1,16 +1,16 @@
 <!DOCTYPE html>
 <html lang="en">
 <head>
-  <meta charset="utf-8">
-  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-  <meta name="theme-color" content="#000000">
-  <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
-  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
-  <title>git-bug-webui(1)</title>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta name="theme-color" content="#000000">
+    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
+    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+    <title>git-bug-webui(1)</title>
 </head>
 <body>
-  <noscript>You need to enable JavaScript to run this app.</noscript>
-  <div id="root">
-  </div>
+<noscript>You need to enable JavaScript to run this app.</noscript>
+<div id="root">
+</div>
 </body>
 </html>

webui/src/App.js 🔗

@@ -1,40 +1,39 @@
-import React from "react";
-import { withRouter, Switch, Route } from "react-router";
-import { Link } from "react-router-dom";
-import { withStyles } from "@material-ui/core/styles";
+import AppBar from '@material-ui/core/AppBar'
+import CssBaseline from '@material-ui/core/CssBaseline'
+import { withStyles } from '@material-ui/core/styles'
+import Toolbar from '@material-ui/core/Toolbar'
+import Typography from '@material-ui/core/Typography'
+import React from 'react'
+import { Route, Switch, withRouter } from 'react-router'
+import { Link } from 'react-router-dom'
 
-import AppBar from "@material-ui/core/AppBar";
-import CssBaseline from "@material-ui/core/CssBaseline";
-import Toolbar from "@material-ui/core/Toolbar";
-import Typography from "@material-ui/core/Typography";
-
-import BugPage from "./BugPage";
-import ListPage from "./ListPage";
+import BugPage from './BugPage'
+import ListPage from './ListPage'
 
 const styles = theme => ({
   appTitle: {
-    color: "white",
-    textDecoration: "none"
+    color: 'white',
+    textDecoration: 'none'
   }
-});
+})
 
-const App = ({ location, classes }) => (
+const App = ({location, classes}) => (
   <React.Fragment>
-    <CssBaseline />
+    <CssBaseline/>
     <AppBar position="static" color="primary">
       <Toolbar>
         <Link to="/" className={classes.appTitle}>
           <Typography variant="title" color="inherit">
-            git-bug-webui(1)
+            git-bug webui
           </Typography>
         </Link>
       </Toolbar>
     </AppBar>
     <Switch>
-      <Route path="/" exact component={ListPage} />
-      <Route path="/bug/:id" exact component={BugPage} />
+      <Route path="/" exact component={ListPage}/>
+      <Route path="/bug/:id" exact component={BugPage}/>
     </Switch>
   </React.Fragment>
-);
+)
 
-export default withStyles(styles)(withRouter(App));
+export default withStyles(styles)(withRouter(App))

webui/src/Bug.js 🔗

@@ -1,27 +1,27 @@
-import React from "react";
-import gql from "graphql-tag";
-import { withStyles } from "@material-ui/core/styles";
+import { withStyles } from '@material-ui/core/styles'
+import gql from 'graphql-tag'
+import React from 'react'
+import BugSummary from './BugSummary'
 
-import Comment from "./Comment";
-import BugSummary from "./BugSummary";
+import Comment from './Comment'
 
 const styles = theme => ({
   main: {
     maxWidth: 600,
-    margin: "auto",
+    margin: 'auto',
     marginTop: theme.spacing.unit * 4
   }
-});
+})
 
-const Bug = ({ bug, classes }) => (
+const Bug = ({bug, classes}) => (
   <main className={classes.main}>
-    <BugSummary bug={bug} />
+    <BugSummary bug={bug}/>
 
-    {bug.comments.edges.map(({ cursor, node }) => (
-      <Comment key={cursor} comment={node} />
+    {bug.comments.edges.map(({cursor, node}) => (
+      <Comment key={cursor} comment={node}/>
     ))}
   </main>
-);
+)
 
 Bug.fragment = gql`
   fragment Bug on Bug {
@@ -38,6 +38,6 @@ Bug.fragment = gql`
 
   ${BugSummary.fragment}
   ${Comment.fragment}
-`;
+`
 
-export default withStyles(styles)(Bug);
+export default withStyles(styles)(Bug)

webui/src/BugPage.js 🔗

@@ -1,10 +1,9 @@
-import React from "react";
-import { Query } from "react-apollo";
-import gql from "graphql-tag";
+import CircularProgress from '@material-ui/core/CircularProgress'
+import gql from 'graphql-tag'
+import React from 'react'
+import { Query } from 'react-apollo'
 
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import Bug from "./Bug";
+import Bug from './Bug'
 
 const QUERY = gql`
   query GetBug($id: String!) {
@@ -16,16 +15,16 @@ const QUERY = gql`
   }
 
   ${Bug.fragment}
-`;
+`
 
-const BugPage = ({ match }) => (
-  <Query query={QUERY} variables={{ id: match.params.id }}>
-    {({ loading, error, data }) => {
-      if (loading) return <CircularProgress />;
-      if (error) return <p>Error.</p>;
-      return <Bug bug={data.defaultRepository.bug} />;
+const BugPage = ({match}) => (
+  <Query query={QUERY} variables={{id: match.params.id}}>
+    {({loading, error, data}) => {
+      if (loading) return <CircularProgress/>
+      if (error) return <p>Error.</p>
+      return <Bug bug={data.defaultRepository.bug}/>
     }}
   </Query>
-);
+)
 
-export default BugPage;
+export default BugPage

webui/src/BugSummary.js 🔗

@@ -1,53 +1,93 @@
-import React from "react";
-import { Link } from "react-router-dom";
-import gql from "graphql-tag";
-import { withStyles } from "@material-ui/core/styles";
+import { withStyles } from '@material-ui/core/styles'
+import TableCell from '@material-ui/core/TableCell/TableCell'
+import TableRow from '@material-ui/core/TableRow/TableRow'
+import Tooltip from '@material-ui/core/Tooltip/Tooltip'
+import Typography from '@material-ui/core/Typography'
+import ErrorOutline from '@material-ui/icons/ErrorOutline'
+import gql from 'graphql-tag'
+import React from 'react'
+import { Link } from 'react-router-dom'
+import * as moment from 'moment'
 
-import Card from "@material-ui/core/Card";
-import CardContent from "@material-ui/core/CardContent";
-import Chip from "@material-ui/core/Chip";
-import Typography from "@material-ui/core/Typography";
+const Open = ({className}) => <Tooltip title="Open">
+  <ErrorOutline nativeColor='#28a745' className={className}/>
+</Tooltip>
+
+const Closed = ({className}) => <Tooltip title="Closed">
+  <ErrorOutline nativeColor='#cb2431' className={className}/>
+</Tooltip>
+
+const Status = ({status, className}) => {
+    switch(status) {
+      case 'OPEN': return <Open className={className}/>
+      case 'CLOSED': return <Closed className={className}/>
+      default: return 'unknown status ' + status
+    }
+}
 
 const styles = theme => ({
-  labelList: {
-    display: "flex",
-    flexWrap: "wrap",
-    marginTop: theme.spacing.unit
+  cell: {
+    display: 'flex',
+    alignItems: 'center'
   },
-  label: {
-    marginRight: theme.spacing.unit
+  status: {
+    margin: 10
   },
-  summary: {
-    marginBottom: theme.spacing.unit * 2
-  }
-});
+  title: {
+    display: 'inline-block',
+    textDecoration: 'none'
+  },
+  labels: {
+    display: 'inline-block',
+    paddingLeft: theme.spacing.unit,
+    '&>span': {
+      padding: '0 4px',
+      margin: '0 1px',
+      backgroundColor: '#da9898',
+      borderRadius: '3px',
+    }
+  },
+})
 
-const BugSummary = ({ bug, classes }) => (
-  <Card className={classes.summary}>
-    <CardContent>
-      <Typography variant="headline" component="h2">
-        {bug.title}
-      </Typography>
-      <Typography variant="subheading" component="h3" title={bug.id}>
-        <Link to={"/bug/" + bug.id.slice(0, 8)}>#{bug.id.slice(0, 8)}</Link> •{" "}
-        {bug.status.toUpperCase()}
-      </Typography>
-      <div className={classes.labelList}>
-        {bug.labels.map(label => (
-          <Chip key={label} label={label} className={classes.label} />
-        ))}
+const BugSummary = ({bug, classes}) => (
+  <TableRow hover>
+    <TableCell className={classes.cell}>
+      <Status status={bug.status} className={classes.status}/>
+      <div>
+        <Link to={'bug/'+bug.humanId}>
+          <Typography variant={'title'} className={classes.title}>
+            {bug.title}
+          </Typography>
+        </Link>
+        <span className={classes.labels}>
+          {bug.labels.map(l => (
+            <span key={l}>{l}</span>)
+          )}
+        </span>
+        <Typography color={'textSecondary'}>
+          {bug.humanId} opened
+          <Tooltip title={moment(bug.createdAt).format('MMMM D, YYYY, h:mm a')}>
+            <span> {moment(bug.createdAt).fromNow()} </span>
+          </Tooltip>
+          by {bug.author.name}
+        </Typography>
       </div>
-    </CardContent>
-  </Card>
-);
+    </TableCell>
+  </TableRow>
+)
 
 BugSummary.fragment = gql`
   fragment BugSummary on Bug {
     id
+    humanId
     title
     status
+    createdAt
     labels
+    author {
+      name
+    }
   }
-`;
+`
 
-export default withStyles(styles)(BugSummary);
+export default withStyles(styles)(BugSummary)

webui/src/Comment.js 🔗

@@ -1,20 +1,19 @@
-import React from "react";
-import gql from "graphql-tag";
-import { withStyles } from "@material-ui/core/styles";
-
-import Avatar from "@material-ui/core/Avatar";
-import Card from "@material-ui/core/Card";
-import CardContent from "@material-ui/core/CardContent";
-import CardHeader from "@material-ui/core/CardHeader";
-import Typography from "@material-ui/core/Typography";
+import Avatar from '@material-ui/core/Avatar'
+import Card from '@material-ui/core/Card'
+import CardContent from '@material-ui/core/CardContent'
+import CardHeader from '@material-ui/core/CardHeader'
+import { withStyles } from '@material-ui/core/styles'
+import Typography from '@material-ui/core/Typography'
+import gql from 'graphql-tag'
+import React from 'react'
 
 const styles = theme => ({
   comment: {
     marginBottom: theme.spacing.unit
   }
-});
+})
 
-const Comment = withStyles(styles)(({ comment, classes }) => (
+const Comment = withStyles(styles)(({comment, classes}) => (
   <Card className={classes.comment}>
     <CardHeader
       avatar={
@@ -29,7 +28,7 @@ const Comment = withStyles(styles)(({ comment, classes }) => (
       <Typography component="p">{comment.message}</Typography>
     </CardContent>
   </Card>
-));
+))
 
 Comment.fragment = gql`
   fragment Comment on Comment {
@@ -39,6 +38,6 @@ Comment.fragment = gql`
       email
     }
   }
-`;
+`
 
-export default withStyles(styles)(Comment);
+export default withStyles(styles)(Comment)

webui/src/ListPage.js 🔗

@@ -1,11 +1,12 @@
-import React from "react";
-import { Query } from "react-apollo";
-import gql from "graphql-tag";
-import { withStyles } from "@material-ui/core/styles";
+import CircularProgress from '@material-ui/core/CircularProgress'
+import { withStyles } from '@material-ui/core/styles'
+import Table from '@material-ui/core/Table/Table'
+import TableBody from '@material-ui/core/TableBody/TableBody'
+import gql from 'graphql-tag'
+import React from 'react'
+import { Query } from 'react-apollo'
 
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import BugSummary from "./BugSummary";
+import BugSummary from './BugSummary'
 
 const QUERY = gql`
   {
@@ -22,32 +23,36 @@ const QUERY = gql`
   }
 
   ${BugSummary.fragment}
-`;
+`
 
 const styles = theme => ({
   main: {
     maxWidth: 600,
-    margin: "auto",
+    margin: 'auto',
     marginTop: theme.spacing.unit * 4
   }
-});
+})
 
-const List = withStyles(styles)(({ bugs, classes }) => (
+const List = withStyles(styles)(({bugs, classes}) => (
   <main className={classes.main}>
-    {bugs.edges.map(({ cursor, node }) => (
-      <BugSummary bug={node} key={cursor} />
-    ))}
+    <Table className={classes.table}>
+      <TableBody>
+        {bugs.edges.map(({ cursor, node }) => (
+          <BugSummary bug={node} key={cursor} />
+        ))}
+      </TableBody>
+    </Table>
   </main>
-));
+))
 
 const ListPage = () => (
   <Query query={QUERY}>
-    {({ loading, error, data }) => {
-      if (loading) return <CircularProgress />;
-      if (error) return <p>Error.</p>;
-      return <List bugs={data.defaultRepository.bugs} />;
+    {({loading, error, data}) => {
+      if (loading) return <CircularProgress/>
+      if (error) return <p>Error.</p>
+      return <List bugs={data.defaultRepository.bugs}/>
     }}
   </Query>
-);
+)
 
-export default ListPage;
+export default ListPage

webui/src/index.js 🔗

@@ -1,23 +1,23 @@
-import React from "react";
-import ReactDOM from "react-dom";
-import { BrowserRouter } from "react-router-dom";
-import ApolloClient from "apollo-boost";
-import { ApolloProvider } from "react-apollo";
+import ApolloClient from 'apollo-boost'
+import React from 'react'
+import { ApolloProvider } from 'react-apollo'
+import ReactDOM from 'react-dom'
+import { BrowserRouter } from 'react-router-dom'
 
-import App from "./App";
+import App from './App'
 
 const client = new ApolloClient({
   uri: "/graphql",
   connectToDevTools: true
-});
+})
 
 ReactDOM.render(
   <ApolloProvider client={client}>
     <BrowserRouter>
       <React.Fragment>
-        <App />
+        <App/>
       </React.Fragment>
     </BrowserRouter>
   </ApolloProvider>,
-  document.getElementById("root")
-);
+  document.getElementById('root')
+)