diff --git a/interface/package-lock.json b/interface/package-lock.json
index 37b3767..f5b38b4 100644
--- a/interface/package-lock.json
+++ b/interface/package-lock.json
@@ -1184,21 +1184,19 @@
}
},
"@material-ui/core": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.4.3.tgz",
- "integrity": "sha512-Lz8sMFeCrtq5/pbhqClWFHpveL0huixjca0tw7uvh9xKKB7VyyYOyTu7RamSZLxb34UCSMPlobR+KK25Nqzkqw==",
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.7.0.tgz",
+ "integrity": "sha512-mwLehUo0Q9ZxjuWo7J1uy1/Grh3nRxlOAaWJ3EtKeJP2HwqlSy8bWrcvRQYlapaYIPXa5jN8zWbTwi8Pk30VQg==",
"requires": {
"@babel/runtime": "^7.4.4",
- "@material-ui/styles": "^4.4.3",
- "@material-ui/system": "^4.4.3",
+ "@material-ui/styles": "^4.6.0",
+ "@material-ui/system": "^4.5.2",
"@material-ui/types": "^4.1.1",
- "@material-ui/utils": "^4.4.0",
+ "@material-ui/utils": "^4.5.2",
"@types/react-transition-group": "^4.2.0",
"clsx": "^1.0.2",
"convert-css-length": "^2.0.1",
- "deepmerge": "^4.0.0",
"hoist-non-react-statics": "^3.2.1",
- "is-plain-object": "^3.0.0",
"normalize-scroll-left": "^0.2.0",
"popper.js": "^1.14.1",
"prop-types": "^15.7.2",
@@ -1206,44 +1204,43 @@
}
},
"@material-ui/icons": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.4.3.tgz",
- "integrity": "sha512-HVVvUyc/78kmaBd93LkfWyGkXMM+zOMKzUfulWXxaV/fFAZ3N0pD0oHjWUd94zrOoF3tZP9JC7EPlIpIcZSNow==",
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.5.1.tgz",
+ "integrity": "sha512-YZ/BgJbXX4a0gOuKWb30mBaHaoXRqPanlePam83JQPZ/y4kl+3aW0Wv9tlR70hB5EGAkEJGW5m4ktJwMgxQAeA==",
"requires": {
"@babel/runtime": "^7.4.4"
}
},
"@material-ui/styles": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.4.3.tgz",
- "integrity": "sha512-kNUdHFWsrvWKIEPx8Xy2/qayqsGMrYmCMq+FIiJiYczVZl5hiS8j5+KayonnpVta/O+Dktk+cxWkVcgwtxMrHg==",
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.6.0.tgz",
+ "integrity": "sha512-lqqh4UEMdIYcU1Yth4pQyMTah02uAkg3NOT3MirN9FUexdL8pNA6zCHigEgDSfwmvnXyxHhxTkphfy0DRfnt9w==",
"requires": {
"@babel/runtime": "^7.4.4",
"@emotion/hash": "^0.7.1",
"@material-ui/types": "^4.1.1",
- "@material-ui/utils": "^4.1.0",
+ "@material-ui/utils": "^4.5.2",
"clsx": "^1.0.2",
"csstype": "^2.5.2",
- "deepmerge": "^4.0.0",
"hoist-non-react-statics": "^3.2.1",
- "jss": "10.0.0-alpha.25",
- "jss-plugin-camel-case": "10.0.0-alpha.25",
- "jss-plugin-default-unit": "10.0.0-alpha.25",
- "jss-plugin-global": "10.0.0-alpha.25",
- "jss-plugin-nested": "10.0.0-alpha.25",
- "jss-plugin-props-sort": "10.0.0-alpha.25",
- "jss-plugin-rule-value-function": "10.0.0-alpha.25",
- "jss-plugin-vendor-prefixer": "10.0.0-alpha.25",
+ "jss": "^10.0.0",
+ "jss-plugin-camel-case": "^10.0.0",
+ "jss-plugin-default-unit": "^10.0.0",
+ "jss-plugin-global": "^10.0.0",
+ "jss-plugin-nested": "^10.0.0",
+ "jss-plugin-props-sort": "^10.0.0",
+ "jss-plugin-rule-value-function": "^10.0.0",
+ "jss-plugin-vendor-prefixer": "^10.0.0",
"prop-types": "^15.7.2"
}
},
"@material-ui/system": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.4.3.tgz",
- "integrity": "sha512-Cb05vLXsaCzssXD/iZKa0/qC6YOwbFWnYdnOEdkXZ3Fn2Ytz7rsnMgFejUSQV1luVhUBlEIm8DVz40N25WwW7w==",
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.5.2.tgz",
+ "integrity": "sha512-h9RWvdM9XKlHHqwiuhyvWdobptQkHli+m2jJFs7i1AI/hmGsIc4reDmS7fInhETgt/Txx7uiAIznfRNIIVHmQw==",
"requires": {
"@babel/runtime": "^7.4.4",
- "deepmerge": "^4.0.0",
+ "@material-ui/utils": "^4.5.2",
"prop-types": "^15.7.2"
}
},
@@ -1256,9 +1253,9 @@
}
},
"@material-ui/utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.4.0.tgz",
- "integrity": "sha512-UXoQVwArQEQWXxf2FPs0iJGT+MePQpKr0Qh0CPoLc1OdF0GSMTmQczcqCzwZkeHxHAOq/NkIKM1Pb/ih1Avicg==",
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.5.2.tgz",
+ "integrity": "sha512-zhbNfHd1gLa8At6RPDG7uMZubHxbY+LtM6IkSfeWi6Lo4Ax80l62YaN1QmUpO1IvGCkn/j62tQX3yObiQZrJsQ==",
"requires": {
"@babel/runtime": "^7.4.4",
"prop-types": "^15.7.2",
@@ -1486,18 +1483,18 @@
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw=="
},
"@types/react": {
- "version": "16.9.4",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.4.tgz",
- "integrity": "sha512-ItGNmJvQ0IvWt8rbk5PLdpdQhvBVxAaXI9hDlx7UMd8Ie1iMIuwMNiKeTfmVN517CdplpyXvA22X4zm4jGGZnw==",
+ "version": "16.9.13",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.13.tgz",
+ "integrity": "sha512-LikzRslbiufJYHyzbHSW0GrAiff8QYLMBFeZmSxzCYGXKxi8m/1PHX+rsVOwhr7mJNq+VIu2Dhf7U6mjFERK6w==",
"requires": {
"@types/prop-types": "*",
"csstype": "^2.2.0"
}
},
"@types/react-transition-group": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.2.tgz",
- "integrity": "sha512-YfoaTNqBwbIqpiJ5NNfxfgg5kyFP1Hqf/jqBtSWNv0E+EkkxmN+3VD6U2fu86tlQvdAc1o0SdWhnWFwcRMTn9A==",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.3.tgz",
+ "integrity": "sha512-Hk8jiuT7iLOHrcjKP/ZVSyCNXK73wJAUz60xm0mVhiRujrdiI++j4duLiL282VGxwAgxetHQFfqA29LgEeSkFA==",
"requires": {
"@types/react": "*"
}
@@ -4210,11 +4207,6 @@
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
},
- "deepmerge": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.0.0.tgz",
- "integrity": "sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww=="
- },
"default-gateway": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
@@ -4439,12 +4431,27 @@
}
},
"dom-helpers": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.0.tgz",
- "integrity": "sha512-zRRYDhpiKuAJHasOqCm7lBnsd22nrM4+OYI4ASWCxen+ocTMl7BIAKgGag97TlLiTl6rrau5aPe1VGUm9jQBng==",
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.3.tgz",
+ "integrity": "sha512-nZD1OtwfWGRBWlpANxacBEZrEuLa16o1nh7YopFWeoF68Zt8GGEmzHu6Xv4F3XaFIC+YXtTLrzgqKxFgLEe4jw==",
"requires": {
- "@babel/runtime": "^7.5.5",
- "csstype": "^2.6.6"
+ "@babel/runtime": "^7.6.3",
+ "csstype": "^2.6.7"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.4.tgz",
+ "integrity": "sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw==",
+ "requires": {
+ "regenerator-runtime": "^0.13.2"
+ }
+ },
+ "csstype": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.7.tgz",
+ "integrity": "sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ=="
+ }
}
},
"dom-serializer": {
@@ -6548,14 +6555,6 @@
"path-is-inside": "^1.0.1"
}
},
- "is-plain-object": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
- "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
- "requires": {
- "isobject": "^4.0.0"
- }
- },
"is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
@@ -6630,11 +6629,6 @@
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
- "isobject": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
- "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA=="
- },
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -7889,9 +7883,9 @@
}
},
"jss": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.25.tgz",
- "integrity": "sha512-zqKnXv181B9vue2yYhmVhc+6ggbbxHF/33rjXfXEjaa22nOvknTI21QDfq3oZ8uCC50kcFp3Z8KU1ghUXdFvIA==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0.tgz",
+ "integrity": "sha512-TPpDFsiBjuERiL+dFDq8QCdiF9oDasPcNqCKLGCo/qED3fNYOQ8PX2lZhknyTiAt3tZrfOFbb0lbQ9lTjPZxsQ==",
"requires": {
"@babel/runtime": "^7.3.1",
"csstype": "^2.6.5",
@@ -7900,13 +7894,13 @@
}
},
"jss-plugin-camel-case": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.0-alpha.25.tgz",
- "integrity": "sha512-J5ZEGDTy9ddqdTUPAF4SJQ25u5kiG1ORP8F+ZPEZAkkiMQJp+/Aol4I7xhTS2aW1Lhg8xNxdhdRfBi5yU7wOvg==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.0.tgz",
+ "integrity": "sha512-yALDL00+pPR4FJh+k07A8FeDvfoPPuXU48HLy63enAubcVd3DnS+2rgqPXglHDGixIDVkCSXecl/l5GAMjzIbA==",
"requires": {
"@babel/runtime": "^7.3.1",
"hyphenate-style-name": "^1.0.3",
- "jss": "10.0.0-alpha.25"
+ "jss": "10.0.0"
}
},
"jss-plugin-compose": {
@@ -7933,12 +7927,12 @@
}
},
"jss-plugin-default-unit": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.0-alpha.25.tgz",
- "integrity": "sha512-auOG459B+yEqkojgaXH02SYO9+xjmAxlmP+WbzhVpXqOFJ2CN/kaxd8P4NJZLdj3BQxHiM7WIyMVh786StE+EA==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.0.tgz",
+ "integrity": "sha512-sURozIOdCtGg9ap18erQ+ijndAfEGtTaetxfU3H4qwC18Bi+fdvjlY/ahKbuu0ASs7R/+WKCP7UaRZOjUDMcdQ==",
"requires": {
"@babel/runtime": "^7.3.1",
- "jss": "10.0.0-alpha.25"
+ "jss": "10.0.0"
}
},
"jss-plugin-expand": {
@@ -7987,40 +7981,40 @@
}
},
"jss-plugin-global": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.0-alpha.25.tgz",
- "integrity": "sha512-cS98Q8X8jwltuaBZd9eYuxMXxkUL+mJGl2Ok3/nmJzH9nLzj6i7kLxSoDtuJNqsRmbP7ogIXVozJUq9lUu2hlQ==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.0.tgz",
+ "integrity": "sha512-80ofWKSQUo62bxLtRoTNe0kFPtHgUbAJeOeR36WEGgWIBEsXLyXOnD5KNnjPqG4heuEkz9eSLccjYST50JnI7Q==",
"requires": {
"@babel/runtime": "^7.3.1",
- "jss": "10.0.0-alpha.25"
+ "jss": "10.0.0"
}
},
"jss-plugin-nested": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.0-alpha.25.tgz",
- "integrity": "sha512-7sk7/6mX1YTgXe+AyeD1zEyKTgIGbbhYtg+wWQcHJlE1flW2JHfcQ5mw84FgHcHQRQ8Dq3l9I3aEY51ev0J1Wg==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.0.tgz",
+ "integrity": "sha512-waxxwl/po1hN3azTyixKnr8ReEqUv5WK7WsO+5AWB0bFndML5Yqnt8ARZ90HEg8/P6WlqE/AB2413TkCRZE8bA==",
"requires": {
"@babel/runtime": "^7.3.1",
- "jss": "10.0.0-alpha.25",
+ "jss": "10.0.0",
"tiny-warning": "^1.0.2"
}
},
"jss-plugin-props-sort": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.0-alpha.25.tgz",
- "integrity": "sha512-8B/6QLQuUX8cIlZbXdjEm5l0jCX4EgacYMcFJhdKwDKEZYeAghpgQQrCKl0/CYHW7iFge5wim67P+uL6QxMzyw==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.0.tgz",
+ "integrity": "sha512-41mf22CImjwNdtOG3r+cdC8+RhwNm616sjHx5YlqTwtSJLyLFinbQC/a4PIFk8xqf1qpFH1kEAIw+yx9HaqZ3g==",
"requires": {
"@babel/runtime": "^7.3.1",
- "jss": "10.0.0-alpha.25"
+ "jss": "10.0.0"
}
},
"jss-plugin-rule-value-function": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.0-alpha.25.tgz",
- "integrity": "sha512-CQQtWO+/OZRGaFRBSGQUgAci9YlVtdoXcWQKBNo70tmpp+kaXKlFNCYaL3jmHbJHMiwKQYG2RYFQNIrwJ9SGmA==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.0.tgz",
+ "integrity": "sha512-Jw+BZ8JIw1f12V0SERqGlBT1JEPWax3vuZpMym54NAXpPb7R1LYHiCTIlaJUyqvIfEy3kiHMtgI+r2whGgRIxQ==",
"requires": {
"@babel/runtime": "^7.3.1",
- "jss": "10.0.0-alpha.25"
+ "jss": "10.0.0"
}
},
"jss-plugin-rule-value-observable": {
@@ -8070,13 +8064,13 @@
}
},
"jss-plugin-vendor-prefixer": {
- "version": "10.0.0-alpha.25",
- "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.0-alpha.25.tgz",
- "integrity": "sha512-5FXpB/TiwckbrkoDCmd27YsWCESl1K4hAX/oro2/geEXgnVQvDgQOf2eWCsjYO2K1lYPPXtskMfws/Q3eKmbYg==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.0.tgz",
+ "integrity": "sha512-qslqvL0MUbWuzXJWdUxpj6mdNUX8jr4FFTo3aZnAT65nmzWL7g8oTr9ZxmTXXgdp7ANhS1QWE7036/Q2isFBpw==",
"requires": {
"@babel/runtime": "^7.3.1",
"css-vendor": "^2.0.6",
- "jss": "10.0.0-alpha.25"
+ "jss": "10.0.0"
}
},
"jss-preset-default": {
@@ -8940,9 +8934,9 @@
"integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg=="
},
"notistack": {
- "version": "0.8.9",
- "resolved": "https://registry.npmjs.org/notistack/-/notistack-0.8.9.tgz",
- "integrity": "sha512-nRHQVWUfgHnvnKrjRbRX9f+YAnbyh96yRyO5bEP/FCLVLuTZcJOwUr0GZ7Xr/8wK3+hXa9JYpXUkUhSxj1K8NQ==",
+ "version": "0.9.6",
+ "resolved": "https://registry.npmjs.org/notistack/-/notistack-0.9.6.tgz",
+ "integrity": "sha512-vo1zOwhQBxwWiMxwVjeSDXNzJuaM/nfkayv4uRo+9ON9CAtaPSNt15QHeELKkbOSLH29fb7zmoZl4AlkCqhGsA==",
"requires": {
"classnames": "^2.2.6",
"hoist-non-react-statics": "^3.3.0",
@@ -9526,9 +9520,9 @@
}
},
"popper.js": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz",
- "integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA=="
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.0.tgz",
+ "integrity": "sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw=="
},
"portfinder": {
"version": "1.0.24",
diff --git a/interface/package.json b/interface/package.json
index c89bd10..e91090c 100644
--- a/interface/package.json
+++ b/interface/package.json
@@ -3,12 +3,12 @@
"version": "0.1.0",
"private": true,
"dependencies": {
- "@material-ui/core": "^4.4.3",
- "@material-ui/icons": "^4.4.3",
+ "@material-ui/core": "^4.7.0",
+ "@material-ui/icons": "^4.5.1",
"compression-webpack-plugin": "^2.0.0",
"jwt-decode": "^2.2.0",
"moment": "^2.24.0",
- "notistack": "^0.8.9",
+ "notistack": "^0.9.6",
"prop-types": "^15.7.2",
"react": "^16.10.1",
"react-dom": "^16.10.1",
diff --git a/interface/src/App.js b/interface/src/App.js
index d26b8a4..06e9a65 100644
--- a/interface/src/App.js
+++ b/interface/src/App.js
@@ -2,22 +2,16 @@ import React, { Component } from 'react';
import { Redirect, Route, Switch } from 'react-router';
import AppRouting from './AppRouting';
+import { PROJECT_NAME } from './constants/Env';
+
import { SnackbarProvider } from 'notistack';
-
-import CssBaseline from '@material-ui/core/CssBaseline';
-import blueGrey from '@material-ui/core/colors/blueGrey';
-import indigo from '@material-ui/core/colors/indigo';
-import orange from '@material-ui/core/colors/orange';
-import red from '@material-ui/core/colors/red';
-import green from '@material-ui/core/colors/green';
-
import { create } from 'jss';
-import { StylesProvider, jssPreset } from '@material-ui/styles';
-import {
- MuiThemeProvider,
- createMuiTheme
-} from '@material-ui/core/styles';
+import { CssBaseline, IconButton, MuiThemeProvider, createMuiTheme } from '@material-ui/core';
+import { StylesProvider, jssPreset } from '@material-ui/styles';
+import { blueGrey, indigo, orange, red, green } from '@material-ui/core/colors';
+import CloseIcon from '@material-ui/icons/Close';
+
// Our theme
const theme = createMuiTheme({
@@ -38,11 +32,28 @@ const jss = create(jssPreset());
const unauthorizedRedirect = () => ;
class App extends Component {
+
+ notistackRef = React.createRef();
+
+ componentDidMount() {
+ document.title = PROJECT_NAME;
+ }
+
+ onClickDismiss = (key) => () => {
+ this.notistackRef.current.closeSnackbar(key);
+ }
+
render() {
return (
-
+ (
+
+
+
+ )}>
diff --git a/interface/src/constants/Endpoints.js b/interface/src/constants/Endpoints.js
index 5474bdf..fc6b7cc 100644
--- a/interface/src/constants/Endpoints.js
+++ b/interface/src/constants/Endpoints.js
@@ -13,3 +13,4 @@ export const SYSTEM_STATUS_ENDPOINT = ENDPOINT_ROOT + "systemStatus";
export const SIGN_IN_ENDPOINT = ENDPOINT_ROOT + "signIn";
export const VERIFY_AUTHORIZATION_ENDPOINT = ENDPOINT_ROOT + "verifyAuthorization";
export const SECURITY_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "securitySettings";
+export const RESET_ENDPOINT = ENDPOINT_ROOT + "reset";
diff --git a/interface/src/containers/APStatus.js b/interface/src/containers/APStatus.js
index eadaf9b..d4ced8e 100644
--- a/interface/src/containers/APStatus.js
+++ b/interface/src/containers/APStatus.js
@@ -11,6 +11,7 @@ import Divider from '@material-ui/core/Divider';
import SettingsInputAntennaIcon from '@material-ui/icons/SettingsInputAntenna';
import DeviceHubIcon from '@material-ui/icons/DeviceHub';
import ComputerIcon from '@material-ui/icons/Computer';
+import RefreshIcon from '@material-ui/icons/Refresh';
import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
@@ -93,7 +94,7 @@ class APStatus extends Component {
{this.createListItems(data, classes)}
-
diff --git a/interface/src/containers/NTPStatus.js b/interface/src/containers/NTPStatus.js
index f58e467..77e35cf 100644
--- a/interface/src/containers/NTPStatus.js
+++ b/interface/src/containers/NTPStatus.js
@@ -14,6 +14,7 @@ import DNSIcon from '@material-ui/icons/Dns';
import TimerIcon from '@material-ui/icons/Timer';
import UpdateIcon from '@material-ui/icons/Update';
import AvTimerIcon from '@material-ui/icons/AvTimer';
+import RefreshIcon from '@material-ui/icons/Refresh';
import { isSynchronized, ntpStatusHighlight, ntpStatus } from '../constants/NTPStatus';
import * as Highlight from '../constants/Highlight';
@@ -118,7 +119,7 @@ class NTPStatus extends Component {
{this.createListItems(data, classes)}
-
+ } variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh
diff --git a/interface/src/containers/SystemStatus.js b/interface/src/containers/SystemStatus.js
index 560c936..126ee37 100644
--- a/interface/src/containers/SystemStatus.js
+++ b/interface/src/containers/SystemStatus.js
@@ -1,4 +1,5 @@
import React, { Component, Fragment } from 'react';
+import { withSnackbar } from 'notistack';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
@@ -8,16 +9,24 @@ import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import ListItemText from '@material-ui/core/ListItemText';
import Avatar from '@material-ui/core/Avatar';
import Divider from '@material-ui/core/Divider';
+import Dialog from '@material-ui/core/Dialog';
+import DialogActions from '@material-ui/core/DialogActions';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import DialogContent from '@material-ui/core/DialogContent';
+
import DevicesIcon from '@material-ui/icons/Devices';
import MemoryIcon from '@material-ui/icons/Memory';
import ShowChartIcon from '@material-ui/icons/ShowChart';
import SdStorageIcon from '@material-ui/icons/SdStorage';
import DataUsageIcon from '@material-ui/icons/DataUsage';
+import AutorenewIcon from '@material-ui/icons/Autorenew';
+import RefreshIcon from '@material-ui/icons/Refresh';
-import { SYSTEM_STATUS_ENDPOINT } from '../constants/Endpoints';
+import { SYSTEM_STATUS_ENDPOINT, RESET_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent';
+import { redirectingAuthorizedFetch } from '../authentication/Authentication';
const styles = theme => ({
button: {
@@ -28,6 +37,16 @@ const styles = theme => ({
class SystemStatus extends Component {
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ confirmReset: false,
+ processing: false
+ }
+ }
+
componentDidMount() {
this.props.loadData();
}
@@ -90,13 +109,63 @@ class SystemStatus extends Component {
{this.createListItems(data, classes)}
-
+ } variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh
+ } variant="contained" color="secondary" className={classes.button} onClick={this.onReset}>
+ Reset
+
);
}
+ onReset = () => {
+ this.setState({ confirmReset: true });
+ }
+
+ onResetRejected = () => {
+ this.setState({ confirmReset: false });
+ }
+
+ onResetConfirmed = () => {
+ this.setState({ processing: true });
+ redirectingAuthorizedFetch(RESET_ENDPOINT, { method: 'POST' })
+ .then(response => {
+ if (response.status === 200) {
+ this.props.enqueueSnackbar("Device is reseting", { variant: 'info' });
+ this.setState({ processing: false, confirmReset: false });
+ } else {
+ throw Error("Invalid status code: " + response.status);
+ }
+ })
+ .catch(error => {
+ this.props.enqueueSnackbar(error.message || "Problem resetting device", { variant: 'error' });
+ this.setState({ processing: false, confirmReset: false });
+ });
+ }
+
+ renderResetDialog() {
+ return (
+
+ )
+ }
+
render() {
const { data, fetched, errorMessage, loadData, classes } = this.props;
return (
@@ -109,9 +178,11 @@ class SystemStatus extends Component {
() => this.renderSystemStatus(data, classes)
}
/>
+ {this.renderResetDialog()}
)
}
+
}
-export default restComponent(SYSTEM_STATUS_ENDPOINT, withStyles(styles)(SystemStatus));
+export default withSnackbar(restComponent(SYSTEM_STATUS_ENDPOINT, withStyles(styles)(SystemStatus)));
diff --git a/interface/src/containers/WiFiStatus.js b/interface/src/containers/WiFiStatus.js
index 43724d9..419105c 100644
--- a/interface/src/containers/WiFiStatus.js
+++ b/interface/src/containers/WiFiStatus.js
@@ -13,6 +13,7 @@ import DNSIcon from '@material-ui/icons/Dns';
import SettingsInputComponentIcon from '@material-ui/icons/SettingsInputComponent';
import SettingsInputAntennaIcon from '@material-ui/icons/SettingsInputAntenna';
import DeviceHubIcon from '@material-ui/icons/DeviceHub';
+import RefreshIcon from '@material-ui/icons/Refresh';
import SectionContent from '../components/SectionContent';
import { WIFI_STATUS_ENDPOINT } from '../constants/Endpoints';
@@ -130,7 +131,7 @@ class WiFiStatus extends Component {
{this.createListItems(data, classes)}
-
+ } variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh
diff --git a/interface/src/forms/APSettingsForm.js b/interface/src/forms/APSettingsForm.js
index e708884..e8d1521 100644
--- a/interface/src/forms/APSettingsForm.js
+++ b/interface/src/forms/APSettingsForm.js
@@ -8,6 +8,7 @@ import PasswordValidator from '../components/PasswordValidator';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import MenuItem from '@material-ui/core/MenuItem';
+import SaveIcon from '@material-ui/icons/Save';
const styles = theme => ({
textField: {
@@ -61,7 +62,7 @@ class APSettingsForm extends React.Component {
/>
}
-
+ } variant="contained" color="primary" className={classes.button} type="submit">
Save
diff --git a/interface/src/forms/ManageUsersForm.js b/interface/src/forms/ManageUsersForm.js
index bdae121..5368a87 100644
--- a/interface/src/forms/ManageUsersForm.js
+++ b/interface/src/forms/ManageUsersForm.js
@@ -18,6 +18,8 @@ import DeleteIcon from '@material-ui/icons/Delete';
import CloseIcon from '@material-ui/icons/Close';
import CheckIcon from '@material-ui/icons/Check';
import IconButton from '@material-ui/core/IconButton';
+import SaveIcon from '@material-ui/icons/Save';
+import PersonAddIcon from '@material-ui/icons/PersonAdd';
import UserForm from './UserForm';
import { withAuthenticationContext } from '../authentication/Context';
@@ -161,7 +163,7 @@ class ManageUsersForm extends React.Component {
-
+ } variant="contained" color="secondary" onClick={this.createUser}>
Add User
@@ -176,7 +178,7 @@ class ManageUsersForm extends React.Component {
}
-
+ } variant="contained" color="primary" className={classes.button} type="submit" disabled={this.noAdminConfigured()}>
Save
diff --git a/interface/src/forms/NTPSettingsForm.js b/interface/src/forms/NTPSettingsForm.js
index 8214825..a99ae92 100644
--- a/interface/src/forms/NTPSettingsForm.js
+++ b/interface/src/forms/NTPSettingsForm.js
@@ -4,6 +4,7 @@ import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
+import SaveIcon from '@material-ui/icons/Save';
import isIP from '../validators/isIP';
import isHostname from '../validators/isHostname';
@@ -50,7 +51,7 @@ class NTPSettingsForm extends React.Component {
onChange={handleValueChange('interval')}
margin="normal"
/>
-
+ } variant="contained" color="primary" className={classes.button} type="submit">
Save
diff --git a/interface/src/forms/OTASettingsForm.js b/interface/src/forms/OTASettingsForm.js
index 29ee5b8..1d980bf 100644
--- a/interface/src/forms/OTASettingsForm.js
+++ b/interface/src/forms/OTASettingsForm.js
@@ -6,6 +6,7 @@ import Button from '@material-ui/core/Button';
import Switch from '@material-ui/core/Switch';
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import FormControlLabel from '@material-ui/core/FormControlLabel';
+import SaveIcon from '@material-ui/icons/Save';
import isIP from '../validators/isIP';
import isHostname from '../validators/isHostname';
@@ -69,7 +70,7 @@ class OTASettingsForm extends React.Component {
onChange={handleValueChange('password')}
margin="normal"
/>
-
+ } variant="contained" color="primary" className={classes.button} type="submit">
Save
diff --git a/interface/src/forms/SecuritySettingsForm.js b/interface/src/forms/SecuritySettingsForm.js
index 16d74a3..7582686 100644
--- a/interface/src/forms/SecuritySettingsForm.js
+++ b/interface/src/forms/SecuritySettingsForm.js
@@ -6,6 +6,7 @@ import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
+import SaveIcon from '@material-ui/icons/Save';
import PasswordValidator from '../components/PasswordValidator';
import { withAuthenticationContext } from '../authentication/Context';
@@ -46,7 +47,7 @@ class SecuritySettingsForm extends React.Component {
If you modify the JWT Secret, all users will be logged out.
-
+ } variant="contained" color="primary" className={classes.button} type="submit">
Save
diff --git a/interface/src/forms/WiFiNetworkSelector.js b/interface/src/forms/WiFiNetworkSelector.js
index 51fff8f..5824da5 100644
--- a/interface/src/forms/WiFiNetworkSelector.js
+++ b/interface/src/forms/WiFiNetworkSelector.js
@@ -18,6 +18,7 @@ import Badge from '@material-ui/core/Badge';
import WifiIcon from '@material-ui/icons/Wifi';
import LockIcon from '@material-ui/icons/Lock';
import LockOpenIcon from '@material-ui/icons/LockOpen';
+import PermScanWifiIcon from '@material-ui/icons/PermScanWifi';
import { isNetworkOpen, networkSecurityMode } from '../constants/WiFiSecurityModes';
@@ -86,7 +87,7 @@ class WiFiNetworkSelector extends Component {
}
-
+ } variant="contained" color="secondary" className={classes.button} onClick={requestNetworkScan} disabled={scanningForNetworks}>
Scan again...
diff --git a/interface/src/forms/WiFiSettingsForm.js b/interface/src/forms/WiFiSettingsForm.js
index eb365ae..0bf2859 100644
--- a/interface/src/forms/WiFiSettingsForm.js
+++ b/interface/src/forms/WiFiSettingsForm.js
@@ -16,6 +16,7 @@ import IconButton from '@material-ui/core/IconButton';
import LockIcon from '@material-ui/icons/Lock';
import LockOpenIcon from '@material-ui/icons/LockOpen';
import DeleteIcon from '@material-ui/icons/Delete';
+import SaveIcon from '@material-ui/icons/Save';
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import { isNetworkOpen, networkSecurityMode } from '../constants/WiFiSecurityModes';
@@ -175,7 +176,7 @@ class WiFiSettingsForm extends React.Component {
/>
}
-
+ } variant="contained" color="primary" className={classes.button} type="submit">
Save
diff --git a/interface/src/project/DemoController.js b/interface/src/project/DemoController.js
index 6d1e586..0624c3a 100644
--- a/interface/src/project/DemoController.js
+++ b/interface/src/project/DemoController.js
@@ -10,6 +10,7 @@ import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Slider from '@material-ui/core/Slider';
import { makeStyles } from '@material-ui/core/styles';
+import SaveIcon from '@material-ui/icons/Save';
export const DEMO_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "demoSettings";
@@ -69,7 +70,7 @@ function DemoControllerForm(props) {
max={255}
onChange={handleSliderChange('blink_speed')}
/>
-
+ } variant="contained" color="primary" className={classes.button} type="submit">
Save
diff --git a/lib/framework/ESP8266React.cpp b/lib/framework/ESP8266React.cpp
index 0087cab..e2cdcb8 100644
--- a/lib/framework/ESP8266React.cpp
+++ b/lib/framework/ESP8266React.cpp
@@ -6,6 +6,7 @@ ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs):
_apSettingsService(server, fs, &_securitySettingsService),
_ntpSettingsService(server, fs, &_securitySettingsService),
_otaSettingsService(server, fs, &_securitySettingsService),
+ _ResetService(server, &_securitySettingsService),
_authenticationService(server, &_securitySettingsService),
_wifiScanner(server, &_securitySettingsService),
_wifiStatus(server, &_securitySettingsService),
diff --git a/lib/framework/ESP8266React.h b/lib/framework/ESP8266React.h
index d71ca31..75e33a8 100644
--- a/lib/framework/ESP8266React.h
+++ b/lib/framework/ESP8266React.h
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
class ESP8266React {
@@ -46,8 +47,10 @@ class ESP8266React {
APSettingsService _apSettingsService;
NTPSettingsService _ntpSettingsService;
OTASettingsService _otaSettingsService;
+ ResetService _ResetService;
AuthenticationService _authenticationService;
+
WiFiScanner _wifiScanner;
WiFiStatus _wifiStatus;
NTPStatus _ntpStatus;
diff --git a/lib/framework/ResetService.cpp b/lib/framework/ResetService.cpp
new file mode 100644
index 0000000..660de7d
--- /dev/null
+++ b/lib/framework/ResetService.cpp
@@ -0,0 +1,18 @@
+#include
+
+ResetService::ResetService(AsyncWebServer* server, SecurityManager* securityManager) {
+ server->on(RESET_SERVICE_PATH, HTTP_POST, securityManager->wrapRequest(
+ std::bind(&ResetService::reset, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN
+ ));
+}
+
+void ResetService::reset(AsyncWebServerRequest* request) {
+ request->onDisconnect([]() {
+#if defined(ESP8266)
+ ESP.reset();
+#elif defined(ESP_PLATFORM)
+ ESP.restart();
+#endif
+ });
+ request->send(200);
+}
diff --git a/lib/framework/ResetService.h b/lib/framework/ResetService.h
new file mode 100644
index 0000000..ab9b729
--- /dev/null
+++ b/lib/framework/ResetService.h
@@ -0,0 +1,29 @@
+#ifndef ResetService_h
+#define ResetService_h
+
+#if defined(ESP8266)
+ #include
+ #include
+#elif defined(ESP_PLATFORM)
+ #include
+ #include
+#endif
+
+#include
+#include
+
+#define RESET_SERVICE_PATH "/rest/reset"
+
+class ResetService {
+
+ public:
+
+ ResetService(AsyncWebServer* server, SecurityManager* securityManager);
+
+ private:
+
+ void reset(AsyncWebServerRequest *request);
+
+};
+
+#endif // end ResetService_h
\ No newline at end of file