From 0c630f0f93f37e6878eba80eed2ab0c56d0546c4 Mon Sep 17 00:00:00 2001 From: Rick Watson Date: Fri, 24 May 2019 12:19:27 +0100 Subject: [PATCH] Upgrade to material ui 4 Add user management and roles - TBA Menu Label Renames - TBA --- interface/package-lock.json | 571 ++++++++++-------- interface/package.json | 6 +- interface/src/App.js | 13 +- interface/src/AppRouting.js | 4 +- interface/src/components/MenuAppBar.js | 16 +- interface/src/components/SectionContent.js | 2 +- interface/src/containers/APStatus.js | 79 +-- interface/src/containers/ManageUsers.js | 27 +- interface/src/containers/NTPStatus.js | 98 +-- .../{UserConfiguration.js => Security.js} | 6 +- interface/src/containers/WiFiStatus.js | 49 +- interface/src/forms/ManageUsersForm.js | 230 +++++-- interface/src/forms/UserForm.js | 112 ++++ platformio.ini | 7 +- src/SecurityManager.cpp | 38 +- src/SecurityManager.h | 10 +- 16 files changed, 799 insertions(+), 469 deletions(-) rename interface/src/containers/{UserConfiguration.js => Security.js} (62%) create mode 100644 interface/src/forms/UserForm.js diff --git a/interface/package-lock.json b/interface/package-lock.json index f6e0094..ec051b7 100644 --- a/interface/package-lock.json +++ b/interface/package-lock.json @@ -890,68 +890,105 @@ "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==" }, + "@emotion/hash": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.1.tgz", + "integrity": "sha512-OYpa/Sg+2GDX+jibUfpZVn1YqSVRpYmTLF2eyAfrFTIJSbwyIrc+YscayoykvaOME/wV4BV0Sa0yqdMrgse6mA==" + }, "@material-ui/core": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.9.3.tgz", - "integrity": "sha512-REIj62+zEvTgI/C//YL4fZxrCVIySygmpZglsu/Nl5jPqy3CDjZv1F9ubBYorHqmRgeVPh64EghMMWqk4egmfg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.0.0.tgz", + "integrity": "sha512-mLEGTuzgUALRKFI3hkRcS0gi/cB3XV0JA4F5PT3rGUt7Dc4liu8/IGiHF7iQh+p337FMk8vkEMxMVdYd9JXKMQ==", "requires": { "@babel/runtime": "^7.2.0", - "@material-ui/system": "^3.0.0-alpha.0", - "@material-ui/utils": "^3.0.0-alpha.2", - "@types/jss": "^9.5.6", - "@types/react-transition-group": "^2.0.8", - "brcast": "^3.0.1", - "classnames": "^2.2.5", + "@material-ui/styles": "^4.0.0", + "@material-ui/system": "^4.0.0", + "@material-ui/types": "^4.0.0", + "@material-ui/utils": "^4.0.0", + "@types/react-transition-group": "^2.0.16", + "clsx": "^1.0.2", + "convert-css-length": "^1.0.2", "csstype": "^2.5.2", "debounce": "^1.1.0", "deepmerge": "^3.0.0", - "dom-helpers": "^3.2.1", "hoist-non-react-statics": "^3.2.1", "is-plain-object": "^2.0.4", - "jss": "^9.8.7", - "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", "normalize-scroll-left": "^0.1.2", "popper.js": "^1.14.1", - "prop-types": "^15.6.0", - "react-event-listener": "^0.6.2", - "react-transition-group": "^2.2.1", - "recompose": "0.28.0 - 0.30.0", + "prop-types": "^15.7.2", + "react-event-listener": "^0.6.6", + "react-transition-group": "^4.0.0", "warning": "^4.0.1" } }, "@material-ui/icons": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-3.0.2.tgz", - "integrity": "sha512-QY/3gJnObZQ3O/e6WjH+0ah2M3MOgLOzCy8HTUoUx9B6dDrS18vP7Ycw3qrDEKlB6q1KNxy6CZHm5FCauWGy2g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.0.0.tgz", + "integrity": "sha512-hXoKnVLmVer+kic84ypoyG3Amym3a8q3pvDg4KYjeKW9fxGru7x/IkelBJODQL0jO+nAPz1+9RNpFWC75v35dg==", + "requires": { + "@babel/runtime": "^7.2.0" + } + }, + "@material-ui/styles": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.0.0.tgz", + "integrity": "sha512-TUpmXlyZDVOl6E2//+UzsZxgi2E+2L753QY02nNkbAC6PPx8FUBqvnjYSGqX0V/BjTJ/fD4CkoS6ZpY3lHf+Gg==", "requires": { "@babel/runtime": "^7.2.0", - "recompose": "0.28.0 - 0.30.0" + "@emotion/hash": "^0.7.1", + "@material-ui/types": "^4.0.0", + "@material-ui/utils": "^4.0.0", + "clsx": "^1.0.2", + "deepmerge": "^3.0.0", + "hoist-non-react-statics": "^3.2.1", + "jss": "^10.0.0-alpha.16", + "jss-plugin-camel-case": "^10.0.0-alpha.16", + "jss-plugin-default-unit": "^10.0.0-alpha.16", + "jss-plugin-global": "^10.0.0-alpha.16", + "jss-plugin-nested": "^10.0.0-alpha.16", + "jss-plugin-props-sort": "^10.0.0-alpha.16", + "jss-plugin-rule-value-function": "^10.0.0-alpha.16", + "jss-plugin-vendor-prefixer": "^10.0.0-alpha.16", + "prop-types": "^15.7.2", + "warning": "^4.0.1" + }, + "dependencies": { + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", + "requires": { + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + } } }, "@material-ui/system": { - "version": "3.0.0-alpha.2", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-3.0.0-alpha.2.tgz", - "integrity": "sha512-odmxQ0peKpP7RQBQ8koly06YhsPzcoVib1vByVPBH4QhwqBXuYoqlCjt02846fYspAqkrWzjxnWUD311EBbxOA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.0.0.tgz", + "integrity": "sha512-SIsqIwjix98Mqw9LVAmRqTs10E4S/SP5n5mlBlhHVHI+2XG2c+MaCPzOF2Zxq0KdqOMgTb7/aevR3mG9UmODxg==", "requires": { "@babel/runtime": "^7.2.0", "deepmerge": "^3.0.0", - "prop-types": "^15.6.0", + "prop-types": "^15.7.2", "warning": "^4.0.1" } }, + "@material-ui/types": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-4.0.0.tgz", + "integrity": "sha512-wuiQMo8nSljZR1oWh57UQYssdtFqaU+Cbhr16uLohzzTllpCAK4LkH0slnH3n+5vCa2dgOdNlZTrmsIDDwvRJQ==" + }, "@material-ui/utils": { - "version": "3.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-3.0.0-alpha.3.tgz", - "integrity": "sha512-rwMdMZptX0DivkqBuC+Jdq7BYTXwqKai5G5ejPpuEDKpWzi1Oxp+LygGw329FrKpuKeiqpcymlqJTjmy+quWng==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.0.0.tgz", + "integrity": "sha512-gjz52hO1hkIbKPMng1diQybVgtfgCptOCrulUs4emSCHHKUoR1zfT+IUrjgOaKIpYZNOgS/CI7KDMp689+FzeQ==", "requires": { "@babel/runtime": "^7.2.0", - "prop-types": "^15.6.0", - "react-is": "^16.6.3" + "prop-types": "^15.7.2", + "react-is": "^16.8.0" } }, "@mrmlnc/readdir-enhanced": { @@ -1107,24 +1144,15 @@ "loader-utils": "^1.1.0" } }, - "@types/jss": { - "version": "9.5.8", - "resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.8.tgz", - "integrity": "sha512-bBbHvjhm42UKki+wZpR89j73ykSXg99/bhuKuYYePtpma3ZAnmeGnl0WxXiZhPGsIfzKwCUkpPC0jlrVMBfRxA==", - "requires": { - "csstype": "^2.0.0", - "indefinite-observable": "^1.0.1" - } - }, "@types/node": { "version": "11.13.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.4.tgz", "integrity": "sha512-+rabAZZ3Yn7tF/XPGHupKIL5EcAbrLxnTr/hgQICxbeuAfWtT0UZSfULE+ndusckBItcv4o6ZeOJplQikVcLvQ==" }, "@types/prop-types": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.0.tgz", - "integrity": "sha512-eItQyV43bj4rR3JPV0Skpl1SncRCdziTEK9/v8VwXmV6d/qOUO8/EuWeHBbCZcsfSHfzI5UyMJLCSXtxxznyZg==" + "version": "15.7.1", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.1.tgz", + "integrity": "sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==" }, "@types/q": { "version": "1.5.2", @@ -1132,18 +1160,18 @@ "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==" }, "@types/react": { - "version": "16.8.13", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.13.tgz", - "integrity": "sha512-otJ4ntMuHGrvm67CdDJMAls4WqotmAmW0g3HmWi9LCjSWXrxoXY/nHXrtmMfvPEEmGFNm6NdgMsJmnfH820Qaw==", + "version": "16.8.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.18.tgz", + "integrity": "sha512-lUXdKzRqWR4FebR5tGHkLCqnvQJS4fdXKCBrNGGbglqZg2gpU+J82pMONevQODUotATs9fc9k66bx3/St8vReg==", "requires": { "@types/prop-types": "*", "csstype": "^2.2.0" } }, "@types/react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-hP7vUaZMVSWKxo133P8U51U6UZ7+pbY+eAQb8+p6SZ2rB1rj3mOTDgTzhhi+R2SCB4S+sWekAAGoxdiZPG0ReQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.9.1.tgz", + "integrity": "sha512-1usq4DRUVBFnxc9KGJAlJO9EpQrLZGDDEC8wDOn2+2ODSyudYo8FiIzPDRaX/hfQjHqGeeoNaNdA2bj0l35hZQ==", "requires": { "@types/react": "*" } @@ -2686,11 +2714,6 @@ "repeat-element": "^1.1.2" } }, - "brcast": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/brcast/-/brcast-3.0.1.tgz", - "integrity": "sha512-eI3yqf9YEqyGl9PCNTR46MGvDylGtaHjalcz6Q3fAPnP/PhpKkkve52vFdfGpwp4VUvK6LUr4TQN+2stCrEwTg==" - }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", @@ -2960,11 +2983,6 @@ "supports-color": "^5.3.0" } }, - "change-emitter": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz", - "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU=" - }, "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -3616,11 +3634,6 @@ } } }, - "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" - }, "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", @@ -3679,6 +3692,11 @@ "shallow-clone": "^0.1.2" } }, + "clsx": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.0.4.tgz", + "integrity": "sha512-1mQ557MIZTrL/140j+JVdRM6e31/OA4vTYxXgqIIZlndyfjHpyawKZia1Im05Vp9BWmImkcNrNtFYQMyFcgJDg==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -3859,6 +3877,11 @@ "date-now": "^0.1.4" } }, + "console-polyfill": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/console-polyfill/-/console-polyfill-0.1.2.tgz", + "integrity": "sha1-ls/tUcr3gYn2mVcubxgnHcN8DjA=" + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -3879,6 +3902,15 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "convert-css-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/convert-css-length/-/convert-css-length-1.0.2.tgz", + "integrity": "sha512-ecV7j3hXyXN1X2XfJBzhMR0o1Obv0v3nHmn0UiS3ACENrzbxE/EknkiunS/fCwQva0U62X1GChi8GaPh4oTlLg==", + "requires": { + "console-polyfill": "^0.1.2", + "parse-unit": "^1.0.1" + } + }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", @@ -4257,14 +4289,6 @@ "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=" }, - "css-vendor": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz", - "integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=", - "requires": { - "is-in-browser": "^1.0.2" - } - }, "css-what": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", @@ -4449,9 +4473,9 @@ } }, "csstype": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.3.tgz", - "integrity": "sha512-rINUZXOkcBmoHWEyu7JdHu5JMzkGRoMX4ov9830WNgxf5UYxcBUO0QTKAqeJ5EZfSdlrcJYkC8WwfVW7JYi4yg==" + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.4.tgz", + "integrity": "sha512-lAJUJP3M6HxFXbqtGRc0iZrdyeN+WzOWeY0q/VnFzI+kqVrYIzC7bWlKqCW7oCIdzoPkvfp82EVvrTlQ8zsWQg==" }, "cyclist": { "version": "0.2.2", @@ -7993,14 +8017,6 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, - "indefinite-observable": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-1.0.2.tgz", - "integrity": "sha512-Mps0898zEduHyPhb7UCgNmfzlqNZknVmaFz5qzr0mm04YQ5FGLhAyK/dJ+NaRxGyR6juQXIxh5Ev0xx+qq0nYA==", - "requires": { - "symbol-observable": "1.2.0" - } - }, "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", @@ -8230,11 +8246,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, - "is-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", - "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" - }, "is-generator-fn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", @@ -9195,148 +9206,242 @@ } }, "jss": { - "version": "9.8.7", - "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz", - "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==", + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", "requires": { + "@babel/runtime": "^7.3.1", "is-in-browser": "^1.1.3", - "symbol-observable": "^1.1.0", - "warning": "^3.0.0" + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.0-alpha.16.tgz", + "integrity": "sha512-nki+smHEsFyoZ0OlOYtaxVqcQA0ZHVJCE1slRnk+1TklbmxbBiO4TwITMTEaNIDv0U0Uyb0Z8wVgFgRwCCIFog==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.0.0-alpha.16" }, "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", "requires": { - "loose-envify": "^1.0.0" + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" } } } }, - "jss-camel-case": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz", - "integrity": "sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==", + "jss-plugin-compose": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-compose/-/jss-plugin-compose-10.0.0-alpha.16.tgz", + "integrity": "sha512-MeOc5RuDSqB3czoUFM32pBq370+sKKjG1K4aamVWpAUWpsphLi/YlotrFOkk/FCb2So1ga4W7/zrCc/50OeRAQ==", "requires": { - "hyphenate-style-name": "^1.0.2" + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16", + "tiny-warning": "^1.0.2" } }, - "jss-compose": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz", - "integrity": "sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==", + "jss-plugin-default-unit": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.0-alpha.16.tgz", + "integrity": "sha512-jjGW4F/r9yKvoyUk22M8nWhdMfvoWzJw/oFO2cDRXCk2onnWFiRALfqeUsEDyocwdZbyVF9WhZbSHn4GL03kSw==", "requires": { - "warning": "^3.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16" }, "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", "requires": { - "loose-envify": "^1.0.0" + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" } } } }, - "jss-default-unit": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz", - "integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg==" - }, - "jss-expand": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.3.0.tgz", - "integrity": "sha512-NiM4TbDVE0ykXSAw6dfFmB1LIqXP/jdd0ZMnlvlGgEMkMt+weJIl8Ynq1DsuBY9WwkNyzWktdqcEW2VN0RAtQg==" - }, - "jss-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.2.0.tgz", - "integrity": "sha512-YszrmcB6o9HOsKPszK7NeDBNNjVyiW864jfoiHoMlgMIg2qlxKw70axZHqgczXHDcoyi/0/ikP1XaHDPRvYtEA==", + "jss-plugin-expand": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-expand/-/jss-plugin-expand-10.0.0-alpha.16.tgz", + "integrity": "sha512-Q3m0PDWGojfcmWBCkegRJxonq2q9lI6ZfixoFgvTvi+b9zKza0KXkHBUzGjeFyM36U/WRWj43SC33dajcI9jAg==", "requires": { - "warning": "^3.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16" + } + }, + "jss-plugin-extend": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-extend/-/jss-plugin-extend-10.0.0-alpha.16.tgz", + "integrity": "sha512-nJ8H5b/dBZlqaPYCLNmcaHRQgzSlnAwhZUcIo30s0IgvhTtN/TaiRtEbrJZjfXPzatTsnFoRwZzJqs8Sakev+A==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-global": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.0-alpha.16.tgz", + "integrity": "sha512-B1mm2ZF9OEsWPmzkG5ZUXqV88smDqpc4unILLXhWVuj0U5JeT0DNitH+QbXFrSueDJzkWVfvqyckvWDR/0qeDg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16" }, "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", "requires": { - "loose-envify": "^1.0.0" + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" } } } }, - "jss-global": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz", - "integrity": "sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q==" - }, - "jss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz", - "integrity": "sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==", + "jss-plugin-nested": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.0-alpha.16.tgz", + "integrity": "sha512-3l/MB6COnIpq4GOXQFae6UydoaIPa81UxhuBTEQuiAojgTeUla9L7nB3h18Q4zAhQQpjxaEsyppAKuEzIP7kPQ==", "requires": { - "warning": "^3.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16", + "tiny-warning": "^1.0.2" }, "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", "requires": { - "loose-envify": "^1.0.0" + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + } + } + }, + "jss-plugin-props-sort": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.0-alpha.16.tgz", + "integrity": "sha512-+Yn9nugHAH58nf/d43H2uxMvlCFPDgLKRSmKO4Q4m1IGYjMbHsWt1Rk2HfC9IiCanqcqpc8hstwtzf+HG7PWFQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16" + }, + "dependencies": { + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", + "requires": { + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + } + } + }, + "jss-plugin-rule-value-function": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.0-alpha.16.tgz", + "integrity": "sha512-MQap9ne6ZGZH0NlpSQTMSm6QalBTF0hYpd2uaGQwam+GlT7IKeO+sTjd46I1WgO3kyOmwb0pIY6CnuLQGXKtSA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16" + }, + "dependencies": { + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", + "requires": { + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + } + } + }, + "jss-plugin-rule-value-observable": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-observable/-/jss-plugin-rule-value-observable-10.0.0-alpha.16.tgz", + "integrity": "sha512-Gmj1sVKWM2KVZpG0Wn3Z+SArvskdXEtSCrww43g/OO+j8DN9O+UEV47tM/HYfdiyLICnvKHc2XGmhNz9LHcpNQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16", + "symbol-observable": "^1.2.0" + } + }, + "jss-plugin-template": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-template/-/jss-plugin-template-10.0.0-alpha.16.tgz", + "integrity": "sha512-L1epTMTDINJPUZkFuyohCXQtJDTMj1CNTBv9ysqVyMc3qjkifAvPEws6XuoRSC9jy1ZvqDTWlxPfbmoJ2r6BWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.0-alpha.16.tgz", + "integrity": "sha512-70yJ6QE5dN8VlPUGKld5jK2SKyrteheEL/ismexpybIufunMs6iJgkhDndbOfv8ia13yZgUVqeakMdhRKYwK1A==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.1", + "jss": "10.0.0-alpha.16" + }, + "dependencies": { + "css-vendor": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.2.tgz", + "integrity": "sha512-Xn5ZAlI00d8HaQ8/oQ8d+iBzSF//NCc77LPzsucM32X/R/yTqmXy6otVsAM0XleXk6HjPuXoVZwXsayky/fsFQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.0.2" + } + }, + "jss": { + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==", + "requires": { + "@babel/runtime": "^7.3.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" } } } }, "jss-preset-default": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-4.5.0.tgz", - "integrity": "sha512-qZbpRVtHT7hBPpZEBPFfafZKWmq3tA/An5RNqywDsZQGrlinIF/mGD9lmj6jGqu8GrED2SMHZ3pPKLmjCZoiaQ==", + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-10.0.0-alpha.16.tgz", + "integrity": "sha512-YBq2XE4iJdl16klxfw0xTaKksfAIXSoC2kPZQ4dmw4n/KMFOz/A26eN30FwWixyObfDMKyZp94vwCKal7711IQ==", "requires": { - "jss-camel-case": "^6.1.0", - "jss-compose": "^5.0.0", - "jss-default-unit": "^8.0.2", - "jss-expand": "^5.3.0", - "jss-extend": "^6.2.0", - "jss-global": "^3.0.0", - "jss-nested": "^6.0.1", - "jss-props-sort": "^6.0.0", - "jss-template": "^1.0.1", - "jss-vendor-prefixer": "^7.0.0" - } - }, - "jss-props-sort": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz", - "integrity": "sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g==" - }, - "jss-template": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jss-template/-/jss-template-1.0.1.tgz", - "integrity": "sha512-m5BqEWha17fmIVXm1z8xbJhY6GFJxNB9H68GVnCWPyGYfxiAgY9WTQyvDAVj+pYRgrXSOfN5V1T4+SzN1sJTeg==", - "requires": { - "warning": "^3.0.0" - }, - "dependencies": { - "warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, - "jss-vendor-prefixer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz", - "integrity": "sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==", - "requires": { - "css-vendor": "^0.3.8" + "@babel/runtime": "^7.3.1", + "jss": "10.0.0-alpha.16", + "jss-plugin-camel-case": "10.0.0-alpha.16", + "jss-plugin-compose": "10.0.0-alpha.16", + "jss-plugin-default-unit": "10.0.0-alpha.16", + "jss-plugin-expand": "10.0.0-alpha.16", + "jss-plugin-extend": "10.0.0-alpha.16", + "jss-plugin-global": "10.0.0-alpha.16", + "jss-plugin-nested": "10.0.0-alpha.16", + "jss-plugin-props-sort": "10.0.0-alpha.16", + "jss-plugin-rule-value-function": "10.0.0-alpha.16", + "jss-plugin-rule-value-observable": "10.0.0-alpha.16", + "jss-plugin-template": "10.0.0-alpha.16", + "jss-plugin-vendor-prefixer": "10.0.0-alpha.16" } }, "jsx-ast-utils": { @@ -10455,6 +10560,11 @@ "json-parse-better-errors": "^1.0.1" } }, + "parse-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-unit/-/parse-unit-1.0.1.tgz", + "integrity": "sha1-fhu21b7zh0wo45JSaiVBFwKR7s8=" + }, "parse5": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", @@ -13013,6 +13123,11 @@ } } }, + "react-display-name": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.4.tgz", + "integrity": "sha512-zvU6iouW+SWwHTyThwxGICjJYCMZFk/6r/+jmOdC7ntQoPlS/Pqb81MkxaMf2bHTSq9TN3K3zX2/ayMW/jCtyA==" + }, "react-dom": { "version": "16.8.6", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", @@ -13054,22 +13169,17 @@ "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" }, "react-jss": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz", - "integrity": "sha512-SH6XrJDJkAphp602J14JTy3puB2Zxz1FkM3bKVE8wON+va99jnUTKWnzGECb3NfIn9JPR5vHykge7K3/A747xQ==", + "version": "10.0.0-alpha.16", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-10.0.0-alpha.16.tgz", + "integrity": "sha512-nGIerGVDV9V6cpRXhkJZgoV0MsoJbKMdAiCoPzCDnsdR+om6zLyhQEvVHNtd0mB16dO+pzNaovhBvElhdj/3ug==", "requires": { - "hoist-non-react-statics": "^2.5.0", - "jss": "^9.7.0", - "jss-preset-default": "^4.3.0", + "@babel/runtime": "^7.3.1", + "hoist-non-react-statics": "^3.2.0", + "jss": "10.0.0-alpha.16", + "jss-preset-default": "10.0.0-alpha.16", "prop-types": "^15.6.0", - "theming": "^1.3.0" - }, - "dependencies": { - "hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" - } + "theming": "^3.0.3", + "tiny-warning": "^1.0.2" } }, "react-lifecycles-compat": { @@ -13171,14 +13281,13 @@ } }, "react-transition-group": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", - "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.0.1.tgz", + "integrity": "sha512-SsLcBYhO4afXJC9esL8XMxi/y0ZvEc7To0TvtrBELqzpjXQHPZOTxvuPh2/4EhYc0uSMfp2SExIxsyJ0pBdNzg==", "requires": { "dom-helpers": "^3.4.0", "loose-envify": "^1.4.0", - "prop-types": "^15.6.2", - "react-lifecycles-compat": "^3.0.4" + "prop-types": "^15.6.2" } }, "read-pkg": { @@ -13514,26 +13623,6 @@ "util.promisify": "^1.0.0" } }, - "recompose": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.30.0.tgz", - "integrity": "sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w==", - "requires": { - "@babel/runtime": "^7.0.0", - "change-emitter": "^0.1.2", - "fbjs": "^0.8.1", - "hoist-non-react-statics": "^2.3.1", - "react-lifecycles-compat": "^3.0.2", - "symbol-observable": "^1.0.4" - }, - "dependencies": { - "hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" - } - } - }, "recursive-readdir": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", @@ -15184,14 +15273,14 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, "theming": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/theming/-/theming-1.3.0.tgz", - "integrity": "sha512-ya5Ef7XDGbTPBv5ENTwrwkPUexrlPeiAg/EI9kdlUAZhNlRbCdhMKRgjNX1IcmsmiPcqDQZE6BpSaH+cr31FKw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-3.2.0.tgz", + "integrity": "sha512-n0fSNYXkX63rcFBBeAthy14IcgPZLHp0OGkGZheaj64j7cBoP7INLd6+7HIXqWVjFn1M5cYSiZ1nszi+jo/Szg==", "requires": { - "brcast": "^3.0.1", - "is-function": "^1.0.1", - "is-plain-object": "^2.0.1", - "prop-types": "^15.5.8" + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.8", + "react-display-name": "^0.2.4", + "tiny-warning": "^1.0.2" } }, "throat": { diff --git a/interface/package.json b/interface/package.json index 7806e30..bd55442 100644 --- a/interface/package.json +++ b/interface/package.json @@ -3,8 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { - "@material-ui/core": "^3.9.3", - "@material-ui/icons": "^3.0.2", + "@material-ui/core": "^4.0.0", + "@material-ui/icons": "^4.0.0", "compression-webpack-plugin": "^2.0.0", "jwt-decode": "^2.2.0", "moment": "^2.24.0", @@ -12,7 +12,7 @@ "react": "^16.8.6", "react-dom": "^16.8.6", "react-form-validator-core": "^0.6.2", - "react-jss": "^8.6.1", + "react-jss": "^10.0.0-alpha.16", "react-material-ui-form-validator": "^2.0.7", "react-router": "^5.0.0", "react-router-dom": "^5.0.0", diff --git a/interface/src/App.js b/interface/src/App.js index 25be835..1f5a7e2 100644 --- a/interface/src/App.js +++ b/interface/src/App.js @@ -10,14 +10,12 @@ 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 JssProvider from 'react-jss/lib/JssProvider'; import { create } from 'jss'; +import { StylesProvider, jssPreset } from '@material-ui/styles'; import { MuiThemeProvider, - createMuiTheme, - createGenerateClassName, - jssPreset, + createMuiTheme } from '@material-ui/core/styles'; // Our theme @@ -35,20 +33,17 @@ const theme = createMuiTheme({ // JSS instance const jss = create(jssPreset()); -// Class name generator. -const generateClassName = createGenerateClassName(); - class App extends Component { render() { return ( - + - + ) } } diff --git a/interface/src/AppRouting.js b/interface/src/AppRouting.js index 8a90d68..cda03d2 100644 --- a/interface/src/AppRouting.js +++ b/interface/src/AppRouting.js @@ -14,7 +14,7 @@ import NTPConfiguration from './containers/NTPConfiguration'; import OTAConfiguration from './containers/OTAConfiguration'; import APConfiguration from './containers/APConfiguration'; import SignInPage from './containers/SignInPage'; -import UserConfiguration from './containers/UserConfiguration'; +import Security from './containers/Security'; class AppRouting extends Component { @@ -31,7 +31,7 @@ class AppRouting extends Component { - + diff --git a/interface/src/components/MenuAppBar.js b/interface/src/components/MenuAppBar.js index 4dd461e..1357279 100644 --- a/interface/src/components/MenuAppBar.js +++ b/interface/src/components/MenuAppBar.js @@ -22,7 +22,7 @@ import SystemUpdateIcon from '@material-ui/icons/SystemUpdate'; import AccessTimeIcon from '@material-ui/icons/AccessTime'; import AccountCircleIcon from '@material-ui/icons/AccountCircle'; import SettingsInputAntennaIcon from '@material-ui/icons/SettingsInputAntenna'; -import PeopleIcon from '@material-ui/icons/People'; +import LockIcon from '@material-ui/icons/Lock'; import { APP_NAME } from '../constants/App'; import { withAuthenticationContext } from '../authentication/Context.js'; @@ -112,31 +112,31 @@ class MenuAppBar extends React.Component { - + - + - + - + - + - + - + diff --git a/interface/src/components/SectionContent.js b/interface/src/components/SectionContent.js index 18bdf96..0881112 100644 --- a/interface/src/components/SectionContent.js +++ b/interface/src/components/SectionContent.js @@ -16,7 +16,7 @@ function SectionContent(props) { const { children, classes, title } = props; return ( - + {title} {children} diff --git a/interface/src/containers/APStatus.js b/interface/src/containers/APStatus.js index fd935bc..41d9abe 100644 --- a/interface/src/containers/APStatus.js +++ b/interface/src/containers/APStatus.js @@ -7,17 +7,18 @@ import Typography from '@material-ui/core/Typography'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemText from '@material-ui/core/ListItemText'; +import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import Avatar from '@material-ui/core/Avatar'; 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 {restComponent} from '../components/RestComponent'; +import { restComponent } from '../components/RestComponent'; import SectionContent from '../components/SectionContent' import * as Highlight from '../constants/Highlight'; -import { AP_STATUS_ENDPOINT } from '../constants/Endpoints'; +import { AP_STATUS_ENDPOINT } from '../constants/Endpoints'; const styles = theme => ({ ["apStatus_" + Highlight.SUCCESS]: { @@ -42,40 +43,48 @@ class APStatus extends Component { this.props.loadData(); } - apStatusHighlight(data){ + apStatusHighlight(data) { return data.active ? Highlight.SUCCESS : Highlight.IDLE; } - apStatus(data){ + apStatus(data) { return data.active ? "Active" : "Inactive"; } - createListItems(data, classes){ + createListItems(data, classes) { return ( - - - + + + + + - IP + + IP + - - - + + + + + - - - + + + + + @@ -83,8 +92,8 @@ class APStatus extends Component { ); } - renderAPStatus(data, classes){ - return ( + renderAPStatus(data, classes) { + return (
@@ -99,30 +108,30 @@ class APStatus extends Component { } render() { - const { data, fetched, errorMessage, classes } = this.props; + const { data, fetched, errorMessage, classes } = this.props; return ( { - !fetched ? -
- - - Loading... + !fetched ? +
+ + + Loading... -
- : - data ? this.renderAPStatus(data, classes) - : -
- - {errorMessage} - -
+ : + data ? this.renderAPStatus(data, classes) + : +
+ + {errorMessage} + + -
- } +
+ }
) } diff --git a/interface/src/containers/ManageUsers.js b/interface/src/containers/ManageUsers.js index d2f17a3..1a69f1f 100644 --- a/interface/src/containers/ManageUsers.js +++ b/interface/src/containers/ManageUsers.js @@ -1,30 +1,27 @@ import React, { Component } from 'react'; -import { USERS_ENDPOINT } from '../constants/Endpoints'; -import {restComponent} from '../components/RestComponent'; -import SectionContent from '../components/SectionContent'; +import { USERS_ENDPOINT } from '../constants/Endpoints'; +import { restComponent } from '../components/RestComponent'; import ManageUsersForm from '../forms/ManageUsersForm'; class ManageUsers extends Component { componentDidMount() { - this.props.loadData(); + this.props.loadData(); } render() { const { data, fetched, errorMessage } = this.props; return ( - - - + ) } diff --git a/interface/src/containers/NTPStatus.js b/interface/src/containers/NTPStatus.js index 6117c64..0ddee74 100644 --- a/interface/src/containers/NTPStatus.js +++ b/interface/src/containers/NTPStatus.js @@ -6,6 +6,7 @@ import LinearProgress from '@material-ui/core/LinearProgress'; import Typography from '@material-ui/core/Typography'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; +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'; @@ -16,10 +17,10 @@ import TimerIcon from '@material-ui/icons/Timer'; import UpdateIcon from '@material-ui/icons/Update'; import AvTimerIcon from '@material-ui/icons/AvTimer'; -import { isSynchronized, ntpStatusHighlight, ntpStatus } from '../constants/NTPStatus'; +import { isSynchronized, ntpStatusHighlight, ntpStatus } from '../constants/NTPStatus'; import * as Highlight from '../constants/Highlight'; import { unixTimeToTimeAndDate } from '../constants/TimeFormat'; -import { NTP_STATUS_ENDPOINT } from '../constants/Endpoints'; +import { NTP_STATUS_ENDPOINT } from '../constants/Endpoints'; import { restComponent } from '../components/RestComponent'; import SectionContent from '../components/SectionContent'; @@ -51,52 +52,61 @@ class NTPStatus extends Component { this.props.loadData(); } - createListItems(data, classes){ + createListItems(data, classes) { return ( - - - - + + + + + + - { isSynchronized(data) && + {isSynchronized(data) && - - - + + + + + - - - - 0 ? unixTimeToTimeAndDate(data.last_sync) : "never" } /> + + + + + 0 ? unixTimeToTimeAndDate(data.last_sync) : "never"} /> } - - - + + + + + - - - + + + + - - - + + + + @@ -104,8 +114,8 @@ class NTPStatus extends Component { ); } - renderNTPStatus(data, classes){ - return ( + renderNTPStatus(data, classes) { + return (
{this.createListItems(data, classes)} @@ -118,30 +128,30 @@ class NTPStatus extends Component { } render() { - const { data, fetched, errorMessage, classes } = this.props; + const { data, fetched, errorMessage, classes } = this.props; return ( { - !fetched ? -
- - - Loading... + !fetched ? +
+ + + Loading... -
- : - data ? this.renderNTPStatus(data, classes) - : -
- - {errorMessage} - -
+ : + data ? this.renderNTPStatus(data, classes) + : +
+ + {errorMessage} + + -
- } +
+ }
) } diff --git a/interface/src/containers/UserConfiguration.js b/interface/src/containers/Security.js similarity index 62% rename from interface/src/containers/UserConfiguration.js rename to interface/src/containers/Security.js index 4a5b576..0eaf6d6 100644 --- a/interface/src/containers/UserConfiguration.js +++ b/interface/src/containers/Security.js @@ -2,14 +2,14 @@ import React, { Component } from 'react'; import MenuAppBar from '../components/MenuAppBar'; import ManageUsers from './ManageUsers'; -class UserConfiguration extends Component { +class Security extends Component { render() { return ( - + ) } } -export default UserConfiguration +export default Security diff --git a/interface/src/containers/WiFiStatus.js b/interface/src/containers/WiFiStatus.js index c779898..9cdac05 100644 --- a/interface/src/containers/WiFiStatus.js +++ b/interface/src/containers/WiFiStatus.js @@ -8,6 +8,7 @@ import Typography from '@material-ui/core/Typography'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemText from '@material-ui/core/ListItemText'; +import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import Avatar from '@material-ui/core/Avatar'; import Divider from '@material-ui/core/Divider'; @@ -63,9 +64,11 @@ class WiFiStatus extends Component { return ( - - - + + + + + @@ -73,40 +76,52 @@ class WiFiStatus extends Component { isConnected(data) && - - - + + + + + - IP + + IP + - - - + + + + + - # + + # + - - - + + + + + - - - + + + + + diff --git a/interface/src/forms/ManageUsersForm.js b/interface/src/forms/ManageUsersForm.js index 1d9163f..e86cd4a 100644 --- a/interface/src/forms/ManageUsersForm.js +++ b/interface/src/forms/ManageUsersForm.js @@ -1,23 +1,26 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { ValidatorForm } from 'react-material-ui-form-validator'; +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; import { withStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; import LinearProgress from '@material-ui/core/LinearProgress'; import Typography from '@material-ui/core/Typography'; - import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; import TableCell from '@material-ui/core/TableCell'; +import TableFooter from '@material-ui/core/TableFooter'; import TableHead from '@material-ui/core/TableHead'; import TableRow from '@material-ui/core/TableRow'; -import IconButton from '@material-ui/core/IconButton'; +import Chip from '@material-ui/core/Chip'; import EditIcon from '@material-ui/icons/Edit'; import DeleteIcon from '@material-ui/icons/Delete'; -import Chip from '@material-ui/core/Chip'; +import IconButton from '@material-ui/core/IconButton'; + +import SectionContent from '../components/SectionContent'; +import UserForm from './UserForm'; const styles = theme => ({ loadingSettings: { @@ -43,95 +46,198 @@ const styles = theme => ({ margin: theme.spacing.unit, }, table: { - '& td, & th': {padding: theme.spacing.unit} - } + '& td, & th': { padding: theme.spacing.unit } + }, + actions: { + color: theme.palette.text.secondary, + } }); +function compareUsers(a, b) { + if (a.username < b.username) { + return -1; + } + if (a.username > b.username) { + return 1; + } + return 0; +} + class ManageUsersForm extends React.Component { - render() { - const { classes, users, usersFetched, errorMessage, onSubmit, onReset } = this.props; - return ( -
- { - !usersFetched ? + constructor(props) { + super(props); + this.state = {}; + } + createUser = () => { + this.setState({ + creating: true, + user: { + username: "", + password: "", + roles: [] + } + }); + }; + + uniqueUsername = username => { + return !this.props.userData.users.find(u => u.username === username); + } + + usersValid = username => { + return !!this.props.userData.users.find(u => u.roles.includes("admin")); + } + + startEditingUser = user => { + this.setState({ + creating: false, + user + }); + }; + + cancelEditingUser = () => { + this.setState({ + user: undefined + }); + } + + sortedUsers(users) { + return users.sort(compareUsers); + } + + doneEditingUser = () => { + const { user } = this.state; + const { userData } = this.props; + let { users } = userData; + users = users.filter(u => u.username !== user.username); + users.push(user); + this.props.setData({ ...userData, users }); + this.setState({ + user: undefined + }); + }; + + handleUserValueChange = name => event => { + const { user } = this.state; + if (user) { + this.setState({ + user: { + ...user, [name]: event.target.value + } + }); + } + }; + + render() { + const { classes, userData, userDataFetched, errorMessage, onSubmit, onReset, handleValueChange } = this.props; + const { user, creating } = this.state; + return ( + + { + !userDataFetched ?
Loading...
- - : users ? - - - - - - Username - Password - Role(s) - Action - - - - {users.users.map(user => ( - - - {user.username} - - {user.password} - - + : + userData ? + user ? + + : + +
+ + + Username + Role(s) + Action + + + + {this.sortedUsers(userData.users).map(user => ( + + + {user.username} + + + { + user.roles.map(role => ( + + )) + } + + + + + + this.startEditingUser(user)}> + + + + + ))} + + + + + { + !this.usersValid() && + + You must have at least one admin user configured. + + } - - - - - - + - ))} - -
- - - - -
- + + + + + : - -
+ {errorMessage} -
+ +
} -
+ ); } + } ManageUsersForm.propTypes = { classes: PropTypes.object.isRequired, - users: PropTypes.object, - usersFetched: PropTypes.bool.isRequired, + userData: PropTypes.object, + userDataFetched: PropTypes.bool.isRequired, errorMessage: PropTypes.string, onSubmit: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired, - handleValueChange: PropTypes.func.isRequired, - handleCheckboxChange: PropTypes.func.isRequired, + setData: PropTypes.func.isRequired, + handleValueChange: PropTypes.func.isRequired }; export default withStyles(styles)(ManageUsersForm); diff --git a/interface/src/forms/UserForm.js b/interface/src/forms/UserForm.js new file mode 100644 index 0000000..99785a7 --- /dev/null +++ b/interface/src/forms/UserForm.js @@ -0,0 +1,112 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { withStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; + +import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; +import PasswordValidator from '../components/PasswordValidator'; + +import Input from '@material-ui/core/Input'; +import InputLabel from '@material-ui/core/InputLabel'; +import MenuItem from '@material-ui/core/MenuItem'; +import FormControl from '@material-ui/core/FormControl'; +import Select from '@material-ui/core/Select'; +import Chip from '@material-ui/core/Chip'; + +const styles = theme => ({ + textField: { + width: "100%" + }, + checkboxControl: { + width: "100%" + }, + chips: { + display: 'flex', + flexWrap: 'wrap', + }, + chip: { + marginRight: theme.spacing.unit, + }, + button: { + marginRight: theme.spacing.unit * 2, + marginTop: theme.spacing.unit * 2, + } +}); + +class UserForm extends React.Component { + + componentWillMount() { + ValidatorForm.addValidationRule('uniqueUsername', this.props.uniqueUsername); + } + + render() { + const { classes, user, roles, creating, handleValueChange, onDoneEditing, onCancelEditing } = this.props; + return ( + + + + + Roles + + + + + + ); + } +} + +UserForm.propTypes = { + classes: PropTypes.object.isRequired, + user: PropTypes.object.isRequired, + creating: PropTypes.bool.isRequired, + roles: PropTypes.array.isRequired, + onDoneEditing: PropTypes.func.isRequired, + onCancelEditing: PropTypes.func.isRequired, + uniqueUsername: PropTypes.func.isRequired, + handleValueChange: PropTypes.func.isRequired +}; + +export default withStyles(styles)(UserForm); diff --git a/platformio.ini b/platformio.ini index 7a152e2..37d9480 100644 --- a/platformio.ini +++ b/platformio.ini @@ -7,10 +7,9 @@ ; ; Please visit documentation for the other options and examples ; http://docs.platformio.org/page/projectconf.html -[env:esp12e] -platform = espressif8266 -board = esp12e -board_build.f_cpu = 160000000L +[env:node32s] +platform = espressif32 +board = node32s framework = arduino ;upload_flags = --port=8266 --auth=esp-react diff --git a/src/SecurityManager.cpp b/src/SecurityManager.cpp index 7d6b854..52a2c3a 100644 --- a/src/SecurityManager.cpp +++ b/src/SecurityManager.cpp @@ -1,9 +1,6 @@ #include -SecurityManager::SecurityManager(AsyncWebServer* server, FS* fs) : SettingsPersistence(fs, SECURITY_SETTINGS_FILE) { - server->on(USERS_PATH, HTTP_GET, std::bind(&SecurityManager::fetchUsers, this, std::placeholders::_1)); -} - +SecurityManager::SecurityManager(AsyncWebServer* server, FS* fs) : SettingsService(server, fs, USERS_PATH, SECURITY_SETTINGS_FILE) {} SecurityManager::~SecurityManager() {} void SecurityManager::readFromJsonObject(JsonObject& root) { @@ -22,16 +19,19 @@ void SecurityManager::readFromJsonObject(JsonObject& root) { // users _users.clear(); if (root["users"].is()) { - JsonArray users = root["users"]; - for (JsonVariant user : users) { - String username = user["username"]; - String password = user["password"]; - String role = user["role"]; - _users.push_back(User(username, password, role)); + for (JsonVariant user : root["users"].as()) { + std::list roles; + if (user["roles"].is()) { + for (JsonVariant role : user["roles"].as()) { + roles.push_back(role.as()); + } + } + _users.push_back(User(user["username"], user["password"], roles)); } } } + void SecurityManager::writeToJsonObject(JsonObject& root) { // secret root["jwt_secret"] = _jwtSecret; @@ -48,18 +48,13 @@ void SecurityManager::writeToJsonObject(JsonObject& root) { JsonObject user = users.createNestedObject(); user["username"] = _user.getUsername(); user["password"] = _user.getPassword(); - user["role"] = _user.getRole(); + JsonArray roles = user.createNestedArray("roles"); + for (String _role : _user.getRoles()){ + roles.add(_role); + } } } -void SecurityManager::fetchUsers(AsyncWebServerRequest *request) { - AsyncJsonResponse * response = new AsyncJsonResponse(MAX_USERS_SIZE); - JsonObject jsonObject = response->getRoot(); - writeToJsonObject(jsonObject); - response->setLength(); - request->send(response); -} - void SecurityManager::begin() { // read config readFromFS(); @@ -105,7 +100,10 @@ Authentication SecurityManager::authenticate(String username, String password) { inline void populateJWTPayload(JsonObject &payload, User *user) { payload["username"] = user->getUsername(); - payload["role"] = user->getRole(); + JsonArray roles = payload.createNestedArray("roles"); + for (String _role : user->getRoles()){ + roles.add(_role); + } } boolean SecurityManager::validatePayload(JsonObject &parsedPayload, User *user) { diff --git a/src/SecurityManager.h b/src/SecurityManager.h index 853571e..f12ac0a 100644 --- a/src/SecurityManager.h +++ b/src/SecurityManager.h @@ -28,17 +28,17 @@ class User { private: String _username; String _password; - String _role; + std::list _roles; public: - User(String username, String password, String role): _username(username), _password(password), _role(role) {} + User(String username, String password, std::list roles): _username(username), _password(password), _roles(roles) {} String getUsername() { return _username; } String getPassword() { return _password; } - String getRole() { - return _role; + std::list getRoles() { + return _roles; } }; @@ -62,7 +62,7 @@ class Authentication { } }; -class SecurityManager : public SettingsPersistence { +class SecurityManager : public SettingsService { public: