From 13d06096c91c23df9ef16b1a369b7736d62018ad Mon Sep 17 00:00:00 2001 From: David Vail Date: Mon, 24 Feb 2025 11:31:20 -0500 Subject: [PATCH 01/38] Update from PF4 -> PF5 --- ui/package.json | 6 +- ui/src/components/AppHeaderLayout.tsx | 6 +- ui/src/components/Countdown.tsx | 8 +- ui/src/components/FullPageError.tsx | 6 +- ui/src/components/FullPageSpinner.tsx | 4 +- .../components/forms/FileUploadFormField.tsx | 40 +++-- ui/src/components/forms/NumberFormField.tsx | 25 ++- ui/src/components/forms/TextFormField.tsx | 28 ++- .../containers/AppHeader/ProductLogoTile.tsx | 2 +- ui/src/containers/AppHeader/Version.tsx | 2 +- .../ClusterInfoPage/DeleteClusterModal.tsx | 6 +- .../DownloadArtifactsModal.tsx | 2 +- .../ClusterInfoPage/MutableLifespan.tsx | 2 +- ui/src/infra.css | 54 +++--- ui/yarn.lock | 159 +++++++----------- 15 files changed, 181 insertions(+), 169 deletions(-) diff --git a/ui/package.json b/ui/package.json index d1c2519f5..a9c41dc57 100644 --- a/ui/package.json +++ b/ui/package.json @@ -22,9 +22,9 @@ "gen:src": "./scripts/generate-client.sh" }, "dependencies": { - "@patternfly/patternfly": "^4.224.2", - "@patternfly/react-core": "^4.276.8", - "@patternfly/react-icons": "^4.93.6", + "@patternfly/patternfly": "^5.4.2", + "@patternfly/react-core": "^5.4.8", + "@patternfly/react-icons": "^5.4.2", "axios": "^0.21.4", "formik": "^2.4.2", "history": "^5.0.1", diff --git a/ui/src/components/AppHeaderLayout.tsx b/ui/src/components/AppHeaderLayout.tsx index 1a59fcc85..588dc7415 100644 --- a/ui/src/components/AppHeaderLayout.tsx +++ b/ui/src/components/AppHeaderLayout.tsx @@ -17,11 +17,13 @@ export default function AppHeaderLayout({ logo, main, ending }: Props): ReactEle return ( - {logo} + + {logo} + {main} - +
{ending}
diff --git a/ui/src/components/Countdown.tsx b/ui/src/components/Countdown.tsx index 49c1e95d1..c1f955b7e 100644 --- a/ui/src/components/Countdown.tsx +++ b/ui/src/components/Countdown.tsx @@ -25,15 +25,15 @@ function ModifiableTimeUnit({ onChange = (): void => {}, }: ModifiableTimeUnitProps): ReactElement { return ( - + {`${value}`.padStart(2, '0')} {notation} - + ) : undefined } - validated={meta.error ? ValidatedOptions.error : ValidatedOptions.default} - helperTextInvalid={meta.error} > handleTextOrDataChange(value)} + onTextChange={(_event, value: string) => handleTextOrDataChange(value)} + onReadStarted={(_event, _fileHandle: File) => handleFileReadStarted(_fileHandle)} + onReadFinished={(_event, _fileHandle: File) => handleFileReadFinished(_fileHandle)} onClearClick={handleClear} isLoading={isLoading} browseButtonText="Upload" aria-describedby={`${id}-helper`} validated={meta.error ? ValidatedOptions.error : ValidatedOptions.default} /> + + + + {meta.error} + + + ); } diff --git a/ui/src/components/forms/NumberFormField.tsx b/ui/src/components/forms/NumberFormField.tsx index 25617b0fb..77d35eef5 100644 --- a/ui/src/components/forms/NumberFormField.tsx +++ b/ui/src/components/forms/NumberFormField.tsx @@ -1,6 +1,13 @@ import React, { ReactElement } from 'react'; import { useField } from 'formik'; -import { FormGroup, NumberInput, ValidatedOptions } from '@patternfly/react-core'; +import { + FormGroup, + FormHelperText, + HelperText, + HelperTextItem, + NumberInput, + ValidatedOptions, +} from '@patternfly/react-core'; type Props = { name: string; @@ -39,14 +46,7 @@ export default function NumberFormField({ }; return ( - + + + + + {meta.error} + + + ); } diff --git a/ui/src/components/forms/TextFormField.tsx b/ui/src/components/forms/TextFormField.tsx index a241c126f..d69e2b638 100644 --- a/ui/src/components/forms/TextFormField.tsx +++ b/ui/src/components/forms/TextFormField.tsx @@ -1,6 +1,15 @@ import React, { ReactElement, ReactNode } from 'react'; import { useField } from 'formik'; -import { FormGroup, Popover, TextInput, ValidatedOptions } from '@patternfly/react-core'; +import { + FormGroup, + FormHelperText, + HelperText, + HelperTextItem, + Icon, + Popover, + TextInput, + ValidatedOptions, +} from '@patternfly/react-core'; import { HelpIcon } from '@patternfly/react-icons'; type Props = { @@ -41,20 +50,20 @@ export default function TextFormField({ aria-label={`Help for ${name}`} onClick={(e) => e.preventDefault()} aria-describedby={id} - className="pf-c-form__group-label-help" + className="pf-v5-c-form__group-label-help" > - + + + ) : undefined } - validated={meta.error ? ValidatedOptions.error : ValidatedOptions.default} - helperTextInvalid={meta.error} > onChange(_value, event)} type="text" value={field.value} // eslint-disable-line @typescript-eslint/no-unsafe-assignment placeholder={placeholder} @@ -63,6 +72,13 @@ export default function TextFormField({ aria-describedby={`${id}-helper`} validated={meta.error ? ValidatedOptions.error : ValidatedOptions.default} /> + + + + {meta.error} + + + ); } diff --git a/ui/src/containers/AppHeader/ProductLogoTile.tsx b/ui/src/containers/AppHeader/ProductLogoTile.tsx index 5e39cd06f..481c5bb04 100644 --- a/ui/src/containers/AppHeader/ProductLogoTile.tsx +++ b/ui/src/containers/AppHeader/ProductLogoTile.tsx @@ -14,7 +14,7 @@ export default function ProductLogoTile(): ReactElement { - + Infra diff --git a/ui/src/containers/AppHeader/Version.tsx b/ui/src/containers/AppHeader/Version.tsx index 7c33d56ec..9620b2c67 100644 --- a/ui/src/containers/AppHeader/Version.tsx +++ b/ui/src/containers/AppHeader/Version.tsx @@ -27,7 +27,7 @@ export default function Version(): ReactElement { if (loading) return ( } + icon={} text="Loading..." /> ); diff --git a/ui/src/containers/ClusterInfoPage/DeleteClusterModal.tsx b/ui/src/containers/ClusterInfoPage/DeleteClusterModal.tsx index 14626b1f0..65385e42f 100644 --- a/ui/src/containers/ClusterInfoPage/DeleteClusterModal.tsx +++ b/ui/src/containers/ClusterInfoPage/DeleteClusterModal.tsx @@ -43,7 +43,7 @@ export default function DeleteClusterModal({ cluster, onCancel, onDeleted }: Pro header={`Are you sure you want to delete ${cluster.ID}?`} buttons={buttons} > - + This action cannot be undone. @@ -64,7 +64,7 @@ export default function DeleteClusterModal({ cluster, onCancel, onDeleted }: Pro const message = `Cannot delete cluster. Server error occurred: "${error.message}".`; return ( - {message} + {message} ); } @@ -73,7 +73,7 @@ export default function DeleteClusterModal({ cluster, onCancel, onDeleted }: Pro const message = `Cluster ${cluster.ID} is being destroyed now.`; return ( - {message} + {message} ); } diff --git a/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx b/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx index 0e660938e..6cb9daabd 100644 --- a/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx +++ b/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx @@ -15,7 +15,7 @@ type ArtifactsListProps = { function ArtifactsList({ artifacts }: ArtifactsListProps): ReactElement { return ( - + {artifacts .sort((a, b) => { if (a.Description && !b.Description) { diff --git a/ui/src/containers/ClusterInfoPage/MutableLifespan.tsx b/ui/src/containers/ClusterInfoPage/MutableLifespan.tsx index ef211c0bf..906304f7e 100644 --- a/ui/src/containers/ClusterInfoPage/MutableLifespan.tsx +++ b/ui/src/containers/ClusterInfoPage/MutableLifespan.tsx @@ -26,7 +26,7 @@ export default function MutableLifespan({ cluster }: Props): ReactElement { header="Cannot change the cluster lifespan" onAcknowledged={(): void => setError(null)} > - {message} + {message} ); } diff --git a/ui/src/infra.css b/ui/src/infra.css index a59d09329..4e69c336f 100644 --- a/ui/src/infra.css +++ b/ui/src/infra.css @@ -1,22 +1,22 @@ -.pf-c-form__group-label { +.pf-v5-c-form__group-label { /* Some more padding for the form field label help icon */ - --pf-c-form__group-label-help--MarginLeft: var(--pf-global--spacer--sm); + --pf-v5-c-form__group-label-help--MarginLeft: var(--pf-v5-global--spacer--sm); } -.pf-c-form__group { +.pf-v5-c-form__group { /* Some separation for form fields */ - margin-bottom: var(--pf-global--spacer--md); + margin-bottom: var(--pf-v5-global--spacer--md); } /* Remove padding from homepage bottom panel */ -.home-page .pf-c-drawer__body { - --pf-c-drawer--child--PaddingTop: 0; - --pf-c-drawer--child--PaddingLeft: 0; - --pf-c-drawer--child--PaddingBottom: 0; - --pf-c-drawer--child--PaddingRight: 0; +.home-page .pf-v5-c-drawer__body { + --pf-v5-c-drawer--child--PaddingTop: 0; + --pf-v5-c-drawer--child--PaddingLeft: 0; + --pf-v5-c-drawer--child--PaddingBottom: 0; + --pf-v5-c-drawer--child--PaddingRight: 0; } -.pf-c-form__label-text { +.pf-v5-c-form__label-text { text-transform: capitalize; } @@ -35,19 +35,19 @@ /* LinkCard */ /* appear to be clickable */ -a:hover > .pf-c-panel { - background-color: var(--pf-global--BackgroundColor--200); +a:hover>.pf-v5-c-panel { + background-color: var(--pf-v5-global--BackgroundColor--200); } /* reset to regular font for LinkCard content */ -a > .pf-c-panel { - font-weight: var(--pf-global--FontWeight--normal); +a>.pf-v5-c-panel { + font-weight: var(--pf-v5-global--FontWeight--normal); } /* LinkCard title */ -a > .pf-c-panel > .pf-c-panel__header { - font-weight: var(--pf-global--FontWeight--bold); - font-size: var(--pf-global--FontSize--lg); +a>.pf-v5-c-panel>.pf-v5-c-panel__header { + font-weight: var(--pf-v5-global--FontWeight--bold); + font-size: var(--pf-v5-global--FontSize--lg); } /* Form help popovers - rendered with react-markdown */ @@ -56,28 +56,32 @@ a > .pf-c-panel > .pf-c-panel__header { .form-help h1, h2, h3 { - font-weight: var(--pf-global--FontWeight--bold); - margin-bottom: var(--pf-global--spacer--sm); + font-weight: var(--pf-v5-global--FontWeight--bold); + margin-bottom: var(--pf-v5-global--spacer--sm); } + .form-help h1 { - font-size: var(--pf-global--FontSize--xl); + font-size: var(--pf-v5-global--FontSize--xl); } + .form-help h2 { - font-size: var(--pf-global--FontSize--lg); + font-size: var(--pf-v5-global--FontSize--lg); } + .form-help h3 { - font-size: var(--pf-global--FontSize--md); + font-size: var(--pf-v5-global--FontSize--md); } /* A text block */ .form-help p { - margin-bottom: var(--pf-global--spacer--lg); + margin-bottom: var(--pf-v5-global--spacer--lg); } /* [link](url) */ .form-help a { - color: var(--pf-global--link--Color); + color: var(--pf-v5-global--link--Color); } + .form-help a:visited { - color: var(--pf-global--link--Color--visited); + color: var(--pf-v5-global--link--Color--visited); } diff --git a/ui/yarn.lock b/ui/yarn.lock index d75746292..a7ba7e1ad 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -1757,38 +1757,37 @@ dependencies: mkdirp "^1.0.4" -"@patternfly/patternfly@^4.224.2": - version "4.224.2" - resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-4.224.2.tgz#9d1b000c3c43457ae47c3556a334412d164fad90" - integrity sha512-HGNV26uyHSIECuhjPg/WGn0mXbAotcs6ODfhAOkfYjIgGylddgiwElxUe1rpEHV5mQJJ2rMn4OdeJIIpzRX61g== - -"@patternfly/react-core@^4.276.8": - version "4.276.8" - resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-4.276.8.tgz#7ef52830dcdda954bd5bec40132da6eef49aba6f" - integrity sha512-dn322rEzBeiVztZEuCZMUUittNb8l1hk30h9ZN31FLZLLVtXGlThFNV9ieqOJYA9zrYxYZrHMkTnOxSWVacMZg== - dependencies: - "@patternfly/react-icons" "^4.93.6" - "@patternfly/react-styles" "^4.92.6" - "@patternfly/react-tokens" "^4.94.6" - focus-trap "6.9.2" - react-dropzone "9.0.0" - tippy.js "5.1.2" - tslib "^2.0.0" - -"@patternfly/react-icons@^4.93.6": - version "4.93.6" - resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-4.93.6.tgz#4aff18724afa30157e3ffd6a6414951dbb39dcb3" - integrity sha512-ZrXegc/81oiuTIeWvoHb3nG/eZODbB4rYmekBEsrbiysyO7m/sUFoi/RLvgFINrRoh6YCJqL5fj06Jg6d7jX1g== - -"@patternfly/react-styles@^4.92.6": - version "4.92.6" - resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-4.92.6.tgz#a72c5f0b7896ce1c419d1db79f8e39ba6632057d" - integrity sha512-b8uQdEReMyeoMzjpMri845QxqtupY/tIFFYfVeKoB2neno8gkcW1RvDdDe62LF88q45OktCwAe/8A99ker10Iw== +"@patternfly/patternfly@^5.4.2": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-5.4.2.tgz#4a87d6a5fb2ffd526b4b9597b651f13ecf8ddd4f" + integrity sha512-+BaokNR8/AmTYMESxby9UtQXPGACg449BXQd0KejAvW/uGxlgO6mY1X1205DeBEHoK3e/vXkYXjvZPpv/tcxSA== + +"@patternfly/react-core@^5.4.8": + version "5.4.14" + resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-5.4.14.tgz#d41d28c81884f6a45dc3c364dc5ae2c933c72e89" + integrity sha512-oXVMzLs9Pa+xmdc39L2u05zbXfY3mWuOFi4GDv44GPdDexZUFy5W69+Nv5P8cwfMim55Nf5kKYpcqmatD2bBXw== + dependencies: + "@patternfly/react-icons" "^5.4.2" + "@patternfly/react-styles" "^5.4.1" + "@patternfly/react-tokens" "^5.4.1" + focus-trap "7.6.2" + react-dropzone "^14.2.3" + tslib "^2.7.0" + +"@patternfly/react-icons@^5.4.2": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-5.4.2.tgz#8937a7167a0b3abdc3c179524f456b4cbd8f0c39" + integrity sha512-CMQ5oHYzW6TPVTs2jpNJmP2vGCAKR/YeTPwHGO9dLkAUej1IcIxtCCWK2Fdo2UJsnBjuZihasyw2b6ehvbUm9Q== + +"@patternfly/react-styles@^5.4.1": + version "5.4.1" + resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-5.4.1.tgz#c101419917bcf309dfa7469820cd7320dd0c5120" + integrity sha512-XA8PXksD8uiA3RTwxdUwJXOCf+V6sVd+2HKapWAdRLvtSV+Sdk7NgCvalb4IAQncsddLopjPQD8gAHA298+N8w== -"@patternfly/react-tokens@^4.94.6": - version "4.94.6" - resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-4.94.6.tgz#47c715721ad3dd315a523f352ba1a0de2b03f0bc" - integrity sha512-tm7C6nat+uKMr1hrapis7hS3rN9cr41tpcCKhx6cod6FLU8KwF2Yt5KUxakhIOCEcE/M/EhXhAw/qejp8w0r7Q== +"@patternfly/react-tokens@^5.4.1": + version "5.4.1" + resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-5.4.1.tgz#03104c5b73ef438076141f897a53d16507d8a115" + integrity sha512-eygdHE7Krta1mijAv/E8RHiKIgysD0eeNTo8EXUYC8/M4e5K6sqpr2p6rQBF8QiRMN8FnbXvZT3K2OQ28pYt9Q== "@pmmmwh/react-refresh-webpack-plugin@0.4.2": version "0.4.2" @@ -3091,12 +3090,10 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -attr-accept@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.3.tgz#48230c79f93790ef2775fcec4f0db0f5db41ca52" - integrity sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ== - dependencies: - core-js "^2.5.0" +attr-accept@^2.2.4: + version "2.2.5" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.5.tgz#d7061d958e6d4f97bf8665c68b75851a0713ab5e" + integrity sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ== autoprefixer@^10.4.14: version "10.4.14" @@ -4205,11 +4202,6 @@ core-js@^2.4.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== -core-js@^2.5.0: - version "2.6.12" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" - integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== - core-js@^3.6.5: version "3.8.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.0.tgz#0fc2d4941cadf80538b030648bb64d230b4da0ce" @@ -5785,12 +5777,12 @@ file-loader@6.1.1: loader-utils "^2.0.0" schema-utils "^3.0.0" -file-selector@^0.1.8: - version "0.1.19" - resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.19.tgz#8ecc9d069a6f544f2e4a096b64a8052e70ec8abf" - integrity sha512-kCWw3+Aai8Uox+5tHCNgMFaUdgidxvMnLWO6fM5sZ0hA2wlHP5/DHGF0ECe84BiB95qdJbKNEJhWKVDvMN+JDQ== +file-selector@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-2.1.2.tgz#fe7c7ee9e550952dfbc863d73b14dc740d7de8b4" + integrity sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig== dependencies: - tslib "^2.0.1" + tslib "^2.7.0" file-uri-to-path@1.0.0: version "1.0.0" @@ -5899,12 +5891,12 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -focus-trap@6.9.2: - version "6.9.2" - resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-6.9.2.tgz#a9ef72847869bd2cbf62cb930aaf8e138fef1ca9" - integrity sha512-gBEuXOPNOKPrLdZpMFUSTyIo1eT2NSZRrwZ9r/0Jqw5tmT3Yvxfmu8KBHw8xW2XQkw6E/JoG+OlEq7UDtSUNgw== +focus-trap@7.6.2: + version "7.6.2" + resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-7.6.2.tgz#a501988821ca23d0150a7229eb7a20a3695bdf0e" + integrity sha512-9FhUxK1hVju2+AiQIDJ5Dd//9R2n2RAfJ0qfhF4IHGHgcoEUTMpbTeG/zbEuwaiYXfuAH6XE0/aCyxDdRM+W5w== dependencies: - tabbable "^5.3.2" + tabbable "^6.2.0" follow-redirects@^1.0.0, follow-redirects@^1.14.0, follow-redirects@^1.14.9: version "1.15.4" @@ -8011,7 +8003,7 @@ loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -9463,11 +9455,6 @@ pnp-webpack-plugin@1.6.4: dependencies: ts-pnp "^1.1.6" -popper.js@^1.16.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - portfinder@^1.0.26: version "1.0.28" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -10314,15 +10301,7 @@ prompts@2.4.0, prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types-extra@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/prop-types-extra/-/prop-types-extra-1.1.1.tgz#58c3b74cbfbb95d304625975aa2f0848329a010b" - integrity sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew== - dependencies: - react-is "^16.3.2" - warning "^4.0.0" - -prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.0.0, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -10554,15 +10533,14 @@ react-dom@^17.0.1: object-assign "^4.1.1" scheduler "^0.20.1" -react-dropzone@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-9.0.0.tgz#4f5223cdcb4d3bd8a66e3298c4041eb0c75c4634" - integrity sha512-wZ2o9B2qkdE3RumWhfyZT9swgJYJPeU5qHEcMU8weYpmLex1eeWX0CC32/Y0VutB+BBi2D+iePV/YZIiB4kZGw== +react-dropzone@^14.2.3: + version "14.3.8" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.3.8.tgz#a7eab118f8a452fe3f8b162d64454e81ba830582" + integrity sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug== dependencies: - attr-accept "^1.1.3" - file-selector "^0.1.8" - prop-types "^15.6.2" - prop-types-extra "^1.1.0" + attr-accept "^2.2.4" + file-selector "^2.1.0" + prop-types "^15.8.1" react-error-overlay@^6.0.9: version "6.0.9" @@ -10581,7 +10559,7 @@ react-feather@^2.0.9: dependencies: prop-types "^15.7.2" -react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -12080,10 +12058,10 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -tabbable@^5.3.2: - version "5.3.3" - resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.3.3.tgz#aac0ff88c73b22d6c3c5a50b1586310006b47fbf" - integrity sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA== +tabbable@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97" + integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew== table@^5.2.3: version "5.4.6" @@ -12273,13 +12251,6 @@ tiny-warning@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tippy.js@5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-5.1.2.tgz#5ac91233c59ab482ef5988cffe6e08bd26528e66" - integrity sha512-Qtrv2wqbRbaKMUb6bWWBQWPayvcDKNrGlvihxtsyowhT7RLGEh1STWuy6EMXC6QLkfKPB2MLnf8W2mzql9VDAw== - dependencies: - popper.js "^1.16.0" - tmp@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" @@ -12408,11 +12379,16 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.1.0: +tslib@^2.0.0, tslib@^2.1.0: version "2.6.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== +tslib@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -12871,13 +12847,6 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -warning@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - watchpack-chokidar2@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" From a0e77fabe8114e2a5357f21d8fb98e223c300faf Mon Sep 17 00:00:00 2001 From: David Vail Date: Mon, 24 Feb 2025 12:06:37 -0500 Subject: [PATCH 02/38] Update from PF5 -> PF6 --- ui/package.json | 6 +- ui/src/components/AppHeaderLayout.tsx | 27 +++++++-- ui/src/components/Countdown.tsx | 12 ++-- ui/src/components/Modal.tsx | 5 +- ui/src/components/RHACSLogo.tsx | 3 +- .../components/forms/FileUploadFormField.tsx | 2 +- ui/src/components/forms/TextFormField.tsx | 2 +- ui/src/containers/AppHeader/AppHeader.tsx | 10 ++-- .../containers/AppHeader/ProductLogoTile.tsx | 18 +----- ui/src/containers/AppHeader/UserInfo.tsx | 2 +- ui/src/infra.css | 2 +- ui/yarn.lock | 58 +++++++++---------- 12 files changed, 73 insertions(+), 74 deletions(-) diff --git a/ui/package.json b/ui/package.json index a9c41dc57..5ad031b1d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -22,9 +22,9 @@ "gen:src": "./scripts/generate-client.sh" }, "dependencies": { - "@patternfly/patternfly": "^5.4.2", - "@patternfly/react-core": "^5.4.8", - "@patternfly/react-icons": "^5.4.2", + "@patternfly/patternfly": "^6.1.1", + "@patternfly/react-core": "^6.0.0", + "@patternfly/react-icons": "^6.0.0", "axios": "^0.21.4", "formik": "^2.4.2", "history": "^5.0.1", diff --git a/ui/src/components/AppHeaderLayout.tsx b/ui/src/components/AppHeaderLayout.tsx index 588dc7415..520ccc59d 100644 --- a/ui/src/components/AppHeaderLayout.tsx +++ b/ui/src/components/AppHeaderLayout.tsx @@ -2,10 +2,13 @@ import React, { ReactElement, ReactNode } from 'react'; import { Masthead, MastheadMain, + MastheadLogo, MastheadBrand, MastheadContent, ToolbarItem, + Flex, } from '@patternfly/react-core'; +import Version from 'containers/AppHeader/Version'; type Props = { logo: ReactNode; @@ -17,14 +20,26 @@ export default function AppHeaderLayout({ logo, main, ending }: Props): ReactEle return ( - - {logo} + + + {logo} + - - {main} - -
{ending}
+ + + Infra + + + + + {main} +
{ending}
+
); diff --git a/ui/src/components/Countdown.tsx b/ui/src/components/Countdown.tsx index c1f955b7e..3c3aa8def 100644 --- a/ui/src/components/Countdown.tsx +++ b/ui/src/components/Countdown.tsx @@ -31,26 +31,22 @@ function ModifiableTimeUnit({ {notation}
- - + />
); diff --git a/ui/src/components/Modal.tsx b/ui/src/components/Modal.tsx index a24050fbc..4253da3b2 100644 --- a/ui/src/components/Modal.tsx +++ b/ui/src/components/Modal.tsx @@ -1,5 +1,8 @@ import React, { ReactElement, ReactNode } from 'react'; -import { Modal, ModalVariant } from '@patternfly/react-core'; +import { + Modal, + ModalVariant +} from '@patternfly/react-core/deprecated'; type Props = { isOpen: boolean; diff --git a/ui/src/components/RHACSLogo.tsx b/ui/src/components/RHACSLogo.tsx index 69135c89c..765ec4f0a 100644 --- a/ui/src/components/RHACSLogo.tsx +++ b/ui/src/components/RHACSLogo.tsx @@ -3,8 +3,7 @@ import React, { forwardRef } from 'react'; const RHACSLogo = forwardRef((_, ref) => ( - Infra - - -
- + + + ); } diff --git a/ui/src/containers/AppHeader/UserInfo.tsx b/ui/src/containers/AppHeader/UserInfo.tsx index 5c480ab37..43761e1da 100644 --- a/ui/src/containers/AppHeader/UserInfo.tsx +++ b/ui/src/containers/AppHeader/UserInfo.tsx @@ -13,7 +13,7 @@ export default function UserInfo(): ReactElement { alt={user?.Name || 'anonymous'} src={user.Picture} size="md" - border="dark" + isBordered className="flex justify-center items-center mr-2" /> ) : ( diff --git a/ui/src/infra.css b/ui/src/infra.css index 4e69c336f..e4c402f78 100644 --- a/ui/src/infra.css +++ b/ui/src/infra.css @@ -29,7 +29,7 @@ } .rhacs-logo-text { - fill: #ffffff; + fill: #000000; } /* LinkCard */ diff --git a/ui/yarn.lock b/ui/yarn.lock index a7ba7e1ad..0fc968911 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -1757,37 +1757,37 @@ dependencies: mkdirp "^1.0.4" -"@patternfly/patternfly@^5.4.2": - version "5.4.2" - resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-5.4.2.tgz#4a87d6a5fb2ffd526b4b9597b651f13ecf8ddd4f" - integrity sha512-+BaokNR8/AmTYMESxby9UtQXPGACg449BXQd0KejAvW/uGxlgO6mY1X1205DeBEHoK3e/vXkYXjvZPpv/tcxSA== - -"@patternfly/react-core@^5.4.8": - version "5.4.14" - resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-5.4.14.tgz#d41d28c81884f6a45dc3c364dc5ae2c933c72e89" - integrity sha512-oXVMzLs9Pa+xmdc39L2u05zbXfY3mWuOFi4GDv44GPdDexZUFy5W69+Nv5P8cwfMim55Nf5kKYpcqmatD2bBXw== - dependencies: - "@patternfly/react-icons" "^5.4.2" - "@patternfly/react-styles" "^5.4.1" - "@patternfly/react-tokens" "^5.4.1" +"@patternfly/patternfly@^6.1.1": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@patternfly/patternfly/-/patternfly-6.1.0.tgz#bd2374bf293b1c2abdde071700b3d9532ec2dfe6" + integrity sha512-w+QazL8NHKkg5j01eotblsswKxQQSYB0CN3yBXQL9ScpHdp/fK8M6TqWbKZNRpf+NqhMxcH/om8eR0N/fDCJqw== + +"@patternfly/react-core@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-6.1.0.tgz#58d35b523c019a33f03b652b065d11cf60921734" + integrity sha512-zj0lJPZxQanXKD8ae2kYnweT0kpp1CzpHYAkaBjTrw2k6ZMfr/UPlp0/ugCjWEokBqh79RUADLkKJJPce/yoSQ== + dependencies: + "@patternfly/react-icons" "^6.1.0" + "@patternfly/react-styles" "^6.1.0" + "@patternfly/react-tokens" "^6.1.0" focus-trap "7.6.2" - react-dropzone "^14.2.3" - tslib "^2.7.0" + react-dropzone "^14.3.5" + tslib "^2.8.1" -"@patternfly/react-icons@^5.4.2": - version "5.4.2" - resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-5.4.2.tgz#8937a7167a0b3abdc3c179524f456b4cbd8f0c39" - integrity sha512-CMQ5oHYzW6TPVTs2jpNJmP2vGCAKR/YeTPwHGO9dLkAUej1IcIxtCCWK2Fdo2UJsnBjuZihasyw2b6ehvbUm9Q== +"@patternfly/react-icons@^6.0.0", "@patternfly/react-icons@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-6.1.0.tgz#4f982f2b8dc0b9366acca1170fcd52fa8c16b85f" + integrity sha512-V1w/j19YmOgvh72IRRf1p07k+u4M5+9P+o/IxunlF0fWzLDX4Hf+utBI11A8cRfUzpQN7eLw/vZIS3BLM8Ge3Q== -"@patternfly/react-styles@^5.4.1": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-5.4.1.tgz#c101419917bcf309dfa7469820cd7320dd0c5120" - integrity sha512-XA8PXksD8uiA3RTwxdUwJXOCf+V6sVd+2HKapWAdRLvtSV+Sdk7NgCvalb4IAQncsddLopjPQD8gAHA298+N8w== +"@patternfly/react-styles@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-6.1.0.tgz#e8aa12c6b1417ba1a739ea435bc02f7f8d516132" + integrity sha512-JQ3zIl5SFiSB0YWVYibcUwgZdsp6Wn8hkfZ7KhtCjHFccSDdJexPOXVV1O9f2h4PfxTlY3YntZ81ZsguBx/Q7A== -"@patternfly/react-tokens@^5.4.1": - version "5.4.1" - resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-5.4.1.tgz#03104c5b73ef438076141f897a53d16507d8a115" - integrity sha512-eygdHE7Krta1mijAv/E8RHiKIgysD0eeNTo8EXUYC8/M4e5K6sqpr2p6rQBF8QiRMN8FnbXvZT3K2OQ28pYt9Q== +"@patternfly/react-tokens@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-6.1.0.tgz#c2a64e68568bde81e56f4b5a8f9ac3ad8cd06e8a" + integrity sha512-t1UcHbOa4txczTR5UlnG4XcAAdnDSfSlCaOddw/HTqRF59pn2ks2JUu9sfnFRZ8SiAAxKRiYdX5bT7Mf4R24+w== "@pmmmwh/react-refresh-webpack-plugin@0.4.2": version "0.4.2" @@ -10533,7 +10533,7 @@ react-dom@^17.0.1: object-assign "^4.1.1" scheduler "^0.20.1" -react-dropzone@^14.2.3: +react-dropzone@^14.3.5: version "14.3.8" resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.3.8.tgz#a7eab118f8a452fe3f8b162d64454e81ba830582" integrity sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug== @@ -12384,7 +12384,7 @@ tslib@^2.0.0, tslib@^2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== -tslib@^2.7.0: +tslib@^2.7.0, tslib@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== From a1ab339bb799af024c672946a48f817c207cafbb Mon Sep 17 00:00:00 2001 From: David Vail Date: Mon, 24 Feb 2025 13:39:36 -0500 Subject: [PATCH 03/38] Tweaks for basic UX cleanup --- ui/src/components/Countdown.tsx | 20 ++++++++------ ui/src/components/FullPageError.tsx | 6 ++--- ui/src/components/FullPageSpinner.tsx | 4 +-- .../components/forms/FileUploadFormField.tsx | 2 +- ui/src/components/forms/TextFormField.tsx | 2 +- ui/src/containers/App.tsx | 9 +++++-- .../ClusterInfoPage/DeleteClusterModal.tsx | 6 ++--- .../DownloadArtifactsModal.tsx | 2 +- .../ClusterInfoPage/MutableLifespan.tsx | 2 +- ui/src/containers/HomePage/HomePage.tsx | 2 +- .../LaunchClusterPage/ClusterForm.tsx | 3 ++- ui/src/infra.css | 26 +++---------------- 12 files changed, 38 insertions(+), 46 deletions(-) diff --git a/ui/src/components/Countdown.tsx b/ui/src/components/Countdown.tsx index 3c3aa8def..e9552d086 100644 --- a/ui/src/components/Countdown.tsx +++ b/ui/src/components/Countdown.tsx @@ -25,28 +25,32 @@ function ModifiableTimeUnit({ onChange = (): void => {}, }: ModifiableTimeUnitProps): ReactElement { return ( - + {`${value}`.padStart(2, '0')} {notation} - - + + ); +}; + +export default ThemeToggleButton; diff --git a/ui/src/containers/App.tsx b/ui/src/containers/App.tsx index 909ded810..4e4ef6609 100644 --- a/ui/src/containers/App.tsx +++ b/ui/src/containers/App.tsx @@ -10,6 +10,7 @@ import DownloadsPage from 'containers/DownloadsPage'; import LaunchClusterPage from 'containers/LaunchClusterPage'; import ClusterInfoPage from 'containers/ClusterInfoPage'; import FourOhFour from 'components/FourOhFour'; +import { ThemeProvider } from 'utils/ThemeProvider'; const queryClient = new QueryClient({ defaultOptions: { @@ -34,19 +35,21 @@ function AppRoutes(): ReactElement { export default function App(): ReactElement { return ( - - - - }> - - - - - + + + + + }> + + + + + + ); } diff --git a/ui/src/containers/AppHeader/AppHeader.tsx b/ui/src/containers/AppHeader/AppHeader.tsx index 8aad49fca..8276e63ae 100644 --- a/ui/src/containers/AppHeader/AppHeader.tsx +++ b/ui/src/containers/AppHeader/AppHeader.tsx @@ -7,6 +7,7 @@ import { OutlinedHandPointRightIcon, TerminalIcon } from '@patternfly/react-icon import AppHeaderLayout from 'components/AppHeaderLayout'; import RHACSLogo from 'components/RHACSLogo'; import { useUserAuth } from 'containers/UserAuthProvider'; +import ThemeToggleButton from 'components/ThemeToggleButton'; export default function AppHeader(): ReactElement { const { user, logout } = useUserAuth(); @@ -28,6 +29,9 @@ export default function AppHeader(): ReactElement { } ending={ +
+ +
{user?.Picture ? ( ) : ( diff --git a/ui/src/infra.css b/ui/src/infra.css index 2448605d6..36e3975de 100644 --- a/ui/src/infra.css +++ b/ui/src/infra.css @@ -14,6 +14,10 @@ fill: #000000; } +html.pf-v6-theme-dark .rhacs-logo-text { + fill: #ffffff; +} + /* Form help popovers - rendered with react-markdown */ /* #, ##, ### */ diff --git a/ui/src/utils/ThemeProvider.tsx b/ui/src/utils/ThemeProvider.tsx new file mode 100644 index 000000000..987426baf --- /dev/null +++ b/ui/src/utils/ThemeProvider.tsx @@ -0,0 +1,82 @@ +import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'; +import { useMediaQuery } from 'react-responsive'; + +const defaultContextData = { + isDarkMode: false, + toggle: () => {}, +}; + +export const ThemeContext = createContext(defaultContextData); +export const useTheme = () => useContext(ThemeContext); + +const DARK_MODE_KEY = 'isDarkMode'; + +type ThemeState = { + isDarkMode: boolean; + hasThemeMounted: boolean; +}; + +// custom react hook to toggle dark mode across UI +function useEffectDarkMode(): [ThemeState, (next: ThemeState) => void] { + const userPrefersDarkMode = useMediaQuery({ query: '(prefers-color-scheme: dark)' }); + const [themeState, setThemeState] = useState({ + isDarkMode: userPrefersDarkMode, + hasThemeMounted: false, + }); + useEffect(() => { + const darkModeValue = localStorage.getItem(DARK_MODE_KEY); + let isDarkMode; + // In the very beginning, default to using what the user prefers. + if (darkModeValue === null) { + isDarkMode = userPrefersDarkMode; + } else { + // It's always either 'true' or 'false', but if it's something unexpected, + // default to light mode. + isDarkMode = darkModeValue === 'true'; + } + + setThemeState({ isDarkMode, hasThemeMounted: true }); + }, [userPrefersDarkMode]); + + return [themeState, setThemeState]; +} + +export function ThemeProvider({ children }: { children: ReactNode }) { + const [themeState, setThemeState] = useEffectDarkMode(); + + // to prevent theme flicker while getting theme from localStorage + if (!themeState.hasThemeMounted) { + return
; + } + + if (themeState.isDarkMode) { + document.documentElement.classList.add('pf-v6-theme-dark'); + } else { + document.documentElement.classList.remove('pf-v6-theme-dark'); + } + + const toggle = () => { + const darkModeToggled = !themeState.isDarkMode; + + localStorage.setItem(DARK_MODE_KEY, JSON.stringify(darkModeToggled)); + + if (themeState.isDarkMode) { + document.documentElement.classList.add('pf-v6-theme-dark'); + } else { + document.documentElement.classList.remove('pf-v6-theme-dark'); + } + + setThemeState({ ...themeState, isDarkMode: darkModeToggled }); + }; + + return ( + + {children} + + ); +} diff --git a/ui/yarn.lock b/ui/yarn.lock index 68b04a41c..48b35b54e 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -2405,6 +2405,11 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +css-mediaquery@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0" + integrity sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q== + css.escape@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" @@ -3556,6 +3561,11 @@ http-proxy@^1.18.1: follow-redirects "^1.0.0" requires-port "^1.0.0" +hyphenate-style-name@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz#1797bf50369588b47b72ca6d5e65374607cf4436" + integrity sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw== + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -4088,6 +4098,13 @@ lz-string@^1.4.4: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= +matchmediaquery@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/matchmediaquery/-/matchmediaquery-0.4.2.tgz#22582bd4ae63ad9f54c53001bba80cbed0f7eafa" + integrity sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA== + dependencies: + css-mediaquery "^0.1.2" + math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" @@ -4736,7 +4753,7 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prop-types@^15.0.0, prop-types@^15.8.1: +prop-types@^15.0.0, prop-types@^15.6.1, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -4835,6 +4852,16 @@ react-refresh@^0.14.2: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== +react-responsive@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/react-responsive/-/react-responsive-10.0.0.tgz#657c7a90823cd565f43aa5918bd8eb0cd2c91c91" + integrity sha512-N6/UiRLGQyGUqrarhBZmrSmHi2FXSD++N5VbSKsBBvWfG0ZV7asvUBluSv5lSzdMyEVjzZ6Y8DL4OHABiztDOg== + dependencies: + hyphenate-style-name "^1.0.0" + matchmediaquery "^0.4.2" + prop-types "^15.6.1" + shallow-equal "^3.1.0" + react-router-dom@^6.29.0: version "6.29.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.29.0.tgz#2ffb56b03ef3d6d6daafcfad9f3922132d2ced94" @@ -5165,6 +5192,11 @@ set-proto@^1.0.0: es-errors "^1.3.0" es-object-atoms "^1.0.0" +shallow-equal@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-3.1.0.tgz#e7a54bac629c7f248eff6c2f5b63122ba4320bec" + integrity sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" From 8570e807ecacdf7be4ff3e2927d9d9ac4b66803e Mon Sep 17 00:00:00 2001 From: David Vail Date: Wed, 26 Feb 2025 15:48:50 -0500 Subject: [PATCH 35/38] Delete "tests" --- ui/package.json | 3 +-- ui/src/containers/AppHeader/AppHeader.test.tsx | 15 --------------- 2 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 ui/src/containers/AppHeader/AppHeader.test.tsx diff --git a/ui/package.json b/ui/package.json index eff0e32de..b68ea62bf 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,8 +5,7 @@ "scripts": { "start": "PORT=3001 HTTPS=true NODE_OPTIONS=--openssl-legacy-provider EXTEND_ESLINT=true vite", "build": "NODE_OPTIONS=--openssl-legacy-provider EXTEND_ESLINT=true vite build", - "test": "react-scripts test", - "eject": "react-scripts eject", + "test": "echo 'Someone should write some tests'", "lint-check": "npm-run-all lint-check:*", "lint-check:non-src": "prettier --check '**/*.{md,css,json}'", "lint-check:src": "eslint --ext .js,.jsx,.ts,.tsx ./", diff --git a/ui/src/containers/AppHeader/AppHeader.test.tsx b/ui/src/containers/AppHeader/AppHeader.test.tsx deleted file mode 100644 index 8f7631f31..000000000 --- a/ui/src/containers/AppHeader/AppHeader.test.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { BrowserRouter as Router } from 'react-router-dom'; - -import AppHeader from './AppHeader'; - -test('renders app with the proper header', () => { - const { getByText } = render( - - - - ); - const headerElement = getByText('Infra'); - expect(headerElement).toBeInTheDocument(); -}); From 85757c129694f38dc2d9960dde591e03ae26d673 Mon Sep 17 00:00:00 2001 From: David Vail Date: Wed, 26 Feb 2025 16:17:14 -0500 Subject: [PATCH 36/38] Re-add drawer layout --- ui/src/containers/App.tsx | 2 +- .../ClusterInfoPage/ClusterInfoPage.tsx | 2 +- ui/src/containers/HomePage/HomePage.tsx | 26 ++++++++++++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/ui/src/containers/App.tsx b/ui/src/containers/App.tsx index 4e4ef6609..da95bd394 100644 --- a/ui/src/containers/App.tsx +++ b/ui/src/containers/App.tsx @@ -43,7 +43,7 @@ export default function App(): ReactElement { flexWrap={{ default: 'nowrap' }} className="pf-v6-u-h-100 pf-v6-u-w-100" > - }> + } isContentFilled> diff --git a/ui/src/containers/ClusterInfoPage/ClusterInfoPage.tsx b/ui/src/containers/ClusterInfoPage/ClusterInfoPage.tsx index f183859aa..eb8d1d87c 100644 --- a/ui/src/containers/ClusterInfoPage/ClusterInfoPage.tsx +++ b/ui/src/containers/ClusterInfoPage/ClusterInfoPage.tsx @@ -55,7 +55,7 @@ export default function ClusterInfoPage(): ReactElement { ) : clusterInfoError || !cluster?.ID ? ( ) : ( - + diff --git a/ui/src/containers/HomePage/HomePage.tsx b/ui/src/containers/HomePage/HomePage.tsx index 20edcc4eb..992cd3c99 100644 --- a/ui/src/containers/HomePage/HomePage.tsx +++ b/ui/src/containers/HomePage/HomePage.tsx @@ -1,15 +1,33 @@ import React, { ReactElement } from 'react'; -import { Divider } from '@patternfly/react-core'; +import { + Drawer, + DrawerContent, + DrawerContentBody, + DrawerHead, + DrawerPanelContent, +} from '@patternfly/react-core'; import LaunchPageSection from './LaunchPageSection'; import MyClustersPageSection from './MyClustersPageSection'; export default function HomePage(): ReactElement { return ( <> - <LaunchPageSection /> - <Divider component="div" /> - <MyClustersPageSection /> + <Drawer isExpanded isInline isStatic position="bottom"> + <DrawerContent + panelContent={ + <DrawerPanelContent isResizable defaultSize="50%" minSize="150px"> + <DrawerHead> + <MyClustersPageSection /> + </DrawerHead> + </DrawerPanelContent> + } + > + <DrawerContentBody> + <LaunchPageSection /> + </DrawerContentBody> + </DrawerContent> + </Drawer> </> ); } From 856f04c85db2e6948e889e4a40bdcd6d13d631e4 Mon Sep 17 00:00:00 2001 From: David Vail <dcvail17@gmail.com> Date: Wed, 26 Feb 2025 16:32:17 -0500 Subject: [PATCH 37/38] Clean up react console errors --- ui/src/components/AppHeaderLayout.tsx | 4 +--- ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx | 2 +- ui/src/containers/HomePage/MyClustersPageSection.tsx | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ui/src/components/AppHeaderLayout.tsx b/ui/src/components/AppHeaderLayout.tsx index 520ccc59d..c35ad86a0 100644 --- a/ui/src/components/AppHeaderLayout.tsx +++ b/ui/src/components/AppHeaderLayout.tsx @@ -21,9 +21,7 @@ export default function AppHeaderLayout({ logo, main, ending }: Props): ReactEle <Masthead> <MastheadMain> <MastheadBrand> - <MastheadLogo component="a" className="pf-v6-u-mr-xl"> - {logo} - </MastheadLogo> + <MastheadLogo className="pf-v6-u-mr-xl">{logo}</MastheadLogo> </MastheadBrand> </MastheadMain> <MastheadContent> diff --git a/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx b/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx index 71ab6d62d..d1d62cf60 100644 --- a/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx +++ b/ui/src/containers/ClusterInfoPage/DownloadArtifactsModal.tsx @@ -80,7 +80,7 @@ export default function DownloadArtifactsModal({ clusterId, onClose }: Props): R assertDefined(clusterId); const closeButton = ( - <Button variant="primary" onClick={onClose}> + <Button key="close" variant="primary" onClick={onClose}> Close </Button> ); diff --git a/ui/src/containers/HomePage/MyClustersPageSection.tsx b/ui/src/containers/HomePage/MyClustersPageSection.tsx index 39bae87f5..8b1036e75 100644 --- a/ui/src/containers/HomePage/MyClustersPageSection.tsx +++ b/ui/src/containers/HomePage/MyClustersPageSection.tsx @@ -79,9 +79,8 @@ function ClusterCards({ showAllClusters = false }: ClusterCardsProps): ReactElem const isMyCluster = cluster.Owner === user?.Email; return ( - <GalleryItem> + <GalleryItem key={cluster.ID}> <LinkCard - key={cluster.ID} to={`cluster/${cluster.ID}`} header={ <Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}> @@ -102,6 +101,7 @@ function ClusterCards({ showAllClusters = false }: ClusterCardsProps): ReactElem </GalleryItem> ); }); + return ( <Gallery hasGutter From e1af8f61e0e25a71439b7b91735de25a2fc5a177 Mon Sep 17 00:00:00 2001 From: David Vail <dcvail17@gmail.com> Date: Thu, 27 Feb 2025 09:24:31 -0500 Subject: [PATCH 38/38] Fix output directory --- ui/vite.config.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/vite.config.ts b/ui/vite.config.ts index 452fc4e53..85d6fc458 100644 --- a/ui/vite.config.ts +++ b/ui/vite.config.ts @@ -9,6 +9,9 @@ import setupProxy from './src/setupProxy'; export default defineConfig(({ mode }) => { setEnv(mode); return { + build: { + assetsDir: './static', + }, plugins: [ react(), tsconfigPaths(),