Merge pull request #7305 from jlmitch5/pfv4upgrade

patternfly v4 upgrade

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2020-06-23 14:07:07 +00:00
committed by GitHub
125 changed files with 1335 additions and 1834 deletions

View File

@@ -1150,31 +1150,6 @@
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
}, },
"@emotion/babel-utils": {
"version": "0.6.10",
"resolved": "https://registry.npmjs.org/@emotion/babel-utils/-/babel-utils-0.6.10.tgz",
"integrity": "sha512-/fnkM/LTEp3jKe++T0KyTszVGWNKPNOUJfjNKLO17BzQ6QPxgbg3whayom1Qr2oLFH3V92tDymU+dT5q676uow==",
"requires": {
"@emotion/hash": "^0.6.6",
"@emotion/memoize": "^0.6.6",
"@emotion/serialize": "^0.9.1",
"convert-source-map": "^1.5.1",
"find-root": "^1.1.0",
"source-map": "^0.7.2"
},
"dependencies": {
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
}
}
},
"@emotion/hash": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.6.6.tgz",
"integrity": "sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ=="
},
"@emotion/is-prop-valid": { "@emotion/is-prop-valid": {
"version": "0.8.8", "version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
@@ -1190,50 +1165,6 @@
} }
} }
}, },
"@emotion/memoize": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.6.tgz",
"integrity": "sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ=="
},
"@emotion/serialize": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.9.1.tgz",
"integrity": "sha512-zTuAFtyPvCctHBEL8KZ5lJuwBanGSutFEncqLn/m9T1a6a93smBStK+bZzcNPgj4QS8Rkw9VTwJGhRIUVO8zsQ==",
"requires": {
"@emotion/hash": "^0.6.6",
"@emotion/memoize": "^0.6.6",
"@emotion/unitless": "^0.6.7",
"@emotion/utils": "^0.8.2"
}
},
"@emotion/stylis": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.7.1.tgz",
"integrity": "sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ=="
},
"@emotion/unitless": {
"version": "0.6.7",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.6.7.tgz",
"integrity": "sha512-Arj1hncvEVqQ2p7Ega08uHLr1JuRYBuO5cIvcA+WWEQ5+VmkOE3ZXzl04NbQxeQpWX78G7u6MqxKuNX3wvYZxg=="
},
"@emotion/utils": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.8.2.tgz",
"integrity": "sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw=="
},
"@fortawesome/fontawesome-common-types": {
"version": "0.2.28",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.28.tgz",
"integrity": "sha512-gtis2/5yLdfI6n0ia0jH7NJs5i/Z/8M/ZbQL6jXQhCthEOe5Cr5NcQPhgTvFxNOtURE03/ZqUcEskdn2M+QaBg=="
},
"@fortawesome/free-brands-svg-icons": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.13.0.tgz",
"integrity": "sha512-/6xXiJFCMEQxqxXbL0FPJpwq5Cv6MRrjsbJEmH/t5vOvB4dILDpnY0f7zZSlA8+TG7jwlt12miF/yZpZkykucA==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.28"
}
},
"@hapi/address": { "@hapi/address": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
@@ -1704,62 +1635,45 @@
"dev": true "dev": true
}, },
"@patternfly/patternfly": { "@patternfly/patternfly": {
"version": "2.71.6", "version": "4.10.31",
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-2.71.6.tgz", "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.10.31.tgz",
"integrity": "sha512-mqqtuCVa+/FbyyK8hSAcfEIwNX73+zbnzHpmC4NrW0kyMzSszPtBqev/ZO79ZxGqZUpLOyUBTVaH7oKn8cL35Q==" "integrity": "sha512-UxdZ/apWRowXYZ5qPz5LPfXwyB4YGpomrCJPX7c36+Zg8jFpYyVqgVYainL8Yf/GrChtC2LKyoHg7UUTtMtp4A=="
}, },
"@patternfly/react-core": { "@patternfly/react-core": {
"version": "3.158.1", "version": "4.18.14",
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-3.158.1.tgz", "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.18.14.tgz",
"integrity": "sha512-LUknvaIBoo0ftu7OBZhyGn7Cu3IfhaO4nXx17M99OYc76yKBv1jJMmTTUh7OX3QyWH961gH1K7Z3GlJV7v57ZA==", "integrity": "sha512-aFOBX02ud78eCu7rtbUTr+Rj/J7BertxDssSWFb+uDQrUN268dSH9/tvHcDd3//YZrsCoBbky9ngRa4Jt1fryg==",
"requires": { "requires": {
"@patternfly/react-icons": "^3.15.17", "@patternfly/react-icons": "^4.3.6",
"@patternfly/react-styles": "^3.7.14", "@patternfly/react-styles": "^4.3.6",
"@patternfly/react-tokens": "^2.8.14", "@patternfly/react-tokens": "^4.4.5",
"focus-trap": "4.0.2", "focus-trap": "4.0.2",
"react-dropzone": "9.0.0", "react-dropzone": "9.0.0",
"tippy.js": "5.1.2" "tippy.js": "5.1.2",
"tslib": "^1.11.1"
}, },
"dependencies": { "dependencies": {
"@patternfly/react-icons": { "@patternfly/react-icons": {
"version": "3.15.17", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-3.15.17.tgz", "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.4.0.tgz",
"integrity": "sha512-Q0JAlxEvSAl5kcMSUMItLiKi9fweO941g5+lS45t3o/Rv4Eg91Ig7AyK1YWw6m1ah+/eHslLfox0Uqw7m7usLg==", "integrity": "sha512-UKQI5luZ6Bd3SLljl4WNFVhtteUiM2lbKz5qjgBZn3zLOW2Zigv6M1zkgII6rMW9Rxql/UEDZkvNmilf84HW+g=="
"requires": {
"@fortawesome/free-brands-svg-icons": "^5.8.1"
}
},
"@patternfly/react-tokens": {
"version": "2.8.14",
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-2.8.14.tgz",
"integrity": "sha512-pha0XyZ3ZiXuQoKstuFsiEHARFQKUFsS6WxVuRSEyNbGTToRNJkKR9cW5swzHgXK6Fuw5EA2XFHLuu8osj52KA=="
} }
} }
}, },
"@patternfly/react-icons": { "@patternfly/react-icons": {
"version": "3.15.17", "version": "4.3.5",
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-3.15.17.tgz", "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.3.5.tgz",
"integrity": "sha512-Q0JAlxEvSAl5kcMSUMItLiKi9fweO941g5+lS45t3o/Rv4Eg91Ig7AyK1YWw6m1ah+/eHslLfox0Uqw7m7usLg==", "integrity": "sha512-+GublxpFXR+y/5zygf9q00/LvIvso8jr0mxZGhVxsKmi2dUu7xAvN+T+5vjS9fiMbXf7WXsSPXST/UTiBIVTdQ=="
"requires": {
"@fortawesome/free-brands-svg-icons": "^5.8.1"
}
}, },
"@patternfly/react-styles": { "@patternfly/react-styles": {
"version": "3.7.14", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-3.7.14.tgz", "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.4.0.tgz",
"integrity": "sha512-NVwbPP9JroulfQgj0LOLWKP4DumArW8RrP1FB1lLOCuw13KkuAcFbLN9MSF8ZBwJ8syxGEdux5mDC3jPjsrQiw==", "integrity": "sha512-0guVqVVvLgDMKAqLM9Vb3T9sjSPBGm9DzTURuZrIz/gx9gKuckSA42OS1aTTtZLXz6ryYoOn7uQJiIhaJu1F0Q=="
"requires": {
"camel-case": "^3.0.0",
"css": "^2.2.3",
"cssstyle": "^0.3.1",
"emotion": "^9.2.9",
"emotion-server": "^9.2.9"
}
}, },
"@patternfly/react-tokens": { "@patternfly/react-tokens": {
"version": "2.8.14", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-2.8.14.tgz", "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.5.0.tgz",
"integrity": "sha512-pha0XyZ3ZiXuQoKstuFsiEHARFQKUFsS6WxVuRSEyNbGTToRNJkKR9cW5swzHgXK6Fuw5EA2XFHLuu8osj52KA==" "integrity": "sha512-cfxWduAIIFuRnuTuTkColGCoGPmdXy2ousabpGd+Yi3vbwWcWYIRlrLuetK1VMmddnt2PW9PnaLDW6bH3+oagQ=="
}, },
"@sheerun/mutationobserver-shim": { "@sheerun/mutationobserver-shim": {
"version": "0.3.3", "version": "0.3.3",
@@ -2565,11 +2479,6 @@
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==" "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg=="
}, },
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"accepts": { "accepts": {
"version": "1.3.7", "version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@@ -3180,32 +3089,6 @@
"object.assign": "^4.1.0" "object.assign": "^4.1.0"
} }
}, },
"babel-plugin-emotion": {
"version": "9.2.11",
"resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz",
"integrity": "sha512-dgCImifnOPPSeXod2znAmgc64NhaaOjGEHROR/M+lmStb3841yK1sgaDYAYMnlvWNz8GnpwIPN0VmNpbWYZ+VQ==",
"requires": {
"@babel/helper-module-imports": "^7.0.0",
"@emotion/babel-utils": "^0.6.4",
"@emotion/hash": "^0.6.2",
"@emotion/memoize": "^0.6.1",
"@emotion/stylis": "^0.7.0",
"babel-plugin-macros": "^2.0.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"convert-source-map": "^1.5.0",
"find-root": "^1.1.0",
"mkdirp": "^0.5.1",
"source-map": "^0.5.7",
"touch": "^2.0.1"
},
"dependencies": {
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
}
}
},
"babel-plugin-istanbul": { "babel-plugin-istanbul": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz",
@@ -3293,7 +3176,7 @@
}, },
"babel-plugin-syntax-jsx": { "babel-plugin-syntax-jsx": {
"version": "6.18.0", "version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", "resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
}, },
"babel-plugin-syntax-object-rest-spread": { "babel-plugin-syntax-object-rest-spread": {
@@ -3735,7 +3618,7 @@
}, },
"browserify-aes": { "browserify-aes": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"requires": { "requires": {
"buffer-xor": "^1.0.3", "buffer-xor": "^1.0.3",
@@ -3769,7 +3652,7 @@
}, },
"browserify-rsa": { "browserify-rsa": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
"requires": { "requires": {
"bn.js": "^4.1.0", "bn.js": "^4.1.0",
@@ -3867,11 +3750,6 @@
} }
} }
}, },
"buffer-from": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz",
"integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg=="
},
"buffer-indexof": { "buffer-indexof": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
@@ -3976,15 +3854,6 @@
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
}, },
"camel-case": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
"integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
"requires": {
"no-case": "^2.2.0",
"upper-case": "^1.1.1"
}
},
"camelcase": { "camelcase": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@@ -4633,33 +4502,9 @@
} }
} }
}, },
"create-emotion": {
"version": "9.2.12",
"resolved": "https://registry.npmjs.org/create-emotion/-/create-emotion-9.2.12.tgz",
"integrity": "sha512-P57uOF9NL2y98Xrbl2OuiDQUZ30GVmASsv5fbsjF4Hlraip2kyAvMm+2PoYUvFFw03Fhgtxk3RqZSm2/qHL9hA==",
"requires": {
"@emotion/hash": "^0.6.2",
"@emotion/memoize": "^0.6.1",
"@emotion/stylis": "^0.7.0",
"@emotion/unitless": "^0.6.2",
"csstype": "^2.5.2",
"stylis": "^3.5.0",
"stylis-rule-sheet": "^0.0.10"
}
},
"create-emotion-server": {
"version": "9.2.12",
"resolved": "https://registry.npmjs.org/create-emotion-server/-/create-emotion-server-9.2.12.tgz",
"integrity": "sha512-ET+E6A5MkQTEBNDYAnjh6+0cB33qStFXhtflkZNPEaOmvzYlB/xcPnpUk4J7ul3MVa8PCQx2Ei5g2MGY/y1n+g==",
"requires": {
"html-tokenize": "^2.0.0",
"multipipe": "^1.0.2",
"through": "^2.3.8"
}
},
"create-hash": { "create-hash": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"requires": { "requires": {
"cipher-base": "^1.0.1", "cipher-base": "^1.0.1",
@@ -4671,7 +4516,7 @@
}, },
"create-hmac": { "create-hmac": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"requires": { "requires": {
"cipher-base": "^1.0.3", "cipher-base": "^1.0.3",
@@ -5015,14 +4860,6 @@
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
}, },
"cssstyle": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.3.1.tgz",
"integrity": "sha512-tNvaxM5blOnxanyxI6panOsnfiyLRj3HV4qjqqS45WPNS1usdYWRUQjqTEEELK73lpeP/1KoIGYUwrBn/VcECA==",
"requires": {
"cssom": "0.3.x"
}
},
"csstype": { "csstype": {
"version": "2.6.10", "version": "2.6.10",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz",
@@ -5593,7 +5430,7 @@
}, },
"diffie-hellman": { "diffie-hellman": {
"version": "5.0.3", "version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"requires": { "requires": {
"bn.js": "^4.1.0", "bn.js": "^4.1.0",
@@ -5792,43 +5629,6 @@
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
}, },
"duplexer2": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
"integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
"requires": {
"readable-stream": "^2.0.2"
},
"dependencies": {
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"duplexify": { "duplexify": {
"version": "3.7.1", "version": "3.7.1",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -5919,23 +5719,6 @@
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
}, },
"emotion": {
"version": "9.2.12",
"resolved": "https://registry.npmjs.org/emotion/-/emotion-9.2.12.tgz",
"integrity": "sha512-hcx7jppaI8VoXxIWEhxpDW7I+B4kq9RNzQLmsrF6LY8BGKqe2N+gFAQr0EfuFucFlPs2A9HM4+xNj4NeqEWIOQ==",
"requires": {
"babel-plugin-emotion": "^9.2.11",
"create-emotion": "^9.2.12"
}
},
"emotion-server": {
"version": "9.2.12",
"resolved": "https://registry.npmjs.org/emotion-server/-/emotion-server-9.2.12.tgz",
"integrity": "sha512-Bhjdl7eNoIeiAVa2QPP5d+1nP/31SiO/K1P/qI9cdXCydg91NwGYmteqhhge8u7PF8fLGTEVQfcPwj21815eBw==",
"requires": {
"create-emotion-server": "^9.2.12"
}
},
"encodeurl": { "encodeurl": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -6496,7 +6279,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"requires": { "requires": {
"graceful-fs": "^4.1.2", "graceful-fs": "^4.1.2",
@@ -7145,7 +6928,8 @@
"find-root": { "find-root": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"dev": true
}, },
"find-up": { "find-up": {
"version": "2.1.0", "version": "2.1.0",
@@ -7220,13 +7004,6 @@
"requires": { "requires": {
"tabbable": "^3.1.2", "tabbable": "^3.1.2",
"xtend": "^4.0.1" "xtend": "^4.0.1"
},
"dependencies": {
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
} }
}, },
"follow-redirects": { "follow-redirects": {
@@ -7812,7 +7589,7 @@
}, },
"string_decoder": { "string_decoder": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": { "requires": {
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
@@ -7892,18 +7669,6 @@
} }
} }
}, },
"html-tokenize": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz",
"integrity": "sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==",
"requires": {
"buffer-from": "~0.1.1",
"inherits": "~2.0.1",
"minimist": "~1.2.5",
"readable-stream": "~1.0.27-1",
"through2": "~0.4.1"
}
},
"html-webpack-plugin": { "html-webpack-plugin": {
"version": "4.0.0-beta.11", "version": "4.0.0-beta.11",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz",
@@ -9661,11 +9426,6 @@
"js-tokens": "^3.0.0 || ^4.0.0" "js-tokens": "^3.0.0 || ^4.0.0"
} }
}, },
"lower-case": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
"integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
},
"lru-cache": { "lru-cache": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -9767,7 +9527,7 @@
}, },
"media-typer": { "media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
}, },
"mem": { "mem": {
@@ -10171,15 +9931,6 @@
"resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
"integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
}, },
"multipipe": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/multipipe/-/multipipe-1.0.2.tgz",
"integrity": "sha1-zBPv2DPJzamfIk+GhGG44aP9k50=",
"requires": {
"duplexer2": "^0.1.2",
"object-assign": "^4.1.0"
}
},
"mute-stream": { "mute-stream": {
"version": "0.0.8", "version": "0.0.8",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
@@ -10262,17 +10013,9 @@
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
}, },
"no-case": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
"integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
"requires": {
"lower-case": "^1.1.1"
}
},
"node-fetch": { "node-fetch": {
"version": "1.6.3", "version": "1.6.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz",
"integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -10415,14 +10158,6 @@
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.55.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.55.tgz",
"integrity": "sha512-H3R3YR/8TjT5WPin/wOoHOUPHgvj8leuU/Keta/rwelEQN9pA/S2Dx8/se4pZ2LBxSd0nAGzsNzhqwa77v7F1w==" "integrity": "sha512-H3R3YR/8TjT5WPin/wOoHOUPHgvj8leuU/Keta/rwelEQN9pA/S2Dx8/se4pZ2LBxSd0nAGzsNzhqwa77v7F1w=="
}, },
"nopt": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
"requires": {
"abbrev": "1"
}
},
"normalize-package-data": { "normalize-package-data": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -10545,11 +10280,6 @@
"es-abstract": "^1.17.5" "es-abstract": "^1.17.5"
} }
}, },
"object-keys": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
"integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY="
},
"object-path": { "object-path": {
"version": "0.11.4", "version": "0.11.4",
"resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz",
@@ -10700,7 +10430,7 @@
"dependencies": { "dependencies": {
"ansi-escapes": { "ansi-escapes": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
"integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
"dev": true "dev": true
}, },
@@ -10746,7 +10476,7 @@
}, },
"external-editor": { "external-editor": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -10808,7 +10538,7 @@
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
}, },
@@ -10829,7 +10559,7 @@
}, },
"opn": { "opn": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", "resolved": "http://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
"integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -13284,7 +13014,7 @@
}, },
"readable-stream": { "readable-stream": {
"version": "1.0.34", "version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"requires": { "requires": {
"core-util-is": "~1.0.0", "core-util-is": "~1.0.0",
@@ -13789,7 +13519,7 @@
}, },
"safe-regex": { "safe-regex": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
"requires": { "requires": {
"ret": "~0.1.10" "ret": "~0.1.10"
@@ -14053,7 +13783,7 @@
}, },
"sha.js": { "sha.js": {
"version": "2.4.11", "version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"requires": { "requires": {
"inherits": "^2.0.1", "inherits": "^2.0.1",
@@ -14814,7 +14544,7 @@
}, },
"strip-eof": { "strip-eof": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
}, },
"strip-indent": { "strip-indent": {
@@ -15133,18 +14863,9 @@
}, },
"through": { "through": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
}, },
"through2": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz",
"integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=",
"requires": {
"readable-stream": "~1.0.17",
"xtend": "~2.1.1"
}
},
"thunky": { "thunky": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
@@ -15237,14 +14958,6 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
}, },
"touch": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/touch/-/touch-2.0.2.tgz",
"integrity": "sha512-qjNtvsFXTRq7IuMLweVgFxmEuQ6gLbRs2jQxL80TtZ31dEKWYIxRXquij6w6VimyDek5hD3PytljHmEtAs2u0A==",
"requires": {
"nopt": "~1.0.10"
}
},
"tough-cookie": { "tough-cookie": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
@@ -15458,11 +15171,6 @@
"resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
"integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
}, },
"upper-case": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
"integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
},
"uri-js": { "uri-js": {
"version": "4.2.2", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -16629,12 +16337,9 @@
} }
}, },
"xtend": { "xtend": {
"version": "2.1.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
"requires": {
"object-keys": "~0.4.0"
}
}, },
"y18n": { "y18n": {
"version": "4.0.0", "version": "4.0.0",

View File

@@ -4,10 +4,9 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@lingui/react": "^2.9.1", "@lingui/react": "^2.9.1",
"@patternfly/patternfly": "^2.71.6", "@patternfly/patternfly": "^4.10.31",
"@patternfly/react-core": "^3.158.1", "@patternfly/react-core": "4.18.14",
"@patternfly/react-icons": "^3.15.17", "@patternfly/react-icons": "^4.3.5",
"@patternfly/react-tokens": "^2.8.14",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",

View File

@@ -8,6 +8,8 @@ import {
InfoCircleIcon, InfoCircleIcon,
TimesCircleIcon, TimesCircleIcon,
} from '@patternfly/react-icons'; } from '@patternfly/react-icons';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import styled from 'styled-components'; import styled from 'styled-components';
const Header = styled.div` const Header = styled.div`
@@ -17,11 +19,14 @@ const Header = styled.div`
} }
`; `;
export default function AlertModal({ function AlertModal({
i18n,
isOpen = null, isOpen = null,
title, title,
label,
variant, variant,
children, children,
i18nHash,
...props ...props
}) { }) {
const variantIcons = { const variantIcons = {
@@ -60,16 +65,19 @@ export default function AlertModal({
const customHeader = ( const customHeader = (
<Header> <Header>
{variant ? variantIcons[variant] : null} {variant ? variantIcons[variant] : null}
<Title size="2xl">{title}</Title> <Title id="alert-modal-header-label" size="2xl" headingLevel="h2">
{title}
</Title>
</Header> </Header>
); );
return ( return (
<Modal <Modal
header={customHeader} header={customHeader}
isFooterLeftAligned aria-label={label || i18n._(t`Alert modal`)}
aria-labelledby="alert-modal-header-label"
isOpen={Boolean(isOpen)} isOpen={Boolean(isOpen)}
isSmall variant="small"
title={title} title={title}
{...props} {...props}
> >
@@ -77,3 +85,5 @@ export default function AlertModal({
</Modal> </Modal>
); );
} }
export default withI18n()(AlertModal);

View File

@@ -1,11 +1,11 @@
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import AlertModal from './AlertModal'; import AlertModal from './AlertModal';
describe('AlertModal', () => { describe('AlertModal', () => {
test('renders the expected content', () => { test('renders the expected content', () => {
const wrapper = mount( const wrapper = mountWithContexts(
<AlertModal title="Danger!">Are you sure?</AlertModal> <AlertModal title="Danger!">Are you sure?</AlertModal>
); );
expect(wrapper).toHaveLength(1); expect(wrapper).toHaveLength(1);

View File

@@ -43,7 +43,7 @@ class AnsibleSelect extends React.Component {
onChange={this.onSelectChange} onChange={this.onSelectChange}
onBlur={onBlur} onBlur={onBlur}
aria-label={i18n._(t`Select Input`)} aria-label={i18n._(t`Select Input`)}
isValid={isValid} validated={isValid ? 'default' : 'error'}
className={className} className={className}
isDisabled={isDisabled} isDisabled={isDisabled}
> >

View File

@@ -1,6 +1,5 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useHistory, useLocation, withRouter } from 'react-router-dom'; import { useHistory, useLocation, withRouter } from 'react-router-dom';
import { global_breakpoint_md } from '@patternfly/react-tokens';
import { import {
Nav, Nav,
NavList, NavList,
@@ -41,15 +40,10 @@ function AppContainer({ i18n, navRouteConfig = [], children }) {
const [config, setConfig] = useState({}); const [config, setConfig] = useState({});
const [configError, setConfigError] = useState(null); const [configError, setConfigError] = useState(null);
const [isAboutModalOpen, setIsAboutModalOpen] = useState(false); const [isAboutModalOpen, setIsAboutModalOpen] = useState(false);
const [isNavOpen, setIsNavOpen] = useState(
typeof window !== 'undefined' &&
window.innerWidth >= parseInt(global_breakpoint_md.value, 10)
);
const handleAboutModalOpen = () => setIsAboutModalOpen(true); const handleAboutModalOpen = () => setIsAboutModalOpen(true);
const handleAboutModalClose = () => setIsAboutModalOpen(false); const handleAboutModalClose = () => setIsAboutModalOpen(false);
const handleConfigErrorClose = () => setConfigError(null); const handleConfigErrorClose = () => setConfigError(null);
const handleNavToggle = () => setIsNavOpen(!isNavOpen);
const handleLogout = async () => { const handleLogout = async () => {
await RootAPI.logout(); await RootAPI.logout();
@@ -79,10 +73,9 @@ function AppContainer({ i18n, navRouteConfig = [], children }) {
const header = ( const header = (
<PageHeader <PageHeader
showNavToggle showNavToggle
onNavToggle={handleNavToggle}
logo={<BrandLogo />} logo={<BrandLogo />}
logoProps={{ href: '/' }} logoProps={{ href: '/' }}
toolbar={ headerTools={
<PageHeaderToolbar <PageHeaderToolbar
loggedInUser={config?.me} loggedInUser={config?.me}
isAboutDisabled={!config?.version} isAboutDisabled={!config?.version}
@@ -95,7 +88,6 @@ function AppContainer({ i18n, navRouteConfig = [], children }) {
const sidebar = ( const sidebar = (
<PageSidebar <PageSidebar
isNavOpen={isNavOpen}
theme="dark" theme="dark"
nav={ nav={
<Nav aria-label={i18n._(t`Navigation`)} theme="dark"> <Nav aria-label={i18n._(t`Navigation`)} theme="dark">
@@ -116,7 +108,7 @@ function AppContainer({ i18n, navRouteConfig = [], children }) {
return ( return (
<> <>
<Page usecondensed="True" header={header} sidebar={sidebar}> <Page isManagedSidebar header={header} sidebar={sidebar}>
<ConfigProvider value={config}>{children}</ConfigProvider> <ConfigProvider value={config}>{children}</ConfigProvider>
</Page> </Page>
<About <About

View File

@@ -7,9 +7,9 @@ import {
DropdownItem, DropdownItem,
DropdownToggle, DropdownToggle,
DropdownPosition, DropdownPosition,
Toolbar, PageHeaderTools,
ToolbarGroup, PageHeaderToolsGroup,
ToolbarItem, PageHeaderToolsItem,
Tooltip, Tooltip,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import { QuestionCircleIcon, UserIcon } from '@patternfly/react-icons'; import { QuestionCircleIcon, UserIcon } from '@patternfly/react-icons';
@@ -62,10 +62,10 @@ class PageHeaderToolbar extends Component {
} = this.props; } = this.props;
return ( return (
<Toolbar> <PageHeaderTools>
<ToolbarGroup> <PageHeaderToolsGroup>
<Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}> <Tooltip position="left" content={<div>{i18n._(t`Info`)}</div>}>
<ToolbarItem> <PageHeaderToolsItem>
<Dropdown <Dropdown
isPlain isPlain
isOpen={isHelpOpen} isOpen={isHelpOpen}
@@ -93,10 +93,10 @@ class PageHeaderToolbar extends Component {
</DropdownItem>, </DropdownItem>,
]} ]}
/> />
</ToolbarItem> </PageHeaderToolsItem>
</Tooltip> </Tooltip>
<Tooltip position="left" content={<div>{i18n._(t`User`)}</div>}> <Tooltip position="left" content={<div>{i18n._(t`User`)}</div>}>
<ToolbarItem> <PageHeaderToolsItem>
<Dropdown <Dropdown
id="toolbar-user-dropdown" id="toolbar-user-dropdown"
isPlain isPlain
@@ -134,10 +134,10 @@ class PageHeaderToolbar extends Component {
</DropdownItem>, </DropdownItem>,
]} ]}
/> />
</ToolbarItem> </PageHeaderToolsItem>
</Tooltip> </Tooltip>
</ToolbarGroup> </PageHeaderToolsGroup>
</Toolbar> </PageHeaderTools>
); );
} }
} }

View File

@@ -74,9 +74,9 @@ function AssociateModal({
return ( return (
<Fragment> <Fragment>
<Modal <Modal
isFooterLeftAligned variant="large"
isLarge
title={title} title={title}
aria-label={i18n._(t`Association modal`)}
isOpen={isModalOpen} isOpen={isModalOpen}
onClose={handleClose} onClose={handleClose}
actions={[ actions={[

View File

@@ -1,18 +1,10 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { BackgroundImage, BackgroundImageSrc } from '@patternfly/react-core'; import { BackgroundImage } from '@patternfly/react-core';
const backgroundImageConfig = {
[BackgroundImageSrc.xs]: './images/pfbg_576.jpg',
[BackgroundImageSrc.xs2x]: './images/pfbg_576@2x.jpg',
[BackgroundImageSrc.sm]: './images/pfbg_768.jpg',
[BackgroundImageSrc.sm2x]: './images/pfbg_768@2x.jpg',
[BackgroundImageSrc.lg]: './images/pfbg_2000.jpg',
};
export default ({ children }) => ( export default ({ children }) => (
<Fragment> <Fragment>
<BackgroundImage src={backgroundImageConfig} /> <BackgroundImage />
{children} {children}
</Fragment> </Fragment>
); );

View File

@@ -11,7 +11,7 @@ describe('Background', () => {
</Background> </Background>
); );
expect(wrapper).toHaveLength(1); expect(wrapper).toHaveLength(1);
expect(wrapper.find('BackgroundImage')).toHaveLength(1); expect(wrapper.find('.pf-c-background-image')).toHaveLength(1);
expect(wrapper.find('#test')).toHaveLength(1); expect(wrapper.find('#test')).toHaveLength(1);
}); });
}); });

View File

@@ -30,19 +30,21 @@ const Breadcrumbs = ({ breadcrumbConfig }) => {
); );
}; };
const Crumb = ({ breadcrumbConfig }) => { const Crumb = ({ breadcrumbConfig, showDivider }) => {
const match = useRouteMatch(); const match = useRouteMatch();
const crumb = breadcrumbConfig[match.url]; const crumb = breadcrumbConfig[match.url];
let crumbElement = ( let crumbElement = (
<BreadcrumbItem key={match.url}> <BreadcrumbItem key={match.url} showDivider={showDivider}>
<Link to={match.url}>{crumb}</Link> <Link to={match.url}>{crumb}</Link>
</BreadcrumbItem> </BreadcrumbItem>
); );
if (match.isExact) { if (match.isExact) {
crumbElement = ( crumbElement = (
<BreadcrumbHeading key="breadcrumb-heading">{crumb}</BreadcrumbHeading> <BreadcrumbHeading key="breadcrumb-heading" showDivider={showDivider}>
{crumb}
</BreadcrumbHeading>
); );
} }
@@ -54,7 +56,7 @@ const Crumb = ({ breadcrumbConfig }) => {
<Fragment> <Fragment>
{crumbElement} {crumbElement}
<Route path={`${match.url}/:path`}> <Route path={`${match.url}/:path`}>
<Crumb breadcrumbConfig={breadcrumbConfig} /> <Crumb breadcrumbConfig={breadcrumbConfig} showDivider />
</Route> </Route>
</Fragment> </Fragment>
); );

View File

@@ -1,13 +0,0 @@
import styled from 'styled-components';
import { CardHeader } from '@patternfly/react-core';
const TabbedCardHeader = styled(CardHeader)`
--pf-c-card--first-child--PaddingTop: 0;
--pf-c-card--child--PaddingLeft: 0;
--pf-c-card--child--PaddingRight: 0;
--pf-c-card__header--not-last-child--PaddingBottom: 24px;
--pf-c-card__header--not-last-child--PaddingBottom: 0;
display: flex;
`;
export default TabbedCardHeader;

View File

@@ -1,3 +1,2 @@
export { default as TabbedCardHeader } from './TabbedCardHeader';
export { default as CardBody } from './CardBody'; export { default as CardBody } from './CardBody';
export { default as CardActionsRow } from './CardActionsRow'; export { default as CardActionsRow } from './CardActionsRow';

View File

@@ -1,36 +0,0 @@
import React from 'react';
import { string } from 'prop-types';
import { Link } from 'react-router-dom';
import { Button } from '@patternfly/react-core';
import { TimesIcon } from '@patternfly/react-icons';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
function CardCloseButton({ linkTo, i18n, i18nHash, ...props }) {
if (linkTo) {
return (
<Link
className="pf-c-button pf-m-plain"
aria-label={i18n._(t`Close`)}
title={i18n._(t`Close`)}
to={linkTo}
{...props}
>
<TimesIcon />
</Link>
);
}
return (
<Button variant="plain" aria-label={i18n._(t`Close`)} {...props}>
<TimesIcon />
</Button>
);
}
CardCloseButton.propTypes = {
linkTo: string,
};
CardCloseButton.defaultProps = {
linkTo: null,
};
export default withI18n()(CardCloseButton);

View File

@@ -1,23 +0,0 @@
import React from 'react';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import CardCloseButton from './CardCloseButton';
describe('<CardCloseButton>', () => {
test('should render close button', () => {
const wrapper = mountWithContexts(<CardCloseButton />);
const button = wrapper.find('Button');
expect(button).toHaveLength(1);
expect(button.prop('variant')).toBe('plain');
expect(button.prop('aria-label')).toBe('Close');
expect(wrapper.find('Link')).toHaveLength(0);
});
test('should render close link when `linkTo` prop provided', () => {
const wrapper = mountWithContexts(<CardCloseButton linkTo="/foo" />);
expect(wrapper.find('Button')).toHaveLength(0);
const link = wrapper.find('Link');
expect(link).toHaveLength(1);
expect(link.prop('to')).toEqual('/foo');
expect(link.prop('aria-label')).toEqual('Close');
});
});

View File

@@ -1 +0,0 @@
export { default } from './CardCloseButton';

View File

@@ -4,7 +4,7 @@ import { t } from '@lingui/macro';
import { ChipGroup as PFChipGroup } from '@patternfly/react-core'; import { ChipGroup as PFChipGroup } from '@patternfly/react-core';
import { number, shape } from 'prop-types'; import { number, shape } from 'prop-types';
function ChipGroup({ i18n, numChips, totalChips, ...props }) { function ChipGroup({ i18n, numChips, totalChips, i18nHash, ...props }) {
return ( return (
<PFChipGroup <PFChipGroup
{...props} {...props}

View File

@@ -39,7 +39,7 @@ function VariablesDetail({ value, label, rows, fullHeight }) {
fullWidth fullWidth
css="grid-column: 1 / -1" css="grid-column: 1 / -1"
> >
<Split gutter="sm"> <Split hasGutter>
<SplitItem> <SplitItem>
<div className="pf-c-form__label"> <div className="pf-c-form__label">
<span <span

View File

@@ -35,7 +35,7 @@ function VariablesField({
return ( return (
<div className="pf-c-form__group"> <div className="pf-c-form__group">
<FieldHeader> <FieldHeader>
<Split gutter="sm"> <Split hasGutter>
<SplitItem> <SplitItem>
<label htmlFor={id} className="pf-c-form__label"> <label htmlFor={id} className="pf-c-form__label">
<span className="pf-c-form__label-text">{label}</span> <span className="pf-c-form__label-text">{label}</span>

View File

@@ -35,7 +35,7 @@ function VariablesInput(props) {
return ( return (
<div className={`pf-c-form__group ${className || ''}`}> <div className={`pf-c-form__group ${className || ''}`}>
<Split gutter="sm"> <Split hasGutter>
<SplitItem> <SplitItem>
<label htmlFor={id} className="pf-c-form__label"> <label htmlFor={id} className="pf-c-form__label">
{label} {label}

View File

@@ -12,7 +12,9 @@ import { CubesIcon } from '@patternfly/react-icons';
const ContentEmpty = ({ i18n, title = '', message = '' }) => ( const ContentEmpty = ({ i18n, title = '', message = '' }) => (
<EmptyState variant="full"> <EmptyState variant="full">
<EmptyStateIcon icon={CubesIcon} /> <EmptyStateIcon icon={CubesIcon} />
<Title size="lg">{title || i18n._(t`No items found.`)}</Title> <Title size="lg" headingLevel="h3">
{title || i18n._(t`No items found.`)}
</Title>
<EmptyStateBody>{message}</EmptyStateBody> <EmptyStateBody>{message}</EmptyStateBody>
</EmptyState> </EmptyState>
); );

View File

@@ -35,7 +35,7 @@ function ContentError({ error, children, isNotFound, i18n }) {
) : ( ) : (
<EmptyState variant="full"> <EmptyState variant="full">
<EmptyStateIcon icon={ExclamationTriangleIcon} /> <EmptyStateIcon icon={ExclamationTriangleIcon} />
<Title size="lg"> <Title size="lg" headingLevel="h3">
{is404 ? i18n._(t`Not Found`) : i18n._(t`Something went wrong...`)} {is404 ? i18n._(t`Not Found`) : i18n._(t`Something went wrong...`)}
</Title> </Title>
<EmptyStateBody> <EmptyStateBody>

View File

@@ -6,7 +6,7 @@ import { Chip } from '@patternfly/react-core';
import { Credential } from '../../types'; import { Credential } from '../../types';
import { toTitleCase } from '../../util/strings'; import { toTitleCase } from '../../util/strings';
function CredentialChip({ credential, i18n, ...props }) { function CredentialChip({ credential, i18n, i18nHash, ...props }) {
let type; let type;
if (credential.cloud) { if (credential.cloud) {
type = i18n._(t`Cloud`); type = i18n._(t`Cloud`);

View File

@@ -2,30 +2,21 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Checkbox } from '@patternfly/react-core';
import styled from 'styled-components';
import { SearchIcon } from '@patternfly/react-icons';
import { import {
DataToolbar, Checkbox,
DataToolbarContent as _DataToolbarContent, Toolbar,
DataToolbarGroup as _DataToolbarGroup, ToolbarContent,
DataToolbarItem, ToolbarGroup,
DataToolbarToggleGroup, ToolbarItem,
} from '@patternfly/react-core/dist/umd/experimental'; ToolbarToggleGroup,
} from '@patternfly/react-core';
import { SearchIcon } from '@patternfly/react-icons';
import ExpandCollapse from '../ExpandCollapse'; import ExpandCollapse from '../ExpandCollapse';
import Search from '../Search'; import Search from '../Search';
import Sort from '../Sort'; import Sort from '../Sort';
import { SearchColumns, SortColumns, QSConfig } from '../../types'; import { SearchColumns, SortColumns, QSConfig } from '../../types';
const DataToolbarContent = styled(_DataToolbarContent)`
--pf-c-data-toolbar__content--PaddingLeft: 24px;
--pf-c-data-toolbar__content--PaddingRight: 8px;
`;
const DataToolbarGroup = styled(_DataToolbarGroup)`
--pf-c-data-toolbar__group--spacer: 24px;
`;
class DataListToolbar extends React.Component { class DataListToolbar extends React.Component {
render() { render() {
const { const {
@@ -49,26 +40,26 @@ class DataListToolbar extends React.Component {
const showExpandCollapse = onCompact && onExpand; const showExpandCollapse = onCompact && onExpand;
return ( return (
<DataToolbar <Toolbar
id={`${qsConfig.namespace}-list-toolbar`} id={`${qsConfig.namespace}-list-toolbar`}
clearAllFilters={clearAllFilters} clearAllFilters={clearAllFilters}
collapseListedFiltersBreakpoint="lg" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
{showSelectAll && ( {showSelectAll && (
<DataToolbarGroup> <ToolbarGroup>
<DataToolbarItem> <ToolbarItem>
<Checkbox <Checkbox
isChecked={isAllSelected} isChecked={isAllSelected}
onChange={onSelectAll} onChange={onSelectAll}
aria-label={i18n._(t`Select all`)} aria-label={i18n._(t`Select all`)}
id="select-all" id="select-all"
/> />
</DataToolbarItem> </ToolbarItem>
</DataToolbarGroup> </ToolbarGroup>
)} )}
<DataToolbarToggleGroup toggleIcon={<SearchIcon />} breakpoint="lg"> <ToolbarToggleGroup toggleIcon={<SearchIcon />} breakpoint="lg">
<DataToolbarItem> <ToolbarItem>
<Search <Search
qsConfig={qsConfig} qsConfig={qsConfig}
columns={searchColumns} columns={searchColumns}
@@ -76,31 +67,31 @@ class DataListToolbar extends React.Component {
onReplaceSearch={onReplaceSearch} onReplaceSearch={onReplaceSearch}
onRemove={onRemove} onRemove={onRemove}
/> />
</DataToolbarItem> </ToolbarItem>
<DataToolbarItem> <ToolbarItem>
<Sort qsConfig={qsConfig} columns={sortColumns} onSort={onSort} /> <Sort qsConfig={qsConfig} columns={sortColumns} onSort={onSort} />
</DataToolbarItem> </ToolbarItem>
</DataToolbarToggleGroup> </ToolbarToggleGroup>
{showExpandCollapse && ( {showExpandCollapse && (
<DataToolbarGroup> <ToolbarGroup>
<Fragment> <Fragment>
<DataToolbarItem> <ToolbarItem>
<ExpandCollapse <ExpandCollapse
isCompact={isCompact} isCompact={isCompact}
onCompact={onCompact} onCompact={onCompact}
onExpand={onExpand} onExpand={onExpand}
/> />
</DataToolbarItem> </ToolbarItem>
</Fragment> </Fragment>
</DataToolbarGroup> </ToolbarGroup>
)} )}
<DataToolbarGroup> <ToolbarGroup>
{additionalControls.map(control => ( {additionalControls.map(control => (
<DataToolbarItem key={control.key}>{control}</DataToolbarItem> <ToolbarItem key={control.key}>{control}</ToolbarItem>
))} ))}
</DataToolbarGroup> </ToolbarGroup>
</DataToolbarContent> </ToolbarContent>
</DataToolbar> </Toolbar>
); );
} }
} }

View File

@@ -7,7 +7,7 @@ import { t } from '@lingui/macro';
import { import {
Card as PFCard, Card as PFCard,
CardBody as PFCardBody, CardBody as PFCardBody,
Expandable as PFExpandable, ExpandableSection as PFExpandable,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import getErrorMessage from './getErrorMessage'; import getErrorMessage from './getErrorMessage';

View File

@@ -39,7 +39,7 @@ describe('ErrorDetail', () => {
} }
/> />
); );
wrapper.find('Expandable').prop('onToggle')(); wrapper.find('ExpandableSection').prop('onToggle')();
wrapper.update(); wrapper.update();
}); });
}); });

View File

@@ -29,14 +29,14 @@ function FormField(props) {
helperText={helperText} helperText={helperText}
helperTextInvalid={meta.error} helperTextInvalid={meta.error}
isRequired={isRequired} isRequired={isRequired}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={label} label={label}
> >
<FieldTooltip content={tooltip} maxWidth={tooltipMaxWidth} /> <FieldTooltip content={tooltip} maxWidth={tooltipMaxWidth} />
<TextArea <TextArea
id={id} id={id}
isRequired={isRequired} isRequired={isRequired}
isValid={isValid} validated={isValid ? 'default' : 'error'}
resizeOrientation="vertical" resizeOrientation="vertical"
{...rest} {...rest}
{...field} {...field}
@@ -51,14 +51,14 @@ function FormField(props) {
helperText={helperText} helperText={helperText}
helperTextInvalid={meta.error} helperTextInvalid={meta.error}
isRequired={isRequired} isRequired={isRequired}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={label} label={label}
> >
<FieldTooltip content={tooltip} maxWidth={tooltipMaxWidth} /> <FieldTooltip content={tooltip} maxWidth={tooltipMaxWidth} />
<TextInput <TextInput
id={id} id={id}
isRequired={isRequired} isRequired={isRequired}
isValid={isValid} validated={isValid ? 'default' : 'error'}
{...rest} {...rest}
{...field} {...field}
type={type} type={type}

View File

@@ -14,7 +14,7 @@ function PasswordField(props) {
fieldId={id} fieldId={id}
helperTextInvalid={meta.error} helperTextInvalid={meta.error}
isRequired={isRequired} isRequired={isRequired}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={label} label={label}
> >
<InputGroup> <InputGroup>

View File

@@ -44,7 +44,7 @@ function PasswordInput(props) {
value={field.value === '$encrypted$' ? '' : field.value} value={field.value === '$encrypted$' ? '' : field.value}
isDisabled={isDisabled} isDisabled={isDisabled}
isRequired={isRequired} isRequired={isRequired}
isValid={isValid} validated={isValid ? 'default' : 'error'}
type={inputType} type={inputType}
onChange={(_, event) => { onChange={(_, event) => {
field.onChange(event); field.onChange(event);

View File

@@ -27,7 +27,9 @@ const InventoryLookupField = withI18n()(({ i18n, host }) => {
label={i18n._(t`Inventory`)} label={i18n._(t`Inventory`)}
isRequired isRequired
fieldId="inventory-lookup" fieldId="inventory-lookup"
isValid={!inventoryMeta.touched || !inventoryMeta.error} validated={
!inventoryMeta.touched || !inventoryMeta.error ? 'default' : 'error'
}
helperTextInvalid={inventoryMeta.error} helperTextInvalid={inventoryMeta.error}
> >
<FieldTooltip <FieldTooltip

View File

@@ -101,7 +101,7 @@ function JobTypeField({ i18n }) {
<FormGroup <FormGroup
fieldId="propmt-job-type" fieldId="propmt-job-type"
label={i18n._(t`Job Type`)} label={i18n._(t`Job Type`)}
isValid={isValid} validated={isValid ? 'default' : 'error'}
> >
<FieldTooltip <FieldTooltip
content={i18n._(t`For job templates, select run to execute the playbook. content={i18n._(t`For job templates, select run to execute the playbook.
@@ -132,7 +132,7 @@ function VerbosityField({ i18n }) {
return ( return (
<FormGroup <FormGroup
fieldId="prompt-verbosity" fieldId="prompt-verbosity"
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={i18n._(t`Verbosity`)} label={i18n._(t`Verbosity`)}
> >
<FieldTooltip <FieldTooltip

View File

@@ -96,7 +96,7 @@ function MultipleChoiceField({ question }) {
fieldId={id} fieldId={id}
helperTextInvalid={meta.error} helperTextInvalid={meta.error}
isRequired={question.required} isRequired={question.required}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={question.question_name} label={question.question_name}
> >
<FieldTooltip content={question.question_description} /> <FieldTooltip content={question.question_description} />
@@ -124,7 +124,7 @@ function MultiSelectField({ question }) {
fieldId={id} fieldId={id}
helperTextInvalid={meta.error} helperTextInvalid={meta.error}
isRequired={question.required} isRequired={question.required}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={question.question_name} label={question.question_name}
> >
<FieldTooltip content={question.question_description} /> <FieldTooltip content={question.question_description} />
@@ -139,7 +139,7 @@ function MultiSelectField({ question }) {
helpers.setValue(field.value.concat(option)); helpers.setValue(field.value.concat(option));
} }
}} }}
isExpanded={isOpen} isOpen={isOpen}
selections={field.value} selections={field.value}
> >
{question.choices.split('\n').map(opt => ( {question.choices.split('\n').map(opt => (

View File

@@ -2,10 +2,7 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import styled from 'styled-components'; import styled from 'styled-components';
import { import { Toolbar, ToolbarContent } from '@patternfly/react-core';
DataToolbar,
DataToolbarContent,
} from '@patternfly/react-core/dist/umd/experimental';
import DataListToolbar from '../DataListToolbar'; import DataListToolbar from '../DataListToolbar';
import { import {
@@ -107,17 +104,17 @@ class ListHeader extends React.Component {
return ( return (
<Fragment> <Fragment>
{isEmpty ? ( {isEmpty ? (
<DataToolbar <Toolbar
id={`${qsConfig.namespace}-list-toolbar`} id={`${qsConfig.namespace}-list-toolbar`}
clearAllFilters={this.handleRemoveAll} clearAllFilters={this.handleRemoveAll}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<EmptyStateControlsWrapper> <EmptyStateControlsWrapper>
{emptyStateControls} {emptyStateControls}
</EmptyStateControlsWrapper> </EmptyStateControlsWrapper>
</DataToolbarContent> </ToolbarContent>
</DataToolbar> </Toolbar>
) : ( ) : (
<Fragment> <Fragment>
{renderToolbar({ {renderToolbar({

View File

@@ -84,7 +84,7 @@ function CredentialLookup({
<FormGroup <FormGroup
fieldId="credential" fieldId="credential"
isRequired={required} isRequired={required}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={label} label={label}
helperTextInvalid={helperTextInvalid} helperTextInvalid={helperTextInvalid}
> >

View File

@@ -142,9 +142,9 @@ function Lookup(props) {
</ChipHolder> </ChipHolder>
</InputGroup> </InputGroup>
<Modal <Modal
isFooterLeftAligned variant="large"
isLarge
title={i18n._(t`Select ${header || i18n._(t`Items`)}`)} title={i18n._(t`Select ${header || i18n._(t`Items`)}`)}
aria-label={i18n._(t`Lookup modal`)}
isOpen={isModalOpen} isOpen={isModalOpen}
onClose={closeModal} onClose={closeModal}
actions={[ actions={[

View File

@@ -81,7 +81,7 @@ describe('<MultiCredentialsLookup />', () => {
}); });
const chip = wrapper.find('CredentialChip'); const chip = wrapper.find('CredentialChip');
expect(chip).toHaveLength(5); expect(chip).toHaveLength(5);
const button = chip.at(1).find('ChipButton'); const button = chip.at(1).find('Chip Button');
await act(async () => { await act(async () => {
button.invoke('onClick')(); button.invoke('onClick')();
}); });

View File

@@ -49,7 +49,7 @@ function OrganizationLookup({
fieldId="organization" fieldId="organization"
helperTextInvalid={helperTextInvalid} helperTextInvalid={helperTextInvalid}
isRequired={required} isRequired={required}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={i18n._(t`Organization`)} label={i18n._(t`Organization`)}
> >
<Lookup <Lookup

View File

@@ -63,7 +63,7 @@ function ProjectLookup({
fieldId="project" fieldId="project"
helperTextInvalid={helperTextInvalid} helperTextInvalid={helperTextInvalid}
isRequired={required} isRequired={required}
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={i18n._(t`Project`)} label={i18n._(t`Project`)}
> >
{tooltip && <FieldTooltip content={tooltip} />} {tooltip && <FieldTooltip content={tooltip} />}

View File

@@ -50,8 +50,8 @@ function TagMultiSelect({ onChange, value }) {
return name; return name;
}} }}
selections={selections} selections={selections}
isExpanded={isExpanded} isOpen={isExpanded}
ariaLabelledBy="tag-select" aria-labelledby="tag-select"
> >
{renderOptions(options)} {renderOptions(options)}
</Select> </Select>

View File

@@ -17,7 +17,7 @@ describe('<TagMultiSelect />', () => {
it('should not treat empty string as an option', () => { it('should not treat empty string as an option', () => {
const wrapper = mount(<TagMultiSelect value="" onChange={jest.fn()} />); const wrapper = mount(<TagMultiSelect value="" onChange={jest.fn()} />);
wrapper.find('input').simulate('focus'); wrapper.find('input').simulate('focus');
expect(wrapper.find('Select').prop('isExpanded')).toEqual(true); expect(wrapper.find('Select').prop('isOpen')).toEqual(true);
expect(wrapper.find('SelectOption')).toHaveLength(0); expect(wrapper.find('SelectOption')).toHaveLength(0);
}); });

View File

@@ -264,7 +264,7 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
className="pf-c-data-list__item-action sc-bwzfXH llKtln" className="pf-c-data-list__item-action sc-bwzfXH llKtln"
rowid="items-list-item-9000" rowid="items-list-item-9000"
> >
<Component <Switch
aria-label="Toggle notification start" aria-label="Toggle notification start"
id="notification-9000-started-toggle" id="notification-9000-started-toggle"
isChecked={false} isChecked={false}
@@ -273,73 +273,43 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
labelOff="Start" labelOff="Start"
onChange={[Function]} onChange={[Function]}
> >
<ComponentWithOuia <label
component={[Function]} className="pf-c-switch"
componentProps={ data-ouia-component-id={0}
Object { data-ouia-component-type="PF4/Switch"
"aria-label": "Toggle notification start", data-ouia-safe={true}
"id": "notification-9000-started-toggle", htmlFor="notification-9000-started-toggle"
"isChecked": false,
"isDisabled": false,
"label": "Start",
"labelOff": "Start",
"onChange": [Function],
}
}
consumerContext={null}
> >
<Switch <input
aria-label="Toggle notification start" aria-label="Toggle notification start"
className="" aria-labelledby={null}
checked={false}
className="pf-c-switch__input"
disabled={false}
id="notification-9000-started-toggle" id="notification-9000-started-toggle"
isChecked={false}
isDisabled={false}
label="Start"
labelOff="Start"
onChange={[Function]} onChange={[Function]}
ouiaContext={ type="checkbox"
Object { />
"isOuia": false, <span
"ouiaId": null, className="pf-c-switch__toggle"
} />
} <span
aria-hidden="true"
className="pf-c-switch__label pf-m-on"
id={null}
> >
<label Start
className="pf-c-switch" </span>
htmlFor="notification-9000-started-toggle" <span
> aria-hidden="true"
<input className="pf-c-switch__label pf-m-off"
aria-label="Toggle notification start" id={null}
aria-labelledby={null} >
checked={false} Start
className="pf-c-switch__input" </span>
disabled={false} </label>
id="notification-9000-started-toggle" </Switch>
onChange={[Function]} <Switch
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
<span
aria-hidden="true"
className="pf-c-switch__label pf-m-on"
id={null}
>
Start
</span>
<span
aria-hidden="true"
className="pf-c-switch__label pf-m-off"
id={null}
>
Start
</span>
</label>
</Switch>
</ComponentWithOuia>
</Component>
<Component
aria-label="Toggle notification success" aria-label="Toggle notification success"
id="notification-9000-success-toggle" id="notification-9000-success-toggle"
isChecked={false} isChecked={false}
@@ -348,73 +318,43 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
labelOff="Success" labelOff="Success"
onChange={[Function]} onChange={[Function]}
> >
<ComponentWithOuia <label
component={[Function]} className="pf-c-switch"
componentProps={ data-ouia-component-id={1}
Object { data-ouia-component-type="PF4/Switch"
"aria-label": "Toggle notification success", data-ouia-safe={true}
"id": "notification-9000-success-toggle", htmlFor="notification-9000-success-toggle"
"isChecked": false,
"isDisabled": false,
"label": "Success",
"labelOff": "Success",
"onChange": [Function],
}
}
consumerContext={null}
> >
<Switch <input
aria-label="Toggle notification success" aria-label="Toggle notification success"
className="" aria-labelledby={null}
checked={false}
className="pf-c-switch__input"
disabled={false}
id="notification-9000-success-toggle" id="notification-9000-success-toggle"
isChecked={false}
isDisabled={false}
label="Success"
labelOff="Success"
onChange={[Function]} onChange={[Function]}
ouiaContext={ type="checkbox"
Object { />
"isOuia": false, <span
"ouiaId": null, className="pf-c-switch__toggle"
} />
} <span
aria-hidden="true"
className="pf-c-switch__label pf-m-on"
id={null}
> >
<label Success
className="pf-c-switch" </span>
htmlFor="notification-9000-success-toggle" <span
> aria-hidden="true"
<input className="pf-c-switch__label pf-m-off"
aria-label="Toggle notification success" id={null}
aria-labelledby={null} >
checked={false} Success
className="pf-c-switch__input" </span>
disabled={false} </label>
id="notification-9000-success-toggle" </Switch>
onChange={[Function]} <Switch
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
<span
aria-hidden="true"
className="pf-c-switch__label pf-m-on"
id={null}
>
Success
</span>
<span
aria-hidden="true"
className="pf-c-switch__label pf-m-off"
id={null}
>
Success
</span>
</label>
</Switch>
</ComponentWithOuia>
</Component>
<Component
aria-label="Toggle notification failure" aria-label="Toggle notification failure"
id="notification-9000-error-toggle" id="notification-9000-error-toggle"
isChecked={false} isChecked={false}
@@ -423,72 +363,42 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
labelOff="Failure" labelOff="Failure"
onChange={[Function]} onChange={[Function]}
> >
<ComponentWithOuia <label
component={[Function]} className="pf-c-switch"
componentProps={ data-ouia-component-id={2}
Object { data-ouia-component-type="PF4/Switch"
"aria-label": "Toggle notification failure", data-ouia-safe={true}
"id": "notification-9000-error-toggle", htmlFor="notification-9000-error-toggle"
"isChecked": false,
"isDisabled": false,
"label": "Failure",
"labelOff": "Failure",
"onChange": [Function],
}
}
consumerContext={null}
> >
<Switch <input
aria-label="Toggle notification failure" aria-label="Toggle notification failure"
className="" aria-labelledby={null}
checked={false}
className="pf-c-switch__input"
disabled={false}
id="notification-9000-error-toggle" id="notification-9000-error-toggle"
isChecked={false}
isDisabled={false}
label="Failure"
labelOff="Failure"
onChange={[Function]} onChange={[Function]}
ouiaContext={ type="checkbox"
Object { />
"isOuia": false, <span
"ouiaId": null, className="pf-c-switch__toggle"
} />
} <span
aria-hidden="true"
className="pf-c-switch__label pf-m-on"
id={null}
> >
<label Failure
className="pf-c-switch" </span>
htmlFor="notification-9000-error-toggle" <span
> aria-hidden="true"
<input className="pf-c-switch__label pf-m-off"
aria-label="Toggle notification failure" id={null}
aria-labelledby={null} >
checked={false} Failure
className="pf-c-switch__input" </span>
disabled={false} </label>
id="notification-9000-error-toggle" </Switch>
onChange={[Function]}
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
<span
aria-hidden="true"
className="pf-c-switch__label pf-m-on"
id={null}
>
Failure
</span>
<span
aria-hidden="true"
className="pf-c-switch__label pf-m-off"
id={null}
>
Failure
</span>
</label>
</Switch>
</ComponentWithOuia>
</Component>
</div> </div>
</DataListAction> </DataListAction>
</StyledComponent> </StyledComponent>

View File

@@ -18,7 +18,7 @@ import DataListToolbar from '../DataListToolbar';
import { QSConfig, SearchColumns, SortColumns } from '../../types'; import { QSConfig, SearchColumns, SortColumns } from '../../types';
const ModalList = styled.div` const ModalList = styled.div`
.pf-c-data-toolbar__content { .pf-c-toolbar__content {
padding: 0 !important; padding: 0 !important;
} }
`; `;

View File

@@ -97,51 +97,27 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
zIndex={9999} zIndex={9999}
> >
<div> <div>
<Component <Button
aria-label="Delete" aria-label="Delete"
isDisabled={true} isDisabled={true}
onClick={[Function]} onClick={[Function]}
variant="danger" variant="danger"
> >
<ComponentWithOuia <button
component={[Function]} aria-disabled={null}
componentProps={ aria-label="Delete"
Object { className="pf-c-button pf-m-danger"
"aria-label": "Delete", data-ouia-component-id={null}
"children": "Delete", data-ouia-component-type="PF4/Button"
"isDisabled": true, data-ouia-safe={true}
"onClick": [Function], disabled={true}
"variant": "danger", onClick={[Function]}
} tabIndex={null}
} type="button"
consumerContext={null}
> >
<Button Delete
aria-label="Delete" </button>
isDisabled={true} </Button>
onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
variant="danger"
>
<button
aria-disabled={null}
aria-label="Delete"
className="pf-c-button pf-m-danger"
disabled={true}
onClick={[Function]}
tabIndex={null}
type="button"
>
Delete
</button>
</Button>
</ComponentWithOuia>
</Component>
</div> </div>
<Portal <Portal
containerInfo={ containerInfo={

View File

@@ -117,7 +117,7 @@ describe('<ResourceAccessList />', () => {
await sleep(0); await sleep(0);
wrapper.update(); wrapper.update();
const button = wrapper.find('ChipButton').at(0); const button = wrapper.find('Chip Button').at(0);
button.prop('onClick')(); button.prop('onClick')();
wrapper.update(); wrapper.update();
@@ -136,7 +136,7 @@ describe('<ResourceAccessList />', () => {
); );
await sleep(0); await sleep(0);
wrapper.update(); wrapper.update();
const button = wrapper.find('ChipButton').at(0); const button = wrapper.find('Chip Button').at(0);
button.prop('onClick')(); button.prop('onClick')();
wrapper.update(); wrapper.update();
@@ -155,7 +155,7 @@ describe('<ResourceAccessList />', () => {
); );
const button = await waitForElement( const button = await waitForElement(
wrapper, wrapper,
'ChipButton', 'Chip Button',
el => el.length === 2 el => el.length === 2
); );
button.at(0).prop('onClick')(); button.at(0).prop('onClick')();
@@ -188,7 +188,7 @@ describe('<ResourceAccessList />', () => {
); );
const button = await waitForElement( const button = await waitForElement(
wrapper, wrapper,
'ChipButton', 'Chip Button',
el => el.length === 2 el => el.length === 2
); );
button.at(1).prop('onClick')(); button.at(1).prop('onClick')();

View File

@@ -59,10 +59,10 @@ class ResourceAccessListItem extends React.Component {
return ( return (
<Chip <Chip
key={role.id} key={role.id}
isReadOnly={!role.user_capabilities.unattach}
onClick={() => { onClick={() => {
onRoleDelete(role, accessRecord); onRoleDelete(role, accessRecord);
}} }}
isReadOnly={!role.user_capabilities.unattach}
> >
{role.name} {role.name}
</Chip> </Chip>

View File

@@ -92,12 +92,17 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
numChips={5} numChips={5}
totalChips={1} totalChips={1}
> >
<Unknown <Chip
className=""
closeBtnAriaLabel="close"
component="div"
isOverflowChip={false}
isReadOnly={false} isReadOnly={false}
onClick={[Function]} onClick={[Function]}
tooltipPosition="top"
> >
Member Member
</Unknown> </Chip>
</WithI18n> </WithI18n>
} }
/> />
@@ -151,12 +156,17 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
numChips={5} numChips={5}
totalChips={1} totalChips={1}
> >
<Unknown <Chip
className=""
closeBtnAriaLabel="close"
component="div"
isOverflowChip={false}
isReadOnly={false} isReadOnly={false}
onClick={[Function]} onClick={[Function]}
tooltipPosition="top"
> >
Member Member
</Unknown> </Chip>
</WithI18n> </WithI18n>
} }
/> />
@@ -233,12 +243,17 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
numChips={5} numChips={5}
totalChips={1} totalChips={1}
> >
<Unknown <Chip
className=""
closeBtnAriaLabel="close"
component="div"
isOverflowChip={false}
isReadOnly={false} isReadOnly={false}
onClick={[Function]} onClick={[Function]}
tooltipPosition="top"
> >
Member Member
</Unknown> </Chip>
</WithI18n> </WithI18n>
} }
/> />
@@ -661,12 +676,17 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
numChips={5} numChips={5}
totalChips={1} totalChips={1}
> >
<Unknown <Chip
className=""
closeBtnAriaLabel="close"
component="div"
isOverflowChip={false}
isReadOnly={false} isReadOnly={false}
onClick={[Function]} onClick={[Function]}
tooltipPosition="top"
> >
Member Member
</Unknown> </Chip>
</WithI18n> </WithI18n>
} }
> >
@@ -801,175 +821,113 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
totalChips={1} totalChips={1}
> >
<ChipGroup <ChipGroup
className="" aria-label="Chip group category"
categoryName=""
closeBtnAriaLabel="Close chip group"
collapsedText="-4 more" collapsedText="-4 more"
defaultIsOpen={false} defaultIsOpen={false}
expandedText="Show less" expandedText="Show less"
isClosable={false}
numChips={5} numChips={5}
withToolbar={false} onClick={[Function]}
tooltipPosition="top"
> >
<ul <GenerateId
className="pf-c-chip-group" prefix="pf-random-id-"
> >
<InnerChipGroup <div
className="" className="pf-c-chip-group"
collapsedText="-4 more"
defaultIsOpen={false}
expandedText="Show less"
isOpen={false}
numChips={5}
onToggleCollapse={[Function]}
withToolbar={false}
> >
<Component <ul
component="li" aria-label="Chip group category"
isReadOnly={false} className="pf-c-chip-group__list"
key=".$3" role="list"
onClick={[Function]}
> >
<ComponentWithOuia <li
component={[Function]} className="pf-c-chip-group__list-item"
componentProps={ key="0"
Object {
"children": "Member",
"component": "li",
"isReadOnly": false,
"onClick": [Function],
}
}
consumerContext={null}
> >
<Chip <Chip
className="" className=""
closeBtnAriaLabel="close" closeBtnAriaLabel="close"
component="li" component="div"
isOverflowChip={false} isOverflowChip={false}
isReadOnly={false} isReadOnly={false}
key=".$3"
onClick={[Function]} onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
tooltipPosition="top" tooltipPosition="top"
> >
<GenerateId <GenerateId
prefix="pf-random-id-" prefix="pf-random-id-"
> >
<li <div
className="pf-c-chip" className="pf-c-chip"
data-ouia-component-id={1}
data-ouia-component-type="PF4/Chip"
data-ouia-safe={true}
> >
<span <span
className="pf-c-chip__text" className="pf-c-chip__text"
id="pf-random-id-0" id="pf-random-id-1"
> >
Member Member
</span> </span>
<ChipButton <Button
aria-labelledby="remove_pf-random-id-0 pf-random-id-0" aria-label="close"
ariaLabel="close" aria-labelledby="remove_pf-random-id-1 pf-random-id-1"
id="remove_pf-random-id-0" id="remove_pf-random-id-1"
onClick={[Function]} onClick={[Function]}
variant="plain"
> >
<Component <button
aria-disabled={null}
aria-label="close" aria-label="close"
aria-labelledby="remove_pf-random-id-0 pf-random-id-0" aria-labelledby="remove_pf-random-id-1 pf-random-id-1"
className="" className="pf-c-button pf-m-plain"
id="remove_pf-random-id-0" data-ouia-component-id={null}
data-ouia-component-type="PF4/Button"
data-ouia-safe={true}
disabled={false}
id="remove_pf-random-id-1"
onClick={[Function]} onClick={[Function]}
variant="plain" tabIndex={null}
type="button"
> >
<ComponentWithOuia <TimesIcon
component={[Function]} aria-hidden="true"
componentProps={ color="currentColor"
Object { noVerticalAlign={false}
"aria-label": "close", size="sm"
"aria-labelledby": "remove_pf-random-id-0 pf-random-id-0",
"children": <TimesCircleIcon
aria-hidden="true"
color="currentColor"
noVerticalAlign={false}
size="sm"
title={null}
/>,
"className": "",
"id": "remove_pf-random-id-0",
"onClick": [Function],
"variant": "plain",
}
}
consumerContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
> >
<Button <svg
aria-label="close" aria-hidden="true"
aria-labelledby="remove_pf-random-id-0 pf-random-id-0" aria-labelledby={null}
className="" fill="currentColor"
id="remove_pf-random-id-0" height="1em"
onClick={[Function]} role="img"
ouiaContext={ style={
Object { Object {
"isOuia": false, "verticalAlign": "-0.125em",
"ouiaId": null,
} }
} }
variant="plain" viewBox="0 0 352 512"
width="1em"
> >
<button <path
aria-disabled={null} d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
aria-label="close" transform=""
aria-labelledby="remove_pf-random-id-0 pf-random-id-0" />
className="pf-c-button pf-m-plain" </svg>
disabled={false} </TimesIcon>
id="remove_pf-random-id-0" </button>
onClick={[Function]} </Button>
tabIndex={null} </div>
type="button"
>
<TimesCircleIcon
aria-hidden="true"
color="currentColor"
noVerticalAlign={false}
size="sm"
title={null}
>
<svg
aria-hidden="true"
aria-labelledby={null}
fill="currentColor"
height="1em"
role="img"
style={
Object {
"verticalAlign": "-0.125em",
}
}
viewBox="0 0 512 512"
width="1em"
>
<path
d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"
transform=""
/>
</svg>
</TimesCircleIcon>
</button>
</Button>
</ComponentWithOuia>
</Component>
</ChipButton>
</li>
</GenerateId> </GenerateId>
</Chip> </Chip>
</ComponentWithOuia> </li>
</Component> </ul>
</InnerChipGroup> </div>
</ul> </GenerateId>
</ChipGroup> </ChipGroup>
</ChipGroup> </ChipGroup>
</I18n> </I18n>

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { shape, string, number, arrayOf, node, oneOfType } from 'prop-types'; import { shape, string, number, arrayOf, node, oneOfType } from 'prop-types';
import { Tab, Tabs } from '@patternfly/react-core'; import { Tab, Tabs, TabTitleText } from '@patternfly/react-core';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
function RoutedTabs(props) { function RoutedTabs(props) {
@@ -36,7 +36,7 @@ function RoutedTabs(props) {
eventKey={tab.id} eventKey={tab.id}
key={tab.id} key={tab.id}
link={tab.link} link={tab.link}
title={tab.name} title={<TabTitleText>{tab.name}</TabTitleText>}
/> />
))} ))}
</Tabs> </Tabs>

View File

@@ -10,13 +10,10 @@ import {
useLocation, useLocation,
useParams, useParams,
} from 'react-router-dom'; } from 'react-router-dom';
import { CardActions } from '@patternfly/react-core';
import { CaretLeftIcon } from '@patternfly/react-icons'; import { CaretLeftIcon } from '@patternfly/react-icons';
import CardCloseButton from '../CardCloseButton';
import RoutedTabs from '../RoutedTabs'; import RoutedTabs from '../RoutedTabs';
import ContentError from '../ContentError'; import ContentError from '../ContentError';
import ContentLoading from '../ContentLoading'; import ContentLoading from '../ContentLoading';
import { TabbedCardHeader } from '../Card';
import ScheduleDetail from './ScheduleDetail'; import ScheduleDetail from './ScheduleDetail';
import ScheduleEdit from './ScheduleEdit'; import ScheduleEdit from './ScheduleEdit';
import { SchedulesAPI } from '../../api'; import { SchedulesAPI } from '../../api';
@@ -90,23 +87,17 @@ function Schedule({ i18n, setBreadcrumb, unifiedJobTemplate }) {
return <ContentError error={contentError} />; return <ContentError error={contentError} />;
} }
let cardHeader = null; let showCardHeader = true;
if ( if (
location.pathname.includes('schedules/') && !location.pathname.includes('schedules/') ||
!location.pathname.endsWith('edit') location.pathname.endsWith('edit')
) { ) {
cardHeader = ( showCardHeader = false;
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo={`${pathRoot}schedules`} />
</CardActions>
</TabbedCardHeader>
);
} }
return ( return (
<> <>
{cardHeader} {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch> <Switch>
<Redirect <Redirect
from={`${pathRoot}schedules/:scheduleId`} from={`${pathRoot}schedules/:scheduleId`}

View File

@@ -24,6 +24,7 @@ import ChipGroup from '../../ChipGroup';
const PromptTitle = styled(Title)` const PromptTitle = styled(Title)`
--pf-c-title--m-md--FontWeight: 700; --pf-c-title--m-md--FontWeight: 700;
grid-column: 1 / -1;
`; `;
function ScheduleDetail({ schedule, i18n }) { function ScheduleDetail({ schedule, i18n }) {
@@ -140,7 +141,7 @@ function ScheduleDetail({ schedule, i18n }) {
/> />
{showPromptedFields && ( {showPromptedFields && (
<> <>
<PromptTitle size="md" css="grid-column: 1 / -1;"> <PromptTitle headingLevel="h2">
{i18n._(t`Prompted Fields`)} {i18n._(t`Prompted Fields`)}
</PromptTitle> </PromptTitle>
<Detail label={i18n._(t`Job Type`)} value={job_type} /> <Detail label={i18n._(t`Job Type`)} value={job_type} />

View File

@@ -136,7 +136,7 @@ describe('<ScheduleDetail />', () => {
expect(wrapper.find('Detail[label="Skip Tags"]').length).toBe(0); expect(wrapper.find('Detail[label="Skip Tags"]').length).toBe(0);
}); });
test('details should render with the proper values with prompts', async () => { test('details should render with the proper values with prompts', async () => {
SchedulesAPI.readCredentials.mockResolvedValueOnce({ SchedulesAPI.readCredentials.mockResolvedValue({
data: { data: {
count: 2, count: 2,
results: [ results: [
@@ -182,6 +182,7 @@ describe('<ScheduleDetail />', () => {
); );
}); });
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
// await waitForElement(wrapper, 'Title', el => el.length > 0);
expect( expect(
wrapper wrapper
.find('Detail[label="Name"]') .find('Detail[label="Name"]')

View File

@@ -36,7 +36,7 @@ function ScheduleOccurrences({ preview = { local: [], utc: [] }, i18n }) {
fullWidth fullWidth
css="grid-column: 1 / -1" css="grid-column: 1 / -1"
> >
<Split gutter="sm"> <Split hasGutter>
<SplitItem> <SplitItem>
<OccurrencesLabel> <OccurrencesLabel>
<span>{i18n._(t`Occurrences`)}</span> <span>{i18n._(t`Occurrences`)}</span>

View File

@@ -231,7 +231,9 @@ const FrequencyDetailSubform = ({ i18n }) => {
fieldId="schedule-run-every" fieldId="schedule-run-every"
helperTextInvalid={intervalMeta.error} helperTextInvalid={intervalMeta.error}
isRequired isRequired
isValid={!intervalMeta.touched || !intervalMeta.error} validated={
!intervalMeta.touched || !intervalMeta.error ? 'default' : 'error'
}
label={i18n._(t`Run every`)} label={i18n._(t`Run every`)}
> >
<div css="display: flex"> <div css="display: flex">
@@ -255,7 +257,11 @@ const FrequencyDetailSubform = ({ i18n }) => {
fieldId="schedule-days-of-week" fieldId="schedule-days-of-week"
helperTextInvalid={daysOfWeekMeta.error} helperTextInvalid={daysOfWeekMeta.error}
isRequired isRequired
isValid={!daysOfWeekMeta.touched || !daysOfWeekMeta.error} validated={
!daysOfWeekMeta.touched || !daysOfWeekMeta.error
? 'default'
: 'error'
}
label={i18n._(t`On days`)} label={i18n._(t`On days`)}
> >
<div css="display: flex"> <div css="display: flex">
@@ -339,7 +345,9 @@ const FrequencyDetailSubform = ({ i18n }) => {
fieldId="schedule-run-on" fieldId="schedule-run-on"
helperTextInvalid={runOnMeta.error} helperTextInvalid={runOnMeta.error}
isRequired isRequired
isValid={!runOnMeta.touched || !runOnMeta.error} validated={
!runOnMeta.touched || !runOnMeta.error ? 'default' : 'error'
}
label={i18n._(t`Run on`)} label={i18n._(t`Run on`)}
> >
<RunOnRadio <RunOnRadio
@@ -502,7 +510,7 @@ const FrequencyDetailSubform = ({ i18n }) => {
fieldId="schedule-end" fieldId="schedule-end"
helperTextInvalid={endMeta.error} helperTextInvalid={endMeta.error}
isRequired isRequired
isValid={!endMeta.touched || !endMeta.error} validated={!endMeta.touched || !endMeta.error ? 'default' : 'error'}
label={i18n._(t`End`)} label={i18n._(t`End`)}
> >
<Radio <Radio
@@ -556,7 +564,11 @@ const FrequencyDetailSubform = ({ i18n }) => {
fieldId="schedule-end-datetime" fieldId="schedule-end-datetime"
helperTextInvalid={endDateTimeMeta.error} helperTextInvalid={endDateTimeMeta.error}
isRequired isRequired
isValid={!endDateTimeMeta.touched || !endDateTimeMeta.error} validated={
!endDateTimeMeta.touched || !endDateTimeMeta.error
? 'default'
: 'error'
}
label={i18n._(t`End date/time`)} label={i18n._(t`End date/time`)}
> >
<input <input

View File

@@ -104,7 +104,11 @@ function ScheduleFormFields({ i18n, zoneOptions }) {
fieldId="schedule-start-datetime" fieldId="schedule-start-datetime"
helperTextInvalid={startDateTimeMeta.error} helperTextInvalid={startDateTimeMeta.error}
isRequired isRequired
isValid={!startDateTimeMeta.touched || !startDateTimeMeta.error} validated={
!startDateTimeMeta.touched || !startDateTimeMeta.error
? 'default'
: 'error'
}
label={i18n._(t`Start date/time`)} label={i18n._(t`Start date/time`)}
> >
<input <input
@@ -120,7 +124,9 @@ function ScheduleFormFields({ i18n, zoneOptions }) {
fieldId="schedule-timezone" fieldId="schedule-timezone"
helperTextInvalid={timezoneMeta.error} helperTextInvalid={timezoneMeta.error}
isRequired isRequired
isValid={!timezoneMeta.touched || !timezoneMeta.error} validated={
!timezoneMeta.touched || !timezoneMeta.error ? 'default' : 'error'
}
label={i18n._(t`Local time zone`)} label={i18n._(t`Local time zone`)}
> >
<AnsibleSelect <AnsibleSelect
@@ -134,7 +140,9 @@ function ScheduleFormFields({ i18n, zoneOptions }) {
fieldId="schedule-requency" fieldId="schedule-requency"
helperTextInvalid={frequencyMeta.error} helperTextInvalid={frequencyMeta.error}
isRequired isRequired
isValid={!frequencyMeta.touched || !frequencyMeta.error} validated={
!frequencyMeta.touched || !frequencyMeta.error ? 'default' : 'error'
}
label={i18n._(t`Run frequency`)} label={i18n._(t`Run frequency`)}
> >
<AnsibleSelect <AnsibleSelect
@@ -153,7 +161,9 @@ function ScheduleFormFields({ i18n, zoneOptions }) {
</FormGroup> </FormGroup>
{frequency.value !== 'none' && ( {frequency.value !== 'none' && (
<SubFormLayout> <SubFormLayout>
<Title size="md">{i18n._(t`Frequency Details`)}</Title> <Title size="md" headingLevel="h4">
{i18n._(t`Frequency Details`)}
</Title>
<FormColumnLayout> <FormColumnLayout>
<FrequencyDetailSubform /> <FrequencyDetailSubform />
</FormColumnLayout> </FormColumnLayout>

View File

@@ -16,12 +16,10 @@ import {
SelectOption, SelectOption,
SelectVariant, SelectVariant,
TextInput, TextInput,
ToolbarGroup,
ToolbarItem,
ToolbarFilter,
} from '@patternfly/react-core'; } from '@patternfly/react-core';
import {
DataToolbarGroup,
DataToolbarItem,
DataToolbarFilter,
} from '@patternfly/react-core/dist/umd/experimental';
import { SearchIcon } from '@patternfly/react-icons'; import { SearchIcon } from '@patternfly/react-icons';
import styled from 'styled-components'; import styled from 'styled-components';
import { parseQueryString } from '../../util/qs'; import { parseQueryString } from '../../util/qs';
@@ -205,8 +203,8 @@ class Search extends React.Component {
const chipsByKey = getChipsByKey(); const chipsByKey = getChipsByKey();
return ( return (
<DataToolbarGroup variant="filter-group"> <ToolbarGroup variant="filter-group">
<DataToolbarItem> <ToolbarItem>
{searchDropdownItems.length > 0 ? ( {searchDropdownItems.length > 0 ? (
<Dropdown <Dropdown
onToggle={this.handleDropdownToggle} onToggle={this.handleDropdownToggle}
@@ -227,10 +225,10 @@ class Search extends React.Component {
) : ( ) : (
<NoOptionDropdown>{searchColumnName}</NoOptionDropdown> <NoOptionDropdown>{searchColumnName}</NoOptionDropdown>
)} )}
</DataToolbarItem> </ToolbarItem>
{columns.map( {columns.map(
({ key, name, options, isBoolean, booleanLabels = {} }) => ( ({ key, name, options, isBoolean, booleanLabels = {} }) => (
<DataToolbarFilter <ToolbarFilter
chips={chipsByKey[key] ? chipsByKey[key].chips : []} chips={chipsByKey[key] ? chipsByKey[key].chips : []}
deleteChip={(unusedKey, chip) => { deleteChip={(unusedKey, chip) => {
const [columnKey, ...value] = chip.key.split(':'); const [columnKey, ...value] = chip.key.split(':');
@@ -253,7 +251,7 @@ class Search extends React.Component {
const [, ...value] = chip.key.split(':'); const [, ...value] = chip.key.split(':');
return value.join(':'); return value.join(':');
})} })}
isExpanded={isFilterDropdownOpen} isOpen={isFilterDropdownOpen}
placeholderText={`Filter By ${name}`} placeholderText={`Filter By ${name}`}
> >
{options.map(([optionKey, optionLabel]) => ( {options.map(([optionKey, optionLabel]) => (
@@ -272,7 +270,7 @@ class Search extends React.Component {
this.handleFilterBooleanSelect(key, selection) this.handleFilterBooleanSelect(key, selection)
} }
selections={chipsByKey[key].chips[0]} selections={chipsByKey[key].chips[0]}
isExpanded={isFilterDropdownOpen} isOpen={isFilterDropdownOpen}
placeholderText={`Filter By ${name}`} placeholderText={`Filter By ${name}`}
> >
<SelectOption key="true" value="true"> <SelectOption key="true" value="true">
@@ -311,10 +309,10 @@ class Search extends React.Component {
</div> </div>
</InputGroup> </InputGroup>
)} )}
</DataToolbarFilter> </ToolbarFilter>
) )
)} )}
</DataToolbarGroup> </ToolbarGroup>
); );
} }
} }

View File

@@ -1,8 +1,5 @@
import React from 'react'; import React from 'react';
import { import { Toolbar, ToolbarContent } from '@patternfly/react-core';
DataToolbar,
DataToolbarContent,
} from '@patternfly/react-core/dist/umd/experimental';
import { createMemoryHistory } from 'history'; import { createMemoryHistory } from 'history';
import { act } from 'react-dom/test-utils'; import { act } from 'react-dom/test-utils';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
@@ -33,15 +30,15 @@ describe('<Search />', () => {
const onSearch = jest.fn(); const onSearch = jest.fn();
search = mountWithContexts( search = mountWithContexts(
<DataToolbar <Toolbar
id={`${QS_CONFIG.namespace}-list-toolbar`} id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} /> <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
</DataToolbarContent> </ToolbarContent>
</DataToolbar> </Toolbar>
); );
search.find(searchTextInput).instance().value = 'test-321'; search.find(searchTextInput).instance().value = 'test-321';
@@ -56,15 +53,15 @@ describe('<Search />', () => {
const columns = [{ name: 'Name', key: 'name', isDefault: true }]; const columns = [{ name: 'Name', key: 'name', isDefault: true }];
const onSearch = jest.fn(); const onSearch = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar <Toolbar
id={`${QS_CONFIG.namespace}-list-toolbar`} id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} /> <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
</DataToolbarContent> </ToolbarContent>
</DataToolbar> </Toolbar>
).find('Search'); ).find('Search');
expect(wrapper.state('isSearchDropdownOpen')).toEqual(false); expect(wrapper.state('isSearchDropdownOpen')).toEqual(false);
wrapper.instance().handleDropdownToggle(true); wrapper.instance().handleDropdownToggle(true);
@@ -78,15 +75,15 @@ describe('<Search />', () => {
]; ];
const onSearch = jest.fn(); const onSearch = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar <Toolbar
id={`${QS_CONFIG.namespace}-list-toolbar`} id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} /> <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
</DataToolbarContent> </ToolbarContent>
</DataToolbar> </Toolbar>
).find('Search'); ).find('Search');
expect(wrapper.state('searchKey')).toEqual('name'); expect(wrapper.state('searchKey')).toEqual('name');
wrapper wrapper
@@ -101,15 +98,15 @@ describe('<Search />', () => {
const columns = [{ name: 'Name', key: 'name', isDefault: true }]; const columns = [{ name: 'Name', key: 'name', isDefault: true }];
const onSearch = jest.fn(); const onSearch = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar <Toolbar
id={`${QS_CONFIG.namespace}-list-toolbar`} id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} /> <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
</DataToolbarContent> </ToolbarContent>
</DataToolbar> </Toolbar>
); );
wrapper.find(searchTextInput).instance().value = ''; wrapper.find(searchTextInput).instance().value = '';
@@ -125,15 +122,15 @@ describe('<Search />', () => {
const columns = [{ name: 'Name', key: 'name', isDefault: true }]; const columns = [{ name: 'Name', key: 'name', isDefault: true }];
const onSearch = jest.fn(); const onSearch = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar <Toolbar
id={`${QS_CONFIG.namespace}-list-toolbar`} id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} /> <Search qsConfig={QS_CONFIG} columns={columns} onSearch={onSearch} />
</DataToolbarContent> </ToolbarContent>
</DataToolbar> </Toolbar>
); );
wrapper.find(searchTextInput).instance().value = 'test-321'; wrapper.find(searchTextInput).instance().value = 'test-321';
@@ -156,23 +153,23 @@ describe('<Search />', () => {
initialEntries: [`/organizations/${query}`], initialEntries: [`/organizations/${query}`],
}); });
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar <Toolbar
id={`${QS_CONFIG.namespace}-list-toolbar`} id={`${QS_CONFIG.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search qsConfig={QS_CONFIG} columns={columns} /> <Search qsConfig={QS_CONFIG} columns={columns} />
</DataToolbarContent> </ToolbarContent>
</DataToolbar>, </Toolbar>,
{ context: { router: { history } } } { context: { router: { history } } }
); );
const typeFilterWrapper = wrapper.find( const typeFilterWrapper = wrapper.find(
'DataToolbarFilter[categoryName="Type"]' 'ToolbarFilter[categoryName="Type"]'
); );
expect(typeFilterWrapper.prop('chips')[0].key).toEqual('or__type:foo'); expect(typeFilterWrapper.prop('chips')[0].key).toEqual('or__type:foo');
const nameFilterWrapper = wrapper.find( const nameFilterWrapper = wrapper.find(
'DataToolbarFilter[categoryName="Name"]' 'ToolbarFilter[categoryName="Name"]'
); );
expect(nameFilterWrapper.prop('chips')[0].key).toEqual('name:bar'); expect(nameFilterWrapper.prop('chips')[0].key).toEqual('name:bar');
}); });
@@ -197,19 +194,19 @@ describe('<Search />', () => {
}); });
const onRemove = jest.fn(); const onRemove = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar <Toolbar
id={`${qsConfigNew.namespace}-list-toolbar`} id={`${qsConfigNew.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search <Search
qsConfig={qsConfigNew} qsConfig={qsConfigNew}
columns={columns} columns={columns}
onRemove={onRemove} onRemove={onRemove}
/> />
</DataToolbarContent> </ToolbarContent>
</DataToolbar>, </Toolbar>,
{ context: { router: { history } } } { context: { router: { history } } }
); );
expect(history.location.search).toEqual(query); expect(history.location.search).toEqual(query);
@@ -243,19 +240,19 @@ describe('<Search />', () => {
}); });
const onRemove = jest.fn(); const onRemove = jest.fn();
const wrapper = mountWithContexts( const wrapper = mountWithContexts(
<DataToolbar <Toolbar
id={`${qsConfigNew.namespace}-list-toolbar`} id={`${qsConfigNew.namespace}-list-toolbar`}
clearAllFilters={() => {}} clearAllFilters={() => {}}
collapseListedFiltersBreakpoint="md" collapseListedFiltersBreakpoint="lg"
> >
<DataToolbarContent> <ToolbarContent>
<Search <Search
qsConfig={qsConfigNew} qsConfig={qsConfigNew}
columns={columns} columns={columns}
onRemove={onRemove} onRemove={onRemove}
/> />
</DataToolbarContent> </ToolbarContent>
</DataToolbar>, </Toolbar>,
{ context: { router: { history } } } { context: { router: { history } } }
); );
expect(history.location.search).toEqual(query); expect(history.location.search).toEqual(query);

View File

@@ -56,6 +56,7 @@ describe('<UserAndTeamAccessAdd/>', () => {
/> />
); );
}); });
await waitForElement(wrapper, 'PFWizard');
}); });
afterEach(() => { afterEach(() => {
wrapper.unmount(); wrapper.unmount();
@@ -68,12 +69,12 @@ describe('<UserAndTeamAccessAdd/>', () => {
expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true); expect(wrapper.find('Button[type="submit"]').prop('isDisabled')).toBe(true);
expect( expect(
wrapper wrapper
.find('WizardNavItem[text="Select items from list"]') .find('WizardNavItem[content="Select items from list"]')
.prop('isDisabled') .prop('isDisabled')
).toBe(true); ).toBe(true);
expect( expect(
wrapper wrapper
.find('WizardNavItem[text="Select roles to apply"]') .find('WizardNavItem[content="Select roles to apply"]')
.prop('isDisabled') .prop('isDisabled')
).toBe(true); ).toBe(true);
await act(async () => await act(async () =>
@@ -89,17 +90,19 @@ describe('<UserAndTeamAccessAdd/>', () => {
wrapper.find('Button[type="submit"]').prop('onClick')() wrapper.find('Button[type="submit"]').prop('onClick')()
); );
wrapper.update(); wrapper.update();
expect(
wrapper.find('WizardNavItem[text="Add resource type"]').prop('isDisabled')
).toBe(false);
expect( expect(
wrapper wrapper
.find('WizardNavItem[text="Select items from list"]') .find('WizardNavItem[content="Add resource type"]')
.prop('isDisabled') .prop('isDisabled')
).toBe(false); ).toBe(false);
expect( expect(
wrapper wrapper
.find('WizardNavItem[text="Select roles to apply"]') .find('WizardNavItem[content="Select items from list"]')
.prop('isDisabled')
).toBe(false);
expect(
wrapper
.find('WizardNavItem[content="Select roles to apply"]')
.prop('isDisabled') .prop('isDisabled')
).toBe(true); ).toBe(true);
}); });

View File

@@ -3,7 +3,7 @@ import styled from 'styled-components';
Wizard.displayName = 'PFWizard'; Wizard.displayName = 'PFWizard';
export default styled(Wizard)` export default styled(Wizard)`
.pf-c-data-toolbar__content { .pf-c-toolbar__content {
padding: 0 !important; padding: 0 !important;
} }
`; `;

View File

@@ -91,8 +91,8 @@ describe('<ApplicationAdd/>', () => {
wrapper.update(); wrapper.update();
expect(wrapper.find('input#name').prop('value')).toBe('new foo'); expect(wrapper.find('input#name').prop('value')).toBe('new foo');
expect(wrapper.find('input#description').prop('value')).toBe('new bar'); expect(wrapper.find('input#description').prop('value')).toBe('new bar');
expect(wrapper.find('InnerChipGroup').length).toBe(1); expect(wrapper.find('Chip').length).toBe(1);
expect(wrapper.find('InnerChipGroup').text()).toBe('organization'); expect(wrapper.find('Chip').text()).toBe('organization');
expect( expect(
wrapper wrapper
.find('AnsibleSelect[name="authorization_grant_type"]') .find('AnsibleSelect[name="authorization_grant_type"]')

View File

@@ -107,8 +107,8 @@ describe('<ApplicationForm', () => {
wrapper.update(); wrapper.update();
expect(wrapper.find('input#name').prop('value')).toBe('new foo'); expect(wrapper.find('input#name').prop('value')).toBe('new foo');
expect(wrapper.find('input#description').prop('value')).toBe('new bar'); expect(wrapper.find('input#description').prop('value')).toBe('new bar');
expect(wrapper.find('InnerChipGroup').length).toBe(1); expect(wrapper.find('Chip').length).toBe(1);
expect(wrapper.find('InnerChipGroup').text()).toBe('organization'); expect(wrapper.find('Chip').text()).toBe('organization');
expect( expect(
wrapper wrapper
.find('AnsibleSelect[name="authorization_grant_type"]') .find('AnsibleSelect[name="authorization_grant_type"]')

View File

@@ -15,7 +15,9 @@ class AuthSettings extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`Authentication Settings`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`Authentication Settings`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -1,7 +1,8 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { Card, PageSection, CardActions } from '@patternfly/react-core'; import { CaretLeftIcon } from '@patternfly/react-icons';
import { Card, PageSection } from '@patternfly/react-core';
import { import {
Switch, Switch,
useParams, useParams,
@@ -11,8 +12,6 @@ import {
Redirect, Redirect,
Link, Link,
} from 'react-router-dom'; } from 'react-router-dom';
import { TabbedCardHeader } from '../../components/Card';
import CardCloseButton from '../../components/CardCloseButton';
import { ResourceAccessList } from '../../components/ResourceAccessList'; import { ResourceAccessList } from '../../components/ResourceAccessList';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import RoutedTabs from '../../components/RoutedTabs'; import RoutedTabs from '../../components/RoutedTabs';
@@ -46,6 +45,16 @@ function Credential({ i18n, setBreadcrumb }) {
}, [id, pathname, setBreadcrumb]); }, [id, pathname, setBreadcrumb]);
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Credentials`)}
</>
),
link: `/credentials`,
id: 99,
},
{ name: i18n._(t`Details`), link: `/credentials/${id}/details`, id: 0 }, { name: i18n._(t`Details`), link: `/credentials/${id}/details`, id: 0 },
]; ];
@@ -57,17 +66,10 @@ function Credential({ i18n, setBreadcrumb }) {
}); });
} }
let cardHeader = hasContentLoading ? null : ( let showCardHeader = true;
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/credentials" />
</CardActions>
</TabbedCardHeader>
);
if (pathname.endsWith('edit') || pathname.endsWith('add')) { if (pathname.endsWith('edit') || pathname.endsWith('add')) {
cardHeader = null; showCardHeader = false;
} }
if (!hasContentLoading && contentError) { if (!hasContentLoading && contentError) {
@@ -90,7 +92,7 @@ function Credential({ i18n, setBreadcrumb }) {
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{cardHeader} {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch> <Switch>
<Redirect <Redirect
from="/credentials/:id" from="/credentials/:id"

View File

@@ -31,7 +31,7 @@ describe('<Credential />', () => {
wrapper = mountWithContexts(<Credential setBreadcrumb={() => {}} />); wrapper = mountWithContexts(<Credential setBreadcrumb={() => {}} />);
}); });
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 1); await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 2);
}); });
test('initially renders org-based credential succesfully', async () => { test('initially renders org-based credential succesfully', async () => {
@@ -44,7 +44,7 @@ describe('<Credential />', () => {
}); });
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
// org-based credential detail needs access tab // org-based credential detail needs access tab
await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 2); await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 3);
}); });
test('should show content error when user attempts to navigate to erroneous route', async () => { test('should show content error when user attempts to navigate to erroneous route', async () => {

View File

@@ -104,7 +104,9 @@ function CredentialFormFields({
fieldId="credential-credentialType" fieldId="credential-credentialType"
helperTextInvalid={credTypeMeta.error} helperTextInvalid={credTypeMeta.error}
isRequired isRequired
isValid={!credTypeMeta.touched || !credTypeMeta.error} validated={
!credTypeMeta.touched || !credTypeMeta.error ? 'default' : 'error'
}
label={i18n._(t`Credential Type`)} label={i18n._(t`Credential Type`)}
> >
<AnsibleSelect <AnsibleSelect

View File

@@ -191,6 +191,12 @@ describe('<CredentialForm />', () => {
).toBe(''); ).toBe('');
}); });
test('should show error when error thrown parsing JSON', async () => { test('should show error when error thrown parsing JSON', async () => {
await act(async () => {
await wrapper
.find('AnsibleSelect[id="credential_type"]')
.invoke('onChange')(null, 10);
});
wrapper.update();
expect(wrapper.find('#credential-gce-file-helper').text()).toBe( expect(wrapper.find('#credential-gce-file-helper').text()).toBe(
'Select a JSON formatted service account key to autopopulate the following fields.' 'Select a JSON formatted service account key to autopopulate the following fields.'
); );
@@ -201,7 +207,15 @@ describe('<CredentialForm />', () => {
}); });
}); });
wrapper.update(); wrapper.update();
expect(wrapper.find('#credential-gce-file-helper').text()).toBe( expect(
wrapper.find('FormGroup[fieldId="credential-gce-file"]').prop('isValid')
).toBe(false);
expect(
wrapper
.find('FormGroup[fieldId="credential-gce-file"]')
.prop('helperTextInvalid')
).toBe(
'There was an error parsing the file. Please check the file formatting and try again.' 'There was an error parsing the file. Please check the file formatting and try again.'
); );
}); });

View File

@@ -21,7 +21,9 @@ function TypeInputsSubForm({ credentialType, i18n }) {
); );
return ( return (
<SubFormLayout> <SubFormLayout>
<Title size="md">{i18n._(t`Type Details`)}</Title> <Title size="md" headingLevel="h4">
{i18n._(t`Type Details`)}
</Title>
<FormColumnLayout> <FormColumnLayout>
{credentialType.namespace === 'gce' && <GceFileUploadField />} {credentialType.namespace === 'gce' && <GceFileUploadField />}
{stringFields.map(fieldOptions => {stringFields.map(fieldOptions =>

View File

@@ -15,7 +15,9 @@ class Dashboard extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`Dashboard`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`Dashboard`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -9,10 +9,8 @@ import {
useRouteMatch, useRouteMatch,
useLocation, useLocation,
} from 'react-router-dom'; } from 'react-router-dom';
import { Card, CardActions, PageSection } from '@patternfly/react-core'; import { CaretLeftIcon } from '@patternfly/react-icons';
import { Card, PageSection } from '@patternfly/react-core';
import { TabbedCardHeader } from '../../components/Card';
import CardCloseButton from '../../components/CardCloseButton';
import RoutedTabs from '../../components/RoutedTabs'; import RoutedTabs from '../../components/RoutedTabs';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import ContentLoading from '../../components/ContentLoading'; import ContentLoading from '../../components/ContentLoading';
@@ -47,6 +45,16 @@ function Host({ i18n, setBreadcrumb }) {
}, [match.params.id, location, setBreadcrumb]); }, [match.params.id, location, setBreadcrumb]);
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Hosts`)}
</>
),
link: `/hosts`,
id: 99,
},
{ {
name: i18n._(t`Details`), name: i18n._(t`Details`),
link: `${match.url}/details`, link: `${match.url}/details`,
@@ -96,17 +104,16 @@ function Host({ i18n, setBreadcrumb }) {
); );
} }
let showCardHeader = true;
if (location.pathname.endsWith('edit')) {
showCardHeader = false;
}
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{location.pathname.endsWith('edit') ? null : ( {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/hosts" />
</CardActions>
</TabbedCardHeader>
)}
<Switch> <Switch>
<Redirect from="/hosts/:id" to="/hosts/:id/details" exact /> <Redirect from="/hosts/:id" to="/hosts/:id/details" exact />
{host && [ {host && [

View File

@@ -15,7 +15,9 @@ class InstanceGroups extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`Instance Groups`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`Instance Groups`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -9,10 +9,8 @@ import {
useLocation, useLocation,
useRouteMatch, useRouteMatch,
} from 'react-router-dom'; } from 'react-router-dom';
import { CaretLeftIcon } from '@patternfly/react-icons';
import { Card, CardActions, PageSection } from '@patternfly/react-core'; import { Card, PageSection } from '@patternfly/react-core';
import { TabbedCardHeader } from '../../components/Card';
import CardCloseButton from '../../components/CardCloseButton';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import ContentLoading from '../../components/ContentLoading'; import ContentLoading from '../../components/ContentLoading';
import JobList from '../../components/JobList'; import JobList from '../../components/JobList';
@@ -51,6 +49,16 @@ function Inventory({ i18n, setBreadcrumb }) {
}, [match.params.id, location.pathname, setBreadcrumb]); }, [match.params.id, location.pathname, setBreadcrumb]);
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Inventories`)}
</>
),
link: `/inventories`,
id: 99,
},
{ name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 }, { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
{ name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 }, { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 },
{ name: i18n._(t`Groups`), link: `${match.url}/groups`, id: 2 }, { name: i18n._(t`Groups`), link: `${match.url}/groups`, id: 2 },
@@ -90,19 +98,20 @@ function Inventory({ i18n, setBreadcrumb }) {
); );
} }
let showCardHeader = true;
if (
['edit', 'add', 'groups/', 'hosts/', 'sources/'].some(name =>
location.pathname.includes(name)
)
) {
showCardHeader = false;
}
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{['edit', 'add', 'groups/', 'hosts/', 'sources/'].some(name => {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
location.pathname.includes(name)
) ? null : (
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/inventories" />
</CardActions>
</TabbedCardHeader>
)}
<Switch> <Switch>
<Redirect <Redirect
from="/inventories/inventory/:id" from="/inventories/inventory/:id"

View File

@@ -30,7 +30,7 @@ describe('<Inventory />', () => {
wrapper = mountWithContexts(<Inventory setBreadcrumb={() => {}} />); wrapper = mountWithContexts(<Inventory setBreadcrumb={() => {}} />);
}); });
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 6); await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 7);
}); });
test('should show content error when user attempts to navigate to erroneous route', async () => { test('should show content error when user attempts to navigate to erroneous route', async () => {

View File

@@ -10,13 +10,10 @@ import {
useLocation, useLocation,
useParams, useParams,
} from 'react-router-dom'; } from 'react-router-dom';
import { CardActions } from '@patternfly/react-core';
import { CaretLeftIcon } from '@patternfly/react-icons'; import { CaretLeftIcon } from '@patternfly/react-icons';
import CardCloseButton from '../../../components/CardCloseButton';
import RoutedTabs from '../../../components/RoutedTabs'; import RoutedTabs from '../../../components/RoutedTabs';
import ContentError from '../../../components/ContentError'; import ContentError from '../../../components/ContentError';
import ContentLoading from '../../../components/ContentLoading'; import ContentLoading from '../../../components/ContentLoading';
import { TabbedCardHeader } from '../../../components/Card';
import InventoryGroupEdit from '../InventoryGroupEdit/InventoryGroupEdit'; import InventoryGroupEdit from '../InventoryGroupEdit/InventoryGroupEdit';
import InventoryGroupDetail from '../InventoryGroupDetail/InventoryGroupDetail'; import InventoryGroupDetail from '../InventoryGroupDetail/InventoryGroupDetail';
import InventoryGroupHosts from '../InventoryGroupHosts'; import InventoryGroupHosts from '../InventoryGroupHosts';
@@ -99,18 +96,14 @@ function InventoryGroup({ i18n, setBreadcrumb, inventory }) {
); );
} }
let showCardHeader = true;
if (['add', 'edit'].some(name => location.pathname.includes(name))) {
showCardHeader = false;
}
return ( return (
<> <>
{['add', 'edit'].some(name => location.pathname.includes(name)) ? null : ( {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton
linkTo={`/inventories/inventory/${inventory.id}/groups`}
/>
</CardActions>
</TabbedCardHeader>
)}
<Switch> <Switch>
<Redirect <Redirect
from="/inventories/inventory/:id/groups/:groupId" from="/inventories/inventory/:id/groups/:groupId"

View File

@@ -163,9 +163,7 @@ describe('<InventoryGroupsList />', () => {
}); });
wrapper.update(); wrapper.update();
await act(async () => { await act(async () => {
wrapper wrapper.find('Toolbar Button[aria-label="Delete"]').invoke('onClick')();
.find('DataToolbar Button[aria-label="Delete"]')
.invoke('onClick')();
}); });
await waitForElement( await waitForElement(
wrapper, wrapper,
@@ -197,14 +195,12 @@ describe('<InventoryGroupsList />', () => {
}); });
wrapper.update(); wrapper.update();
await act(async () => { await act(async () => {
wrapper wrapper.find('Toolbar Button[aria-label="Delete"]').invoke('onClick')();
.find('DataToolbar Button[aria-label="Delete"]')
.invoke('onClick')();
}); });
await waitForElement( await waitForElement(
wrapper, wrapper,
'InventoryGroupsDeleteModal', 'AlertModal[title="Delete Group?"]',
el => el.props().isModalOpen === true el => el.props().isOpen === true
); );
await act(async () => { await act(async () => {
wrapper.find('Radio[id="radio-delete"]').invoke('onChange')(); wrapper.find('Radio[id="radio-delete"]').invoke('onChange')();
@@ -215,7 +211,11 @@ describe('<InventoryGroupsList />', () => {
.find('ModalBoxFooter Button[aria-label="Delete"]') .find('ModalBoxFooter Button[aria-label="Delete"]')
.invoke('onClick')(); .invoke('onClick')();
}); });
await waitForElement(wrapper, { title: 'Error!', variant: 'error' }); await waitForElement(
wrapper,
'AlertModal[title="Error!"] Modal',
el => el.props().isOpen === true && el.props().title === 'Error!'
);
await act(async () => { await act(async () => {
wrapper.find('ModalBoxCloseButton').invoke('onClose')(); wrapper.find('ModalBoxCloseButton').invoke('onClose')();
}); });

View File

@@ -9,13 +9,11 @@ import {
useRouteMatch, useRouteMatch,
useLocation, useLocation,
} from 'react-router-dom'; } from 'react-router-dom';
import { Card, CardActions } from '@patternfly/react-core'; import { Card } from '@patternfly/react-core';
import { CaretLeftIcon } from '@patternfly/react-icons'; import { CaretLeftIcon } from '@patternfly/react-icons';
import useRequest from '../../../util/useRequest'; import useRequest from '../../../util/useRequest';
import { InventoriesAPI } from '../../../api'; import { InventoriesAPI } from '../../../api';
import { TabbedCardHeader } from '../../../components/Card';
import CardCloseButton from '../../../components/CardCloseButton';
import ContentError from '../../../components/ContentError'; import ContentError from '../../../components/ContentError';
import ContentLoading from '../../../components/ContentLoading'; import ContentLoading from '../../../components/ContentLoading';
import RoutedTabs from '../../../components/RoutedTabs'; import RoutedTabs from '../../../components/RoutedTabs';
@@ -110,16 +108,14 @@ function InventoryHost({ i18n, setBreadcrumb, inventory }) {
); );
} }
let showCardHeader = true;
if (['edit'].some(name => location.pathname.includes(name))) {
showCardHeader = false;
}
return ( return (
<> <>
{['edit'].some(name => location.pathname.includes(name)) ? null : ( {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo={hostListUrl} />
</CardActions>
</TabbedCardHeader>
)}
{isLoading && <ContentLoading />} {isLoading && <ContentLoading />}

View File

@@ -10,7 +10,6 @@ import {
useLocation, useLocation,
} from 'react-router-dom'; } from 'react-router-dom';
import { CaretLeftIcon } from '@patternfly/react-icons'; import { CaretLeftIcon } from '@patternfly/react-icons';
import { CardActions } from '@patternfly/react-core';
import useRequest from '../../../util/useRequest'; import useRequest from '../../../util/useRequest';
import { import {
@@ -18,9 +17,7 @@ import {
InventorySourcesAPI, InventorySourcesAPI,
OrganizationsAPI, OrganizationsAPI,
} from '../../../api'; } from '../../../api';
import { TabbedCardHeader } from '../../../components/Card';
import { Schedules } from '../../../components/Schedule'; import { Schedules } from '../../../components/Schedule';
import CardCloseButton from '../../../components/CardCloseButton';
import ContentError from '../../../components/ContentError'; import ContentError from '../../../components/ContentError';
import ContentLoading from '../../../components/ContentLoading'; import ContentLoading from '../../../components/ContentLoading';
import RoutedTabs from '../../../components/RoutedTabs'; import RoutedTabs from '../../../components/RoutedTabs';
@@ -112,18 +109,15 @@ function InventorySource({ i18n, inventory, setBreadcrumb, me }) {
return <ContentError error={error} />; return <ContentError error={error} />;
} }
let showCardHeader = true;
if (['edit', 'schedules/'].some(name => location.pathname.includes(name))) {
showCardHeader = false;
}
return ( return (
<> <>
{['edit', 'schedules/'].some(name => {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
location.pathname.includes(name)
) ? null : (
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo={sourceListUrl} />
</CardActions>
</TabbedCardHeader>
)}
{isLoading && <ContentLoading />} {isLoading && <ContentLoading />}

View File

@@ -1,10 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { Card, CardActions, PageSection } from '@patternfly/react-core'; import { CaretLeftIcon } from '@patternfly/react-icons';
import { Card, PageSection } from '@patternfly/react-core';
import { Switch, Route, Redirect, withRouter, Link } from 'react-router-dom'; import { Switch, Route, Redirect, withRouter, Link } from 'react-router-dom';
import { TabbedCardHeader } from '../../components/Card';
import CardCloseButton from '../../components/CardCloseButton';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import JobList from '../../components/JobList'; import JobList from '../../components/JobList';
import RoutedTabs from '../../components/RoutedTabs'; import RoutedTabs from '../../components/RoutedTabs';
@@ -64,6 +63,16 @@ class SmartInventory extends Component {
const { contentError, hasContentLoading, inventory } = this.state; const { contentError, hasContentLoading, inventory } = this.state;
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Inventories`)}
</>
),
link: `/inventories`,
id: 99,
},
{ name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 }, { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
{ name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 }, { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 },
{ name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 2 }, { name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 2 },
@@ -74,17 +83,10 @@ class SmartInventory extends Component {
}, },
]; ];
let cardHeader = hasContentLoading ? null : ( let showCardHeader = true;
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/inventories" />
</CardActions>
</TabbedCardHeader>
);
if (location.pathname.endsWith('edit')) { if (location.pathname.endsWith('edit')) {
cardHeader = null; showCardHeader = false;
} }
if (!hasContentLoading && contentError) { if (!hasContentLoading && contentError) {
@@ -108,7 +110,7 @@ class SmartInventory extends Component {
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{cardHeader} {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch> <Switch>
<Redirect <Redirect
from="/inventories/smart_inventory/:id" from="/inventories/smart_inventory/:id"

View File

@@ -29,7 +29,7 @@ describe('<SmartInventory />', () => {
'SmartInventory', 'SmartInventory',
el => el.state('hasContentLoading') === false el => el.state('hasContentLoading') === false
); );
await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 4); await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 5);
done(); done();
}); });
test('should show content error when user attempts to navigate to erroneous route', async () => { test('should show content error when user attempts to navigate to erroneous route', async () => {

View File

@@ -117,7 +117,9 @@ const InventorySourceFormFields = ({ sourceOptions, i18n }) => {
fieldId="source" fieldId="source"
helperTextInvalid={sourceMeta.error} helperTextInvalid={sourceMeta.error}
isRequired isRequired
isValid={!sourceMeta.touched || !sourceMeta.error} validated={
!sourceMeta.touched || !sourceMeta.error ? 'default' : 'error'
}
label={i18n._(t`Source`)} label={i18n._(t`Source`)}
> >
<AnsibleSelect <AnsibleSelect
@@ -161,7 +163,9 @@ const InventorySourceFormFields = ({ sourceOptions, i18n }) => {
)} )}
{sourceField.value !== '' && ( {sourceField.value !== '' && (
<SubFormLayout> <SubFormLayout>
<Title size="md">{i18n._(t`Source details`)}</Title> <Title size="md" headingLevel="h4">
{i18n._(t`Source details`)}
</Title>
<FormColumnLayout> <FormColumnLayout>
{ {
{ {

View File

@@ -83,9 +83,11 @@ const SCMSubForm = ({ i18n }) => {
<FormGroup <FormGroup
fieldId="source_path" fieldId="source_path"
helperTextInvalid={sourcePathError?.message || sourcePathMeta.error} helperTextInvalid={sourcePathError?.message || sourcePathMeta.error}
isValid={ validated={
(!sourcePathMeta.error || !sourcePathMeta.touched) && (!sourcePathMeta.error || !sourcePathMeta.touched) &&
!sourcePathError?.message !sourcePathError?.message
? 'default'
: 'error'
} }
isRequired isRequired
label={i18n._(t`Inventory file`)} label={i18n._(t`Inventory file`)}

View File

@@ -229,7 +229,7 @@ export const VerbosityField = withI18n()(({ i18n }) => {
return ( return (
<FormGroup <FormGroup
fieldId="verbosity" fieldId="verbosity"
isValid={isValid} validated={isValid ? 'default' : 'error'}
label={i18n._(t`Verbosity`)} label={i18n._(t`Verbosity`)}
> >
<FieldTooltip <FieldTooltip

View File

@@ -15,7 +15,9 @@ class InventoryScripts extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`Inventory Scripts`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`Inventory Scripts`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -2,11 +2,10 @@ import React, { Component } from 'react';
import { Route, withRouter, Switch, Redirect, Link } from 'react-router-dom'; import { Route, withRouter, Switch, Redirect, Link } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Card, CardActions, PageSection } from '@patternfly/react-core'; import { CaretLeftIcon } from '@patternfly/react-icons';
import { Card, PageSection } from '@patternfly/react-core';
import { JobsAPI } from '../../api'; import { JobsAPI } from '../../api';
import { TabbedCardHeader } from '../../components/Card';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import CardCloseButton from '../../components/CardCloseButton';
import RoutedTabs from '../../components/RoutedTabs'; import RoutedTabs from '../../components/RoutedTabs';
import JobDetail from './JobDetail'; import JobDetail from './JobDetail';
@@ -67,21 +66,24 @@ class Job extends Component {
} }
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Jobs`)}
</>
),
link: `/jobs`,
id: 99,
},
{ name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 }, { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
{ name: i18n._(t`Output`), link: `${match.url}/output`, id: 1 }, { name: i18n._(t`Output`), link: `${match.url}/output`, id: 1 },
]; ];
let cardHeader = ( let showCardHeader = true;
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/jobs" />
</CardActions>
</TabbedCardHeader>
);
if (!isInitialized) { if (!isInitialized) {
cardHeader = null; showCardHeader = false;
} }
if (!hasContentLoading && contentError) { if (!hasContentLoading && contentError) {
@@ -117,7 +119,7 @@ class Job extends Component {
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{cardHeader} {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch> <Switch>
<Redirect <Redirect
from="/jobs/:type/:id" from="/jobs/:type/:id"

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Modal as PFModal, Tab, Tabs as PFTabs } from '@patternfly/react-core'; import { Modal, Tab, Tabs, TabTitleText } from '@patternfly/react-core';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
@@ -12,18 +12,6 @@ import CodeMirrorInput from '../../../components/CodeMirrorInput';
const entities = new AllHtmlEntities(); const entities = new AllHtmlEntities();
const Modal = styled(PFModal)`
--pf-c-modal-box__footer--MarginTop: 0;
align-self: flex-start;
margin-top: 200px;
.pf-c-modal-box__body {
overflow-y: hidden;
}
.pf-c-tab-content {
padding: 24px 0;
}
`;
const HostNameDetailValue = styled.div` const HostNameDetailValue = styled.div`
align-items: center; align-items: center;
display: inline-grid; display: inline-grid;
@@ -31,31 +19,6 @@ const HostNameDetailValue = styled.div`
grid-template-columns: auto auto; grid-template-columns: auto auto;
`; `;
const Tabs = styled(PFTabs)`
--pf-c-tabs__button--PaddingLeft: 20px;
--pf-c-tabs__button--PaddingRight: 20px;
.pf-c-tabs__list {
li:first-of-type .pf-c-tabs__button {
&::after {
margin-left: 0;
}
}
}
&:not(.pf-c-tabs__item)::before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
content: '';
border-bottom: solid var(--pf-c-tabs__item--BorderColor);
border-width: var(--pf-c-tabs__item--BorderWidth) 0
var(--pf-c-tabs__item--BorderWidth) 0;
}
`;
const processEventStatus = event => { const processEventStatus = event => {
let status = null; let status = null;
if (event.event === 'runner_on_unreachable') { if (event.event === 'runner_on_unreachable') {
@@ -133,11 +96,11 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
return ( return (
<Modal <Modal
isFooterLeftAligned
isLarge
isOpen={isOpen} isOpen={isOpen}
onClose={onClose} onClose={onClose}
title={i18n._(t`Host Details`)} title={i18n._(t`Host Details`)}
aria-label={i18n._(t`Host details modal`)}
width="75%"
> >
<Tabs <Tabs
aria-label={i18n._(t`Tabs`)} aria-label={i18n._(t`Tabs`)}
@@ -147,9 +110,12 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
<Tab <Tab
aria-label={i18n._(t`Details tab`)} aria-label={i18n._(t`Details tab`)}
eventKey={0} eventKey={0}
title={i18n._(t`Details`)} title={<TabTitleText>{i18n._(t`Details`)}</TabTitleText>}
> >
<DetailList style={{ alignItems: 'center' }} gutter="sm"> <DetailList
style={{ alignItems: 'center', marginTop: '20px' }}
gutter="sm"
>
<Detail <Detail
label={i18n._(t`Host Name`)} label={i18n._(t`Host Name`)}
value={ value={
@@ -175,7 +141,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
</Tab> </Tab>
<Tab <Tab
eventKey={1} eventKey={1}
title={i18n._(t`JSON`)} title={<TabTitleText>{i18n._(t`JSON`)}</TabTitleText>}
aria-label={i18n._(t`JSON tab`)} aria-label={i18n._(t`JSON tab`)}
> >
{activeTabKey === 1 && jsonObj ? ( {activeTabKey === 1 && jsonObj ? (
@@ -193,7 +159,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
</Tab> </Tab>
<Tab <Tab
eventKey={2} eventKey={2}
title={i18n._(t`Standard Out`)} title={<TabTitleText>{i18n._(t`Standard Out`)}</TabTitleText>}
aria-label={i18n._(t`Standard out tab`)} aria-label={i18n._(t`Standard out tab`)}
> >
{activeTabKey === 2 && stdOut ? ( {activeTabKey === 2 && stdOut ? (
@@ -211,7 +177,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
</Tab> </Tab>
<Tab <Tab
eventKey={3} eventKey={3}
title={i18n._(t`Standard Error`)} title={<TabTitleText>{i18n._(t`Standard Error`)}</TabTitleText>}
aria-label={i18n._(t`Standard error tab`)} aria-label={i18n._(t`Standard error tab`)}
> >
{activeTabKey === 3 && stdErr ? ( {activeTabKey === 3 && stdErr ? (

View File

@@ -88,16 +88,7 @@ describe('HostEventModal', () => {
); );
/* eslint-disable react/button-has-type */ /* eslint-disable react/button-has-type */
expect( expect(wrapper.find('Tabs TabButton').length).toEqual(4);
wrapper
.find('Tabs')
.containsAllMatchingElements([
<button aria-label="Details tab">Details</button>,
<button aria-label="JSON tab">JSON</button>,
<button aria-label="Standard out tab">Standard Out</button>,
<button aria-label="Standard error tab">Standard Error</button>,
])
).toEqual(true);
}); });
test('should show details tab content on mount', () => { test('should show details tab content on mount', () => {

View File

@@ -475,6 +475,7 @@ class JobOutput extends Component {
variant="danger" variant="danger"
onClose={() => this.setState({ deletionError: null })} onClose={() => this.setState({ deletionError: null })}
title={i18n._(t`Job Delete Error`)} title={i18n._(t`Job Delete Error`)}
label={i18n._(t`Job Delete Error`)}
> >
<ErrorDetail error={deletionError} /> <ErrorDetail error={deletionError} />
</AlertModal> </AlertModal>

View File

@@ -338,7 +338,7 @@ describe('<JobOutput />', () => {
wrapper.find('Modal button[aria-label="Delete"]').simulate('click'); wrapper.find('Modal button[aria-label="Delete"]').simulate('click');
await waitForElement(wrapper, 'Modal ErrorDetail'); await waitForElement(wrapper, 'Modal ErrorDetail');
const errorModalCloseBtn = wrapper.find( const errorModalCloseBtn = wrapper.find(
'ModalBox div[aria-label="Job Delete Error"] button[aria-label="Close"]' 'ModalBox[aria-label="Job Delete Error"] ModalBoxCloseButton'
); );
errorModalCloseBtn.simulate('click'); errorModalCloseBtn.simulate('click');
await waitForElement(wrapper, 'Modal ErrorDetail', el => el.length === 0); await waitForElement(wrapper, 'Modal ErrorDetail', el => el.length === 0);

View File

@@ -15,7 +15,9 @@ class JobsSettings extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`Jobs Settings`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`Jobs Settings`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -15,7 +15,9 @@ class License extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`License`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`License`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -15,7 +15,9 @@ class ManagementJobs extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`Management Jobs`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`Management Jobs`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -15,7 +15,9 @@ class NotificationTemplates extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`Notification Templates`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`Notification Templates`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -2,9 +2,8 @@ import React, { Component } from 'react';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Switch, Route, withRouter, Redirect, Link } from 'react-router-dom'; import { Switch, Route, withRouter, Redirect, Link } from 'react-router-dom';
import { Card, CardActions, PageSection } from '@patternfly/react-core'; import { CaretLeftIcon } from '@patternfly/react-icons';
import CardCloseButton from '../../components/CardCloseButton'; import { Card, PageSection } from '@patternfly/react-core';
import { TabbedCardHeader } from '../../components/Card';
import RoutedTabs from '../../components/RoutedTabs'; import RoutedTabs from '../../components/RoutedTabs';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import NotificationList from '../../components/NotificationList/NotificationList'; import NotificationList from '../../components/NotificationList/NotificationList';
@@ -116,6 +115,16 @@ class Organization extends Component {
(me.is_system_auditor || isAuditorOfThisOrg || isAdminOfThisOrg); (me.is_system_auditor || isAuditorOfThisOrg || isAdminOfThisOrg);
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Organizations`)}
</>
),
link: `/organizations`,
id: 99,
},
{ name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 }, { name: i18n._(t`Details`), link: `${match.url}/details`, id: 0 },
{ name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 }, { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 },
{ name: i18n._(t`Teams`), link: `${match.url}/teams`, id: 2 }, { name: i18n._(t`Teams`), link: `${match.url}/teams`, id: 2 },
@@ -129,21 +138,10 @@ class Organization extends Component {
}); });
} }
let cardHeader = ( let showCardHeader = true;
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/organizations" />
</CardActions>
</TabbedCardHeader>
);
if (!isInitialized) { if (!isInitialized || location.pathname.endsWith('edit')) {
cardHeader = null; showCardHeader = false;
}
if (location.pathname.endsWith('edit')) {
cardHeader = null;
} }
if (!hasContentLoading && contentError) { if (!hasContentLoading && contentError) {
@@ -168,7 +166,7 @@ class Organization extends Component {
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{cardHeader} {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch> <Switch>
<Redirect <Redirect
from="/organizations/:id" from="/organizations/:id"

View File

@@ -53,7 +53,7 @@ describe('<Organization />', () => {
const tabs = await waitForElement( const tabs = await waitForElement(
wrapper, wrapper,
'.pf-c-tabs__item', '.pf-c-tabs__item',
el => el.length === 4 el => el.length === 5
); );
expect(tabs.last().text()).toEqual('Notifications'); expect(tabs.last().text()).toEqual('Notifications');
done(); done();
@@ -74,7 +74,7 @@ describe('<Organization />', () => {
const tabs = await waitForElement( const tabs = await waitForElement(
wrapper, wrapper,
'.pf-c-tabs__item', '.pf-c-tabs__item',
el => el.length === 3 el => el.length === 4
); );
tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications')); tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications'));
done(); done();

View File

@@ -15,7 +15,9 @@ class Portal extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`My View`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`My View`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -2,9 +2,8 @@ import React, { Component } from 'react';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { Switch, Route, withRouter, Redirect, Link } from 'react-router-dom'; import { Switch, Route, withRouter, Redirect, Link } from 'react-router-dom';
import { Card, CardActions, PageSection } from '@patternfly/react-core'; import { CaretLeftIcon } from '@patternfly/react-icons';
import { TabbedCardHeader } from '../../components/Card'; import { Card, PageSection } from '@patternfly/react-core';
import CardCloseButton from '../../components/CardCloseButton';
import RoutedTabs from '../../components/RoutedTabs'; import RoutedTabs from '../../components/RoutedTabs';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import NotificationList from '../../components/NotificationList'; import NotificationList from '../../components/NotificationList';
@@ -121,6 +120,16 @@ class Project extends Component {
const canToggleNotifications = isNotifAdmin; const canToggleNotifications = isNotifAdmin;
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Projects`)}
</>
),
link: `/projects`,
id: 99,
},
{ name: i18n._(t`Details`), link: `${match.url}/details` }, { name: i18n._(t`Details`), link: `${match.url}/details` },
{ name: i18n._(t`Access`), link: `${match.url}/access` }, { name: i18n._(t`Access`), link: `${match.url}/access` },
]; ];
@@ -148,24 +157,14 @@ class Project extends Component {
tab.id = n; tab.id = n;
}); });
let cardHeader = ( let showCardHeader = true;
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/projects" />
</CardActions>
</TabbedCardHeader>
);
if (!isInitialized) {
cardHeader = null;
}
if ( if (
!isInitialized ||
location.pathname.endsWith('edit') || location.pathname.endsWith('edit') ||
location.pathname.includes('schedules/') location.pathname.includes('schedules/')
) { ) {
cardHeader = null; showCardHeader = false;
} }
if (!hasContentLoading && contentError) { if (!hasContentLoading && contentError) {
@@ -188,7 +187,7 @@ class Project extends Component {
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{cardHeader} {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch> <Switch>
<Redirect from="/projects/:id" to="/projects/:id/details" exact /> <Redirect from="/projects/:id" to="/projects/:id/details" exact />
{project && ( {project && (

View File

@@ -44,9 +44,9 @@ describe('<Project />', () => {
const tabs = await waitForElement( const tabs = await waitForElement(
wrapper, wrapper,
'.pf-c-tabs__item', '.pf-c-tabs__item',
el => el.length === 5 el => el.length === 6
); );
expect(tabs.at(2).text()).toEqual('Notifications'); expect(tabs.at(3).text()).toEqual('Notifications');
done(); done();
}); });
@@ -65,7 +65,7 @@ describe('<Project />', () => {
const tabs = await waitForElement( const tabs = await waitForElement(
wrapper, wrapper,
'.pf-c-tabs__item', '.pf-c-tabs__item',
el => el.length === 4 el => el.length === 5
); );
tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications')); tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications'));
done(); done();
@@ -86,9 +86,9 @@ describe('<Project />', () => {
const tabs = await waitForElement( const tabs = await waitForElement(
wrapper, wrapper,
'.pf-c-tabs__item', '.pf-c-tabs__item',
el => el.length === 4 el => el.length === 5
); );
expect(tabs.at(3).text()).toEqual('Schedules'); expect(tabs.at(4).text()).toEqual('Schedules');
done(); done();
}); });
@@ -108,7 +108,7 @@ describe('<Project />', () => {
const tabs = await waitForElement( const tabs = await waitForElement(
wrapper, wrapper,
'.pf-c-tabs__item', '.pf-c-tabs__item',
el => el.length === 3 el => el.length === 4
); );
tabs.forEach(tab => expect(tab.text()).not.toEqual('Schedules')); tabs.forEach(tab => expect(tab.text()).not.toEqual('Schedules'));
done(); done();

View File

@@ -172,7 +172,9 @@ function ProjectFormFields({
fieldId="project-scm-type" fieldId="project-scm-type"
helperTextInvalid={scmTypeMeta.error} helperTextInvalid={scmTypeMeta.error}
isRequired isRequired
isValid={!scmTypeMeta.touched || !scmTypeMeta.error} validated={
!scmTypeMeta.touched || !scmTypeMeta.error ? 'default' : 'error'
}
label={i18n._(t`Source Control Credential Type`)} label={i18n._(t`Source Control Credential Type`)}
> >
<AnsibleSelect <AnsibleSelect
@@ -204,7 +206,9 @@ function ProjectFormFields({
</FormGroup> </FormGroup>
{formik.values.scm_type !== '' && ( {formik.values.scm_type !== '' && (
<SubFormLayout> <SubFormLayout>
<Title size="md">{i18n._(t`Type Details`)}</Title> <Title size="md" headingLevel="h4">
{i18n._(t`Type Details`)}
</Title>
<FormColumnLayout> <FormColumnLayout>
{ {
{ {

View File

@@ -81,7 +81,7 @@ const ManualSubForm = ({
fieldId="project-local-path" fieldId="project-local-path"
helperTextInvalid={pathMeta.error} helperTextInvalid={pathMeta.error}
isRequired isRequired
isValid={!pathMeta.touched || !pathMeta.error} validated={!pathMeta.touched || !pathMeta.error ? 'default' : 'error'}
label={i18n._(t`Playbook Directory`)} label={i18n._(t`Playbook Directory`)}
> >
<FieldTooltip <FieldTooltip

View File

@@ -104,7 +104,9 @@ export const ScmTypeOptions = withI18n()(
{scmUpdateOnLaunch && ( {scmUpdateOnLaunch && (
<> <>
<Title size="md">{i18n._(t`Option Details`)}</Title> <Title size="md" headingLevel="h4">
{i18n._(t`Option Details`)}
</Title>
<FormField <FormField
id="project-cache-timeout" id="project-cache-timeout"
name="scm_update_cache_timeout" name="scm_update_cache_timeout"

View File

@@ -15,7 +15,9 @@ class SystemSettings extends Component {
return ( return (
<Fragment> <Fragment>
<PageSection variant={light} className="pf-m-condensed"> <PageSection variant={light} className="pf-m-condensed">
<Title size="2xl">{i18n._(t`System Settings`)}</Title> <Title size="2xl" headingLevel="h2">
{i18n._(t`System Settings`)}
</Title>
</PageSection> </PageSection>
<PageSection /> <PageSection />
</Fragment> </Fragment>

View File

@@ -9,9 +9,8 @@ import {
useLocation, useLocation,
useParams, useParams,
} from 'react-router-dom'; } from 'react-router-dom';
import { Card, CardActions, PageSection } from '@patternfly/react-core'; import { CaretLeftIcon } from '@patternfly/react-icons';
import CardCloseButton from '../../components/CardCloseButton'; import { Card, PageSection } from '@patternfly/react-core';
import { TabbedCardHeader } from '../../components/Card';
import RoutedTabs from '../../components/RoutedTabs'; import RoutedTabs from '../../components/RoutedTabs';
import ContentError from '../../components/ContentError'; import ContentError from '../../components/ContentError';
import TeamDetail from './TeamDetail'; import TeamDetail from './TeamDetail';
@@ -41,22 +40,25 @@ function Team({ i18n, setBreadcrumb }) {
}, [id, setBreadcrumb, location]); }, [id, setBreadcrumb, location]);
const tabsArray = [ const tabsArray = [
{
name: (
<>
<CaretLeftIcon />
{i18n._(t`Back to Teams`)}
</>
),
link: `/teams`,
id: 99,
},
{ name: i18n._(t`Details`), link: `/teams/${id}/details`, id: 0 }, { name: i18n._(t`Details`), link: `/teams/${id}/details`, id: 0 },
{ name: i18n._(t`Users`), link: `/teams/${id}/users`, id: 1 }, { name: i18n._(t`Users`), link: `/teams/${id}/users`, id: 1 },
{ name: i18n._(t`Access`), link: `/teams/${id}/access`, id: 2 }, { name: i18n._(t`Access`), link: `/teams/${id}/access`, id: 2 },
]; ];
let cardHeader = ( let showCardHeader = true;
<TabbedCardHeader>
<RoutedTabs tabsArray={tabsArray} />
<CardActions>
<CardCloseButton linkTo="/teams" />
</CardActions>
</TabbedCardHeader>
);
if (location.pathname.endsWith('edit')) { if (location.pathname.endsWith('edit')) {
cardHeader = null; showCardHeader = false;
} }
if (!hasContentLoading && contentError) { if (!hasContentLoading && contentError) {
@@ -79,7 +81,7 @@ function Team({ i18n, setBreadcrumb }) {
return ( return (
<PageSection> <PageSection>
<Card> <Card>
{cardHeader} {showCardHeader && <RoutedTabs tabsArray={tabsArray} />}
<Switch> <Switch>
<Redirect from="/teams/:id" to="/teams/:id/details" exact /> <Redirect from="/teams/:id" to="/teams/:id/details" exact />
{team && ( {team && (

Some files were not shown because too many files have changed in this diff Show More