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

@@ -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

@@ -263,49 +263,21 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
<div <div
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
aria-label="Toggle notification start"
id="notification-9000-started-toggle"
isChecked={false}
isDisabled={false}
label="Start"
labelOff="Start"
onChange={[Function]}
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"aria-label": "Toggle notification start",
"id": "notification-9000-started-toggle",
"isChecked": false,
"isDisabled": false,
"label": "Start",
"labelOff": "Start",
"onChange": [Function],
}
}
consumerContext={null}
> >
<Switch <Switch
aria-label="Toggle notification start" aria-label="Toggle notification start"
className=""
id="notification-9000-started-toggle" id="notification-9000-started-toggle"
isChecked={false} isChecked={false}
isDisabled={false} isDisabled={false}
label="Start" label="Start"
labelOff="Start" labelOff="Start"
onChange={[Function]} onChange={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
> >
<label <label
className="pf-c-switch" className="pf-c-switch"
data-ouia-component-id={0}
data-ouia-component-type="PF4/Switch"
data-ouia-safe={true}
htmlFor="notification-9000-started-toggle" htmlFor="notification-9000-started-toggle"
> >
<input <input
@@ -337,50 +309,20 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
</span> </span>
</label> </label>
</Switch> </Switch>
</ComponentWithOuia>
</Component>
<Component
aria-label="Toggle notification success"
id="notification-9000-success-toggle"
isChecked={false}
isDisabled={false}
label="Success"
labelOff="Success"
onChange={[Function]}
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"aria-label": "Toggle notification success",
"id": "notification-9000-success-toggle",
"isChecked": false,
"isDisabled": false,
"label": "Success",
"labelOff": "Success",
"onChange": [Function],
}
}
consumerContext={null}
>
<Switch <Switch
aria-label="Toggle notification success" aria-label="Toggle notification success"
className=""
id="notification-9000-success-toggle" id="notification-9000-success-toggle"
isChecked={false} isChecked={false}
isDisabled={false} isDisabled={false}
label="Success" label="Success"
labelOff="Success" labelOff="Success"
onChange={[Function]} onChange={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
> >
<label <label
className="pf-c-switch" className="pf-c-switch"
data-ouia-component-id={1}
data-ouia-component-type="PF4/Switch"
data-ouia-safe={true}
htmlFor="notification-9000-success-toggle" htmlFor="notification-9000-success-toggle"
> >
<input <input
@@ -412,50 +354,20 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
</span> </span>
</label> </label>
</Switch> </Switch>
</ComponentWithOuia>
</Component>
<Component
aria-label="Toggle notification failure"
id="notification-9000-error-toggle"
isChecked={false}
isDisabled={false}
label="Failure"
labelOff="Failure"
onChange={[Function]}
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"aria-label": "Toggle notification failure",
"id": "notification-9000-error-toggle",
"isChecked": false,
"isDisabled": false,
"label": "Failure",
"labelOff": "Failure",
"onChange": [Function],
}
}
consumerContext={null}
>
<Switch <Switch
aria-label="Toggle notification failure" aria-label="Toggle notification failure"
className=""
id="notification-9000-error-toggle" id="notification-9000-error-toggle"
isChecked={false} isChecked={false}
isDisabled={false} isDisabled={false}
label="Failure" label="Failure"
labelOff="Failure" labelOff="Failure"
onChange={[Function]} onChange={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
> >
<label <label
className="pf-c-switch" className="pf-c-switch"
data-ouia-component-id={2}
data-ouia-component-type="PF4/Switch"
data-ouia-safe={true}
htmlFor="notification-9000-error-toggle" htmlFor="notification-9000-error-toggle"
> >
<input <input
@@ -487,8 +399,6 @@ exports[`<NotificationListItem canToggleNotifications /> initially renders succe
</span> </span>
</label> </label>
</Switch> </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,41 +97,19 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
zIndex={9999} zIndex={9999}
> >
<div> <div>
<Component
aria-label="Delete"
isDisabled={true}
onClick={[Function]}
variant="danger"
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"aria-label": "Delete",
"children": "Delete",
"isDisabled": true,
"onClick": [Function],
"variant": "danger",
}
}
consumerContext={null}
>
<Button <Button
aria-label="Delete" aria-label="Delete"
isDisabled={true} isDisabled={true}
onClick={[Function]} onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
variant="danger" variant="danger"
> >
<button <button
aria-disabled={null} aria-disabled={null}
aria-label="Delete" aria-label="Delete"
className="pf-c-button pf-m-danger" className="pf-c-button pf-m-danger"
data-ouia-component-id={null}
data-ouia-component-type="PF4/Button"
data-ouia-safe={true}
disabled={true} disabled={true}
onClick={[Function]} onClick={[Function]}
tabIndex={null} tabIndex={null}
@@ -140,8 +118,6 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
Delete Delete
</button> </button>
</Button> </Button>
</ComponentWithOuia>
</Component>
</div> </div>
<Portal <Portal
containerInfo={ containerInfo={

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

@@ -17,45 +17,73 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
} }
username="jane" username="jane"
> >
<AlertModal <WithI18n
actions={ actions={
Array [ Array [
<Unknown <Button
aria-label="Confirm delete" aria-label="Confirm delete"
onClick={[Function]} onClick={[Function]}
variant="danger" variant="danger"
> >
Delete Delete
</Unknown>, </Button>,
<Unknown <Button
onClick={[Function]} onClick={[Function]}
variant="secondary" variant="secondary"
> >
Cancel Cancel
</Unknown>, </Button>,
] ]
} }
isOpen={true} isOpen={true}
onClose={[Function]} onClose={[Function]}
title="Remove Team Access" title="Remove Team Access"
variant="danger" variant="danger"
>
<I18n
update={true}
withHash={true}
>
<AlertModal
actions={
Array [
<Button
aria-label="Confirm delete"
onClick={[Function]}
variant="danger"
>
Delete
</Button>,
<Button
onClick={[Function]}
variant="secondary"
>
Cancel
</Button>,
]
}
i18n={"/i18n/"}
isOpen={true}
onClose={[Function]}
title="Remove Team Access"
variant="danger"
> >
<Modal <Modal
actions={ actions={
Array [ Array [
<Unknown <Button
aria-label="Confirm delete" aria-label="Confirm delete"
onClick={[Function]} onClick={[Function]}
variant="danger" variant="danger"
> >
Delete Delete
</Unknown>, </Button>,
<Unknown <Button
onClick={[Function]} onClick={[Function]}
variant="secondary" variant="secondary"
> >
Cancel Cancel
</Unknown>, </Button>,
] ]
} }
appendTo={ appendTo={
@@ -70,15 +98,19 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
class="pf-l-bullseye" class="pf-l-bullseye"
> >
<div <div
aria-describedby="pf-modal-0" aria-describedby="pf-modal-part-2"
aria-label="Remove Team Access" aria-label="Alert modal"
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
aria-modal="true" aria-modal="true"
class="pf-c-modal-box pf-m-sm" class="pf-c-modal-box pf-m-sm"
id="pf-modal-part-0"
role="dialog" role="dialog"
> >
<button <button
aria-label="Close" aria-label="Close"
class="pf-c-button pf-m-plain" class="pf-c-button pf-m-plain"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button" type="button"
> >
<svg <svg
@@ -96,8 +128,8 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
/> />
</svg> </svg>
</button> </button>
<div <header
class="pf-c-title" class="pf-c-modal-box__header"
> >
<div <div
class="AlertModal__Header-l9z1bu-0 hQFWHX" class="AlertModal__Header-l9z1bu-0 hQFWHX"
@@ -117,67 +149,74 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
transform="" transform=""
/> />
</svg> </svg>
<h1 <h2
class="pf-c-title pf-m-2xl" class="pf-c-title pf-m-2xl"
id="alert-modal-header-label"
> >
Remove Team Access Remove Team Access
</h1> </h2>
</div>
</div> </div>
</header>
<div <div
class="pf-c-modal-box__body" class="pf-c-modal-box__body"
id="pf-modal-0" id="pf-modal-part-2"
> >
Are you sure you want to remove Member access from The Team? Doing so affects all members of the team. Are you sure you want to remove Member access from The Team? Doing so affects all members of the team.
<br /> <br />
<br /> <br />
If you only want to remove access for this particular user, please remove them from the team. If you only want to remove access for this particular user, please remove them from the team.
</div> </div>
<div <footer
class="pf-c-modal-box__footer pf-m-align-left" class="pf-c-modal-box__footer"
> >
<button <button
aria-label="Confirm delete" aria-label="Confirm delete"
class="pf-c-button pf-m-danger" class="pf-c-button pf-m-danger"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button" type="button"
> >
Delete Delete
</button> </button>
<button <button
class="pf-c-button pf-m-secondary" class="pf-c-button pf-m-secondary"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button" type="button"
> >
Cancel Cancel
</button> </button>
</div> </footer>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</body> </body>
} }
ariaDescribedById="" aria-describedby=""
aria-label="Alert modal"
aria-labelledby="alert-modal-header-label"
className="" className=""
hasNoBodyWrapper={false}
header={ header={
<ForwardRef(AlertModal__Header)> <ForwardRef(AlertModal__Header)>
<ForwardRef(AlertModal___StyledExclamationCircleIcon) <ForwardRef(AlertModal___StyledExclamationCircleIcon)
size="lg" size="lg"
/> />
<Title <Title
headingLevel="h2"
id="alert-modal-header-label"
size="2xl" size="2xl"
> >
Remove Team Access Remove Team Access
</Title> </Title>
</ForwardRef(AlertModal__Header)> </ForwardRef(AlertModal__Header)>
} }
hideTitle={false}
isFooterLeftAligned={true}
isLarge={false}
isOpen={true} isOpen={true}
isSmall={true}
onClose={[Function]} onClose={[Function]}
showClose={true} showClose={true}
title="Remove Team Access" title="Remove Team Access"
variant="small"
> >
<Portal <Portal
containerInfo={ containerInfo={
@@ -189,15 +228,19 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
class="pf-l-bullseye" class="pf-l-bullseye"
> >
<div <div
aria-describedby="pf-modal-0" aria-describedby="pf-modal-part-2"
aria-label="Remove Team Access" aria-label="Alert modal"
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
aria-modal="true" aria-modal="true"
class="pf-c-modal-box pf-m-sm" class="pf-c-modal-box pf-m-sm"
id="pf-modal-part-0"
role="dialog" role="dialog"
> >
<button <button
aria-label="Close" aria-label="Close"
class="pf-c-button pf-m-plain" class="pf-c-button pf-m-plain"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button" type="button"
> >
<svg <svg
@@ -215,8 +258,8 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
/> />
</svg> </svg>
</button> </button>
<div <header
class="pf-c-title" class="pf-c-modal-box__header"
> >
<div <div
class="AlertModal__Header-l9z1bu-0 hQFWHX" class="AlertModal__Header-l9z1bu-0 hQFWHX"
@@ -236,39 +279,44 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
transform="" transform=""
/> />
</svg> </svg>
<h1 <h2
class="pf-c-title pf-m-2xl" class="pf-c-title pf-m-2xl"
id="alert-modal-header-label"
> >
Remove Team Access Remove Team Access
</h1> </h2>
</div>
</div> </div>
</header>
<div <div
class="pf-c-modal-box__body" class="pf-c-modal-box__body"
id="pf-modal-0" id="pf-modal-part-2"
> >
Are you sure you want to remove Member access from The Team? Doing so affects all members of the team. Are you sure you want to remove Member access from The Team? Doing so affects all members of the team.
<br /> <br />
<br /> <br />
If you only want to remove access for this particular user, please remove them from the team. If you only want to remove access for this particular user, please remove them from the team.
</div> </div>
<div <footer
class="pf-c-modal-box__footer pf-m-align-left" class="pf-c-modal-box__footer"
> >
<button <button
aria-label="Confirm delete" aria-label="Confirm delete"
class="pf-c-button pf-m-danger" class="pf-c-button pf-m-danger"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button" type="button"
> >
Delete Delete
</button> </button>
<button <button
class="pf-c-button pf-m-secondary" class="pf-c-button pf-m-secondary"
data-ouia-component-type="PF4/Button"
data-ouia-safe="true"
type="button" type="button"
> >
Cancel Cancel
</button> </button>
</div> </footer>
</div> </div>
</div> </div>
</div> </div>
@@ -278,44 +326,48 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
<ModalContent <ModalContent
actions={ actions={
Array [ Array [
<Unknown <Button
aria-label="Confirm delete" aria-label="Confirm delete"
onClick={[Function]} onClick={[Function]}
variant="danger" variant="danger"
> >
Delete Delete
</Unknown>, </Button>,
<Unknown <Button
onClick={[Function]} onClick={[Function]}
variant="secondary" variant="secondary"
> >
Cancel Cancel
</Unknown>, </Button>,
] ]
} }
ariaDescribedById="" aria-describedby=""
aria-label="Alert modal"
aria-labelledby="alert-modal-header-label"
boxId="pf-modal-part-0"
className="" className=""
descriptorId="pf-modal-part-2"
hasNoBodyWrapper={false}
header={ header={
<ForwardRef(AlertModal__Header)> <ForwardRef(AlertModal__Header)>
<ForwardRef(AlertModal___StyledExclamationCircleIcon) <ForwardRef(AlertModal___StyledExclamationCircleIcon)
size="lg" size="lg"
/> />
<Title <Title
headingLevel="h2"
id="alert-modal-header-label"
size="2xl" size="2xl"
> >
Remove Team Access Remove Team Access
</Title> </Title>
</ForwardRef(AlertModal__Header)> </ForwardRef(AlertModal__Header)>
} }
hideTitle={false}
id="pf-modal-0"
isFooterLeftAligned={true}
isLarge={false}
isOpen={true} isOpen={true}
isSmall={true} labelId="pf-modal-part-1"
onClose={[Function]} onClose={[Function]}
showClose={true} showClose={true}
title="Remove Team Access" title="Remove Team Access"
variant="small"
> >
<Backdrop> <Backdrop>
<div <div
@@ -335,64 +387,40 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
className="pf-l-bullseye" className="pf-l-bullseye"
> >
<ModalBox <ModalBox
aria-describedby="pf-modal-part-2"
aria-label="Alert modal"
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
className="" className=""
id="pf-modal-0" id="pf-modal-part-0"
isLarge={false}
isSmall={true}
style={Object {}} style={Object {}}
title="Remove Team Access" variant="small"
> >
<div <div
aria-describedby="pf-modal-0" aria-describedby="pf-modal-part-2"
aria-label="Remove Team Access" aria-label="Alert modal"
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
aria-modal="true" aria-modal="true"
className="pf-c-modal-box pf-m-sm" className="pf-c-modal-box pf-m-sm"
id="pf-modal-part-0"
role="dialog" role="dialog"
style={Object {}} style={Object {}}
> >
<ModalBoxCloseButton <ModalBoxCloseButton
onClose={[Function]} onClose={[Function]}
>
<Component
aria-label="Close"
className=""
onClick={[Function]}
variant="plain"
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"aria-label": "Close",
"children": <TimesIcon
color="currentColor"
noVerticalAlign={false}
size="sm"
title={null}
/>,
"className": "",
"onClick": [Function],
"variant": "plain",
}
}
consumerContext={null}
> >
<Button <Button
aria-label="Close" aria-label="Close"
className="" className=""
onClick={[Function]} onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
variant="plain" variant="plain"
> >
<button <button
aria-disabled={null} aria-disabled={null}
aria-label="Close" aria-label="Close"
className="pf-c-button pf-m-plain" className="pf-c-button pf-m-plain"
data-ouia-component-id={null}
data-ouia-component-type="PF4/Button"
data-ouia-safe={true}
disabled={false} disabled={false}
onClick={[Function]} onClick={[Function]}
tabIndex={null} tabIndex={null}
@@ -402,7 +430,6 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
color="currentColor" color="currentColor"
noVerticalAlign={false} noVerticalAlign={false}
size="sm" size="sm"
title={null}
> >
<svg <svg
aria-hidden={true} aria-hidden={true}
@@ -426,11 +453,10 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
</TimesIcon> </TimesIcon>
</button> </button>
</Button> </Button>
</ComponentWithOuia>
</Component>
</ModalBoxCloseButton> </ModalBoxCloseButton>
<div <ModalBoxHeader>
className="pf-c-title" <header
className="pf-c-modal-box__header"
> >
<AlertModal__Header> <AlertModal__Header>
<StyledComponent <StyledComponent
@@ -495,7 +521,6 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
color="currentColor" color="currentColor"
noVerticalAlign={false} noVerticalAlign={false}
size="lg" size="lg"
title={null}
> >
<svg <svg
aria-hidden={true} aria-hidden={true}
@@ -521,24 +546,28 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
</StyledComponent> </StyledComponent>
</AlertModal___StyledExclamationCircleIcon> </AlertModal___StyledExclamationCircleIcon>
<Title <Title
headingLevel="h2"
id="alert-modal-header-label"
size="2xl" size="2xl"
> >
<h1 <h2
className="pf-c-title pf-m-2xl" className="pf-c-title pf-m-2xl"
id="alert-modal-header-label"
> >
Remove Team Access Remove Team Access
</h1> </h2>
</Title> </Title>
</div> </div>
</StyledComponent> </StyledComponent>
</AlertModal__Header> </AlertModal__Header>
</div> </header>
</ModalBoxHeader>
<ModalBoxBody <ModalBoxBody
id="pf-modal-0" id="pf-modal-part-2"
> >
<div <div
className="pf-c-modal-box__body" className="pf-c-modal-box__body"
id="pf-modal-0" id="pf-modal-part-2"
> >
Are you sure you want to remove Member access from The Team? Doing so affects all members of the team. Are you sure you want to remove Member access from The Team? Doing so affects all members of the team.
<br /> <br />
@@ -546,45 +575,23 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
If you only want to remove access for this particular user, please remove them from the team. If you only want to remove access for this particular user, please remove them from the team.
</div> </div>
</ModalBoxBody> </ModalBoxBody>
<ModalBoxFooter <ModalBoxFooter>
isLeftAligned={true} <footer
> className="pf-c-modal-box__footer"
<div
className="pf-c-modal-box__footer pf-m-align-left"
>
<Component
aria-label="Confirm delete"
key="delete"
onClick={[Function]}
variant="danger"
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"aria-label": "Confirm delete",
"children": "Delete",
"onClick": [Function],
"variant": "danger",
}
}
consumerContext={null}
> >
<Button <Button
aria-label="Confirm delete" aria-label="Confirm delete"
key="delete"
onClick={[Function]} onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
variant="danger" variant="danger"
> >
<button <button
aria-disabled={null} aria-disabled={null}
aria-label="Confirm delete" aria-label="Confirm delete"
className="pf-c-button pf-m-danger" className="pf-c-button pf-m-danger"
data-ouia-component-id={null}
data-ouia-component-type="PF4/Button"
data-ouia-safe={true}
disabled={false} disabled={false}
onClick={[Function]} onClick={[Function]}
tabIndex={null} tabIndex={null}
@@ -593,38 +600,18 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
Delete Delete
</button> </button>
</Button> </Button>
</ComponentWithOuia> <Button
</Component>
<Component
key="cancel" key="cancel"
onClick={[Function]} onClick={[Function]}
variant="secondary" variant="secondary"
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"children": "Cancel",
"onClick": [Function],
"variant": "secondary",
}
}
consumerContext={null}
>
<Button
onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
variant="secondary"
> >
<button <button
aria-disabled={null} aria-disabled={null}
aria-label={null} aria-label={null}
className="pf-c-button pf-m-secondary" className="pf-c-button pf-m-secondary"
data-ouia-component-id={null}
data-ouia-component-type="PF4/Button"
data-ouia-safe={true}
disabled={false} disabled={false}
onClick={[Function]} onClick={[Function]}
tabIndex={null} tabIndex={null}
@@ -633,9 +620,7 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
Cancel Cancel
</button> </button>
</Button> </Button>
</ComponentWithOuia> </footer>
</Component>
</div>
</ModalBoxFooter> </ModalBoxFooter>
</div> </div>
</ModalBox> </ModalBox>
@@ -647,5 +632,7 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
</Portal> </Portal>
</Modal> </Modal>
</AlertModal> </AlertModal>
</I18n>
</WithI18n>
</DeleteRoleConfirmationModal> </DeleteRoleConfirmationModal>
`; `;

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,142 +821,83 @@ 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}
>
<ul
className="pf-c-chip-group"
>
<InnerChipGroup
className=""
collapsedText="-4 more"
defaultIsOpen={false}
expandedText="Show less"
isOpen={false}
numChips={5}
onToggleCollapse={[Function]}
withToolbar={false}
>
<Component
component="li"
isReadOnly={false}
key=".$3"
onClick={[Function]} onClick={[Function]}
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"children": "Member",
"component": "li",
"isReadOnly": false,
"onClick": [Function],
}
}
consumerContext={null}
>
<Chip
className=""
closeBtnAriaLabel="close"
component="li"
isOverflowChip={false}
isReadOnly={false}
onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
tooltipPosition="top" tooltipPosition="top"
> >
<GenerateId <GenerateId
prefix="pf-random-id-" prefix="pf-random-id-"
>
<div
className="pf-c-chip-group"
>
<ul
aria-label="Chip group category"
className="pf-c-chip-group__list"
role="list"
> >
<li <li
className="pf-c-chip-group__list-item"
key="0"
>
<Chip
className=""
closeBtnAriaLabel="close"
component="div"
isOverflowChip={false}
isReadOnly={false}
key=".$3"
onClick={[Function]}
tooltipPosition="top"
>
<GenerateId
prefix="pf-random-id-"
>
<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
aria-labelledby="remove_pf-random-id-0 pf-random-id-0"
ariaLabel="close"
id="remove_pf-random-id-0"
onClick={[Function]}
>
<Component
aria-label="close"
aria-labelledby="remove_pf-random-id-0 pf-random-id-0"
className=""
id="remove_pf-random-id-0"
onClick={[Function]}
variant="plain"
>
<ComponentWithOuia
component={[Function]}
componentProps={
Object {
"aria-label": "close",
"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 <Button
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="" id="remove_pf-random-id-1"
id="remove_pf-random-id-0"
onClick={[Function]} onClick={[Function]}
ouiaContext={
Object {
"isOuia": false,
"ouiaId": null,
}
}
variant="plain" variant="plain"
> >
<button <button
aria-disabled={null} 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="pf-c-button pf-m-plain" className="pf-c-button pf-m-plain"
data-ouia-component-id={null}
data-ouia-component-type="PF4/Button"
data-ouia-safe={true}
disabled={false} disabled={false}
id="remove_pf-random-id-0" id="remove_pf-random-id-1"
onClick={[Function]} onClick={[Function]}
tabIndex={null} tabIndex={null}
type="button" type="button"
> >
<TimesCircleIcon <TimesIcon
aria-hidden="true" aria-hidden="true"
color="currentColor" color="currentColor"
noVerticalAlign={false} noVerticalAlign={false}
size="sm" size="sm"
title={null}
> >
<svg <svg
aria-hidden="true" aria-hidden="true"
@@ -949,27 +910,24 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
"verticalAlign": "-0.125em", "verticalAlign": "-0.125em",
} }
} }
viewBox="0 0 512 512" viewBox="0 0 352 512"
width="1em" width="1em"
> >
<path <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" 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"
transform="" transform=""
/> />
</svg> </svg>
</TimesCircleIcon> </TimesIcon>
</button> </button>
</Button> </Button>
</ComponentWithOuia> </div>
</Component>
</ChipButton>
</li>
</GenerateId> </GenerateId>
</Chip> </Chip>
</ComponentWithOuia> </li>
</Component>
</InnerChipGroup>
</ul> </ul>
</div>
</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', marginTop: '20px' }}
gutter="sm"
> >
<DetailList style={{ alignItems: 'center' }} 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 && (

View File

@@ -40,12 +40,12 @@ function TeamAccessListItem({ role, i18n, detailUrl, onSelect }) {
label={i18n._(t`Role`)} label={i18n._(t`Role`)}
value={ value={
<Chip <Chip
isReadOnly={
!role.summary_fields.user_capabilities.unattach
}
key={role.name} key={role.name}
aria-label={role.name} aria-label={role.name}
onClick={() => onSelect(role)} onClick={() => onSelect(role)}
isReadOnly={
!role.summary_fields.user_capabilities.unattach
}
> >
{role.name} {role.name}
</Chip> </Chip>

View File

@@ -142,7 +142,7 @@ describe('<SurveyList />', () => {
expect( expect(
wrapper wrapper
.find('DataToolbar') .find('Toolbar')
.find('Checkbox') .find('Checkbox')
.prop('isDisabled') .prop('isDisabled')
).toBe(true); ).toBe(true);

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