diff --git a/.eslintrc b/.eslintrc index a993eee292..13453473b1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -48,5 +48,7 @@ "no-trailing-spaces": ["error"], "react/prefer-stateless-function": "off", "react/prop-types": "off", + "jsx-a11y/label-has-for": "off", + "jsx-a11y/label-has-associated-control": "off" } } diff --git a/package-lock.json b/package-lock.json index b3f30290cc..f125607178 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,12 +14,12 @@ } }, "@babel/generator": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.2.tgz", - "integrity": "sha512-70A9HWLS/1RHk3Ck8tNHKxOoKQuSKocYgwDN85Pyl/RBduss6AKxUR7RIZ/lzduQMSYfWEM4DDBu6A+XGbkFig==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz", + "integrity": "sha512-ZoCZGcfIJFJuZBqxcY9OjC1KW2lWK64qrX1o4UYL3yshVhwKFYgzpWZ0vvtGMNJdTlvkw0W+HR1VnYN8q3QPFQ==", "dev": true, "requires": { - "@babel/types": "^7.1.2", + "@babel/types": "^7.1.3", "jsesc": "^2.5.1", "lodash": "^4.17.10", "source-map": "^0.5.0", @@ -131,9 +131,9 @@ } }, "@babel/parser": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.2.tgz", - "integrity": "sha512-x5HFsW+E/nQalGMw7hu+fvPqnBeBaIr0lWJ2SG0PPL2j+Pm9lYvCrsZJGIgauPIENx0v10INIyFjmSNUD/gSqQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz", + "integrity": "sha512-gqmspPZOMW3MIRb9HlrnbZHXI1/KHTOroBwN1NcLL6pWxzqzEKGvRTq0W/PxS45OtQGbaFikSQpkS5zbnsQm2w==", "dev": true }, "@babel/template": { @@ -148,17 +148,17 @@ } }, "@babel/traverse": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.0.tgz", - "integrity": "sha512-bwgln0FsMoxm3pLOgrrnGaXk18sSM9JNf1/nHC/FksmNGFbYnPWY4GYCfLxyP1KRmfsxqkRpfoa6xr6VuuSxdw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz", + "integrity": "sha512-my9mdrAIGdDiSVBuMjpn/oXYpva0/EZwWL3sm3Wcy/AVWO2eXnsoZruOT9jOGNRXU8KbCIu5zsKnXcAJ6PcV6Q==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.0.0", + "@babel/generator": "^7.1.3", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.1.3", + "@babel/types": "^7.1.3", "debug": "^3.1.0", "globals": "^11.1.0", "lodash": "^4.17.10" @@ -188,9 +188,9 @@ } }, "@babel/types": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.2.tgz", - "integrity": "sha512-pb1I05sZEKiSlMUV9UReaqsCPUpgbHHHu2n1piRm7JkuBkm6QxcaIzKu6FMnMtCbih/cEYTR+RGYYC96Yk9HAg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz", + "integrity": "sha512-RpPOVfK+yatXyn8n4PB1NW6k9qjinrXrRR8ugBN8fD6hCy5RXI6PSbVqpOJBO9oSaY7Nom4ohj35feb0UR9hSA==", "requires": { "esutils": "^2.0.2", "lodash": "^4.17.10", @@ -259,20 +259,20 @@ "integrity": "sha512-I9LGoxDR1ezb3GsS4l9XIDd5yv4jUP4X0FkVOIedRe+XN3OSU2zHSUkwCHdM2zKQRxrZyRCvR9vSzF5yUjG8FA==" }, "@patternfly/react-core": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-1.19.1.tgz", - "integrity": "sha512-e7DrOF78CF5D/hqGSCbOqC/Txxqu6OD2z8xDhjcl9JlNVIyIPdLKp4ksRMQ0vKj+ctQtAfWgsfTbduRCyo5L2g==", + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-1.23.0.tgz", + "integrity": "sha512-1AAYdNo2EYdjv6oIglPSde9BWwRXOFw8uL8o9owxCOIhynnMybA/8T0ZvPdbO5DysDsGKHyYHiWvETaEpzUlbg==", "requires": { - "@patternfly/react-icons": "^2.5.0", - "@patternfly/react-styles": "^2.2.0", + "@patternfly/react-icons": "^2.5.1", + "@patternfly/react-styles": "^2.3.0", "@patternfly/react-tokens": "^1.0.0", "exenv": "^1.2.2" } }, "@patternfly/react-icons": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-2.5.0.tgz", - "integrity": "sha512-A+2+hZB+WFPlug/UWCTYEB0DRCyUjgf4tXf8jcanlsUON9mHAfcdWy4CvAxCLCUQHozn4efT1QWtGCLY+iW6zA==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-2.5.1.tgz", + "integrity": "sha512-WCijrkj48gbSAUV7qsf9OiBv1PbO5/Tc8MIHNCPoLVnriAHmzgzH3tNsAKa/ejP4ePYG1Oq8EIFu9OQlwdsjQw==" }, "@patternfly/react-styles": { "version": "2.3.0", @@ -294,9 +294,9 @@ } }, "@patternfly/react-tokens": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-1.5.1.tgz", - "integrity": "sha512-qu+He+tO3p7akte0K75DDhl+8FiSXdAKyos+UBPeB1tlHUAaOfKfve1k0ehjDI9IpVajxauC23ezg35iA+wwIw==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-1.5.2.tgz", + "integrity": "sha512-KpZ9D+x86xUpzznz+Jsa/2H09Dl9UIO9uiNKcWIHwkzNHIO8CA+exKV1R89k9tVkEOScYbDb5JFGVeQin2cmLg==", "optional": true }, "@webassemblyjs/ast": { @@ -904,9 +904,9 @@ } }, "axobject-query": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.1.tgz", - "integrity": "sha1-Bd+nBa2orZ25k/polvItOVsLCgc=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", "dev": true, "requires": { "ast-types-flow": "0.0.7" @@ -1902,7 +1902,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "optional": true, "requires": { "tweetnacl": "^0.14.3" } @@ -2267,9 +2266,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000890", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000890.tgz", - "integrity": "sha512-4NI3s4Y6ROm+SgZN5sLUG4k7nVWQnedis3c/RWkynV5G6cHSY7+a8fwFyn2yoBDE3E6VswhTNNwR3PvzGqlTkg==" + "version": "1.0.30000892", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000892.tgz", + "integrity": "sha512-X9rxMaWZNbJB5qjkDqPtNv/yfViTeUL6ILk0QJNxLV3OhKC5Acn5vxsuUvllR6B48mog8lmS+whwHq/QIYSL9w==" }, "caseless": { "version": "0.12.0", @@ -3209,9 +3208,9 @@ } }, "duplexify": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", + "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -3256,7 +3255,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "optional": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -3269,9 +3267,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.77", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.77.tgz", - "integrity": "sha512-XIfQcdU9L4qUte31fFATwptHodMH0Otf53N8y1AKxd1+79vR+2UYpLq+Z1Zbtbuy+w0xd7KwIUrvlnje/htiOg==" + "version": "1.3.79", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.79.tgz", + "integrity": "sha512-LQdY3j4PxuUl6xfxiFruTSlCniTrTrzAd8/HfsLEMi0PUpaQ0Iy+Pr4N4VllDYjs0Hyu2lkTbvzqlG+PX9NsNw==" }, "elliptic": { "version": "6.4.1", @@ -3415,9 +3413,9 @@ } }, "eslint": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.6.1.tgz", - "integrity": "sha512-hgrDtGWz368b7Wqf+v1Z69O3ZebNR0+GA7PtDdbmuz4rInFVUV9uw7whjZEiWyLzCjVb5Rs5WRN1TAS6eo7AYA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz", + "integrity": "sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -3451,12 +3449,12 @@ "path-is-inside": "^1.0.2", "pluralize": "^7.0.0", "progress": "^2.0.0", - "regexpp": "^2.0.0", + "regexpp": "^2.0.1", "require-uncached": "^1.0.3", "semver": "^5.5.1", "strip-ansi": "^4.0.0", "strip-json-comments": "^2.0.1", - "table": "^4.0.3", + "table": "^5.0.2", "text-table": "^0.2.0" }, "dependencies": { @@ -6037,8 +6035,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdom": { "version": "11.12.0", @@ -6924,9 +6921,9 @@ "dev": true }, "neo-async": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.2.tgz", - "integrity": "sha512-vdqTKI9GBIYcAEbFAcpKPErKINfPF5zIuz3/niBfq8WUZjpT2tytLlFVrBgWdOtqI4uaA/Rb6No0hux39XXDuw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", "dev": true }, "nice-try": { @@ -7062,9 +7059,9 @@ } }, "node-sass": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.3.tgz", - "integrity": "sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.4.tgz", + "integrity": "sha512-MXyurANsUoE4/6KmfMkwGcBzAnJQ5xJBGW7Ei6ea8KnUKuzHr/SguVBIi3uaUAHtZCPUYkvlJ3Ef5T5VAwVpaA==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -7082,7 +7079,7 @@ "nan": "^2.10.0", "node-gyp": "^3.8.0", "npmlog": "^4.0.0", - "request": "2.87.0", + "request": "^2.88.0", "sass-graph": "^2.2.4", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" @@ -7097,65 +7094,6 @@ "lru-cache": "^4.0.1", "which": "^1.2.9" } - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "dev": true, - "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "request": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" - } - }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "dev": true, - "requires": { - "punycode": "^1.4.1" - } } } }, @@ -7807,9 +7745,9 @@ } }, "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, "prelude-ls": { @@ -8159,11 +8097,11 @@ } }, "redux": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.0.tgz", - "integrity": "sha512-NnnHF0h0WVE/hXyrB6OlX67LYRuaf/rJcbWvnHHEPCF/Xa/AZpwhs/20WyqzQae5x4SD2F9nPObgBh2rxAgLiA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz", + "integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==", "requires": { - "loose-envify": "^1.1.0", + "loose-envify": "^1.4.0", "symbol-observable": "^1.2.0" } }, @@ -9102,9 +9040,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz", + "integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -9411,15 +9349,13 @@ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=" }, "table": { - "version": "4.0.3", - "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz", + "integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==", "dev": true, "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", + "ajv": "^6.5.3", + "lodash": "^4.17.10", "slice-ansi": "1.0.0", "string-width": "^2.1.1" }, @@ -9436,26 +9372,6 @@ "uri-js": "^4.2.2" } }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -9467,15 +9383,6 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, @@ -9694,8 +9601,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-check": { "version": "0.3.2", diff --git a/package.json b/package.json index 70d768dab7..7e8aba6089 100644 --- a/package.json +++ b/package.json @@ -33,14 +33,14 @@ "webpack-dev-server": "^3.1.4" }, "dependencies": { + "@patternfly/patternfly-next": "^1.0.58", + "@patternfly/react-core": "1.23.0", "axios": "^0.18.0", "babel-preset-env": "^1.7.0", "react": "^16.4.1", "react-dom": "^16.4.1", "react-redux": "^5.0.7", "react-router-dom": "^4.3.1", - "redux": "^4.0.0", - "@patternfly/patternfly-next": "^1.0.41", - "@patternfly/react-core": "1.19.1" + "redux": "^4.0.0" } } diff --git a/src/App.jsx b/src/App.jsx index 7ff47fd2a3..b1d738f912 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import { render } from 'react-dom'; import { HashRouter as Router, @@ -7,20 +7,29 @@ import { Redirect, Switch, } from 'react-router-dom'; + import { + BackgroundImage, + BackgroundImageSrc, Brand, + Button, + ButtonVariant, Nav, - NavList, NavGroup, NavItem, Page, PageHeader, + PageSection, + PageSectionVariants, PageSidebar, - Title, + TextContent, + Text, Toolbar, ToolbarGroup, - ToolbarItem, + ToolbarItem } from '@patternfly/react-core'; +import { global_breakpoint_md as breakpointMd } from '@patternfly/react-tokens'; +import { css } from '@patternfly/react-styles'; import api from './api'; @@ -47,7 +56,6 @@ import Teams from './pages/Teams'; import Templates from './pages/Templates'; import Users from './pages/Users'; - const AuthenticatedRoute = ({ component: Component, ...rest }) => ( ( api.isAuthenticated() ? ( @@ -61,11 +69,28 @@ const AuthenticatedRoute = ({ component: Component, ...rest }) => ( )}/> ); +const UnauthenticatedRoute = ({ component: Component, ...rest }) => ( + ( + !api.isAuthenticated() ? ( + + ) : ( + + ) + )}/> +); + class App extends React.Component { constructor(props) { super(props); - this.state = { activeItem: 'dashboard', isNavOpen: true }; + this.state = { + activeItem: 'dashboard', + isNavOpen: (typeof window !== 'undefined' && + window.innerWidth >= parseInt(breakpointMd.value, 10)), + }; } onNavToggle = () => { @@ -78,93 +103,107 @@ class App extends React.Component { this.setState({ activeItem: itemId }); }; + onLogoClick = () => { + this.setState({ activeItem: "dashboard" }); + } + + onDevLogout = () => { + api.logout() + .then(() => { + this.setState({ activeItem: "dashboard" }); + }) + } + render() { const { activeItem, isNavOpen } = this.state; + const { logo, loginInfo } = this.props; return ( - - - ( - } - toolbar={( - - - Item 1 - - - Item 2 - Item 3 - - + + + + } /> + ( + } + avatar={} + showNavToggle + onNavToggle={this.onNavToggle} + /> )} - avatar="| avatar" - showNavToggle - onNavToggle={this.onNavToggle} - /> - )} - sidebar={( - - - Dashboard - Jobs - Schedules - My View - - - Templates - Credentials - Projects - Inventories - Inventory Scripts - - - Organizations - Users - Teams - - - Credential Types - Notifications - Management Jobs - Instance Groups - Applications - Settings - - - )} - /> - )}> - - ()} /> - - - - - - - - - - - - - - - - - - - - - )} /> - + sidebar={( + + + Dashboard + Jobs + Schedules + My View + + + Templates + Credentials + Projects + Inventories + Inventory Scripts + + + Organizations + Users + Teams + + + Credential Types + Notifications + Management Jobs + Instance Groups + Applications + Settings + + + )} + /> + )}> + + ()} /> + + + + + + + + + + + + + + + + + + + + + )} /> + + ); } @@ -172,4 +211,9 @@ class App extends React.Component { const el = document.getElementById('app'); -render(, el); +api.getRoot() + .then(({ data }) => { + const { custom_logo, custom_login_info } = data; + + render(, el); + }); diff --git a/src/api.js b/src/api.js index bd3ad42d2d..f442a8b765 100644 --- a/src/api.js +++ b/src/api.js @@ -2,6 +2,7 @@ import axios from 'axios'; const API_ROOT = '/api/'; const API_LOGIN = `${API_ROOT}login/`; +const API_LOGOUT = `${API_ROOT}logout/`; const API_V2 = `${API_ROOT}v2/`; const API_CONFIG = `${API_V2}config/`; const API_PROJECTS = `${API_V2}projects/`; @@ -12,7 +13,6 @@ const CSRF_HEADER_NAME = 'X-CSRFToken'; class APIClient { constructor () { - this.authenticated = false; // temporary this.http = axios.create({ xsrfCookieName: CSRF_COOKIE_NAME, xsrfHeaderName: CSRF_HEADER_NAME, @@ -20,7 +20,15 @@ class APIClient { } isAuthenticated () { - return this.authenticated; + let authenticated = false; + + const parsed = (`; ${document.cookie}`).split('; userLoggedIn='); + + if (parsed.length === 2) { + authenticated = parsed.pop().split(';').shift() === 'true'; + } + + return authenticated; } login (username, password, redirect = API_CONFIG) { @@ -32,16 +40,15 @@ class APIClient { const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; return this.http.get(API_LOGIN, { headers }) - .then(() => this.http.post(API_LOGIN, data, { headers })) - .then(res => { - this.authenticated = true; // temporary - - return res; - }); + .then(() => this.http.post(API_LOGIN, data, { headers })); } logout () { - return this.http.delete(API_LOGIN); + return this.http.get(API_LOGOUT); + } + + getConfig () { + return this.http.get(API_CONFIG); } getProjects () { @@ -51,6 +58,10 @@ class APIClient { getOrganizations () { return this.http.get(API_ORGANIZATIONS); } + + getRoot () { + return this.http.get(API_ROOT); + } } export default new APIClient(); diff --git a/src/app.scss b/src/app.scss index a70ea7fefa..1f6936f527 100644 --- a/src/app.scss +++ b/src/app.scss @@ -1,34 +1,95 @@ +// +// Header +// + .pf-l-page__header { --pf-l-page__header--MinHeight: 0px; display: flex; align-items: center; height: 60px; - background-color: #030303; - } .pf-l-page__header-brand { - --pf-l-page__header-brand--PaddingBottom: 0px; + align-self: center; + height: 60px; + max-width: 190px; + padding: 0px; + margin: 0px; } +.pf-l-page__header-tools { + align-self: center; + height: 60px; + padding-left: 190px; + + .fa-user:hover { + // temporary dev logout + cursor: pointer; + } +} + +.pf-l-toolbar { + align-self: center; + height: 60px; +} + +.pf-l-page__header-brand-link { + align-self: center; +} + +.pf-l-page__header-brand-link img { + transform: scale(1.1, 1.1); + position: relative; + top: 6px; +} + +.pf-l-page__header-brand-toggle { + align-self: center; + position: relative; + right: 14px; + --pf-l-page__header-brand-link--MarginLeft: 0px; + --pf-l-page__header-brand-link--MarginLeft: 0px; + + button { + --pf-l-page__header-sidebar-toggle--FontSize: 18px; + } +} + +// +// Side Navigation +// + +.pf-c-nav { + overflow-y: auto; +} + +.pf-c-nav__section { + --pf-c-nav__section--MarginTop: 8px; +} + +.pf-l-page__sidebar{ + --pf-l-page__sidebar--Width--lg: 190px; +} + +.pf-c-nav__section + .pf-c-nav__section { + --pf-c-nav__section--MarginTop: 8px; +} + +.pf-c-nav__simple-list .pf-c-nav__link { + --pf-c-nav__simple-list-link--PaddingLeft: 24px; + --pf-c-nav__simple-list-link--PaddingBottom: 6px; + --pf-c-nav__simple-list-link--PaddingTop: 6px; +} + +.pf-c-nav__section-title { + --pf-c-nav__section-title--PaddingLeft: 24px; +} + +// +// Page +// + .pf-l-page__main-section { --pf-l-page__main-section--PaddingTop: 11px; --pf-l-page__main-section--PaddingLeft: 11px; } - -.pf-c-nav__section + .pf-c-nav__section { - --pf-c-nav__section--MarginTop: 16px; -} - -.pf-l-page__header-brand-toggle { - padding-bottom: 4px; - padding-right: 0px; -} - -.pf-l-page__header-brand-link { - transform: scale(0.75, 0.75); -} - -.pf-l-page__sidebar{ - --pf-l-page__sidebar--Width--lg: 200px; -} diff --git a/src/components/TowerLogo.jsx b/src/components/TowerLogo/TowerLogo.jsx similarity index 90% rename from src/components/TowerLogo.jsx rename to src/components/TowerLogo/TowerLogo.jsx index c283c91e43..242e77864c 100644 --- a/src/components/TowerLogo.jsx +++ b/src/components/TowerLogo/TowerLogo.jsx @@ -13,9 +13,13 @@ class TowerLogo extends Component { } onClick = () => { + if (!this.props.onClick) return; + const { history } = this.props; history.push('/'); + + this.props.onClick(); }; onHover = () => { @@ -29,7 +33,7 @@ class TowerLogo extends Component { let src = TowerLogoHeader; - if (hover) { + if (hover && this.props.onClick) { src = TowerLogoHeaderHover; } diff --git a/src/components/TowerLogo/index.js b/src/components/TowerLogo/index.js new file mode 100644 index 0000000000..b1ed1985d8 --- /dev/null +++ b/src/components/TowerLogo/index.js @@ -0,0 +1,3 @@ +import TowerLogo from './TowerLogo'; + +export default TowerLogo; diff --git a/src/components/tower-logo-header-hover.svg b/src/components/TowerLogo/tower-logo-header-hover.svg similarity index 100% rename from src/components/tower-logo-header-hover.svg rename to src/components/TowerLogo/tower-logo-header-hover.svg diff --git a/src/components/tower-logo-header.svg b/src/components/TowerLogo/tower-logo-header.svg similarity index 100% rename from src/components/tower-logo-header.svg rename to src/components/TowerLogo/tower-logo-header.svg diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 78e272ab4f..77fb3902a7 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,69 +1,135 @@ import React, { Component } from 'react'; import { Redirect } from 'react-router-dom'; - import { - Bullseye, + Brand, Button, - TextInput + Level, + LevelItem, + Login, + LoginBox, + LoginBoxHeader, + LoginBoxBody, + LoginFooter, + LoginHeaderBrand, + TextInput, } from '@patternfly/react-core'; +import TowerLogo from '../components/TowerLogo'; import api from '../api'; -class Login extends Component { - state = { - username: '', - password: '', - redirect: false, - }; +const LOGIN_ERROR_MESSAGE = 'Invalid username or password. Please try again.'; - handleUsernameChange = value => this.setState({ username: value }); +class LoginPage extends Component { + constructor (props) { + super(props); - handlePasswordChange = value => this.setState({ password: value }); + this.state = { + username: '', + password: '', + redirect: false, + loading: false, + }; + } + + componentWillUnmount () { + this.unmounting = true; // todo: state management + } + + safeSetState = obj => !this.unmounting && this.setState(obj); + + handleUsernameChange = value => this.safeSetState({ username: value, error: '' }); + + handlePasswordChange = value => this.safeSetState({ password: value, error: '' }); handleSubmit = event => { const { username, password } = this.state; event.preventDefault(); + this.safeSetState({ loading: true }); + api.login(username, password) - .then(() => this.setState({ redirect: true })); + .then(() => this.safeSetState({ redirect: true })) + .catch(error => { + if (error.response.status === 401) { + this.safeSetState({ error: LOGIN_ERROR_MESSAGE }); + } + }) + .finally(() => { + this.safeSetState({ loading: false }); + }); } render () { - const { username, password, redirect } = this.state; + const { username, password, redirect, loading, error } = this.state; + const { logo, loginInfo } = this.props; if (redirect) { return (); } return ( - -
-
- -
-
- -
- -
-
+ + {logo ? : } + + )} + footer={{ loginInfo }} + > + + + Welcome to Ansible Tower! Please Sign In. + + +
+
+ + +
+
+ + +
+ + +

+ { error } +

+
+ + + +
+
+
+
+
); } } -export default Login; +export default LoginPage; diff --git a/webpack.config.js b/webpack.config.js index c20a63c814..1791d39837 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -16,26 +16,34 @@ module.exports = { use: [ { loader: 'style-loader' }, { loader: 'css-loader' }, - { - loader: 'sass-loader', - options: { - includePaths: [ - 'node_modules/patternfly/dist/sass', - 'node_modules/patternfly/node_modules/bootstrap-sass/assets/stylesheet', - 'node_modules/patternfly/node_modules/font-awesome-sass/assets/stylesheets' - ] - } - } + { loader: 'sass-loader' }, ] }, { - test: /\.(woff(2)?|ttf|jpg|png|eot|gif|svg)(\?v=\d+\.\d+\.\d+)?$/, + test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/, use: [{ loader: 'file-loader', options: { name: '[name].[ext]', - outputPath: 'fonts/', - publicPatH: '../' + outputPath: 'assets/fonts/', + publicPatH: '../', + includePaths: [ + 'node_modules/@patternfly/patternfly-next/assets/fonts', + ] + } + }] + }, + { + test: /\.(jpg|png|gif|svg)(\?v=\d+\.\d+\.\d+)?$/, + use: [{ + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'assets/images/', + publicPatH: '../', + includePaths: [ + 'node_modules/@patternfly/patternfly-next/assets/images', + ] } }] }