diff --git a/locales/data.json b/locales/data.json index 74600a0ac..8d1f6ca64 100644 --- a/locales/data.json +++ b/locales/data.json @@ -3565,7 +3565,7 @@ "docsAddOcpSources": [ { "type": 0, - "value": "https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html-single/adding_an_openshift_container_platform_source_to_cost_management" + "value": "https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html/integrating_openshift_container_platform_data_into_cost_management" } ], "docsCostCategory": [ @@ -12215,7 +12215,7 @@ "tagMappingDeleteDesc": [ { "type": 0, - "value": "This action will remove the " + "value": "Deleting " }, { "type": 1, @@ -12223,7 +12223,13 @@ }, { "type": 0, - "value": " tag mapping. Changes will be reflected within 24 hours." + "value": " will queue a resummarization. Changes will be reflected within 24 hours." + } + ], + "tagMappingDeleteTitle": [ + { + "type": 0, + "value": "Delete tag mapping?" } ], "tagMappingDesc": [ @@ -12244,6 +12250,32 @@ "value": "learnMore" } ], + "tagMappingRemove": [ + { + "type": 0, + "value": "Remove child tag" + } + ], + "tagMappingRemoveDesc": [ + { + "type": 0, + "value": "Removing " + }, + { + "type": 1, + "value": "value" + }, + { + "type": 0, + "value": " will queue a resummarization. Changes will be reflected within 24 hours." + } + ], + "tagMappingRemoveTitle": [ + { + "type": 0, + "value": "Remove child tag?" + } + ], "tagMappingSelectChildTags": [ { "type": 0, diff --git a/locales/translations.json b/locales/translations.json index c1e813d7a..c7c88b159 100644 --- a/locales/translations.json +++ b/locales/translations.json @@ -244,7 +244,7 @@ "distributionType": "Distribution type", "distributionTypeDesc": "{type, select, cpu {Distribute costs based on CPU usage}memory {Distribute costs based on memory usage}other {}}", "doNotDistribute": "Do not distribute", - "docsAddOcpSources": "https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html-single/adding_an_openshift_container_platform_source_to_cost_management", + "docsAddOcpSources": "https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html/integrating_openshift_container_platform_data_into_cost_management", "docsCostCategory": "https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html/managing_cost_data_using_tagging/assembly-configuring-tags-and-labels-in-cost-management#configuring-categories_configuring-tags-int", "docsCostModelTerminology": "https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html-single/using_cost_models/index#cost-model-terminology", "docsCostModels": "https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html-single/using_cost_models/index#assembly-setting-up-cost-models", @@ -561,8 +561,12 @@ "tagMappingAddChildTags": "Add child tags", "tagMappingAddChildTagsDesc": "Select additional tag key(s) that will be mapped to the {value} tag map. Tags that have been already mapped will not be available for selection.", "tagMappingDelete": "Delete tag mapping", - "tagMappingDeleteDesc": "This action will remove the {value} tag mapping. Changes will be reflected within 24 hours.", + "tagMappingDeleteDesc": "Deleting {value} will queue a resummarization. Changes will be reflected within 24 hours.", + "tagMappingDeleteTitle": "Delete tag mapping?", "tagMappingDesc": "Combine multiple tags across your cloud integrations to group and filter similar tags with one tag key. {warning} Changes will be reflected within 24 hours. {learnMore}", + "tagMappingRemove": "Remove child tag", + "tagMappingRemoveDesc": "Removing {value} will queue a resummarization. Changes will be reflected within 24 hours.", + "tagMappingRemoveTitle": "Remove child tag?", "tagMappingSelectChildTags": "Select child tags", "tagMappingSelectChildTagsDesc": "Select the child tags that you want to map to a parent key. Tags that have been already mapped will not be available for selection. {learnMore}", "tagMappingSelectParentTags": "Select parent tag", diff --git a/package-lock.json b/package-lock.json index aba5a8a46..fed3751c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@redhat-cloud-services/frontend-components-translations": "^3.2.7", "@redhat-cloud-services/frontend-components-utilities": "^4.0.7", "@redhat-cloud-services/rbac-client": "^1.2.13", - "@reduxjs/toolkit": "^2.2.1", + "@reduxjs/toolkit": "^2.2.2", "@unleash/proxy-client-react": "^4.2.2", "axios": "^1.6.8", "date-fns": "^3.6.0", @@ -31,17 +31,17 @@ "qs": "^6.12.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-intl": "^6.6.2", + "react-intl": "^6.6.3", "react-redux": "^9.1.0", "react-router-dom": "^6.22.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "typesafe-actions": "^5.1.0", "unleash-proxy-client": "^3.3.2", - "victory-core": "^37.0.0" + "victory-core": "^37.0.1" }, "devDependencies": { - "@formatjs/cli": "^6.2.7", + "@formatjs/cli": "^6.2.8", "@formatjs/ecma402-abstract": "^1.18.2", "@formatjs/icu-messageformat-parser": "^2.7.6", "@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.3", @@ -50,21 +50,21 @@ "@swc/core": "1.3.105", "@swc/jest": "^0.2.36", "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^14.2.1", + "@testing-library/react": "^14.2.2", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.12", - "@types/qs": "^6.9.12", - "@types/react": "^18.2.67", + "@types/qs": "^6.9.14", + "@types/react": "^18.2.70", "@types/react-dom": "^18.2.22", "@types/react-redux": "^7.1.33", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", "aphrodite": "^2.4.0", "copy-webpack-plugin": "^12.0.2", "eslint": "^8.57.0", "eslint-plugin-formatjs": "^4.12.2", - "eslint-plugin-jest-dom": "^5.1.0", + "eslint-plugin-jest-dom": "^5.2.0", "eslint-plugin-jsdoc": "^48.2.1", "eslint-plugin-markdown": "^4.0.1", "eslint-plugin-patternfly-react": "^5.2.1", @@ -86,7 +86,7 @@ "rimraf": "^5.0.5", "ts-jest": "^29.1.2", "ts-patch": "^3.1.2", - "typescript": "^5.4.2", + "typescript": "^5.4.3", "webpack-bundle-analyzer": "^4.10.1" }, "engines": { @@ -872,9 +872,9 @@ } }, "node_modules/@formatjs/cli": { - "version": "6.2.7", - "resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.2.7.tgz", - "integrity": "sha512-F8sPvXsrjOXKAXpbZo3HObq3TZWNa91cimRukmy/54GRo83V0q2ybj9YXtBfcGlnFhzRFXq8ukkTtHgYeRMJaQ==", + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.2.8.tgz", + "integrity": "sha512-sGtFehlHpNL5xbCkP5/zz5lgIVPPdQFqhY6Pcc9+whpBawln6VDzbaGA5ttWjtBDVVKZbEukiCFk8HW2H0OVxQ==", "dev": true, "bin": { "formatjs": "bin/formatjs" @@ -928,9 +928,9 @@ } }, "node_modules/@formatjs/intl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.0.tgz", - "integrity": "sha512-X3xT9guVkKDS86EKV80lS0KxoazUglkJTGZO66sKY7otgl0VeStPA8B3u8UkKT47PexVV98fUzjpkchYmbe9nw==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-2.10.1.tgz", + "integrity": "sha512-dsLG15U7xDi8yzKf4hcAWSsCaez3XrjTO2oaRHPyHtXLm1aEzYbDw6bClo/HMHu+iwS5GbDqT3DV+hYP2ylScg==", "dependencies": { "@formatjs/ecma402-abstract": "1.18.2", "@formatjs/fast-memoize": "2.2.0", @@ -3002,9 +3002,9 @@ "integrity": "sha512-P50stc+mnWLycID46/AKmD/760r5N1eoam//O6MUVriqVorUdht7xkUL78aJZU1vw8WW6xlrDHwz3F6BM148qg==" }, "node_modules/@reduxjs/toolkit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.1.tgz", - "integrity": "sha512-8CREoqJovQW/5I4yvvijm/emUiCCmcs4Ev4XPWd4mizSO+dD3g5G6w34QK5AGeNrSH7qM8Fl66j4vuV7dpOdkw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.2.tgz", + "integrity": "sha512-454GZrEx3G6QSYwIx9ROaso1HR6sTH8qyZBe3KEsdWVGU3ayV8jYCwdaEJV3vl9V6+pi3GRl+7Xl7AeDna6qwQ==", "dependencies": { "immer": "^10.0.3", "redux": "^5.0.1", @@ -3629,9 +3629,9 @@ } }, "node_modules/@testing-library/react": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.1.tgz", - "integrity": "sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==", + "version": "14.2.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.2.tgz", + "integrity": "sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", @@ -4074,9 +4074,9 @@ "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/qs": { - "version": "6.9.12", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.12.tgz", - "integrity": "sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==", + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", "dev": true }, "node_modules/@types/range-parser": { @@ -4086,9 +4086,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.2.67", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.67.tgz", - "integrity": "sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==", + "version": "18.2.70", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.70.tgz", + "integrity": "sha512-hjlM2hho2vqklPhopNkXkdkeq6Lv8WSZTpr7956zY+3WS5cfYUewtCzsJLsbW5dEv3lfSeQ4W14ZFeKC437JRQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4327,16 +4327,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz", - "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", + "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/type-utils": "7.2.0", - "@typescript-eslint/utils": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/type-utils": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -4345,7 +4345,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4395,19 +4395,19 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", - "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", + "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4423,16 +4423,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", - "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0" + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4440,18 +4440,18 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz", - "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", + "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.2.0", - "@typescript-eslint/utils": "7.2.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/utils": "7.4.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4467,12 +4467,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", - "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4480,13 +4480,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", - "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/visitor-keys": "7.2.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4495,7 +4495,7 @@ "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4541,21 +4541,21 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz", - "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.2.0", - "@typescript-eslint/types": "7.2.0", - "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", "semver": "^7.5.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -4599,16 +4599,16 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", - "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/types": "7.4.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -6807,9 +6807,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, "engines": { "node": ">= 0.6" @@ -9118,9 +9118,9 @@ } }, "node_modules/eslint-plugin-jest-dom": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.1.0.tgz", - "integrity": "sha512-JIXZp+E/h/aGlP/rQc4tuOejiHlZXg65qw8JAJMIJA5VsdjOkss/SYcRSqBrQuEOytEM8JvngUjcz31d1RrCrA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-5.2.0.tgz", + "integrity": "sha512-ctnCP0MsLmUvbCyhnOQ+/1OmsZj+e7V6kFunazIx5728Yq7TQnuKI8HOsgPTStB+9iYEpiEa+VfKB09Lq7/3fA==", "dev": true, "dependencies": { "@babel/runtime": "^7.16.3", @@ -10422,9 +10422,9 @@ } }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, "dependencies": { "accepts": "~1.3.8", @@ -10432,7 +10432,7 @@ "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -17862,13 +17862,13 @@ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, "node_modules/react-intl": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.2.tgz", - "integrity": "sha512-IpW2IkLtGENSFlX3vfH11rjuCIsW0VyjT0Q1pPKMZPtT2z1FxLt4weFT5Ezti2TScT1xiyb3aQBFth9EB7jzAg==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-6.6.3.tgz", + "integrity": "sha512-vLKI0f+Q3pXD5szmCUPikTY7CJDPtxCBMG5YABQZ3IGEKzNB47zlvXyasUFfT25zpgQXeOfhRCdx4q6ubuR6bA==", "dependencies": { "@formatjs/ecma402-abstract": "1.18.2", "@formatjs/icu-messageformat-parser": "2.7.6", - "@formatjs/intl": "2.10.0", + "@formatjs/intl": "2.10.1", "@formatjs/intl-displaynames": "6.6.6", "@formatjs/intl-listformat": "7.5.5", "@types/hoist-non-react-statics": "^3.3.1", @@ -20378,9 +20378,9 @@ } }, "node_modules/typescript": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", - "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -20840,22 +20840,22 @@ } }, "node_modules/victory-core": { - "version": "37.0.0", - "resolved": "https://registry.npmjs.org/victory-core/-/victory-core-37.0.0.tgz", - "integrity": "sha512-aN5ZK9OO/HukifkX942Nsr0RidL/jsi/kTsBW68Ir6c6HazsfRFp0Ee3fIxy1ikUGe2XUaOu0eBv1v06+hfJKQ==", + "version": "37.0.1", + "resolved": "https://registry.npmjs.org/victory-core/-/victory-core-37.0.1.tgz", + "integrity": "sha512-PI/7ktVVb2wE7c5zUbpakgTu4n4f7+JMYXqajA/dnMEbh8ATLSRZja8sII3TjpG+QeOX4VEJNW6JxCHKTluhhw==", "dependencies": { "lodash": "^4.17.21", "react-fast-compare": "^3.2.0", - "victory-vendor": "^37.0.0" + "victory-vendor": "^37.0.1" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-core/node_modules/victory-vendor": { - "version": "37.0.0", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.0.0.tgz", - "integrity": "sha512-jNqpyUTCw2EbNplG8KsbVkHCBPSOL5fTQHVf/1oOBecfVoO8dwAGDm0xFCAD4w4c9llck6zgIV3eqR04jVYRHA==", + "version": "37.0.1", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.0.1.tgz", + "integrity": "sha512-1AZGLvUO81GLtqbgfkxVoqCGzL5Cz4LnmEb4M/6jV48RfVRUBpE0mwv7NtdVDhjTVzkeyci82lPDJDaDBkTllw==", "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", @@ -21502,9 +21502,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, "dependencies": { "colorette": "^2.0.10", diff --git a/package.json b/package.json index 4fbdce394..075a962a5 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@redhat-cloud-services/frontend-components-translations": "^3.2.7", "@redhat-cloud-services/frontend-components-utilities": "^4.0.7", "@redhat-cloud-services/rbac-client": "^1.2.13", - "@reduxjs/toolkit": "^2.2.1", + "@reduxjs/toolkit": "^2.2.2", "@unleash/proxy-client-react": "^4.2.2", "axios": "^1.6.8", "date-fns": "^3.6.0", @@ -71,17 +71,17 @@ "qs": "^6.12.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-intl": "^6.6.2", + "react-intl": "^6.6.3", "react-redux": "^9.1.0", "react-router-dom": "^6.22.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "typesafe-actions": "^5.1.0", "unleash-proxy-client": "^3.3.2", - "victory-core": "^37.0.0" + "victory-core": "^37.0.1" }, "devDependencies": { - "@formatjs/cli": "^6.2.7", + "@formatjs/cli": "^6.2.8", "@formatjs/ecma402-abstract": "^1.18.2", "@formatjs/icu-messageformat-parser": "^2.7.6", "@redhat-cloud-services/eslint-config-redhat-cloud-services": "^2.0.3", @@ -90,21 +90,21 @@ "@swc/core": "1.3.105", "@swc/jest": "^0.2.36", "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^14.2.1", + "@testing-library/react": "^14.2.2", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.12", - "@types/qs": "^6.9.12", - "@types/react": "^18.2.67", + "@types/qs": "^6.9.14", + "@types/react": "^18.2.70", "@types/react-dom": "^18.2.22", "@types/react-redux": "^7.1.33", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", "aphrodite": "^2.4.0", "copy-webpack-plugin": "^12.0.2", "eslint": "^8.57.0", "eslint-plugin-formatjs": "^4.12.2", - "eslint-plugin-jest-dom": "^5.1.0", + "eslint-plugin-jest-dom": "^5.2.0", "eslint-plugin-jsdoc": "^48.2.1", "eslint-plugin-markdown": "^4.0.1", "eslint-plugin-patternfly-react": "^5.2.1", @@ -126,11 +126,10 @@ "rimraf": "^5.0.5", "ts-jest": "^29.1.2", "ts-patch": "^3.1.2", - "typescript": "^5.4.2", + "typescript": "^5.4.3", "webpack-bundle-analyzer": "^4.10.1" }, "overrides": { - "@typescript-eslint/eslint-plugin": "^7.2.0", "redux": "^5.0.1" }, "insights": { diff --git a/src/locales/messages.ts b/src/locales/messages.ts index a36591085..90e8491c1 100644 --- a/src/locales/messages.ts +++ b/src/locales/messages.ts @@ -1441,9 +1441,9 @@ export default defineMessages({ }, docsAddOcpSources: { defaultMessage: - 'https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html-single/adding_an_openshift_container_platform_source_to_cost_management', + 'https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html/integrating_openshift_container_platform_data_into_cost_management', description: - 'https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html-single/adding_an_openshift_container_platform_source_to_cost_management', + 'https://access.redhat.com/documentation/en-us/cost_management_service/1-latest/html/integrating_openshift_container_platform_data_into_cost_management', id: 'docsAddOcpSources', }, docsCostCategory: { @@ -3446,10 +3446,15 @@ export default defineMessages({ id: 'tagMappingDelete', }, tagMappingDeleteDesc: { - defaultMessage: 'This action will remove the {value} tag mapping. Changes will be reflected within 24 hours.', - description: 'This action will remove the {value} tag mapping. Changes will be reflected within 24 hours.', + defaultMessage: 'Deleting {value} will queue a resummarization. Changes will be reflected within 24 hours.', + description: 'Deleting {value} will queue a resummarization. Changes will be reflected within 24 hours.', id: 'tagMappingDeleteDesc', }, + tagMappingDeleteTitle: { + defaultMessage: 'Delete tag mapping?', + description: 'Delete tag mapping?', + id: 'tagMappingDeleteTitle', + }, tagMappingDesc: { defaultMessage: 'Combine multiple tags across your cloud integrations to group and filter similar tags with one tag key. {warning} Changes will be reflected within 24 hours. {learnMore}', @@ -3457,6 +3462,21 @@ export default defineMessages({ 'Combine multiple tags across your cloud integrations to group and filter similar tags with one tag key. {warning} Changes will be reflected within 24 hours. {learnMore}', id: 'tagMappingDesc', }, + tagMappingRemove: { + defaultMessage: 'Remove child tag', + description: 'Remove child tag', + id: 'tagMappingRemove', + }, + tagMappingRemoveDesc: { + defaultMessage: 'Removing {value} will queue a resummarization. Changes will be reflected within 24 hours.', + description: 'Removing {value} will queue a resummarization. Changes will be reflected within 24 hours.', + id: 'tagMappingRemoveDesc', + }, + tagMappingRemoveTitle: { + defaultMessage: 'Remove child tag?', + description: 'Remove child tag?', + id: 'tagMappingRemoveTitle', + }, tagMappingSelectChildTags: { defaultMessage: 'Select child tags', description: 'Select child tags', diff --git a/src/routes/details/components/breakdown/breakdownBase.tsx b/src/routes/details/components/breakdown/breakdownBase.tsx index e233c85fe..23953650d 100644 --- a/src/routes/details/components/breakdown/breakdownBase.tsx +++ b/src/routes/details/components/breakdown/breakdownBase.tsx @@ -74,6 +74,7 @@ export interface BreakdownStateProps { providersFetchStatus?: FetchStatus; providerType?: ProviderType; query?: Query; + queryState?: Query; report?: Report; reportError?: AxiosError; reportFetchStatus?: FetchStatus; @@ -152,7 +153,7 @@ class BreakdownBase extends React.Component { }; private getTab = (tab: BreakdownTab, contentRef, showBadge: boolean, index: number) => { - const { groupBy, groupByValue } = this.props; + const { groupBy, groupByValue, queryState } = this.props; return ( { scope="costManagementMfe" appName="cost-management-mfe" module="./MfeOptimizationsBadge" - groupBy={groupBy} - groupByValue={groupByValue} + cluster={queryState?.filter_by?.cluster ? queryState.filter_by.cluster : undefined} + project={groupBy === 'project' ? groupByValue : undefined} /> } diff --git a/src/routes/details/components/breakdown/breakdownHeader.styles.ts b/src/routes/details/components/breakdown/breakdownHeader.styles.ts index 20a98dc0a..18498165b 100644 --- a/src/routes/details/components/breakdown/breakdownHeader.styles.ts +++ b/src/routes/details/components/breakdown/breakdownHeader.styles.ts @@ -8,6 +8,9 @@ import global_spacer_xs from '@patternfly/react-tokens/dist/js/global_spacer_xs' import type React from 'react'; export const styles = { + clusterInfoContainer: { + marginLeft: '-17px', + }, cost: { marginTop: global_spacer_xl.var, }, @@ -31,6 +34,8 @@ export const styles = { description: { color: global_disabled_color_100.value, fontSize: global_FontSize_xs.value, + }, + descriptionContainer: { paddingLeft: '1px', }, header: { diff --git a/src/routes/details/components/breakdown/breakdownHeader.tsx b/src/routes/details/components/breakdown/breakdownHeader.tsx index 9a1666ed4..c500fb1c4 100644 --- a/src/routes/details/components/breakdown/breakdownHeader.tsx +++ b/src/routes/details/components/breakdown/breakdownHeader.tsx @@ -160,13 +160,13 @@ class BreakdownHeader extends React.Component { {intl.formatMessage(messages.breakdownTitle, { value: title })} - {description && ( -
- {description} +
+ {description && {description}} + {clusterInfoComponent && isClusterInfoToggleEnabled ? clusterInfoComponent : null} - {dataDetailsComponent && isClusterInfoToggleEnabled ?
{dataDetailsComponent}
: null} -
- )} + + {dataDetailsComponent && isClusterInfoToggleEnabled ?
{dataDetailsComponent}
: null} +
{showCostDistribution && (
diff --git a/src/routes/details/components/pvcChart/modal/pvcContent.tsx b/src/routes/details/components/pvcChart/modal/pvcContent.tsx index 993897226..b6c59b70a 100644 --- a/src/routes/details/components/pvcChart/modal/pvcContent.tsx +++ b/src/routes/details/components/pvcChart/modal/pvcContent.tsx @@ -117,7 +117,6 @@ const PvcContent: React.FC = () => { return ( handleOnFilterAdded(filter)} diff --git a/src/routes/details/components/pvcChart/modal/pvcToolbar.tsx b/src/routes/details/components/pvcChart/modal/pvcToolbar.tsx index 8d29b4262..d5c352438 100644 --- a/src/routes/details/components/pvcChart/modal/pvcToolbar.tsx +++ b/src/routes/details/components/pvcChart/modal/pvcToolbar.tsx @@ -9,7 +9,6 @@ import type { Filter } from 'routes/utils/filter'; interface PvcToolbarOwnProps { isDisabled?: boolean; - isProject?: boolean; itemsPerPage?: number; itemsTotal?: number; onFilterAdded(filter: Filter); @@ -35,7 +34,7 @@ class PvcToolbarBase extends React.Component { } private getCategoryOptions = (): ToolbarChipGroup[] => { - const { intl, isProject } = this.props; + const { intl } = this.props; const options = [ { @@ -46,7 +45,7 @@ class PvcToolbarBase extends React.Component { { name: intl.formatMessage(messages.filterByValues, { value: 'cluster' }), key: 'cluster' }, { name: intl.formatMessage(messages.filterByValues, { value: 'storage_class' }), key: 'storageclass' }, ]; - return isProject ? options : options.filter(option => option.key !== 'project'); + return options; }; public render() { diff --git a/src/routes/details/ocpBreakdown/ocpBreakdown.tsx b/src/routes/details/ocpBreakdown/ocpBreakdown.tsx index 3e5107d14..a6c4209d4 100644 --- a/src/routes/details/ocpBreakdown/ocpBreakdown.tsx +++ b/src/routes/details/ocpBreakdown/ocpBreakdown.tsx @@ -125,6 +125,7 @@ const mapStateToProps = createMapStateToProps { return parseQuery(location.search); }; +const useQueryState = () => { + const location = useLocation(); + return getQueryState(location, 'details'); +}; + const OcpBreakdownOptimizations: React.FC = () => { const intl = useIntl(); const location = useLocation(); const queryFromRoute = useQueryFromRoute(); + const queryState = useQueryState(); const groupBy = getGroupById(queryFromRoute); const groupByValue = getGroupByValue(queryFromRoute); const otimizationsTab = location.search.indexOf('optimizationsTab') === -1 ? '&optimizationsTab=true' : ''; + const clusterFilter = queryState?.filter_by?.cluster ? queryState.filter_by.cluster : undefined; + return ( = () = module="./MfeOptimizationsTable" breadcrumbLabel={intl.formatMessage(messages.breakdownBackToOptimizationsProject, { value: groupByValue })} breadcrumbPath={formatPath(`${routes.ocpBreakdown.path}${location.search}${otimizationsTab}`)} - groupBy={groupBy} - groupByValue={groupByValue} - isProject={false} + cluster={clusterFilter} + hideCluster={clusterFilter !== undefined} + hideProject={groupBy === 'project'} linkPath={formatPath(routes.optimizationsBreakdown.path)} linkState={{ ...(location.state && location.state), }} + project={groupBy === 'project' ? groupByValue : undefined} /> ); }; diff --git a/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.styles.ts b/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.styles.ts index a82b201a2..c20bdbf4e 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.styles.ts +++ b/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.styles.ts @@ -5,7 +5,7 @@ import global_warning_color_100 from '@patternfly/react-tokens/dist/js/global_wa import type React from 'react'; export const styles = { - clusterInfo: { + clusterInfoButton: { fontSize: global_FontSize_xs.value, }, loading: { diff --git a/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.tsx b/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.tsx index fb74fcac8..6c210ff74 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.tsx +++ b/src/routes/details/ocpBreakdown/providerDetails/clusterInfo/clusterInfo.tsx @@ -30,7 +30,7 @@ const ClusterInfo: React.FC = ({ clusterId }: ClusterInfoProps return ( <> - diff --git a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/cloudIData.tsx b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/cloudIData.tsx index d3ed48b1c..9ca896c53 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/cloudIData.tsx +++ b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/cloudIData.tsx @@ -31,10 +31,10 @@ const CloudIData: React.FC = ({ provider }: CloudDataProps) => { {intl.formatMessage(messages.dataDetailsCloudIntegrationStatus)}
diff --git a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/clusterData.tsx b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/clusterData.tsx index a4fa4a099..17a1b61b6 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/clusterData.tsx +++ b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/clusterData.tsx @@ -35,10 +35,10 @@ const ClusterData: React.FC = ({ provider }: ClusterDataProps) > {intl.formatMessage(messages.dataDetailsIntegrationStatus)}
diff --git a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/overallStatus.tsx b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/overallStatus.tsx index 69a2a45e4..e96ef266d 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/overallStatus.tsx +++ b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/components/overallStatus.tsx @@ -3,6 +3,8 @@ import { ProviderType } from 'api/providers'; import { getProvidersQuery } from 'api/queries/providersQuery'; import type { AxiosError } from 'axios/index'; import React from 'react'; +import type { MessageDescriptor } from 'react-intl'; +import { useIntl } from 'react-intl'; import { useSelector } from 'react-redux'; import { styles } from 'routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.styles'; import { getOverallStatusIcon } from 'routes/details/ocpBreakdown/providerDetails/dataDetails/utils/icon'; @@ -31,6 +33,7 @@ type OverallStatusProps = OverallStatusOwnProps; const OverallStatus: React.FC = ({ clusterId }: OverallStatusProps) => { const { providers, providersError } = useMapToProps(); + const intl = useIntl(); if (!providers || providersError) { return null; @@ -41,36 +44,68 @@ const OverallStatus: React.FC = ({ clusterId }: OverallStatu const clusterProvider = ocpProviders?.data?.find(val => val.authentication?.credentials?.cluster_id === clusterId); const cloudProvider = providers?.data?.find(val => val.uuid === clusterProvider?.infrastructure?.uuid); - const getOverallStatus = () => { + const getOverallStatus = (): { msg: MessageDescriptor; status: StatusType } => { + let msg; let status; const cloudAvailability = getProviderAvailability(cloudProvider); const clusterAvailability = getProviderAvailability(clusterProvider); - const cloudStatus = getProviderStatus(cloudProvider); + const cloudStatus = getProviderStatus(cloudProvider, true); const clusterStatus = getProviderStatus(clusterProvider); - if (cloudAvailability === StatusType.failed || clusterAvailability === StatusType.failed) { - status = StatusType.failed; - } else if (cloudStatus === StatusType.failed || clusterStatus === StatusType.failed) { - status = 'failed'; - } else if (cloudAvailability === StatusType.paused || clusterAvailability === StatusType.paused) { - status = 'paused'; - } else if (cloudStatus === StatusType.inProgress || clusterStatus === StatusType.inProgress) { - status = 'in_progress'; - } else if (cloudStatus === StatusType.pending || clusterStatus === StatusType.pending) { - status = 'pending'; - } else if ( - cloudStatus === StatusType.complete && - clusterStatus === StatusType.complete && - cloudAvailability === StatusType.complete && - clusterAvailability === StatusType.complete - ) { - status = 'complete'; - } - return status; + const initializeState = (statusType: StatusType, state1, state2, state3, state4) => { + if (msg && status) { + return; + } + if (statusType === StatusType.complete) { + // A cluster may not have an integration, so cloudProvider could be undefined + if ( + (state1 === undefined || state1.status === statusType) && + (state2 === undefined || state2?.status === statusType) && + (state3 === undefined || state3?.status === statusType) && + (state4 === undefined || state4?.status === statusType) + ) { + msg = state1.msg; + status = statusType; + } + } else { + if (state1?.status === statusType) { + msg = state1.msg; + status = statusType; + } else if (state2?.status === statusType) { + msg = state2.msg; + status = statusType; + } else if (state3?.status === statusType) { + msg = state3.msg; + status = statusType; + } else if (state4?.status === statusType) { + msg = state4.msg; + status = statusType; + } + } + }; + + // Note: status is not synchronous; however, status shall be applied in order provided below (e.g., failed takes precedence over any other state). + // Cloud availability takes precedence over cloud status, while cluster availability takes precedence over cluster status, and so on... + initializeState(StatusType.failed, cloudAvailability, clusterAvailability, cloudStatus, clusterStatus); + initializeState(StatusType.paused, cloudAvailability, clusterAvailability, cloudStatus, clusterStatus); + initializeState(StatusType.inProgress, cloudAvailability, clusterAvailability, cloudStatus, clusterStatus); // Availability won't likely have in-progress and pending states + initializeState(StatusType.pending, cloudAvailability, clusterAvailability, cloudStatus, clusterStatus); + initializeState(StatusType.complete, clusterStatus, cloudStatus, clusterAvailability, cloudAvailability); // Must display the cluster status msg here + + return { msg, status }; }; - return {getOverallStatusIcon(getOverallStatus())}; + const overallStatus = getOverallStatus(); + if (overallStatus.msg && overallStatus.status) { + return ( + <> + {getOverallStatusIcon(overallStatus.status)} + {intl.formatMessage(overallStatus.msg)} + + ); + } + return null; }; // eslint-disable-next-line no-empty-pattern diff --git a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.styles.ts b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.styles.ts index 4f7833cec..33f39d5aa 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.styles.ts +++ b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.styles.ts @@ -9,7 +9,6 @@ import type React from 'react'; export const styles = { dataDetailsButton: { fontSize: global_FontSize_xs.value, - paddingLeft: global_spacer_sm.value, }, description: { color: global_disabled_color_100.value, @@ -25,8 +24,8 @@ export const styles = { marginRight: global_spacer_md.value, }, statusIcon: { - paddingLeft: '1px', - paddingRight: '5px', + fontSize: global_FontSize_xs.value, + paddingRight: global_spacer_sm.value, }, stepper: { margin: global_spacer_lg.value, diff --git a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.tsx b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.tsx index 448fae66a..d9dbd8090 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.tsx +++ b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/dataDetails.tsx @@ -31,12 +31,10 @@ const DataDetails: React.FC = ({ clusterId }: DataDetailsProps return ( <> -
- - -
+ + diff --git a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/utils/status.ts b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/utils/status.ts index e82b3f938..a1c57c29d 100644 --- a/src/routes/details/ocpBreakdown/providerDetails/dataDetails/utils/status.ts +++ b/src/routes/details/ocpBreakdown/providerDetails/dataDetails/utils/status.ts @@ -1,4 +1,7 @@ import type { Provider } from 'api/providers'; +import { ProviderType } from 'api/providers'; +import messages from 'locales/messages'; +import type { MessageDescriptor } from 'react-intl'; import { normalize } from 'routes/details/ocpBreakdown/providerDetails/utils/normailize'; // eslint-disable-next-line no-shadow @@ -27,12 +30,17 @@ export const lookupKey = (value: string) => { } }; -export const getProviderAvailability = (provider: Provider) => { +export const getProviderAvailability = (provider: Provider): { msg: MessageDescriptor; status: StatusType } => { let status; if (!provider) { return status; } + const msg = + provider.source_type === ProviderType.ocp + ? messages.dataDetailsIntegrationStatus + : messages.dataDetailsCloudIntegrationStatus; + if (provider.active === false && provider.paused === false) { status = StatusType.failed; // Inactive sources } else if (provider.paused === true) { @@ -40,18 +48,48 @@ export const getProviderAvailability = (provider: Provider) => { } else { status = StatusType.complete; } - return status; + return { msg, status }; +}; + +const getProviderStatusMsg = ( + { + downloadState, + processingState, + summaryState, + }: { + downloadState: StatusType; + processingState: StatusType; + summaryState: StatusType; + }, + status: StatusType +): MessageDescriptor => { + let msg; + + // We don't have a separate messages for cloud and on-prem + if (downloadState === status) { + msg = messages.dataDetailsRetrieval; + } else if (processingState === status) { + msg = messages.dataDetailsProcessing; + } else if (summaryState === status) { + msg = messages.dataDetailsIntegrationAndFinalization; + } + return msg; }; -export const getProviderStatus = (provider: Provider) => { +export const getProviderStatus = ( + provider: Provider, + isCloud = false +): { msg: MessageDescriptor; status: StatusType } => { let status; + let msg; if (!provider) { return status; } + // Skip summaryState for cloud const downloadState = lookupKey(provider.status.download.state); const processingState = lookupKey(provider.status.processing.state); - const summaryState = lookupKey(provider.status.summary.state); + const summaryState = isCloud ? StatusType.complete : lookupKey(provider.status.summary.state); if ( downloadState === StatusType.failed || @@ -59,24 +97,28 @@ export const getProviderStatus = (provider: Provider) => { summaryState === StatusType.failed ) { status = StatusType.failed; + msg = getProviderStatusMsg({ downloadState, processingState, summaryState }, StatusType.failed); } else if ( downloadState === StatusType.inProgress || processingState === StatusType.inProgress || summaryState === StatusType.inProgress ) { status = StatusType.inProgress; + msg = getProviderStatusMsg({ downloadState, processingState, summaryState }, StatusType.inProgress); } else if ( downloadState === StatusType.pending || processingState === StatusType.pending || summaryState === StatusType.pending ) { status = StatusType.pending; + msg = getProviderStatusMsg({ downloadState, processingState, summaryState }, StatusType.pending); } else if ( - downloadState === StatusType.complete || - processingState === StatusType.complete || + downloadState === StatusType.complete && + processingState === StatusType.complete && summaryState === StatusType.complete ) { status = StatusType.complete; + msg = messages.dataDetailsIntegrationAndFinalization; // only one final step } - return status; + return { msg, status }; }; diff --git a/src/routes/details/ocpDetails/detailsTable.tsx b/src/routes/details/ocpDetails/detailsTable.tsx index c830ab09f..b852ec99c 100644 --- a/src/routes/details/ocpDetails/detailsTable.tsx +++ b/src/routes/details/ocpDetails/detailsTable.tsx @@ -282,8 +282,7 @@ class DetailsTableBase extends React.Component ), }, diff --git a/src/routes/settings/costModels/components/rateForm/taggingRatesForm.tsx b/src/routes/settings/costModels/components/rateForm/taggingRatesForm.tsx index 95d28cf9f..8dd783b5f 100644 --- a/src/routes/settings/costModels/components/rateForm/taggingRatesForm.tsx +++ b/src/routes/settings/costModels/components/rateForm/taggingRatesForm.tsx @@ -7,6 +7,7 @@ import type { WrappedComponentProps } from 'react-intl'; import { injectIntl } from 'react-intl'; import { RateInput } from 'routes/settings/costModels/components/inputs/rateInput'; import { SimpleInput } from 'routes/settings/costModels/components/inputs/simpleInput'; +import { ReadOnlyTooltip } from 'routes/settings/costModels/components/readOnlyTooltip'; import type { UseRateData } from './useRateForm'; import type { RateFormErrors, RateFormTagValue } from './utils'; @@ -88,14 +89,16 @@ const TaggingRatesFormBase: React.FC = ({  
}> - + + + diff --git a/src/routes/settings/costModels/components/readOnlyTooltip.tsx b/src/routes/settings/costModels/components/readOnlyTooltip.tsx index e6cd88531..dc6f05faa 100644 --- a/src/routes/settings/costModels/components/readOnlyTooltip.tsx +++ b/src/routes/settings/costModels/components/readOnlyTooltip.tsx @@ -1,25 +1,34 @@ import { Tooltip } from '@patternfly/react-core'; import messages from 'locales/messages'; import React from 'react'; +import type { MessageDescriptor } from 'react-intl'; import { useIntl } from 'react-intl'; interface ReadOnlyTooltipBase { - tooltip?: string; + defaultMsg?: MessageDescriptor; children: JSX.Element; - isDisabled: boolean; + isDisabled?: boolean; } -const ReadOnlyTooltip: React.FC = ({ children, tooltip, isDisabled }) => { +const ReadOnlyTooltip: React.FC = ({ children, defaultMsg, isDisabled }) => { const intl = useIntl(); - const content = tooltip ? tooltip : intl.formatMessage(messages.readOnlyPermissions); - return isDisabled ? ( - {content}
}> -
{children}
- - ) : ( - children - ); + const getChildren = () => { + if (isDisabled) { + return
{children}
; + } + return children; + }; + + if (defaultMsg || isDisabled) { + const msg = intl.formatMessage(isDisabled ? messages.readOnly : defaultMsg); + return ( + + {getChildren()} + + ); + } + return children; }; export { ReadOnlyTooltip }; diff --git a/src/routes/settings/costModels/costModel/sourcesTable.tsx b/src/routes/settings/costModels/costModel/sourcesTable.tsx index 47378bbc8..03b9ee65c 100644 --- a/src/routes/settings/costModels/costModel/sourcesTable.tsx +++ b/src/routes/settings/costModels/costModel/sourcesTable.tsx @@ -56,7 +56,7 @@ const SourcesTable: React.FC = ({ canWrite, costModels, intl, })} - +