diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 15e6d3ac2..000000000
--- a/.editorconfig
+++ /dev/null
@@ -1,23 +0,0 @@
-# EditorConfig: https://EditorConfig.org
-
-# top-most EditorConfig file
-root = true
-
-# Unix-style newlines with a newline ending every file
-[*]
-end_of_line = lf
-insert_final_newline = true
-indent_brace_style = Horstmann
-
-# Matches multiple files with brace expansion notation
-# Set default charset
-# 4 space indentation
-[*.{html,scss,js}]
-charset = utf-8
-indent_style = space
-indent_size = 4
-
-# Matches the exact files either package.json
-[{package.json}]
-indent_style = space
-indent_size = 2
diff --git a/.eslintrc.yml b/.eslintrc.yml
deleted file mode 100644
index 3483c278a..000000000
--- a/.eslintrc.yml
+++ /dev/null
@@ -1,147 +0,0 @@
-parser: "@babel/eslint-parser"
-root: true
-env:
- browser: true
- es6: true
- node: true
- jest: true
-settings:
- react:
- version: detect
-extends:
- - "eslint:recommended"
- - "prettier"
- - "plugin:react/recommended"
- - "plugin:cypress/recommended"
-parserOptions:
- ecmaVersion: 7
- sourceType: module
-globals:
- beforeAll: true
- describe: true
- expect: true
- global: true
- insights: true
- it: true
- mount: true
- process: true
- render: true
- shallow: true
- React: true
- jest: true
-rules:
- rulesdir/disallow-fec-relative-imports: 0
- array-bracket-spacing: 2
- react/no-console: 0
- react/boolean-prop-naming: 2
- react/no-children-prop: 2
- react/display-name: 0
- react/no-danger: 2
- react/no-deprecated: 2
- react/no-direct-mutation-state: 2
- react/no-typos: 2
- react/no-unused-prop-types: 2
- react/no-unused-state: 2
- react/prefer-es6-class: 2
- react/prefer-read-only-props: 2
- react/require-render-return: 2
- react/state-in-constructor: 2
- react/style-prop-object: 2
- react/jsx-boolean-value: 2
- react/jsx-handler-names: 2
- react/sort-comp:
- [
- 2,
- {
- order:
- [
- "static-methods",
- "lifecycle",
- "everything-else",
- "/^handle.+$/",
- "render",
- ],
- },
- ]
- comma-dangle: 2
- comma-spacing:
- - 2
- - after: true
- comma-style: 2
- camelcase: [2, { properties: never }]
- curly:
- - error
- - all
- dot-notation: 2
- eol-last: 2
- eqeqeq: 2
- func-names:
- - error
- - never
- indent:
- - error
- - 4
- - SwitchCase: 1
- MemberExpression: 0
- ImportDeclaration: 1
- ObjectExpression: 1
- key-spacing: 2
- keyword-spacing: 2
- linebreak-style:
- - error
- - unix
- max-len:
- - 2
- - 130
- new-cap: [2, { "capIsNewExceptions": ["Immutable"] }]
- no-bitwise: 2
- no-caller: 2
- no-mixed-spaces-and-tabs: 2
- no-multiple-empty-lines:
- - error
- - max: 1
- no-redeclare: 0
- no-prototype-builtins: 0
- no-trailing-spaces: 2
- no-use-before-define:
- - error
- - functions: false
- no-undef: 2
- no-unused-vars: 2
- no-var: 2
- no-with: 2
- object-shorthand: 2
- object-curly-spacing:
- - error
- - always
- one-var:
- - error
- - never
- padding-line-between-statements:
- - error
- - blankLine: always
- prev: block-like
- next: "*"
- quote-props:
- - error
- - as-needed
- quotes:
- - error
- - single
- - allowTemplateLiterals: true
- semi:
- - error
- - always
- space-before-blocks: 2
- space-in-parens: 2
-
- space-infix-ops: 2
- space-unary-ops:
- - error
- - words: false
- nonwords: false
- vars-on-top: 2
- wrap-iife: 2
- yoda:
- - error
- - never
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000..4b3d54095
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "semi": true,
+ "tabWidth": 2,
+ "printWidth": 100,
+ "singleQuote": true,
+ "trailingComma": "all",
+ "jsxSingleQuote": true,
+ "bracketSpacing": true
+}
\ No newline at end of file
diff --git a/.stylelintrc.json b/.stylelintrc.json
index 9ec71e91a..1ca44a661 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -1,3 +1,6 @@
{
- "extends": "stylelint-config-recommended-scss"
-}
+ "extends": [
+ "stylelint-config-recommended-scss",
+ "stylelint-config-prettier-scss"
+ ]
+}
\ No newline at end of file
diff --git a/commitlint.config.js b/commitlint.config.js
index 113f1596d..69606995c 100644
--- a/commitlint.config.js
+++ b/commitlint.config.js
@@ -1,10 +1,11 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
+ 'header-max-length': [2, 'always', 50], // Enforce 50 character max for commit title
+ 'body-max-line-length': [2, 'always', 72], // Wrap body lines at 72 characters
'subject-case': [0, 'always'],
'footer-max-length': [0, 'always'],
'footer-max-line-length': [0, 'always'],
'body-max-length': [0, 'always'],
- 'body-max-line-length': [0, 'always'],
},
};
diff --git a/config/cypress.webpack.config.js b/config/cypress.webpack.config.js
index 110c75207..417ff8bb7 100644
--- a/config/cypress.webpack.config.js
+++ b/config/cypress.webpack.config.js
@@ -1,38 +1,34 @@
-/* global require, module, __dirname */
const { resolve } = require('path');
const config = require('@redhat-cloud-services/frontend-components-config');
const { config: webpackConfig, plugins } = config({
- rootFolder: resolve(__dirname, '../')
+ rootFolder: resolve(__dirname, '../'),
});
webpackConfig.module.rules.push({
- resolve: {
- alias: {
- '@redhat-cloud-services/frontend-components/useChrome': resolve(
- __dirname,
- './overrideChrome.js'
- ),
- '../useChrome': resolve(
- __dirname,
- './overrideChrome.js'
- )
- }
- }
+ resolve: {
+ alias: {
+ '@redhat-cloud-services/frontend-components/useChrome': resolve(
+ __dirname,
+ './overrideChrome.js',
+ ),
+ '../useChrome': resolve(__dirname, './overrideChrome.js'),
+ },
+ },
});
module.exports = {
- ...webpackConfig,
- plugins,
- module: {
- ...webpackConfig.module,
- rules: [
- ...webpackConfig.module.rules,
- {
- test: /\.(?:js|mjs|cjs)$/,
- exclude: /(node_modules|bower_components)/i,
- use: ['babel-loader']
- }
- ]
- }
+ ...webpackConfig,
+ plugins,
+ module: {
+ ...webpackConfig.module,
+ rules: [
+ ...webpackConfig.module.rules,
+ {
+ test: /\.(?:js|mjs|cjs)$/,
+ exclude: /(node_modules|bower_components)/i,
+ use: ['babel-loader'],
+ },
+ ],
+ },
};
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 000000000..01f065d5a
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,130 @@
+import react from 'eslint-plugin-react';
+import prettier from 'eslint-plugin-prettier';
+import unusedImports from 'eslint-plugin-unused-imports';
+import importPlugin from 'eslint-plugin-import';
+import cypress from 'eslint-plugin-cypress';
+import globals from 'globals';
+import babelParser from '@babel/eslint-parser';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import js from '@eslint/js';
+import { FlatCompat } from '@eslint/eslintrc';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+ recommendedConfig: js.configs.recommended,
+ allConfig: js.configs.all,
+});
+
+export default [
+ {
+ ignores: ['node_modules/*', 'dist/*', 'coverage-jest/*', 'coverage-cypress/*'],
+ },
+ ...compat.extends(
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:cypress/recommended',
+ 'prettier',
+ ),
+ {
+ plugins: {
+ react,
+ prettier,
+ 'unused-imports': unusedImports,
+ cypress,
+ import: importPlugin,
+ },
+
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.node,
+ ...globals.jest,
+ insights: true,
+ React: true,
+ mount: true, // Set to true to allow it to be used without definition
+ },
+
+ parser: babelParser,
+ ecmaVersion: 2020,
+ sourceType: 'module',
+
+ parserOptions: {
+ requireConfigFile: true,
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ },
+
+ settings: {
+ react: {
+ version: 'detect',
+ },
+ },
+
+ rules: {
+ 'react/jsx-curly-brace-presence': [
+ 'error',
+ {
+ props: 'never',
+ children: 'never',
+ },
+ ],
+
+ 'arrow-body-style': ['error', 'as-needed'],
+ 'react/react-in-jsx-scope': 'off',
+ camelcase: 'off',
+ 'spaced-comment': 'error',
+ 'prettier/prettier': ['warn', { singleQuote: true }],
+ 'import/no-duplicates': 'error', // This rule provides auto-fix capability
+ 'unused-imports/no-unused-imports': 'error',
+ 'unused-imports/no-unused-vars': ['warn'],
+ 'no-empty-pattern': ['error', { allowObjectPatternsAsParameters: true }],
+
+ // React-specific rules from the original config
+ 'react/boolean-prop-naming': 'error',
+ 'react/no-children-prop': 'error',
+ 'react/display-name': 'off',
+ 'react/no-danger': 'error',
+ 'react/no-deprecated': 'error',
+ 'react/no-direct-mutation-state': 'error',
+ 'react/no-typos': 'error',
+ 'react/no-unused-prop-types': 'error',
+ 'react/no-unused-state': 'error',
+ 'react/prefer-es6-class': 'error',
+ 'react/prefer-read-only-props': 'error',
+ 'react/require-render-return': 'error',
+ 'react/state-in-constructor': 'error',
+ 'react/style-prop-object': 'error',
+ 'react/jsx-boolean-value': 'error',
+ 'react/jsx-handler-names': 'error',
+ 'react/sort-comp': [
+ 'error',
+ {
+ order: ['static-methods', 'lifecycle', 'everything-else', '/^handle.+$/', 'render'],
+ },
+ ],
+
+ // Code quality rules (not formatting)
+ curly: ['error', 'all'],
+ 'dot-notation': 'error',
+ eqeqeq: 'error',
+ 'no-bitwise': 'error',
+ 'no-caller': 'error',
+ 'no-prototype-builtins': 'off',
+ 'no-use-before-define': ['error', { functions: false }],
+ 'no-undef': 'error',
+ 'no-unused-vars': 'off', // Handled by unused-imports plugin
+ 'no-var': 'error',
+ 'no-with': 'error',
+ 'object-shorthand': 'error',
+ 'one-var': ['error', 'never'],
+ 'vars-on-top': 'error',
+ 'wrap-iife': 'error',
+ yoda: ['error', 'never'],
+ },
+ },
+];
diff --git a/package-lock.json b/package-lock.json
index 7f431069b..a3633d28e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -46,6 +46,8 @@
"@commitlint/cli": "^19.8.0",
"@commitlint/config-conventional": "^19.8.0",
"@cypress/code-coverage": "^3.13.4",
+ "@eslint/eslintrc": "^3.2.0",
+ "@eslint/js": "^9.17.0",
"@patternfly/patternfly": "^6.3.1",
"@redhat-cloud-services/frontend-components-config": "^6.7.1",
"@redhat-cloud-services/tsc-transform-imports": "^1.0.16",
@@ -58,22 +60,27 @@
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
"css-loader": "^5.2.7",
"cypress": "^14.4.0",
- "eslint": "^7.32.0",
- "eslint-config-prettier": "^7.2.0",
- "eslint-loader": "^4.0.2",
- "eslint-plugin-cypress": "^2.15.1",
- "eslint-plugin-react": "^7.32.2",
+ "eslint": "^9.17.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-cypress": "^4.2.0",
+ "eslint-plugin-import": "^2.32.0",
+ "eslint-plugin-prettier": "^5.2.1",
+ "eslint-plugin-react": "^7.37.2",
+ "eslint-plugin-unused-imports": "^4.1.4",
"glob": "^7.2.3",
+ "globals": "^15.13.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.21",
+ "prettier": "^3.4.2",
"prop-types": "^15.8.1",
"react-intl": "^6.6.2",
"redux-mock-store": "^1.5.4",
"sass-loader": "^12.6.0",
"source-map-loader": "^2.0.2",
"stylelint": "^16.10.0",
+ "stylelint-config-prettier-scss": "^1.0.0",
"stylelint-config-recommended-scss": "^14.1.0",
"stylelint-scss": "^6.8.0",
"ts-patch": "^3.1.2",
@@ -455,70 +462,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@babel/highlight": {
- "version": "7.25.9",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz",
- "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.25.9",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@babel/highlight/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/@babel/parser": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz",
@@ -2682,25 +2625,111 @@
"integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==",
"license": "MIT"
},
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+ "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz",
+ "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.6",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz",
+ "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.16.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.16.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz",
+ "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@eslint/eslintrc": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
- "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
+ "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
- "debug": "^4.1.1",
- "espree": "^7.3.0",
- "globals": "^13.9.0",
- "ignore": "^4.0.6",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
"import-fresh": "^3.2.1",
- "js-yaml": "^3.13.1",
- "minimatch": "^3.0.4",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/eslintrc/node_modules/ajv": {
@@ -2720,28 +2749,17 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/@eslint/eslintrc/node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
+ "engines": {
+ "node": ">=18"
},
- "bin": {
- "js-yaml": "bin/js-yaml.js"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
@@ -2751,6 +2769,43 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@eslint/js": {
+ "version": "9.37.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz",
+ "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
+ "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz",
+ "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.16.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@formatjs/ecma402-abstract": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.2.4.tgz",
@@ -2863,29 +2918,57 @@
"@hapi/hoek": "^9.0.0"
}
},
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
- "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
- "deprecated": "Use @eslint/config-array instead",
+ "node_modules/@humanfs/core": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+ "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@humanwhocodes/object-schema": "^1.2.0",
- "debug": "^4.1.1",
- "minimatch": "^3.0.4"
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.4.0"
},
"engines": {
- "node": ">=10.10.0"
+ "node": ">=18.18.0"
}
},
- "node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "deprecated": "Use @eslint/object-schema instead",
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true,
- "license": "BSD-3-Clause"
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
},
"node_modules/@inquirer/external-editor": {
"version": "1.0.1",
@@ -4523,6 +4606,19 @@
"node": ">=14"
}
},
+ "node_modules/@pkgr/core": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
+ "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/pkgr"
+ }
+ },
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.5.17",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.17.tgz",
@@ -5238,6 +5334,13 @@
"node": ">=14.0.0"
}
},
+ "node_modules/@rtsao/scc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@scalprum/core": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/@scalprum/core/-/core-0.8.3.tgz",
@@ -6421,6 +6524,13 @@
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"license": "MIT"
},
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
@@ -6850,10 +6960,9 @@
}
},
"node_modules/acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
- "dev": true,
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -6872,18 +6981,6 @@
"acorn-walk": "^8.0.2"
}
},
- "node_modules/acorn-globals/node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/acorn-jsx": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -6906,18 +7003,6 @@
"node": ">=0.4.0"
}
},
- "node_modules/acorn-walk/node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -7243,6 +7328,28 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/array.prototype.findlastindex": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
+ "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-shim-unscopables": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/array.prototype.flat": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
@@ -10055,16 +10162,16 @@
}
},
"node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
- "node": ">=6.0.0"
+ "node": ">=0.10.0"
}
},
"node_modules/dom-accessibility-api": {
@@ -10650,68 +10757,70 @@
}
},
"node_modules/eslint": {
- "version": "7.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
- "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
- "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.3",
- "@humanwhocodes/config-array": "^0.5.0",
- "ajv": "^6.10.0",
+ "version": "9.37.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz",
+ "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.0",
+ "@eslint/config-helpers": "^0.4.0",
+ "@eslint/core": "^0.16.0",
+ "@eslint/eslintrc": "^3.3.1",
+ "@eslint/js": "9.37.0",
+ "@eslint/plugin-kit": "^0.4.0",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "@types/json-schema": "^7.0.15",
+ "ajv": "^6.12.4",
"chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.0.1",
- "doctrine": "^3.0.0",
- "enquirer": "^2.3.5",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^2.0.0",
- "espree": "^7.3.1",
- "esquery": "^1.4.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.1.2",
- "globals": "^13.6.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.0.0",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
- "js-yaml": "^3.13.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
"lodash.merge": "^4.6.2",
- "minimatch": "^3.0.4",
+ "minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "progress": "^2.0.0",
- "regexpp": "^3.1.0",
- "semver": "^7.2.1",
- "strip-ansi": "^6.0.0",
- "strip-json-comments": "^3.1.0",
- "table": "^6.0.9",
- "text-table": "^0.2.0",
- "v8-compile-cache": "^2.0.3"
+ "optionator": "^0.9.3"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
}
},
"node_modules/eslint-config-prettier": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz",
- "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==",
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz",
+ "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==",
"dev": true,
"license": "MIT",
"bin": {
@@ -10721,240 +10830,142 @@
"eslint": ">=7.0.0"
}
},
- "node_modules/eslint-loader": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-4.0.2.tgz",
- "integrity": "sha512-EDpXor6lsjtTzZpLUn7KmXs02+nIjGcgees9BYjNkWra3jVq5vVa8IoCKgzT2M7dNNeoMBtaSG83Bd40N3poLw==",
- "deprecated": "This loader has been deprecated. Please use eslint-webpack-plugin",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "find-cache-dir": "^3.3.1",
- "fs-extra": "^8.1.0",
- "loader-utils": "^2.0.0",
- "object-hash": "^2.0.3",
- "schema-utils": "^2.6.5"
- },
- "engines": {
- "node": ">= 10.13.0"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0",
- "webpack": "^4.0.0 || ^5.0.0"
- }
- },
- "node_modules/eslint-loader/node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+ "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/eslint-loader/node_modules/ajv-keywords": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
- "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "ajv": "^6.9.1"
+ "debug": "^3.2.7",
+ "is-core-module": "^2.13.0",
+ "resolve": "^1.22.4"
}
},
- "node_modules/eslint-loader/node_modules/find-cache-dir": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
- "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+ "ms": "^2.1.1"
}
},
- "node_modules/eslint-loader/node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "node_modules/eslint-module-utils": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
+ "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
+ "debug": "^3.2.7"
},
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint-loader/node_modules/fs-extra": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
- "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.2.0",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
+ "node": ">=4"
},
- "engines": {
- "node": ">=6 <7 || >=8"
- }
- },
- "node_modules/eslint-loader/node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/eslint-loader/node_modules/jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
- "dev": true,
- "license": "MIT",
- "optionalDependencies": {
- "graceful-fs": "^4.1.6"
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
}
},
- "node_modules/eslint-loader/node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
+ "ms": "^2.1.1"
}
},
- "node_modules/eslint-loader/node_modules/make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "node_modules/eslint-plugin-cypress": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-4.3.0.tgz",
+ "integrity": "sha512-CgS/S940MJlT8jtnWGKI0LvZQBGb/BB0QCpgBOxFMM/Z6znD+PZUwBhCTwHKN2GEr5AOny3xB92an0QfzBGooQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "semver": "^6.0.0"
+ "globals": "^15.15.0"
},
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "peerDependencies": {
+ "eslint": ">=9"
}
},
- "node_modules/eslint-loader/node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "node_modules/eslint-plugin-import": {
+ "version": "2.32.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "p-try": "^2.0.0"
+ "@rtsao/scc": "^1.1.0",
+ "array-includes": "^3.1.9",
+ "array.prototype.findlastindex": "^1.2.6",
+ "array.prototype.flat": "^1.3.3",
+ "array.prototype.flatmap": "^1.3.3",
+ "debug": "^3.2.7",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.9",
+ "eslint-module-utils": "^2.12.1",
+ "hasown": "^2.0.2",
+ "is-core-module": "^2.16.1",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.8",
+ "object.groupby": "^1.0.3",
+ "object.values": "^1.2.1",
+ "semver": "^6.3.1",
+ "string.prototype.trimend": "^1.0.9",
+ "tsconfig-paths": "^3.15.0"
},
"engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint-loader/node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-limit": "^2.2.0"
+ "node": ">=4"
},
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint-loader/node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
}
},
- "node_modules/eslint-loader/node_modules/pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "find-up": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
+ "ms": "^2.1.1"
}
},
- "node_modules/eslint-loader/node_modules/schema-utils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
- "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
+ "node_modules/eslint-plugin-prettier": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz",
+ "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/json-schema": "^7.0.5",
- "ajv": "^6.12.4",
- "ajv-keywords": "^3.5.2"
+ "prettier-linter-helpers": "^1.0.0",
+ "synckit": "^0.11.7"
},
"engines": {
- "node": ">= 8.9.0"
+ "node": "^14.18.0 || >=16.0.0"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- }
- },
- "node_modules/eslint-loader/node_modules/universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4.0.0"
- }
- },
- "node_modules/eslint-plugin-cypress": {
- "version": "2.15.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.2.tgz",
- "integrity": "sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "globals": "^13.20.0"
+ "url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
- "eslint": ">= 3.2.1"
+ "@types/eslint": ">=8.0.0",
+ "eslint": ">=8.0.0",
+ "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
+ "prettier": ">=3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/eslint": {
+ "optional": true
+ },
+ "eslint-config-prettier": {
+ "optional": true
+ }
}
},
"node_modules/eslint-plugin-react": {
@@ -10990,19 +11001,6 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
}
},
- "node_modules/eslint-plugin-react/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/eslint-plugin-react/node_modules/resolve": {
"version": "2.0.0-next.5",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
@@ -11021,6 +11019,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/eslint-plugin-unused-imports": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.2.0.tgz",
+ "integrity": "sha512-hLbJ2/wnjKq4kGA9AUaExVFIbNzyxYdVo49QZmKCnhk5pc9wcYRbfgLHvWJ8tnsdcseGhoUAddm9gn/lt+d74w==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0",
+ "eslint": "^9.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@typescript-eslint/eslint-plugin": {
+ "optional": true
+ }
+ }
+ },
"node_modules/eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -11043,32 +11057,6 @@
"node": ">=4.0"
}
},
- "node_modules/eslint-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
- "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "eslint-visitor-keys": "^1.1.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
- "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/eslint-visitor-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
@@ -11079,16 +11067,6 @@
"node": ">=10"
}
},
- "node_modules/eslint/node_modules/@babel/code-frame": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
- "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/highlight": "^7.10.4"
- }
- },
"node_modules/eslint/node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -11122,16 +11100,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/eslint/node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
"node_modules/eslint/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -11169,18 +11137,64 @@
"dev": true,
"license": "MIT"
},
- "node_modules/eslint/node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "node_modules/eslint/node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
- "license": "MIT",
+ "license": "ISC",
"dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
+ "is-glob": "^4.0.3"
},
- "bin": {
- "js-yaml": "bin/js-yaml.js"
+ "engines": {
+ "node": ">=10.13.0"
}
},
"node_modules/eslint/node_modules/json-schema-traverse": {
@@ -11190,17 +11204,46 @@
"dev": true,
"license": "MIT"
},
- "node_modules/eslint/node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "node_modules/eslint/node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
},
"engines": {
"node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
}
},
"node_modules/eslint/node_modules/supports-color": {
@@ -11217,28 +11260,34 @@
}
},
"node_modules/espree": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
- "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^7.4.0",
- "acorn-jsx": "^5.3.1",
- "eslint-visitor-keys": "^1.3.0"
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
}
},
"node_modules/espree/node_modules/eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
- "node": ">=4"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
}
},
"node_modules/esprima": {
@@ -11527,6 +11576,13 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
+ "node_modules/fast-diff": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/fast-glob": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
@@ -11654,16 +11710,16 @@
}
},
"node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "flat-cache": "^3.0.4"
+ "flat-cache": "^4.0.0"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16.0.0"
}
},
"node_modules/file-selector": {
@@ -11815,35 +11871,17 @@
}
},
"node_modules/flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
"license": "MIT",
"dependencies": {
"flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
+ "keyv": "^4.5.4"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flat-cache/node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "deprecated": "Rimraf versions prior to v4 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "node": ">=16"
}
},
"node_modules/flatted": {
@@ -12254,13 +12292,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/functional-red-black-tree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/functions-have-names": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
@@ -12570,16 +12601,13 @@
}
},
"node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "version": "15.15.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
+ "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
"engines": {
- "node": ">=8"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -12623,16 +12651,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/globby/node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
"node_modules/globjoin": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
@@ -13320,9 +13338,9 @@
"license": "BSD-3-Clause"
},
"node_modules/ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT",
"engines": {
@@ -16591,18 +16609,6 @@
}
}
},
- "node_modules/jsdom/node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/jsdom/node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -18541,16 +18547,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/object-hash": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
- "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
@@ -18647,6 +18643,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/object.groupby": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/object.values": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
@@ -19541,6 +19552,35 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
+ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/pretty-bytes": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@@ -20264,19 +20304,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/regexpp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
- "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- }
- },
"node_modules/regexpu-core": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
@@ -21965,6 +21992,23 @@
"node": ">=18.12.0"
}
},
+ "node_modules/stylelint-config-prettier-scss": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-prettier-scss/-/stylelint-config-prettier-scss-1.0.0.tgz",
+ "integrity": "sha512-Gr2qLiyvJGKeDk0E/+awNTrZB/UtNVPLqCDOr07na/sLekZwm26Br6yYIeBYz3ulsEcQgs5j+2IIMXCC+wsaQA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "stylelint-config-prettier-scss": "bin/check.js",
+ "stylelint-config-prettier-scss-check": "bin/check.js"
+ },
+ "engines": {
+ "node": "14.* || 16.* || >= 18"
+ },
+ "peerDependencies": {
+ "stylelint": ">=15.0.0"
+ }
+ },
"node_modules/stylelint-config-recommended": {
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz",
@@ -22221,6 +22265,22 @@
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
"license": "MIT"
},
+ "node_modules/synckit": {
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
+ "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@pkgr/core": "^0.2.9"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/synckit"
+ }
+ },
"node_modules/tabbable": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
@@ -22377,18 +22437,6 @@
"node": ">= 10.13.0"
}
},
- "node_modules/terser/node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/terser/node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -22436,13 +22484,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/theming": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/theming/-/theming-3.3.0.tgz",
@@ -22897,6 +22938,42 @@
"node": "^16.13.0 || >=18.0.0"
}
},
+ "node_modules/tsconfig-paths": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/tsconfig-paths/node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/tsconfig-paths/node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@@ -22951,6 +23028,8 @@
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
"license": "(MIT OR CC0-1.0)",
+ "optional": true,
+ "peer": true,
"engines": {
"node": ">=10"
},
@@ -23211,18 +23290,6 @@
"webpack-virtual-modules": "^0.5.0"
}
},
- "node_modules/unplugin/node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/unplugin/node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -23403,13 +23470,6 @@
"uuid": "dist/bin/uuid"
}
},
- "node_modules/v8-compile-cache": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz",
- "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
@@ -23837,18 +23897,6 @@
"integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==",
"license": "MIT"
},
- "node_modules/webpack/node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/webpack/node_modules/acorn-import-phases": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
diff --git a/package.json b/package.json
index e87257c65..3957edcfd 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,8 @@
"@commitlint/cli": "^19.8.0",
"@commitlint/config-conventional": "^19.8.0",
"@cypress/code-coverage": "^3.13.4",
+ "@eslint/eslintrc": "^3.2.0",
+ "@eslint/js": "^9.17.0",
"@patternfly/patternfly": "^6.3.1",
"@redhat-cloud-services/frontend-components-config": "^6.7.1",
"@redhat-cloud-services/tsc-transform-imports": "^1.0.16",
@@ -53,22 +55,27 @@
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
"css-loader": "^5.2.7",
"cypress": "^14.4.0",
- "eslint": "^7.32.0",
- "eslint-config-prettier": "^7.2.0",
- "eslint-loader": "^4.0.2",
- "eslint-plugin-cypress": "^2.15.1",
- "eslint-plugin-react": "^7.32.2",
+ "eslint": "^9.17.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-cypress": "^4.2.0",
+ "eslint-plugin-import": "^2.32.0",
+ "eslint-plugin-prettier": "^5.2.1",
+ "eslint-plugin-react": "^7.37.2",
+ "eslint-plugin-unused-imports": "^4.1.4",
"glob": "^7.2.3",
+ "globals": "^15.13.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.21",
+ "prettier": "^3.4.2",
"prop-types": "^15.8.1",
"react-intl": "^6.6.2",
"redux-mock-store": "^1.5.4",
"sass-loader": "^12.6.0",
"source-map-loader": "^2.0.2",
"stylelint": "^16.10.0",
+ "stylelint-config-prettier-scss": "^1.0.0",
"stylelint-config-recommended-scss": "^14.1.0",
"stylelint-scss": "^6.8.0",
"ts-patch": "^3.1.2",
@@ -82,9 +89,12 @@
"test:local": "TZ=UTC jest --verbose",
"test:update": "TZ=UTC jest --updateSnapshot --passWithNoTests --no-cache",
"lint": "npm-run-all lint:*",
- "lint:js": "eslint config src",
- "lint:js:fix": "eslint config src --fix",
+ "lint:js": "eslint src",
+ "lint:js:fix": "eslint src --fix",
"lint:sass": "stylelint 'src/**/*.scss' --config .stylelintrc.json",
+ "lint:sass:fix": "stylelint 'src/**/*.scss' --config .stylelintrc.json --fix",
+ "prettier": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'",
+ "prettier:check": "prettier --check 'src/**/*.{js,jsx,ts,tsx,json,css,scss,md}'",
"postinstall": "ts-patch install",
"server:ctr": "node src/server/generateServerKey.js",
"start": "fec dev-proxy",
diff --git a/src/App.js b/src/App.js
index ed5489b3c..abf8d5ee8 100644
--- a/src/App.js
+++ b/src/App.js
@@ -10,46 +10,44 @@ import './App.scss';
import Routes from './Routes';
const App = () => {
- const dispatch = useDispatch();
- const chrome = useChrome();
- const [config, setConfig] = useState({
- selectedTags: [],
- systemProfile: false
- });
-
- useEffect(() => {
- chrome?.globalFilterScope?.('insights');
- if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
- chrome?.enablePackagesDebug();
+ const dispatch = useDispatch();
+ const chrome = useChrome();
+ const [config, setConfig] = useState({
+ selectedTags: [],
+ systemProfile: false,
+ });
+
+ useEffect(() => {
+ chrome?.globalFilterScope?.('insights');
+ if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
+ chrome?.enablePackagesDebug();
+ }
+
+ if (chrome?.globalFilterScope) {
+ chrome?.on('GLOBAL_FILTER_UPDATE', ({ data }) => {
+ const SIDs = chrome?.mapGlobalFilter?.(data, false, true)[1];
+ const TAGs = chrome?.mapGlobalFilter?.(data)?.filter((item) => !item.includes('Workloads'));
+
+ const globalFilterConfig = mapGlobalFilters(TAGs, SIDs, data?.Workloads);
+
+ if (JSON.stringify(config) !== JSON.stringify(globalFilterConfig)) {
+ dispatch(globalFilter(globalFilterConfig));
+ setConfig(globalFilterConfig);
+ dispatch(changeGlobalTags(globalFilterConfig.selectedTags));
+ dispatch(changeProfile(globalFilterConfig.systemProfile));
}
-
- if (chrome?.globalFilterScope) {
- chrome?.on('GLOBAL_FILTER_UPDATE', ({ data }) => {
- const SIDs = chrome?.mapGlobalFilter?.(data, false, true)[1];
- const TAGs = chrome?.mapGlobalFilter?.(data)
- ?.filter(item => !item.includes('Workloads'));
-
- const globalFilterConfig = mapGlobalFilters(TAGs, SIDs, data?.Workloads);
-
- if (JSON.stringify(config) !== JSON.stringify(globalFilterConfig)) {
- dispatch(globalFilter(globalFilterConfig));
- setConfig(globalFilterConfig);
- dispatch(changeGlobalTags(globalFilterConfig.selectedTags));
- dispatch(changeProfile(globalFilterConfig.systemProfile));
- }
-
- });
- }
- }, []);
-
- return (
-
-
-
-
-
-
- );
+ });
+ }
+ }, []);
+
+ return (
+
+
+
+
+
+
+ );
};
export default App;
diff --git a/src/App.scss b/src/App.scss
index d8b26dcda..a99dba5e8 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -1,59 +1,59 @@
table.patchCompactInventory {
- .ins-composed-col {
- font-size: var(--pf-v6-c-table--m-compact--FontSize);
- }
+ .ins-composed-col {
+ font-size: var(--pf-v6-c-table--m-compact--FontSize);
+ }
}
.patch-root {
- overflow: inherit !important;
-
- .pf-v6-c-table__expandable-row-content {
- .patch-advisory-description {
- font-size: var(--pf-t--global--font--size--body--default);
- }
- }
-
- .ins-c-primary-toolbar__filter {
- margin-right: 16px;
- }
-
- .ins-c-inventory__list-tags {
- display: block !important;
- }
+ overflow: inherit !important;
- .ins-c-tag-count{
- padding-top: 2px;
- padding-bottom: 0;
- padding-left: 2px;
- display: contents;
- height: 20px;
+ .pf-v6-c-table__expandable-row-content {
+ .patch-advisory-description {
+ font-size: var(--pf-t--global--font--size--body--default);
}
+ }
+
+ .ins-c-primary-toolbar__filter {
+ margin-right: 16px;
+ }
+
+ .ins-c-inventory__list-tags {
+ display: block !important;
+ }
+
+ .ins-c-tag-count {
+ padding-top: 2px;
+ padding-bottom: 0;
+ padding-left: 2px;
+ display: contents;
+ height: 20px;
+ }
}
.ins-c-primary-toolbar {
- .pf-v6-c-toolbar__content.pf-m-hidden {
- display: none !important;
- }
+ .pf-v6-c-toolbar__content.pf-m-hidden {
+ display: none !important;
+ }
}
.patch-root
- .ins-c-inventory__table--toolbar:not(.ins-c-inventory__table--toolbar-has-items)
- .pf-v6-c-toolbar__content
- .pf-v6-c-toolbar__item:last-child {
- min-width: unset !important;
+ .ins-c-inventory__table--toolbar:not(.ins-c-inventory__table--toolbar-has-items)
+ .pf-v6-c-toolbar__content
+ .pf-v6-c-toolbar__item:last-child {
+ min-width: unset !important;
}
.patch-status-report-text {
- color: var(--pf-t--global--icon--color--brand--default);
- font-weight: bold;
- margin: 0px;
- padding: 0px
+ color: var(--pf-t--global--icon--color--brand--default);
+ font-weight: bold;
+ margin: 0px;
+ padding: 0px;
}
.pf-v6-c-table__th {
- font-weight: var(--pf-t--global--font--weight--heading--default);
+ font-weight: var(--pf-t--global--font--weight--heading--default);
}
.pf-v6-c-page__main-section {
- --pf-v6-c-page__main-section--RowGap: 0;
+ --pf-v6-c-page__main-section--RowGap: 0;
}
diff --git a/src/AppEntry.js b/src/AppEntry.js
index 578ef7b75..5059a6e62 100644
--- a/src/AppEntry.js
+++ b/src/AppEntry.js
@@ -6,13 +6,14 @@ import { store } from './store';
import { IntlProvider } from '@redhat-cloud-services/frontend-components-translations';
import messages from '../locales/en.json';
-const Patchman = () => (
+const Patchman = () => (
+
+
);
export default Patchman;
diff --git a/src/Messages.js b/src/Messages.js
index 2ed8db946..2b4aa28c5 100644
--- a/src/Messages.js
+++ b/src/Messages.js
@@ -1,969 +1,960 @@
-/* eslint-disable max-len */
/* eslint sort-keys: ["error", "asc", {minKeys: 4}] */
import { defineMessages } from 'react-intl';
export default defineMessages({
- generalAppName: {
- id: 'generalAppName',
- description: 'regsiter page title',
- defaultMessage: 'Patch'
- },
- labelsActions: {
- id: 'labelsActions',
- description: 'dropdown with actions label',
- defaultMessage: 'Actions'
- },
- labelsAffectedSystemsCount: {
- id: 'labelsAffectedSystemsCount',
- description: 'applicable systems number label',
- defaultMessage: '{systemsCount} affected systems'
- },
- labelsBulkSelectAll: {
- id: 'labelsBulkSelectAll',
- description: 'bulk select option',
- defaultMessage: 'Select all ({count})'
- },
- labelsBulkSelectNone: {
- id: 'labelsBulkSelectNone',
- description: 'bulk select option',
- defaultMessage: 'Select none (0)'
- },
- labelsBulkSelectPage: {
- id: 'labelsBulkSelectPage',
- description: 'bulk select option',
- defaultMessage: 'Select page ({count})'
- },
- labelsButtonCreateTemplate: {
- id: 'labelsButtonCreateTemplate',
- description: 'button label',
- defaultMessage: 'Create a template'
- },
- labelsButtonEditTemplate: {
- id: 'labelsButtonEditTemplate',
- description: 'button label',
- defaultMessage: 'Edit template'
- },
- labelsButtonRemoveTemplate: {
- id: 'labelsButtonRemoveTemplate',
- description: 'button label',
- defaultMessage: 'Delete template'
- },
- labelsCancel: {
- id: 'labelsCancel',
- description: 'Button label',
- defaultMessage: 'Cancel'
- },
- labelsColumnsAffectedSystems: {
- id: 'labelsColumnsAffectedSystems',
- description: 'shared label',
- defaultMessage: 'Affected systems'
- },
- labelsColumnsApplicableSystems: {
- id: 'labelsColumnsApplicableSystems',
- description: 'shared label',
- defaultMessage: 'Applicable systems'
- },
- labelsColumnsCVSS: {
- id: 'labelsColumnsCVSS',
- description: 'shared label',
- defaultMessage: 'CVSS'
- },
- labelsColumnsCveID: {
- id: 'labelsColumnsCveID',
- description: 'shared label',
- defaultMessage: 'CVE ID'
- },
- labelsColumnsInstallableSystems: {
- id: 'labelsColumnsApplicableSystems',
- description: 'shared label',
- defaultMessage: 'Installable systems'
- },
- labelsColumnsInstalledSystems: {
- id: 'labelsColumnsApplicableSystems',
- description: 'shared label',
- defaultMessage: 'Installed systems'
- },
- labelsColumnsInstalledVersion: {
- id: 'labelsColumnsInstalledVersion',
- description: 'shared label',
- defaultMessage: 'Installed version'
- },
- labelsColumnsLatestApplicableVersion: {
- id: 'labelsColumnsLatestApplicableVersion',
- description: 'shared label',
- defaultMessage: 'Latest applicable version'
- },
- labelsColumnsLatestInstallableVersion: {
- id: 'labelsColumnsLatestInstallableVersion',
- description: 'shared label',
- defaultMessage: 'Installable version'
- },
- labelsColumnsName: {
- id: 'labelsColumnsName',
- description: 'shared label',
- defaultMessage: 'Name'
- },
- labelsColumnsPublishDate: {
- id: 'labelsColumnsPublishDate',
- description: 'shared label',
- defaultMessage: 'Publish date'
- },
- labelsColumnsReboot: {
- id: 'labelsColumnsRebootRequired',
- description: 'shared label',
- defaultMessage: 'Reboot'
- },
- labelsColumnsSeverity: {
- id: 'labelsColumnsSeverity',
- description: 'shared label',
- defaultMessage: 'Severity'
- },
- labelsColumnsStatus: {
- id: 'labelsColumnsStatus',
- description: 'Label for status filter',
- defaultMessage: 'Status'
- },
- labelsColumnsStatusPlaceholder: {
- id: 'labelsColumnsStatus',
- description: 'Label for status filter placeholder',
- defaultMessage: 'Filter by status'
- },
- labelsColumnsSummary: {
- id: 'labelsColumnsSummary',
- description: 'shared label',
- defaultMessage: 'Summary'
- },
- labelsColumnsSynopsis: {
- id: 'labelsColumnsSynopsis',
- description: 'shared label',
- defaultMessage: 'Synopsis'
- },
- labelsColumnsTemplate: {
- id: 'labelsColumnsTemplate',
- description: 'Label for patch template column',
- defaultMessage: 'Template'
- },
- labelsColumnsType: {
- id: 'labelsColumnsType',
- description: 'Label for type filter placeholder',
- defaultMessage: 'Type'
- },
- labelsColumnsUpToApplicable: {
- id: 'labelsColumnsUpToApplicable',
- description: 'shared label',
- defaultMessage: 'Up to applicable version'
- },
- labelsColumnsUpToDate: {
- id: 'labelsColumnsUpToDate',
- description: 'shared label',
- defaultMessage: 'Red Hat advisories up to date'
- },
- labelsColumnsUpToInstallable: {
- id: 'labelsColumnsUpToInstallable',
- description: 'shared label',
- defaultMessage: 'Up to latest installable version'
- },
- labelsColumnsUpgradable: {
- id: 'labelsColumnsUpgradable',
- description: 'shared label',
- defaultMessage: 'Upgradable'
- },
- labelsCves: {
- id: 'labelsCves',
- description: 'label for cves info link',
- defaultMessage: 'CVEs'
- },
- labelsCvesButton: {
- id: 'labelsCvesButton',
- description: 'label for cves button',
- defaultMessage:
- '{cvesCount, plural, one {# CVE} other {# CVEs}} associated with this patch'
- },
- labelsDate: {
- id: 'labelsDate',
- description: 'Label',
- defaultMessage: 'Date'
- },
- labelsDelete: {
- id: 'labelsDelete',
- description: 'button label',
- defaultMessage: 'Delete'
- },
- labelsDescription: {
- id: 'labelsDescription',
- description: 'Label',
- defaultMessage: 'Description'
- },
- labelsDocumentation: {
- id: 'labelsDocumentation',
- description: 'Documentation link text',
- defaultMessage: 'Documentation'
- },
- labelsErrorDateLimit: {
- id: 'labelsErrorDateLimit',
- description: 'Label',
- defaultMessage: 'Date is before the allowable range.'
- },
- labelsErrorInvalidDate: {
- id: 'labelsErrorInvalidDate',
- description: 'Label',
- defaultMessage: 'The date should be valid of a type YYYY-MM-DD'
- },
- labelsFiltersClear: {
- id: 'labelsFiltersClear',
- description: 'label for remove filter chips',
- defaultMessage: 'Reset filters'
- },
- labelsFiltersCreator: {
- id: 'labelsFiltersCreator',
- description: 'Label for creator filter',
- defaultMessage: 'Creator'
- },
- labelsFiltersCreatorPlaceholder: {
- id: 'labelsFiltersCreatorPlaceholder',
- description: 'Label for creator filter',
- defaultMessage: 'Filter by creator'
- },
- labelsFiltersCvesSearchPlaceHolder: {
- id: 'labelsFiltersCvesSearch',
- description: 'search filter placeholder for packages pages',
- defaultMessage: 'Filter by CVE ID'
- },
- labelsFiltersOsVersion: {
- id: 'labelsFiltersOsVersion',
- description: 'filter for systems pages',
- defaultMessage: 'Operating system'
- },
- labelsFiltersOsVersionPlaceholder: {
- id: 'labelsFiltersOsVersionPlaceholder',
- description: 'filter for systems pages',
- defaultMessage: 'Filter by operating system'
- },
- labelsFiltersPackageVersionPlaceholder: {
- id: 'labelFiltersPackageVersionPlaceholder',
- description: 'Label for version filter placeholder',
- defaultMessage: 'Filter by version'
- },
- labelsFiltersPackageVersionTitle: {
- id: 'labelsFiltersPackageVersionTitle',
- description: 'Label for version filter title',
- defaultMessage: 'Version'
- },
- labelsFiltersPackagesSearchPlaceHolder: {
- id: 'labelsFiltersPackagesSearchPlaceHolder',
- description: 'search filter placeholder for packages pages',
- defaultMessage: 'Filter by name or summary'
- },
- labelsFiltersPackagesSearchTitle: {
- id: 'labelsFiltersPackagesSearchTitle',
- description: 'search filter placeholder for packages pages',
- defaultMessage: 'Package'
- },
- labelsFiltersPublishDate: {
- id: 'labelsFiltersPublishDate',
- description: 'shared label',
- defaultMessage: 'Publish date'
- },
- labelsFiltersPublishDatePlaceholder: {
- id: 'labelsFiltersPublishDate',
- description: 'shared placeholder label',
- defaultMessage: 'Filter by publish date'
- },
- labelsFiltersReboot: {
- id: 'labelsFiltersReboot',
- description: 'label for reboot filter chips',
- defaultMessage: 'Reboot'
- },
- labelsFiltersRebootPlaceholder: {
- id: 'labelsFiltersRebootPlaceholder',
- description: 'placeholder for reboot filter chips',
- defaultMessage: 'Filter by reboot'
- },
- labelsFiltersReset: {
- id: 'labelsFiltersReset',
- description: 'label for remove filter chips',
- defaultMessage: 'Reset filters'
- },
- labelsFiltersSearch: {
- id: 'labelsFiltersSearch',
- description: 'Label for search filter placeholder',
- defaultMessage: 'Search '
- },
- labelsFiltersSearchAdvisoriesPlaceholder: {
- id: 'labelsFiltersSearchAdvisoriesPlaceholder',
- description: 'Label for search filter placeholder',
- defaultMessage: 'Filter by name or synopsis'
- },
- labelsFiltersSearchAdvisoriesTitle: {
- id: 'labelsFiltersSearchAdvisoriesTitle',
- description: 'Label for search filter placeholder',
- defaultMessage: 'Advisory'
- },
- labelsFiltersSearchTemplatePlaceholder: {
- id: 'labelsFiltersSearchTemplatePlaceholder',
- description: 'Label for search filter placeholder',
- defaultMessage: 'Filter by template name '
- },
- labelsFiltersSearchTemplateTitle: {
- id: 'labelsFiltersSearchTemplateTitle',
- description: 'Label for search filter placeholder',
- defaultMessage: 'Template'
- },
- labelsFiltersSeverity: {
- id: 'labelsFiltersSeverity',
- description: 'Label for severity filter',
- defaultMessage: 'Severity'
- },
- labelsFiltersSeverityPlaceholder: {
- id: 'labelsFiltersSeverity',
- description: 'Label for severity filter placeholder',
- defaultMessage: 'Filter by severity'
- },
- labelsFiltersStale: {
- id: 'labelsFiltersStale',
- description: 'Label for stale filter title',
- defaultMessage: 'Status'
- },
- labelsFiltersStalePlaceholder: {
- id: 'labelsFiltersStalePlaceholder',
- description: 'Label for stale filter placeholder',
- defaultMessage: 'Filter by status'
- },
- labelsFiltersStatus: {
- id: 'labelsFiltersStatus',
- description: 'Label for status filter placeholder',
- defaultMessage: 'Status'
- },
- labelsFiltersSystemsSearchPlaceholder: {
- id: 'labelsFiltersSystemsSearch',
- description: 'search filter placeholder for systems pages',
- defaultMessage: 'Filter by name'
- },
- labelsFiltersSystemsSearchTitle: {
- id: 'labelsFiltersSystemsSearchTitle',
- description: 'search filter placeholder for systems pages',
- defaultMessage: 'System'
- },
- labelsFiltersType: {
- id: 'labelsFiltersType',
- description: 'Label for type filter',
- defaultMessage: 'Type'
- },
- labelsFiltersTypePlaceholder: {
- id: 'labelsFiltersType',
- description: 'Label for type filter placeholder',
- defaultMessage: 'Filter by type'
- },
- labelsFiltersUpdatable: {
- id: 'labelsFiltersUpdatable',
- description: 'search filter placeholder for systems pages',
- defaultMessage: 'Patch status'
- },
- labelsFiltersUpdatablePlaceholder: {
- id: 'labelsFiltersUpdatablePlaceholder',
- description: 'search filter placeholder for systems updatable pages',
- defaultMessage: 'Filter by patch status'
- },
- labelsModifiedDate: {
- id: 'labelsModifiedDate',
- description: 'Modified date label',
- defaultMessage: 'Modified {date}'
- },
- labelsNotAuthorizedDescription: {
- id: 'notAuthorizedDescription',
- description:
- 'Description for component which shows up when user doesn\'t have permission to view content',
- defaultMessage:
- 'Contact your organization administrator(s) for more information.'
- },
- labelsNotAuthorizedTitle: {
- id: 'notAuthorizedTitle',
- description:
- 'Title for component which shows up when user doesn\'t have permission to view content',
- defaultMessage: 'You do not have permissions to view or manage Patch'
- },
- labelsPublicDate: {
- id: 'labelsPublicDate',
- description: 'Public date label',
- defaultMessage: 'Issued {date}'
- },
- labelsRebootNotRequired: {
- id: 'labelsRequired',
- description: 'shared label',
- defaultMessage: 'Not required'
- },
- labelsRebootRequired: {
- id: 'labelsRequired',
- description: 'shared label',
- defaultMessage: 'Required'
- },
- labelsRemediate: {
- id: 'labelsRemediate',
- description: 'Button label',
- defaultMessage: 'Plan remediation'
- },
- labelsRemove: {
- id: 'labelsRemove',
- description: 'Button label',
- defaultMessage: 'Remove'
- },
- labelsReturnToLandingPage: {
- id: 'returnToLandingPage',
- description: 'Return to landing page label for general usage',
- defaultMessage: 'Go to landing page'
- },
- labelsReturnToPreviousPage: {
- id: 'returnPreviousPage',
- description: 'Return to previous page label for general usage',
- defaultMessage: 'Return to previous page'
- },
- labelsSelectedSystems: {
- id: 'labelsSelectedSystems',
- description: 'label',
- defaultMessage: 'Template applied to'
- },
- labelsSeverity: {
- id: 'labelsSeverity',
- description: 'label for cves info',
- defaultMessage: 'Severity'
- },
- labelsStatusStaleSystems: {
- id: 'labelsStatusStaleSystems',
- description: 'Label for status report',
- defaultMessage: 'Stale systems'
- },
- labelsStatusSystemsUpToDate: {
- id: 'labelsSystemsUpToDate',
- description: 'Label for status report',
- defaultMessage: 'Systems up to date'
- },
- labelsStatusSystemsWithPatchesAvailable: {
- id: 'labelsSystemsWithPatchesAvailable',
- description: 'Label for status report',
- defaultMessage: 'Systems with patches available'
- },
- labelsSystem: {
- id: 'labelsSystem',
- description: 'Generic pluralized systems label',
- defaultMessage:
- '{systemsCount, plural, one { # system } other { # systems }}'
- },
- labelsTemplateNoSystems: {
- id: 'labelsTemplateNoSystems',
- description: 'Template list table applied systems column fallback',
- defaultMessage: 'No systems applied'
- },
- linksLearnAboutInsights: {
- id: 'linksLearnAboutInsights',
- description: 'no system data page button label',
- defaultMessage: 'Learn about the Insights client'
- },
- linksLearnMore: {
- id: 'linksLearnMore',
- description: 'Learn more',
- defaultMessage: 'Learn more'
- },
- linksReadMore: {
- id: 'linksReadMore',
- description: 'Label',
- defaultMessage: 'Read more'
- },
- linksSearchSecurityRatings: {
- id: 'linksSearchSecurityRatings',
- description: 'A link label to security ratings page',
- defaultMessage: 'Learn more about security ratings'
- },
- linksViewPackagesAndErrata: {
- id: 'viewPackagesAndErrata',
- description: 'A link label to access.redhat.com ',
- defaultMessage: 'View packages and errata at access.redhat.com'
- },
- statesError: {
- id: 'statesError',
- description: 'Label',
- defaultMessage: 'Error'
- },
- statesMinimumPatchPermissionsRequired: {
- id: 'statesMinimumPatchPermissionsRequired',
- description: 'No access page body',
- defaultMessage:
- 'To view the content of this page, you must be granted a minimum of Patch permissions from your Organisation Administratior'
- },
- statesNoApplicableAdvisories: {
- id: 'statesNoApplicableAdvisories',
- description: 'system up to date page title',
- defaultMessage: 'No applicable advisories'
- },
- statesNoMatchingAdvisories: {
- id: 'statesNoMatchingAdvisories',
- description: 'Label',
- defaultMessage: 'No matching advisories found'
- },
- statesNoMatchingCve: {
- id: 'statesNoMatchingCve',
- description: 'Label',
- defaultMessage: 'No matching CVES found'
- },
- statesNoMatchingPackages: {
- id: 'statesNoMatchingPackages',
- description: 'Label',
- defaultMessage: 'No matching packages found'
- },
- statesNoMatchingSystems: {
- id: 'statesNoMatchingSystems',
- description: 'Label',
- defaultMessage: 'No matching systems found'
- },
- statesNoMatchingTemplate: {
- id: 'statesNoMatchingTemplate',
- description: 'Label',
- defaultMessage: 'No matching patch template found'
- },
- statesNoTemplate: {
- id: 'statesNoTemplate',
- description: 'Label',
- defaultMessage: 'No templates yet'
- },
- statesNoTemplateBody: {
- id: 'statesNoTemplateBody',
- description: 'Label',
- defaultMessage:
- 'Control the scope of package and advisory updates to be installed on selected systems with templates. To get started, create a template.'
- },
- statesNoTemplateLink: {
- id: 'statesNoTemplateLink',
- description: 'Label',
- defaultMessage: 'Learn more about templates'
- },
- statesRequiresPatchPermissions: {
- id: 'statesRequiresPatchPermissions',
- description: 'No access page title',
- defaultMessage: 'This application requires Patch permissions'
- },
- statesSystemUpToDate: {
- id: 'statesSystemUpToDate',
- description: 'system up to date page body',
- defaultMessage:
- 'This system is up to date, based on package information submitted at the most recent system check-in'
- },
- templateAlertSystems: {
- id: 'templateAlertSystems',
- description: 'Template wizard alert',
- defaultMessage:
- 'A system can have only one content template, therefore if you apply a new content template to the system, it will be overwritten.'
- },
- templateApply: {
- id: 'templateApply',
- description: 'title with capital letters',
- defaultMessage: 'Apply template'
- },
- templateApplySystems: {
- id: 'templateApplySystems',
- description: 'step name of the patch template wizard',
- defaultMessage: 'Apply to systems (optional)'
- },
- templateContentStepExpandable: {
- id: 'templateContentStepExpandable',
- description: 'template wizard template expandable text',
- defaultMessage:
- 'You have a system with 10 applicable RHEL advisories, the most recent of which was published today. You apply a template with a date of yesterday to that system. After re-evaluation, the advisory published today will not be considered installable on the system, but will be considered applicable.'
- },
- templateContentStepExpandableTitle: {
- id: 'templateContentStepExpandableTitle',
- description: 'template wizard template expandable title',
- defaultMessage: 'What does it mean?'
- },
- templateContentStepSidebarName: {
- id: 'templateContentStepSidebarName',
- description: 'template wizard template left sidebar label',
- defaultMessage: 'Content'
- },
- templateContentStepText: {
- id: 'templateContentStepText',
- description: 'template wizard template text',
- defaultMessage:
- 'Templates provide you with consistent content across environments and time by allowing you to control the scope of package and advisory updates to be installed on selected systems.'
- },
- templateContentStepTitle: {
- id: 'templateContentStepTitle',
- description: 'template wizard template title',
- defaultMessage: 'Define template content'
- },
- templateCreate: {
- id: 'templateCreate',
- description: 'title with capital letters',
- defaultMessage: 'Create'
- },
- templateDateField: {
- id: 'templateDateField',
- description: 'Field name of the patch template wizard',
- defaultMessage: 'Select date of Red Hat repositiories'
- },
- templateDateUpto: {
- id: 'templateDateUpto',
- description: 'Field text of the patch template wizard',
- defaultMessage: 'Include advisories up to this date'
- },
- templateDescription: {
- id: 'templateDescription',
- description: 'description of the patch template wizard',
- defaultMessage:
- 'Prepare for your next patching cycle with a content template.'
- },
- templateDetailHeaderBreadcrumb: {
- id: 'templateDetailHeaderBreadcrumb',
- description: 'breadcrumb for template detail header',
- defaultMessage: 'Templates'
- },
- templateDetailStepSidebarName: {
- id: 'templateDetailStepSidebarName',
- description: 'template wizard template left sidebar label',
- defaultMessage: 'Details'
- },
- templateDetailStepText: {
- id: 'templateDetailStepText',
- description: 'template wizard template detail step text',
- defaultMessage: 'Enter a name and description for your template.'
- },
- templateDetailStepTitle: {
- id: 'templateDetailStepTitle',
- description: 'template wizard template detail step title',
- defaultMessage: 'Enter template details'
- },
- templateDetailTableCreatedBy: {
- id: 'templateDetailTableCreatedBy',
- description: 'label inside template detail header',
- defaultMessage: 'Created by:'
- },
- templateDetailTableDescription: {
- id: 'templateDetailTableDescription',
- description: 'label inside template detail header',
- defaultMessage: 'Template description:'
- },
- templateDetailTableLastEdited: {
- id: 'templateDetailTableLastEdited',
- description: 'title of template assigned systems table',
- defaultMessage: 'Last edited:'
- },
- templateDetailTablePublished: {
- id: 'templateDetailTablePublished',
- description: 'title of template assigned systems table',
- defaultMessage: 'Published:'
- },
- templateDetailTableTitle: {
- id: 'templateDetailTableTitle',
- description: 'title of template assigned systems table',
- defaultMessage: 'Systems applied'
- },
- templateDetailTableUpToDate: {
- id: 'templateDetailTableUpToDate',
- description: 'label inside template detail header',
- defaultMessage: 'Includes Red Hat repositories up to:'
- },
- templateEdit: {
- id: 'templateEdit',
- description: 'step name of the patch template wizard',
- defaultMessage: 'Edit content template '
- },
- templateError: {
- id: 'templateError',
- description: 'error text for the patch template wizard',
- defaultMessage:
- 'There was a problem processing the patch template. Please try again. If the problem persists, contact Red Hat support'
- },
- templateNew: {
- id: 'templateNew',
- description: 'step name of the patch template wizard',
- defaultMessage: 'New patch template '
- },
- templateNoAppliedSystemsButton: {
- id: 'templateNoAppliedSystemsButton',
- description:
- 'button in the empty state in template assigned systems table',
- defaultMessage: 'Apply to systems'
- },
- templateNoAppliedSystemsTitle: {
- id: 'templateNoAppliedSystemsTitle',
- description:
- 'title of the empty state in template assigned systems table',
- defaultMessage: 'Not applied to any systems'
- },
- templateNoSystemSelected: {
- id: 'templateNoSystemSelected',
- description: 'validation text of the patch template wizard',
- defaultMessage:
- 'At least one system must be selected. Actions must be associated to a system to be added to a playbook.'
- },
- templateOr: {
- id: 'templateOr',
- description: 'title with capital letters',
- defaultMessage: 'Or'
- },
- templatePopoverBody: {
- id: 'templatePopoverBody',
- description: 'Template page header popover body',
- defaultMessage:
- 'Templates allow you to control the scope of package and advisory updates to be installed on selected systems.'
- },
- templatePopoverHeader: {
- id: 'templatePopoverHeader',
- description: 'Template page header popover title',
- defaultMessage: 'About Templates'
- },
- templateReview: {
- id: 'templateReview',
- description: 'step name of the patch template wizard',
- defaultMessage: 'Review '
- },
- templateSelect: {
- id: 'templateSelect',
- description: 'title with capital letters',
- defaultMessage:
- 'Select a template to apply to the selected {systemCount, plural, one {# system} other {# systems}}.'
- },
- templateSelectExisting: {
- id: 'templateSelectExisting',
- description: 'title with capital letters',
- defaultMessage: 'Select an existing template'
- },
- templateSelectSatellite: {
- id: 'templateSelectSatellite',
- description: 'title with capital letters',
- defaultMessage:
- '{systemCount} of the selected systems content is Managed by Satellite therefore Template is not applicable.'
- },
- templateStepSystems: {
- id: 'templateStepSystems',
- description: 'step name of the patch template wizard',
- defaultMessage: 'Systems (optional)'
- },
- templateTitle: {
- id: 'templateTitle',
- description: 'title of the patch template wizard',
- defaultMessage: 'Create content template '
- },
- templateTitleAssignSystem: {
- id: 'templateTitleAssignSystem',
- description: 'title of the patch template wizard',
- defaultMessage: 'Assign system(s) to a patch template '
- },
- templateWizardValidateLoading: {
- id: 'templateWizardValidateLoading',
- description: 'template wizard text when user input is not valid',
- defaultMessage: 'Template details are loading.'
- },
- templateWizardValidateNameTaken: {
- id: 'templateWizardValidateNameTaken',
- description: 'template wizard text when user input is not valid',
- defaultMessage: 'Template name already exists. Try a different name.'
- },
- textConfigurationInProgress: {
- id: 'textConfigurationInProgress',
- description: 'text for the patch template',
- defaultMessage: 'Configuration in progress'
- },
- textEmptyStateBody: {
- id: 'textEmptyStateBody',
- description: 'text for the Empty state body',
- defaultMessage:
- 'To continue, edit your filter settings and search again.'
- },
- textErrorSomethingWrong: {
- id: 'textErrorSomethingWrong',
- description: 'text for the error state body',
- defaultMessage: 'Something went wrong'
- },
- textLockVersionTooltip: {
- id: 'textLockVersionTooltip',
- description: 'Tooltip text for vesrion lock column',
- defaultMessage: `Your RHEL version is locked at version {lockedVersion}`
- },
- textNoVersionAvailable: {
- id: 'textNoVersionAvailable',
- description: 'text to notify there is not available version',
- defaultMessage: 'No version is available'
- },
- textPatchTemplateContent: {
- id: 'textPatchTemplateContent',
- description: 'text for the patch template',
- defaultMessage: 'Content'
- },
- textPatchTemplateDetails: {
- id: 'textPatchTemplateDetails',
- description: 'text for the patch template',
- defaultMessage: 'Details'
- },
- textPatchTemplatePending: {
- id: 'textPatchTemplatePending',
- description: 'text for the patch template',
- defaultMessage:
- 'Please allow a few minutes to set up a patch template. You will receive a notification when finished.'
- },
- textPatchTemplateReview: {
- id: 'textPatchTemplateReview',
- description: 'text for the patch template',
- defaultMessage: 'Review the details of your template.'
- },
- textPatchTemplateSuccessfuly: {
- id: 'textPatchTemplateSuccessfuly',
- description: 'text for the patch template',
- defaultMessage: 'Patch template configuration successful'
- },
- textPatchTemplateSystems: {
- id: 'textPatchTemplateSystems',
- description: 'text for the patch template',
- defaultMessage: 'Systems'
- },
- textRebootIsRequired: {
- id: 'textRebootIsRequired',
- description: 'Advisories table cell text',
- defaultMessage: 'Reboot is required'
- },
- textReturnToApp: {
- id: 'textReturnToApp',
- description: 'text for wizards',
- defaultMessage: 'Return to application'
- },
- textTemplateAddToExisting: {
- id: 'textTemplateAddToExisting',
- description: 'text for patch template wizard',
- defaultMessage: 'Add to existing patch template '
- },
- textTemplateChoose: {
- id: 'textTemplateChoose',
- description: 'text for patch template wizard',
- defaultMessage: 'Template'
- },
- textTemplateCreateNew: {
- id: 'textTemplateCreateNew',
- description: 'text for patch template wizard',
- defaultMessage: 'Create new patch template '
- },
- textTemplateSelectedSystems: {
- id: 'textTemplateSelectedSystems',
- description: 'text for patch template wizard',
- defaultMessage:
- 'You selected {systemsCount, plural, one { # system } other { # systems }}'
- },
- textUnassignSystemsNoAssignedSystems: {
- id: 'textUnassignSystemsNoAssignedSystems',
- description: 'text about systems being removed',
- defaultMessage:
- 'None of the systems you have selected are assigned to existing Patch template.'
- },
- textUnassignSystemsShortTitle: {
- id: 'textUnassignSystemsShortTitle',
- description: 'text about systems being removed',
- defaultMessage: 'Remove system'
- },
- textUnassignSystemsStatement: {
- id: 'textUnassignSystemsStatement',
- description: 'text about systems being removed',
- defaultMessage:
- 'Do you want to remove the {systemsCount, plural, one { # selected system } other { # selected systems }} from assigned Patch templates?'
- },
- textUnassignSystemsTitle: {
- id: 'textUnassignSystemsTitle',
- description: 'text about systems being removed',
- defaultMessage: 'Remove systems from patch template '
- },
- textUnassignSystemsWarning: {
- id: 'textUnassignSystemsWarning',
- description: 'warning about systems without patch template assigned',
- defaultMessage:
- 'There {systemsCount, plural, one {is # system } other { are # systems }} you are trying to remove that {systemsCount, plural, one {is} other {are}} not assigned to any existing Patch template. This action will not affect {systemsCount, plural, one {it} other {them}}.'
- },
- titlesAdvisories: {
- id: 'titlesAdvisories',
- description: 'page title with capital letter',
- defaultMessage: 'Advisories'
- },
- titlesAdvisoryType: {
- id: 'titlesAdvisoryType',
- description: 'title with capital letter',
- defaultMessage: 'Advisory type'
- },
- titlesAffectedSystems: {
- id: 'affectedSystems',
- description: 'page title with capital letter',
- defaultMessage: 'Systems'
- },
- titlesMostImpactfulAdvisories: {
- id: 'titlesMostImpactfulAdvisories',
- description: 'page title with capital letter',
- defaultMessage: 'Most impactful advisories'
- },
- titlesPackages: {
- id: 'titlesPackages',
- description: 'page title with capital letters',
- defaultMessage: 'Packages'
- },
- titlesPatchAdvisories: {
- id: 'titlesPatchAdvisories',
- description: 'title for Advisories page',
- defaultMessage: 'Advisories'
- },
- titlesPatchPackages: {
- id: 'titlesPatchPackages',
- description: 'title for Packages page',
- defaultMessage: 'Packages'
- },
- titlesPatchSystems: {
- id: 'titlesPatchSystems',
- description: 'title for Systems page',
- defaultMessage: 'Systems'
- },
- titlesSystems: {
- id: 'titlesSystems',
- description: 'title with capital letters',
- defaultMessage: 'Systems'
- },
- titlesTemplate: {
- id: 'titlesTemplate',
- description: 'page title with capital letter',
- defaultMessage: 'Templates'
- },
- titlesTemplateAssign: {
- id: 'titlesTemplateAssign',
- description: 'title with capital letters',
- defaultMessage: 'Assign to a template'
- },
- titlesTemplateDeleteModalCheckbox: {
- id: 'titlesTemplateDeleteModalCheckbox',
- description: 'page title with capital letter',
- defaultMessage: 'I understand that this action cannot be undone.'
- },
- titlesTemplateDeleteModalText: {
- id: 'titlesTemplateDeleteModalText',
- description: 'page title with capital letter',
- defaultMessage:
- '{templateName} and all its data will be permanently deleted. Associated systems will be removed from the template but will not be deleted.'
- },
- titlesTemplateDeleteModalTitle: {
- id: 'titlesTemplateDeleteModalTitle',
- description: 'page title with capital letter',
- defaultMessage: 'Delete template?'
- },
- titlesTemplateNoDescription: {
- id: 'titlesTemplateNoDescription',
- description: 'title with capital letters',
- defaultMessage: 'No description available'
- },
- titlesTemplateNoDescriptionProvided: {
- id: 'titlesTemplateNoDescriptionProvided',
- description: 'title with capital letters',
- defaultMessage: 'No description provided'
- },
- titlesTemplateRemoveFromSystems: {
- id: 'titlesTemplateRemoveMultipleButton',
- description: 'title with capital letters',
- defaultMessage:
- 'Remove from {systemsCount, plural, one {system} other {systems}}'
- },
- titlesTemplateRemoveMultipleButton: {
- id: 'titlesTemplateRemoveMultipleButton',
- description: 'title with capital letters',
- defaultMessage: 'Remove from a template'
- }
+ generalAppName: {
+ id: 'generalAppName',
+ description: 'regsiter page title',
+ defaultMessage: 'Patch',
+ },
+ labelsActions: {
+ id: 'labelsActions',
+ description: 'dropdown with actions label',
+ defaultMessage: 'Actions',
+ },
+ labelsAffectedSystemsCount: {
+ id: 'labelsAffectedSystemsCount',
+ description: 'applicable systems number label',
+ defaultMessage: '{systemsCount} affected systems',
+ },
+ labelsBulkSelectAll: {
+ id: 'labelsBulkSelectAll',
+ description: 'bulk select option',
+ defaultMessage: 'Select all ({count})',
+ },
+ labelsBulkSelectNone: {
+ id: 'labelsBulkSelectNone',
+ description: 'bulk select option',
+ defaultMessage: 'Select none (0)',
+ },
+ labelsBulkSelectPage: {
+ id: 'labelsBulkSelectPage',
+ description: 'bulk select option',
+ defaultMessage: 'Select page ({count})',
+ },
+ labelsButtonCreateTemplate: {
+ id: 'labelsButtonCreateTemplate',
+ description: 'button label',
+ defaultMessage: 'Create a template',
+ },
+ labelsButtonEditTemplate: {
+ id: 'labelsButtonEditTemplate',
+ description: 'button label',
+ defaultMessage: 'Edit template',
+ },
+ labelsButtonRemoveTemplate: {
+ id: 'labelsButtonRemoveTemplate',
+ description: 'button label',
+ defaultMessage: 'Delete template',
+ },
+ labelsCancel: {
+ id: 'labelsCancel',
+ description: 'Button label',
+ defaultMessage: 'Cancel',
+ },
+ labelsColumnsAffectedSystems: {
+ id: 'labelsColumnsAffectedSystems',
+ description: 'shared label',
+ defaultMessage: 'Affected systems',
+ },
+ labelsColumnsApplicableSystems: {
+ id: 'labelsColumnsApplicableSystems',
+ description: 'shared label',
+ defaultMessage: 'Applicable systems',
+ },
+ labelsColumnsCVSS: {
+ id: 'labelsColumnsCVSS',
+ description: 'shared label',
+ defaultMessage: 'CVSS',
+ },
+ labelsColumnsCveID: {
+ id: 'labelsColumnsCveID',
+ description: 'shared label',
+ defaultMessage: 'CVE ID',
+ },
+ labelsColumnsInstallableSystems: {
+ id: 'labelsColumnsApplicableSystems',
+ description: 'shared label',
+ defaultMessage: 'Installable systems',
+ },
+ labelsColumnsInstalledSystems: {
+ id: 'labelsColumnsApplicableSystems',
+ description: 'shared label',
+ defaultMessage: 'Installed systems',
+ },
+ labelsColumnsInstalledVersion: {
+ id: 'labelsColumnsInstalledVersion',
+ description: 'shared label',
+ defaultMessage: 'Installed version',
+ },
+ labelsColumnsLatestApplicableVersion: {
+ id: 'labelsColumnsLatestApplicableVersion',
+ description: 'shared label',
+ defaultMessage: 'Latest applicable version',
+ },
+ labelsColumnsLatestInstallableVersion: {
+ id: 'labelsColumnsLatestInstallableVersion',
+ description: 'shared label',
+ defaultMessage: 'Installable version',
+ },
+ labelsColumnsName: {
+ id: 'labelsColumnsName',
+ description: 'shared label',
+ defaultMessage: 'Name',
+ },
+ labelsColumnsPublishDate: {
+ id: 'labelsColumnsPublishDate',
+ description: 'shared label',
+ defaultMessage: 'Publish date',
+ },
+ labelsColumnsReboot: {
+ id: 'labelsColumnsRebootRequired',
+ description: 'shared label',
+ defaultMessage: 'Reboot',
+ },
+ labelsColumnsSeverity: {
+ id: 'labelsColumnsSeverity',
+ description: 'shared label',
+ defaultMessage: 'Severity',
+ },
+ labelsColumnsStatus: {
+ id: 'labelsColumnsStatus',
+ description: 'Label for status filter',
+ defaultMessage: 'Status',
+ },
+ labelsColumnsStatusPlaceholder: {
+ id: 'labelsColumnsStatus',
+ description: 'Label for status filter placeholder',
+ defaultMessage: 'Filter by status',
+ },
+ labelsColumnsSummary: {
+ id: 'labelsColumnsSummary',
+ description: 'shared label',
+ defaultMessage: 'Summary',
+ },
+ labelsColumnsSynopsis: {
+ id: 'labelsColumnsSynopsis',
+ description: 'shared label',
+ defaultMessage: 'Synopsis',
+ },
+ labelsColumnsTemplate: {
+ id: 'labelsColumnsTemplate',
+ description: 'Label for patch template column',
+ defaultMessage: 'Template',
+ },
+ labelsColumnsType: {
+ id: 'labelsColumnsType',
+ description: 'Label for type filter placeholder',
+ defaultMessage: 'Type',
+ },
+ labelsColumnsUpToApplicable: {
+ id: 'labelsColumnsUpToApplicable',
+ description: 'shared label',
+ defaultMessage: 'Up to applicable version',
+ },
+ labelsColumnsUpToDate: {
+ id: 'labelsColumnsUpToDate',
+ description: 'shared label',
+ defaultMessage: 'Red Hat advisories up to date',
+ },
+ labelsColumnsUpToInstallable: {
+ id: 'labelsColumnsUpToInstallable',
+ description: 'shared label',
+ defaultMessage: 'Up to latest installable version',
+ },
+ labelsColumnsUpgradable: {
+ id: 'labelsColumnsUpgradable',
+ description: 'shared label',
+ defaultMessage: 'Upgradable',
+ },
+ labelsCves: {
+ id: 'labelsCves',
+ description: 'label for cves info link',
+ defaultMessage: 'CVEs',
+ },
+ labelsCvesButton: {
+ id: 'labelsCvesButton',
+ description: 'label for cves button',
+ defaultMessage: '{cvesCount, plural, one {# CVE} other {# CVEs}} associated with this patch',
+ },
+ labelsDate: {
+ id: 'labelsDate',
+ description: 'Label',
+ defaultMessage: 'Date',
+ },
+ labelsDelete: {
+ id: 'labelsDelete',
+ description: 'button label',
+ defaultMessage: 'Delete',
+ },
+ labelsDescription: {
+ id: 'labelsDescription',
+ description: 'Label',
+ defaultMessage: 'Description',
+ },
+ labelsDocumentation: {
+ id: 'labelsDocumentation',
+ description: 'Documentation link text',
+ defaultMessage: 'Documentation',
+ },
+ labelsErrorDateLimit: {
+ id: 'labelsErrorDateLimit',
+ description: 'Label',
+ defaultMessage: 'Date is before the allowable range.',
+ },
+ labelsErrorInvalidDate: {
+ id: 'labelsErrorInvalidDate',
+ description: 'Label',
+ defaultMessage: 'The date should be valid of a type YYYY-MM-DD',
+ },
+ labelsFiltersClear: {
+ id: 'labelsFiltersClear',
+ description: 'label for remove filter chips',
+ defaultMessage: 'Reset filters',
+ },
+ labelsFiltersCreator: {
+ id: 'labelsFiltersCreator',
+ description: 'Label for creator filter',
+ defaultMessage: 'Creator',
+ },
+ labelsFiltersCreatorPlaceholder: {
+ id: 'labelsFiltersCreatorPlaceholder',
+ description: 'Label for creator filter',
+ defaultMessage: 'Filter by creator',
+ },
+ labelsFiltersCvesSearchPlaceHolder: {
+ id: 'labelsFiltersCvesSearch',
+ description: 'search filter placeholder for packages pages',
+ defaultMessage: 'Filter by CVE ID',
+ },
+ labelsFiltersOsVersion: {
+ id: 'labelsFiltersOsVersion',
+ description: 'filter for systems pages',
+ defaultMessage: 'Operating system',
+ },
+ labelsFiltersOsVersionPlaceholder: {
+ id: 'labelsFiltersOsVersionPlaceholder',
+ description: 'filter for systems pages',
+ defaultMessage: 'Filter by operating system',
+ },
+ labelsFiltersPackageVersionPlaceholder: {
+ id: 'labelFiltersPackageVersionPlaceholder',
+ description: 'Label for version filter placeholder',
+ defaultMessage: 'Filter by version',
+ },
+ labelsFiltersPackageVersionTitle: {
+ id: 'labelsFiltersPackageVersionTitle',
+ description: 'Label for version filter title',
+ defaultMessage: 'Version',
+ },
+ labelsFiltersPackagesSearchPlaceHolder: {
+ id: 'labelsFiltersPackagesSearchPlaceHolder',
+ description: 'search filter placeholder for packages pages',
+ defaultMessage: 'Filter by name or summary',
+ },
+ labelsFiltersPackagesSearchTitle: {
+ id: 'labelsFiltersPackagesSearchTitle',
+ description: 'search filter placeholder for packages pages',
+ defaultMessage: 'Package',
+ },
+ labelsFiltersPublishDate: {
+ id: 'labelsFiltersPublishDate',
+ description: 'shared label',
+ defaultMessage: 'Publish date',
+ },
+ labelsFiltersPublishDatePlaceholder: {
+ id: 'labelsFiltersPublishDate',
+ description: 'shared placeholder label',
+ defaultMessage: 'Filter by publish date',
+ },
+ labelsFiltersReboot: {
+ id: 'labelsFiltersReboot',
+ description: 'label for reboot filter chips',
+ defaultMessage: 'Reboot',
+ },
+ labelsFiltersRebootPlaceholder: {
+ id: 'labelsFiltersRebootPlaceholder',
+ description: 'placeholder for reboot filter chips',
+ defaultMessage: 'Filter by reboot',
+ },
+ labelsFiltersReset: {
+ id: 'labelsFiltersReset',
+ description: 'label for remove filter chips',
+ defaultMessage: 'Reset filters',
+ },
+ labelsFiltersSearch: {
+ id: 'labelsFiltersSearch',
+ description: 'Label for search filter placeholder',
+ defaultMessage: 'Search ',
+ },
+ labelsFiltersSearchAdvisoriesPlaceholder: {
+ id: 'labelsFiltersSearchAdvisoriesPlaceholder',
+ description: 'Label for search filter placeholder',
+ defaultMessage: 'Filter by name or synopsis',
+ },
+ labelsFiltersSearchAdvisoriesTitle: {
+ id: 'labelsFiltersSearchAdvisoriesTitle',
+ description: 'Label for search filter placeholder',
+ defaultMessage: 'Advisory',
+ },
+ labelsFiltersSearchTemplatePlaceholder: {
+ id: 'labelsFiltersSearchTemplatePlaceholder',
+ description: 'Label for search filter placeholder',
+ defaultMessage: 'Filter by template name ',
+ },
+ labelsFiltersSearchTemplateTitle: {
+ id: 'labelsFiltersSearchTemplateTitle',
+ description: 'Label for search filter placeholder',
+ defaultMessage: 'Template',
+ },
+ labelsFiltersSeverity: {
+ id: 'labelsFiltersSeverity',
+ description: 'Label for severity filter',
+ defaultMessage: 'Severity',
+ },
+ labelsFiltersSeverityPlaceholder: {
+ id: 'labelsFiltersSeverity',
+ description: 'Label for severity filter placeholder',
+ defaultMessage: 'Filter by severity',
+ },
+ labelsFiltersStale: {
+ id: 'labelsFiltersStale',
+ description: 'Label for stale filter title',
+ defaultMessage: 'Status',
+ },
+ labelsFiltersStalePlaceholder: {
+ id: 'labelsFiltersStalePlaceholder',
+ description: 'Label for stale filter placeholder',
+ defaultMessage: 'Filter by status',
+ },
+ labelsFiltersStatus: {
+ id: 'labelsFiltersStatus',
+ description: 'Label for status filter placeholder',
+ defaultMessage: 'Status',
+ },
+ labelsFiltersSystemsSearchPlaceholder: {
+ id: 'labelsFiltersSystemsSearch',
+ description: 'search filter placeholder for systems pages',
+ defaultMessage: 'Filter by name',
+ },
+ labelsFiltersSystemsSearchTitle: {
+ id: 'labelsFiltersSystemsSearchTitle',
+ description: 'search filter placeholder for systems pages',
+ defaultMessage: 'System',
+ },
+ labelsFiltersType: {
+ id: 'labelsFiltersType',
+ description: 'Label for type filter',
+ defaultMessage: 'Type',
+ },
+ labelsFiltersTypePlaceholder: {
+ id: 'labelsFiltersType',
+ description: 'Label for type filter placeholder',
+ defaultMessage: 'Filter by type',
+ },
+ labelsFiltersUpdatable: {
+ id: 'labelsFiltersUpdatable',
+ description: 'search filter placeholder for systems pages',
+ defaultMessage: 'Patch status',
+ },
+ labelsFiltersUpdatablePlaceholder: {
+ id: 'labelsFiltersUpdatablePlaceholder',
+ description: 'search filter placeholder for systems updatable pages',
+ defaultMessage: 'Filter by patch status',
+ },
+ labelsModifiedDate: {
+ id: 'labelsModifiedDate',
+ description: 'Modified date label',
+ defaultMessage: 'Modified {date}',
+ },
+ labelsNotAuthorizedDescription: {
+ id: 'notAuthorizedDescription',
+ description:
+ "Description for component which shows up when user doesn't have permission to view content",
+ defaultMessage: 'Contact your organization administrator(s) for more information.',
+ },
+ labelsNotAuthorizedTitle: {
+ id: 'notAuthorizedTitle',
+ description:
+ "Title for component which shows up when user doesn't have permission to view content",
+ defaultMessage: 'You do not have permissions to view or manage Patch',
+ },
+ labelsPublicDate: {
+ id: 'labelsPublicDate',
+ description: 'Public date label',
+ defaultMessage: 'Issued {date}',
+ },
+ labelsRebootNotRequired: {
+ id: 'labelsRequired',
+ description: 'shared label',
+ defaultMessage: 'Not required',
+ },
+ labelsRebootRequired: {
+ id: 'labelsRequired',
+ description: 'shared label',
+ defaultMessage: 'Required',
+ },
+ labelsRemediate: {
+ id: 'labelsRemediate',
+ description: 'Button label',
+ defaultMessage: 'Plan remediation',
+ },
+ labelsRemove: {
+ id: 'labelsRemove',
+ description: 'Button label',
+ defaultMessage: 'Remove',
+ },
+ labelsReturnToLandingPage: {
+ id: 'returnToLandingPage',
+ description: 'Return to landing page label for general usage',
+ defaultMessage: 'Go to landing page',
+ },
+ labelsReturnToPreviousPage: {
+ id: 'returnPreviousPage',
+ description: 'Return to previous page label for general usage',
+ defaultMessage: 'Return to previous page',
+ },
+ labelsSelectedSystems: {
+ id: 'labelsSelectedSystems',
+ description: 'label',
+ defaultMessage: 'Template applied to',
+ },
+ labelsSeverity: {
+ id: 'labelsSeverity',
+ description: 'label for cves info',
+ defaultMessage: 'Severity',
+ },
+ labelsStatusStaleSystems: {
+ id: 'labelsStatusStaleSystems',
+ description: 'Label for status report',
+ defaultMessage: 'Stale systems',
+ },
+ labelsStatusSystemsUpToDate: {
+ id: 'labelsSystemsUpToDate',
+ description: 'Label for status report',
+ defaultMessage: 'Systems up to date',
+ },
+ labelsStatusSystemsWithPatchesAvailable: {
+ id: 'labelsSystemsWithPatchesAvailable',
+ description: 'Label for status report',
+ defaultMessage: 'Systems with patches available',
+ },
+ labelsSystem: {
+ id: 'labelsSystem',
+ description: 'Generic pluralized systems label',
+ defaultMessage: '{systemsCount, plural, one { # system } other { # systems }}',
+ },
+ labelsTemplateNoSystems: {
+ id: 'labelsTemplateNoSystems',
+ description: 'Template list table applied systems column fallback',
+ defaultMessage: 'No systems applied',
+ },
+ linksLearnAboutInsights: {
+ id: 'linksLearnAboutInsights',
+ description: 'no system data page button label',
+ defaultMessage: 'Learn about the Insights client',
+ },
+ linksLearnMore: {
+ id: 'linksLearnMore',
+ description: 'Learn more',
+ defaultMessage: 'Learn more',
+ },
+ linksReadMore: {
+ id: 'linksReadMore',
+ description: 'Label',
+ defaultMessage: 'Read more',
+ },
+ linksSearchSecurityRatings: {
+ id: 'linksSearchSecurityRatings',
+ description: 'A link label to security ratings page',
+ defaultMessage: 'Learn more about security ratings',
+ },
+ linksViewPackagesAndErrata: {
+ id: 'viewPackagesAndErrata',
+ description: 'A link label to access.redhat.com ',
+ defaultMessage: 'View packages and errata at access.redhat.com',
+ },
+ statesError: {
+ id: 'statesError',
+ description: 'Label',
+ defaultMessage: 'Error',
+ },
+ statesMinimumPatchPermissionsRequired: {
+ id: 'statesMinimumPatchPermissionsRequired',
+ description: 'No access page body',
+ defaultMessage:
+ 'To view the content of this page, you must be granted a minimum of Patch permissions from your Organisation Administratior',
+ },
+ statesNoApplicableAdvisories: {
+ id: 'statesNoApplicableAdvisories',
+ description: 'system up to date page title',
+ defaultMessage: 'No applicable advisories',
+ },
+ statesNoMatchingAdvisories: {
+ id: 'statesNoMatchingAdvisories',
+ description: 'Label',
+ defaultMessage: 'No matching advisories found',
+ },
+ statesNoMatchingCve: {
+ id: 'statesNoMatchingCve',
+ description: 'Label',
+ defaultMessage: 'No matching CVES found',
+ },
+ statesNoMatchingPackages: {
+ id: 'statesNoMatchingPackages',
+ description: 'Label',
+ defaultMessage: 'No matching packages found',
+ },
+ statesNoMatchingSystems: {
+ id: 'statesNoMatchingSystems',
+ description: 'Label',
+ defaultMessage: 'No matching systems found',
+ },
+ statesNoMatchingTemplate: {
+ id: 'statesNoMatchingTemplate',
+ description: 'Label',
+ defaultMessage: 'No matching patch template found',
+ },
+ statesNoTemplate: {
+ id: 'statesNoTemplate',
+ description: 'Label',
+ defaultMessage: 'No templates yet',
+ },
+ statesNoTemplateBody: {
+ id: 'statesNoTemplateBody',
+ description: 'Label',
+ defaultMessage:
+ 'Control the scope of package and advisory updates to be installed on selected systems with templates. To get started, create a template.',
+ },
+ statesNoTemplateLink: {
+ id: 'statesNoTemplateLink',
+ description: 'Label',
+ defaultMessage: 'Learn more about templates',
+ },
+ statesRequiresPatchPermissions: {
+ id: 'statesRequiresPatchPermissions',
+ description: 'No access page title',
+ defaultMessage: 'This application requires Patch permissions',
+ },
+ statesSystemUpToDate: {
+ id: 'statesSystemUpToDate',
+ description: 'system up to date page body',
+ defaultMessage:
+ 'This system is up to date, based on package information submitted at the most recent system check-in',
+ },
+ templateAlertSystems: {
+ id: 'templateAlertSystems',
+ description: 'Template wizard alert',
+ defaultMessage:
+ 'A system can have only one content template, therefore if you apply a new content template to the system, it will be overwritten.',
+ },
+ templateApply: {
+ id: 'templateApply',
+ description: 'title with capital letters',
+ defaultMessage: 'Apply template',
+ },
+ templateApplySystems: {
+ id: 'templateApplySystems',
+ description: 'step name of the patch template wizard',
+ defaultMessage: 'Apply to systems (optional)',
+ },
+ templateContentStepExpandable: {
+ id: 'templateContentStepExpandable',
+ description: 'template wizard template expandable text',
+ defaultMessage:
+ 'You have a system with 10 applicable RHEL advisories, the most recent of which was published today. You apply a template with a date of yesterday to that system. After re-evaluation, the advisory published today will not be considered installable on the system, but will be considered applicable.',
+ },
+ templateContentStepExpandableTitle: {
+ id: 'templateContentStepExpandableTitle',
+ description: 'template wizard template expandable title',
+ defaultMessage: 'What does it mean?',
+ },
+ templateContentStepSidebarName: {
+ id: 'templateContentStepSidebarName',
+ description: 'template wizard template left sidebar label',
+ defaultMessage: 'Content',
+ },
+ templateContentStepText: {
+ id: 'templateContentStepText',
+ description: 'template wizard template text',
+ defaultMessage:
+ 'Templates provide you with consistent content across environments and time by allowing you to control the scope of package and advisory updates to be installed on selected systems.',
+ },
+ templateContentStepTitle: {
+ id: 'templateContentStepTitle',
+ description: 'template wizard template title',
+ defaultMessage: 'Define template content',
+ },
+ templateCreate: {
+ id: 'templateCreate',
+ description: 'title with capital letters',
+ defaultMessage: 'Create',
+ },
+ templateDateField: {
+ id: 'templateDateField',
+ description: 'Field name of the patch template wizard',
+ defaultMessage: 'Select date of Red Hat repositiories',
+ },
+ templateDateUpto: {
+ id: 'templateDateUpto',
+ description: 'Field text of the patch template wizard',
+ defaultMessage: 'Include advisories up to this date',
+ },
+ templateDescription: {
+ id: 'templateDescription',
+ description: 'description of the patch template wizard',
+ defaultMessage: 'Prepare for your next patching cycle with a content template.',
+ },
+ templateDetailHeaderBreadcrumb: {
+ id: 'templateDetailHeaderBreadcrumb',
+ description: 'breadcrumb for template detail header',
+ defaultMessage: 'Templates',
+ },
+ templateDetailStepSidebarName: {
+ id: 'templateDetailStepSidebarName',
+ description: 'template wizard template left sidebar label',
+ defaultMessage: 'Details',
+ },
+ templateDetailStepText: {
+ id: 'templateDetailStepText',
+ description: 'template wizard template detail step text',
+ defaultMessage: 'Enter a name and description for your template.',
+ },
+ templateDetailStepTitle: {
+ id: 'templateDetailStepTitle',
+ description: 'template wizard template detail step title',
+ defaultMessage: 'Enter template details',
+ },
+ templateDetailTableCreatedBy: {
+ id: 'templateDetailTableCreatedBy',
+ description: 'label inside template detail header',
+ defaultMessage: 'Created by:',
+ },
+ templateDetailTableDescription: {
+ id: 'templateDetailTableDescription',
+ description: 'label inside template detail header',
+ defaultMessage: 'Template description:',
+ },
+ templateDetailTableLastEdited: {
+ id: 'templateDetailTableLastEdited',
+ description: 'title of template assigned systems table',
+ defaultMessage: 'Last edited:',
+ },
+ templateDetailTablePublished: {
+ id: 'templateDetailTablePublished',
+ description: 'title of template assigned systems table',
+ defaultMessage: 'Published:',
+ },
+ templateDetailTableTitle: {
+ id: 'templateDetailTableTitle',
+ description: 'title of template assigned systems table',
+ defaultMessage: 'Systems applied',
+ },
+ templateDetailTableUpToDate: {
+ id: 'templateDetailTableUpToDate',
+ description: 'label inside template detail header',
+ defaultMessage: 'Includes Red Hat repositories up to:',
+ },
+ templateEdit: {
+ id: 'templateEdit',
+ description: 'step name of the patch template wizard',
+ defaultMessage: 'Edit content template ',
+ },
+ templateError: {
+ id: 'templateError',
+ description: 'error text for the patch template wizard',
+ defaultMessage:
+ 'There was a problem processing the patch template. Please try again. If the problem persists, contact Red Hat support',
+ },
+ templateNew: {
+ id: 'templateNew',
+ description: 'step name of the patch template wizard',
+ defaultMessage: 'New patch template ',
+ },
+ templateNoAppliedSystemsButton: {
+ id: 'templateNoAppliedSystemsButton',
+ description: 'button in the empty state in template assigned systems table',
+ defaultMessage: 'Apply to systems',
+ },
+ templateNoAppliedSystemsTitle: {
+ id: 'templateNoAppliedSystemsTitle',
+ description: 'title of the empty state in template assigned systems table',
+ defaultMessage: 'Not applied to any systems',
+ },
+ templateNoSystemSelected: {
+ id: 'templateNoSystemSelected',
+ description: 'validation text of the patch template wizard',
+ defaultMessage:
+ 'At least one system must be selected. Actions must be associated to a system to be added to a playbook.',
+ },
+ templateOr: {
+ id: 'templateOr',
+ description: 'title with capital letters',
+ defaultMessage: 'Or',
+ },
+ templatePopoverBody: {
+ id: 'templatePopoverBody',
+ description: 'Template page header popover body',
+ defaultMessage:
+ 'Templates allow you to control the scope of package and advisory updates to be installed on selected systems.',
+ },
+ templatePopoverHeader: {
+ id: 'templatePopoverHeader',
+ description: 'Template page header popover title',
+ defaultMessage: 'About Templates',
+ },
+ templateReview: {
+ id: 'templateReview',
+ description: 'step name of the patch template wizard',
+ defaultMessage: 'Review ',
+ },
+ templateSelect: {
+ id: 'templateSelect',
+ description: 'title with capital letters',
+ defaultMessage:
+ 'Select a template to apply to the selected {systemCount, plural, one {# system} other {# systems}}.',
+ },
+ templateSelectExisting: {
+ id: 'templateSelectExisting',
+ description: 'title with capital letters',
+ defaultMessage: 'Select an existing template',
+ },
+ templateSelectSatellite: {
+ id: 'templateSelectSatellite',
+ description: 'title with capital letters',
+ defaultMessage:
+ '{systemCount} of the selected systems content is Managed by Satellite therefore Template is not applicable.',
+ },
+ templateStepSystems: {
+ id: 'templateStepSystems',
+ description: 'step name of the patch template wizard',
+ defaultMessage: 'Systems (optional)',
+ },
+ templateTitle: {
+ id: 'templateTitle',
+ description: 'title of the patch template wizard',
+ defaultMessage: 'Create content template ',
+ },
+ templateTitleAssignSystem: {
+ id: 'templateTitleAssignSystem',
+ description: 'title of the patch template wizard',
+ defaultMessage: 'Assign system(s) to a patch template ',
+ },
+ templateWizardValidateLoading: {
+ id: 'templateWizardValidateLoading',
+ description: 'template wizard text when user input is not valid',
+ defaultMessage: 'Template details are loading.',
+ },
+ templateWizardValidateNameTaken: {
+ id: 'templateWizardValidateNameTaken',
+ description: 'template wizard text when user input is not valid',
+ defaultMessage: 'Template name already exists. Try a different name.',
+ },
+ textConfigurationInProgress: {
+ id: 'textConfigurationInProgress',
+ description: 'text for the patch template',
+ defaultMessage: 'Configuration in progress',
+ },
+ textEmptyStateBody: {
+ id: 'textEmptyStateBody',
+ description: 'text for the Empty state body',
+ defaultMessage: 'To continue, edit your filter settings and search again.',
+ },
+ textErrorSomethingWrong: {
+ id: 'textErrorSomethingWrong',
+ description: 'text for the error state body',
+ defaultMessage: 'Something went wrong',
+ },
+ textLockVersionTooltip: {
+ id: 'textLockVersionTooltip',
+ description: 'Tooltip text for vesrion lock column',
+ defaultMessage: `Your RHEL version is locked at version {lockedVersion}`,
+ },
+ textNoVersionAvailable: {
+ id: 'textNoVersionAvailable',
+ description: 'text to notify there is not available version',
+ defaultMessage: 'No version is available',
+ },
+ textPatchTemplateContent: {
+ id: 'textPatchTemplateContent',
+ description: 'text for the patch template',
+ defaultMessage: 'Content',
+ },
+ textPatchTemplateDetails: {
+ id: 'textPatchTemplateDetails',
+ description: 'text for the patch template',
+ defaultMessage: 'Details',
+ },
+ textPatchTemplatePending: {
+ id: 'textPatchTemplatePending',
+ description: 'text for the patch template',
+ defaultMessage:
+ 'Please allow a few minutes to set up a patch template. You will receive a notification when finished.',
+ },
+ textPatchTemplateReview: {
+ id: 'textPatchTemplateReview',
+ description: 'text for the patch template',
+ defaultMessage: 'Review the details of your template.',
+ },
+ textPatchTemplateSuccessfuly: {
+ id: 'textPatchTemplateSuccessfuly',
+ description: 'text for the patch template',
+ defaultMessage: 'Patch template configuration successful',
+ },
+ textPatchTemplateSystems: {
+ id: 'textPatchTemplateSystems',
+ description: 'text for the patch template',
+ defaultMessage: 'Systems',
+ },
+ textRebootIsRequired: {
+ id: 'textRebootIsRequired',
+ description: 'Advisories table cell text',
+ defaultMessage: 'Reboot is required',
+ },
+ textReturnToApp: {
+ id: 'textReturnToApp',
+ description: 'text for wizards',
+ defaultMessage: 'Return to application',
+ },
+ textTemplateAddToExisting: {
+ id: 'textTemplateAddToExisting',
+ description: 'text for patch template wizard',
+ defaultMessage: 'Add to existing patch template ',
+ },
+ textTemplateChoose: {
+ id: 'textTemplateChoose',
+ description: 'text for patch template wizard',
+ defaultMessage: 'Template',
+ },
+ textTemplateCreateNew: {
+ id: 'textTemplateCreateNew',
+ description: 'text for patch template wizard',
+ defaultMessage: 'Create new patch template ',
+ },
+ textTemplateSelectedSystems: {
+ id: 'textTemplateSelectedSystems',
+ description: 'text for patch template wizard',
+ defaultMessage:
+ 'You selected {systemsCount, plural, one { # system } other { # systems }}',
+ },
+ textUnassignSystemsNoAssignedSystems: {
+ id: 'textUnassignSystemsNoAssignedSystems',
+ description: 'text about systems being removed',
+ defaultMessage:
+ 'None of the systems you have selected are assigned to existing Patch template.',
+ },
+ textUnassignSystemsShortTitle: {
+ id: 'textUnassignSystemsShortTitle',
+ description: 'text about systems being removed',
+ defaultMessage: 'Remove system',
+ },
+ textUnassignSystemsStatement: {
+ id: 'textUnassignSystemsStatement',
+ description: 'text about systems being removed',
+ defaultMessage:
+ 'Do you want to remove the {systemsCount, plural, one { # selected system } other { # selected systems }} from assigned Patch templates?',
+ },
+ textUnassignSystemsTitle: {
+ id: 'textUnassignSystemsTitle',
+ description: 'text about systems being removed',
+ defaultMessage: 'Remove systems from patch template ',
+ },
+ textUnassignSystemsWarning: {
+ id: 'textUnassignSystemsWarning',
+ description: 'warning about systems without patch template assigned',
+ defaultMessage:
+ 'There {systemsCount, plural, one {is # system } other { are # systems }} you are trying to remove that {systemsCount, plural, one {is} other {are}} not assigned to any existing Patch template. This action will not affect {systemsCount, plural, one {it} other {them}}.',
+ },
+ titlesAdvisories: {
+ id: 'titlesAdvisories',
+ description: 'page title with capital letter',
+ defaultMessage: 'Advisories',
+ },
+ titlesAdvisoryType: {
+ id: 'titlesAdvisoryType',
+ description: 'title with capital letter',
+ defaultMessage: 'Advisory type',
+ },
+ titlesAffectedSystems: {
+ id: 'affectedSystems',
+ description: 'page title with capital letter',
+ defaultMessage: 'Systems',
+ },
+ titlesMostImpactfulAdvisories: {
+ id: 'titlesMostImpactfulAdvisories',
+ description: 'page title with capital letter',
+ defaultMessage: 'Most impactful advisories',
+ },
+ titlesPackages: {
+ id: 'titlesPackages',
+ description: 'page title with capital letters',
+ defaultMessage: 'Packages',
+ },
+ titlesPatchAdvisories: {
+ id: 'titlesPatchAdvisories',
+ description: 'title for Advisories page',
+ defaultMessage: 'Advisories',
+ },
+ titlesPatchPackages: {
+ id: 'titlesPatchPackages',
+ description: 'title for Packages page',
+ defaultMessage: 'Packages',
+ },
+ titlesPatchSystems: {
+ id: 'titlesPatchSystems',
+ description: 'title for Systems page',
+ defaultMessage: 'Systems',
+ },
+ titlesSystems: {
+ id: 'titlesSystems',
+ description: 'title with capital letters',
+ defaultMessage: 'Systems',
+ },
+ titlesTemplate: {
+ id: 'titlesTemplate',
+ description: 'page title with capital letter',
+ defaultMessage: 'Templates',
+ },
+ titlesTemplateAssign: {
+ id: 'titlesTemplateAssign',
+ description: 'title with capital letters',
+ defaultMessage: 'Assign to a template',
+ },
+ titlesTemplateDeleteModalCheckbox: {
+ id: 'titlesTemplateDeleteModalCheckbox',
+ description: 'page title with capital letter',
+ defaultMessage: 'I understand that this action cannot be undone.',
+ },
+ titlesTemplateDeleteModalText: {
+ id: 'titlesTemplateDeleteModalText',
+ description: 'page title with capital letter',
+ defaultMessage:
+ '{templateName} and all its data will be permanently deleted. Associated systems will be removed from the template but will not be deleted.',
+ },
+ titlesTemplateDeleteModalTitle: {
+ id: 'titlesTemplateDeleteModalTitle',
+ description: 'page title with capital letter',
+ defaultMessage: 'Delete template?',
+ },
+ titlesTemplateNoDescription: {
+ id: 'titlesTemplateNoDescription',
+ description: 'title with capital letters',
+ defaultMessage: 'No description available',
+ },
+ titlesTemplateNoDescriptionProvided: {
+ id: 'titlesTemplateNoDescriptionProvided',
+ description: 'title with capital letters',
+ defaultMessage: 'No description provided',
+ },
+ titlesTemplateRemoveFromSystems: {
+ id: 'titlesTemplateRemoveMultipleButton',
+ description: 'title with capital letters',
+ defaultMessage: 'Remove from {systemsCount, plural, one {system} other {systems}}',
+ },
+ titlesTemplateRemoveMultipleButton: {
+ id: 'titlesTemplateRemoveMultipleButton',
+ description: 'title with capital letters',
+ defaultMessage: 'Remove from a template',
+ },
});
diff --git a/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.js b/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.js
index 813b2a3f5..1c2ebb140 100644
--- a/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.js
+++ b/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.js
@@ -1,22 +1,24 @@
import {
- Button,
- Content,
- ContentVariants,
- Flex,
- FlexItem,
- Grid,
- GridItem,
- Split,
- SplitItem,
- Stack,
- StackItem,
- Title
+ Button,
+ Content,
+ ContentVariants,
+ Flex,
+ FlexItem,
+ Grid,
+ GridItem,
+ Split,
+ SplitItem,
+ Stack,
+ StackItem,
+ Title,
} from '@patternfly/react-core';
import { processDate } from '@redhat-cloud-services/frontend-components-utilities/helpers';
import propTypes from 'prop-types';
import React, { Fragment, lazy, Suspense, useState } from 'react';
import messages from '../../Messages';
-import WithLoader, { WithLoaderVariants } from '../../PresentationalComponents/WithLoader/WithLoader';
+import WithLoader, {
+ WithLoaderVariants,
+} from '../../PresentationalComponents/WithLoader/WithLoader';
import { getSeverityByValue, isRHAdvisory, truncateDescription } from '../../Utilities/Helpers';
import { intl } from '../../Utilities/IntlProvider';
import RebootRequired from '../Snippets/RebootRequired';
@@ -24,119 +26,113 @@ import AdvisorySeverityInfo from '../Snippets/AdvisorySeverityInfo';
import ExternalLink from '../Snippets/ExternalLink';
import AdvisoryType from '../AdvisoryType/AdvisoryType';
-const CvesModal = lazy(() =>
- import(
- /* webpackChunkName: "CvesModal" */ '../../SmartComponents/AdvisoryDetail/CvesModal'
- )
+const CvesModal = lazy(
+ () =>
+ import(/* webpackChunkName: "CvesModal" */ '../../SmartComponents/AdvisoryDetail/CvesModal'),
);
const AdvisoryHeader = ({ attributes, isLoading }) => {
- const [CvesInfoModal, setCvesModal] = useState(() => () => null);
- const [wordLength, setWordLength] = useState(1000);
- const severityObject = getSeverityByValue(attributes?.severity);
- const cves = attributes.cves;
+ const [CvesInfoModal, setCvesModal] = useState(() => () => null);
+ const [wordLength, setWordLength] = useState(1000);
+ const severityObject = getSeverityByValue(attributes?.severity);
+ const cves = attributes.cves;
- const showCvesModal = () => {
- setCvesModal(() => () => );
- };
+ const showCvesModal = () => {
+ setCvesModal(() => () => );
+ };
- return (
-
-
-
-
-
-
- {
- attributes.description && truncateDescription(attributes.description, wordLength, setWordLength)
- }
-
-
- {attributes.public_date && (
-
- {intl.formatMessage(messages.labelsPublicDate, {
- date: processDate(
- attributes.public_date
- )
- })}
-
-
- )}
- {attributes.modified_date && (
-
- {intl.formatMessage(messages.labelsModifiedDate, {
- date: processDate(
- attributes.modified_date
- )
- })}
-
- )}
-
- {isRHAdvisory(attributes.id) &&
-
-
-
- }
-
-
-
-
-
- {attributes.advisory_type_name && (
-
-
-
-
-
- {intl.formatMessage(messages.titlesAdvisoryType)}
-
-
-
-
-
-
-
-
+ return (
+
+
+
+
+
+
+ {attributes.description &&
+ truncateDescription(attributes.description, wordLength, setWordLength)}
+
+
+ {attributes.public_date && (
+
+ {intl.formatMessage(messages.labelsPublicDate, {
+ date: processDate(attributes.public_date),
+ })}
+
+
+ )}
+ {attributes.modified_date && (
+
+ {intl.formatMessage(messages.labelsModifiedDate, {
+ date: processDate(attributes.modified_date),
+ })}
+
+ )}
+
+ {isRHAdvisory(attributes.id) && (
+
+
+
+ )}
+
+
+
+
+
+ {attributes.advisory_type_name && (
+
+
+
+
+
+
+ {intl.formatMessage(messages.titlesAdvisoryType)}
+
- )}
- {severityObject.value === null ? null : (
-
+
+
- )}
- {attributes.reboot_required && (
-
- )}
-
-
- {cves && cves.length !== 0 && (
-
-
-
- {intl.formatMessage(messages.labelsCves)}
-
-
-
-
- )}
- }>
-
-
-
- );
+
+
+
+
+ )}
+ {severityObject.value === null ? null : (
+
+
+
+ )}
+ {attributes.reboot_required && (
+
+
+
+ )}
+
+
+ {cves && cves.length !== 0 && (
+
+
+
+ {intl.formatMessage(messages.labelsCves)}
+
+
+
+
+ )}
+ }>
+
+
+
+ );
};
AdvisoryHeader.propTypes = {
- attributes: propTypes.object,
- isLoading: propTypes.bool
+ attributes: propTypes.object,
+ isLoading: propTypes.bool,
};
export default AdvisoryHeader;
diff --git a/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.test.js b/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.test.js
index 213923f2f..03569e077 100644
--- a/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.test.js
+++ b/src/PresentationalComponents/AdvisoryHeader/AdvisoryHeader.test.js
@@ -3,17 +3,17 @@ import { advisoryHeader } from '../../Utilities/RawDataForTesting';
import { render } from '@testing-library/react';
describe('AdvisoryHeader', () => {
- it('Should match the snapshots when loading', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshots when loading', () => {
+ const { asFragment } = render(
+ ,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('Should match the snapshots when loaded', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshots when loaded', () => {
+ const { asFragment } = render(
+ ,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.js b/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.js
index 1f04d35fe..752f14576 100644
--- a/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.js
+++ b/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.js
@@ -4,21 +4,21 @@ import PropTypes from 'prop-types';
import React from 'react';
const AdvisorySeverity = ({ severity: { label, color } = {} }) => (
-
-
-
-
-
- {label}
-
+
+
+
+
+
+ {label}
+
);
AdvisorySeverity.propTypes = {
- severity: PropTypes.shape({
- label: PropTypes.string,
- color: PropTypes.string
- })
+ severity: PropTypes.shape({
+ label: PropTypes.string,
+ color: PropTypes.string,
+ }),
};
export default AdvisorySeverity;
diff --git a/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.test.js b/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.test.js
index 553aeaf34..0605f37c8 100644
--- a/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.test.js
+++ b/src/PresentationalComponents/AdvisorySeverity/AdvisorySeverity.test.js
@@ -2,11 +2,15 @@ import { render } from '@testing-library/react';
import AdvisorySeverity from './AdvisorySeverity';
describe('AdvisorySeverity', () => {
- it('Should match the snapshots', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshots', () => {
+ const { asFragment } = render(
+ ,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/PresentationalComponents/AdvisoryType/AdvisoryType.js b/src/PresentationalComponents/AdvisoryType/AdvisoryType.js
index ca7b979a9..f5fb8756d 100644
--- a/src/PresentationalComponents/AdvisoryType/AdvisoryType.js
+++ b/src/PresentationalComponents/AdvisoryType/AdvisoryType.js
@@ -4,22 +4,19 @@ import { advisoryTypes } from '../../Utilities/constants';
import { Icon, Split, SplitItem } from '@patternfly/react-core';
const AdvisoryType = ({ type }) => {
- const advisoryType =
- advisoryTypes.find(item => item.value === type) || advisoryTypes[3];
- return (
-
-
-
- {advisoryType.icon}
-
-
- {advisoryType.label}
-
- );
+ const advisoryType = advisoryTypes.find((item) => item.value === type) || advisoryTypes[3];
+ return (
+
+
+ {advisoryType.icon}
+
+ {advisoryType.label}
+
+ );
};
AdvisoryType.propTypes = {
- type: PropTypes.string
+ type: PropTypes.string,
};
export default AdvisoryType;
diff --git a/src/PresentationalComponents/AdvisoryType/AdvisoryType.test.js b/src/PresentationalComponents/AdvisoryType/AdvisoryType.test.js
index 146b31ecf..448bbc0ee 100644
--- a/src/PresentationalComponents/AdvisoryType/AdvisoryType.test.js
+++ b/src/PresentationalComponents/AdvisoryType/AdvisoryType.test.js
@@ -2,10 +2,8 @@ import AdvisoryType from './AdvisoryType';
import { render } from '@testing-library/react';
describe('AdvisoryType', () => {
- it('Should match the snapshots', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshots', () => {
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/PresentationalComponents/Filters/AdvisoryStatusFilter.js b/src/PresentationalComponents/Filters/AdvisoryStatusFilter.js
index 8e06b16ff..fed72b972 100644
--- a/src/PresentationalComponents/Filters/AdvisoryStatusFilter.js
+++ b/src/PresentationalComponents/Filters/AdvisoryStatusFilter.js
@@ -4,26 +4,27 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const advisoryStatusFilter = (apply, currentFilter = {}) => {
- const filterByStatus = value => {
- value.length === 0
- ? apply({ filter: { status: undefined } })
- : apply({ filter: { status: value } });
- };
+ const filterByStatus = (value) => {
+ value.length === 0
+ ? apply({ filter: { status: undefined } })
+ : apply({ filter: { status: value } });
+ };
- return {
- label: intl.formatMessage(messages.labelsFiltersStatus),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterByStatus(value);
- },
- items: advisoryStatuses,
- value: !currentFilter.status || Array.isArray(currentFilter.status)
- ? currentFilter.status
- : [currentFilter.status],
- placeholder: intl.formatMessage(messages.labelsColumnsStatusPlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersStatus),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByStatus(value);
+ },
+ items: advisoryStatuses,
+ value:
+ !currentFilter.status || Array.isArray(currentFilter.status)
+ ? currentFilter.status
+ : [currentFilter.status],
+ placeholder: intl.formatMessage(messages.labelsColumnsStatusPlaceholder),
+ },
+ };
};
export default advisoryStatusFilter;
diff --git a/src/PresentationalComponents/Filters/AdvisoryStatusFilter.test.js b/src/PresentationalComponents/Filters/AdvisoryStatusFilter.test.js
index d57487cd7..60d37629b 100644
--- a/src/PresentationalComponents/Filters/AdvisoryStatusFilter.test.js
+++ b/src/PresentationalComponents/Filters/AdvisoryStatusFilter.test.js
@@ -4,21 +4,21 @@ const apply = jest.fn();
const currentFilter = { status: 'Installable' };
jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useMemo: jest.fn(callback => callback())
+ ...jest.requireActual('react'),
+ useMemo: jest.fn((callback) => callback()),
}));
describe('StatusFilter', () => {
- it('Should set currentValue to zero and init', () => {
- const response = advisoryStatusFilter(apply, currentFilter);
- expect(response.filterValues.value).toEqual(['Installable']);
- expect(response.label).toEqual('Status');
- expect(response.type).toEqual('checkbox');
- });
+ it('Should set currentValue to zero and init', () => {
+ const response = advisoryStatusFilter(apply, currentFilter);
+ expect(response.filterValues.value).toEqual(['Installable']);
+ expect(response.label).toEqual('Status');
+ expect(response.type).toEqual('checkbox');
+ });
- it('Should call apply with a date', () => {
- const response = advisoryStatusFilter(apply, currentFilter);
- response.filterValues.onChange('event', 'Applicable');
- expect(apply).toHaveBeenCalledWith({ filter: { status: 'Applicable' } });
- });
+ it('Should call apply with a date', () => {
+ const response = advisoryStatusFilter(apply, currentFilter);
+ response.filterValues.onChange('event', 'Applicable');
+ expect(apply).toHaveBeenCalledWith({ filter: { status: 'Applicable' } });
+ });
});
diff --git a/src/PresentationalComponents/Filters/CreatorFilter.js b/src/PresentationalComponents/Filters/CreatorFilter.js
index 046c1a5ff..21152998e 100644
--- a/src/PresentationalComponents/Filters/CreatorFilter.js
+++ b/src/PresentationalComponents/Filters/CreatorFilter.js
@@ -3,26 +3,28 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const creatorFilter = (apply, currentFilter = {}, items) => {
- const filterByCreator = value => {
- value.length === 0
- ? apply({ filter: { creator: undefined } })
- : apply({ filter: { creator: value } });
- };
+ const filterByCreator = (value) => {
+ value.length === 0
+ ? apply({ filter: { creator: undefined } })
+ : apply({ filter: { creator: value } });
+ };
- return {
- label: intl.formatMessage(messages.labelsFiltersCreator),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterByCreator(value);
- },
- items: items?.filter(item => item !== null).map(item => ({ value: item, label: item })) ?? [],
- value: !currentFilter.creator || Array.isArray(currentFilter.creator)
- ? currentFilter.creator
- : [currentFilter.creator],
- placeholder: intl.formatMessage(messages.labelsFiltersCreatorPlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersCreator),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByCreator(value);
+ },
+ items:
+ items?.filter((item) => item !== null).map((item) => ({ value: item, label: item })) ?? [],
+ value:
+ !currentFilter.creator || Array.isArray(currentFilter.creator)
+ ? currentFilter.creator
+ : [currentFilter.creator],
+ placeholder: intl.formatMessage(messages.labelsFiltersCreatorPlaceholder),
+ },
+ };
};
export default creatorFilter;
diff --git a/src/PresentationalComponents/Filters/OsVersionFilter.js b/src/PresentationalComponents/Filters/OsVersionFilter.js
index e80316ac5..c92d1d26e 100644
--- a/src/PresentationalComponents/Filters/OsVersionFilter.js
+++ b/src/PresentationalComponents/Filters/OsVersionFilter.js
@@ -4,62 +4,68 @@ import { useLoadModule } from '@scalprum/react-core';
import { getOperatingSystems } from '../../Utilities/api';
const useOsVersionFilter = (currentFilter = '', apply) => {
- const versions = useSelector(({ entities }) => entities?.operatingSystems);
- const versionsLoaded = useSelector(({ entities }) => entities?.operatingSystemsLoaded);
+ const versions = useSelector(({ entities }) => entities?.operatingSystems);
+ const versionsLoaded = useSelector(({ entities }) => entities?.operatingSystemsLoaded);
- const [operatingSystems, setOperatingSystems] = useState([]);
- const [{ toGroupSelectionValue, buildOSFilterConfig } = {}] = useLoadModule(
- {
- appName: 'inventory',
- scope: 'inventory',
- module: './OsFilterHelpers'
- }
- );
+ const [operatingSystems, setOperatingSystems] = useState([]);
+ const [{ toGroupSelectionValue, buildOSFilterConfig } = {}] = useLoadModule({
+ appName: 'inventory',
+ scope: 'inventory',
+ module: './OsFilterHelpers',
+ });
- useEffect(() => {
- if (versions === undefined || versionsLoaded === undefined) {
- /* explicitly request OS versions from API */
- getOperatingSystems().then(({ results }) => {
- setOperatingSystems((results || []).map(entry => {
- const { name, major, minor } = entry.value;
- const versionStringified = `${major}.${minor}`;
- return { label: `${name} ${versionStringified}`, value: `${versionStringified}` };
- }));
- });
- }
- }, []);
+ useEffect(() => {
+ if (versions === undefined || versionsLoaded === undefined) {
+ /* explicitly request OS versions from API */
+ getOperatingSystems().then(({ results }) => {
+ setOperatingSystems(
+ (results || []).map((entry) => {
+ const { name, major, minor } = entry.value;
+ const versionStringified = `${major}.${minor}`;
+ return { label: `${name} ${versionStringified}`, value: `${versionStringified}` };
+ }),
+ );
+ });
+ }
+ }, []);
- useEffect(() => {
- if (versionsLoaded === true) {
- setOperatingSystems(versions);
- }
- }, [versionsLoaded]);
+ useEffect(() => {
+ if (versionsLoaded === true) {
+ setOperatingSystems(versions);
+ }
+ }, [versionsLoaded]);
- const osVersionValue = (currentFilter === '' ? [] : Array.isArray(currentFilter) ? currentFilter : currentFilter.split(','))
+ const osVersionValue = (
+ currentFilter === ''
+ ? []
+ : Array.isArray(currentFilter)
+ ? currentFilter
+ : currentFilter.split(',')
+ )
// patchman uses "RHEL " prefix in values; need to remove
.map((version) => version.substring(5));
- return [
- ...(buildOSFilterConfig
- ? [
- buildOSFilterConfig(
- {
- id: 'rhel_version',
- value: toGroupSelectionValue(osVersionValue),
- onChange: (event, value) => {
- /* `versions` must be of type string, e.g., "8.9,9.0" */
- const versions = Object.values(value)
- .flatMap((versions) => Object.keys(versions))
- .map((version) => `RHEL ${version}`)
- .toString();
- apply({ filter: { os: versions } });
- }
- },
- operatingSystems
- )
- ]
- : [])
- ];
+ return [
+ ...(buildOSFilterConfig
+ ? [
+ buildOSFilterConfig(
+ {
+ id: 'rhel_version',
+ value: toGroupSelectionValue(osVersionValue),
+ onChange: (event, value) => {
+ /* `versions` must be of type string, e.g., "8.9,9.0" */
+ const versions = Object.values(value)
+ .flatMap((versions) => Object.keys(versions))
+ .map((version) => `RHEL ${version}`)
+ .toString();
+ apply({ filter: { os: versions } });
+ },
+ },
+ operatingSystems,
+ ),
+ ]
+ : []),
+ ];
};
export default useOsVersionFilter;
diff --git a/src/PresentationalComponents/Filters/OsVersionFilter.test.js b/src/PresentationalComponents/Filters/OsVersionFilter.test.js
index 7bfc025c5..ed3ff4c3d 100644
--- a/src/PresentationalComponents/Filters/OsVersionFilter.test.js
+++ b/src/PresentationalComponents/Filters/OsVersionFilter.test.js
@@ -4,70 +4,70 @@ import { useSelector } from 'react-redux';
const apply = jest.fn();
const mockEntities = {
- operatingSystems: [
- {
- label: 'RHEL 8.7',
- value: '8.7'
- },
- {
- label: 'RHEL 8.8',
- value: '8.8'
- },
- {
- label: 'RHEL 8.9',
- value: '8.9'
- },
- {
- label: 'RHEL 9.0',
- value: '9.0'
- }
- ],
- operatingSystemsLoaded: true
+ operatingSystems: [
+ {
+ label: 'RHEL 8.7',
+ value: '8.7',
+ },
+ {
+ label: 'RHEL 8.8',
+ value: '8.8',
+ },
+ {
+ label: 'RHEL 8.9',
+ value: '8.9',
+ },
+ {
+ label: 'RHEL 9.0',
+ value: '9.0',
+ },
+ ],
+ operatingSystemsLoaded: true,
};
jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useState: jest.fn().mockReturnValue(['', () => {}]),
- useEffect: jest.fn(),
- useCallback: jest.fn()
+ ...jest.requireActual('react'),
+ useState: jest.fn().mockReturnValue(['', () => {}]),
+ useEffect: jest.fn(),
+ useCallback: jest.fn(),
}));
jest.mock('react-redux', () => ({
- ...jest.requireActual('react-redux'),
- useSelector: jest.fn()
+ ...jest.requireActual('react-redux'),
+ useSelector: jest.fn(),
}));
jest.mock('@scalprum/react-core', () => ({
- useLoadModule: jest.fn().mockImplementation(() => [
- { toGroupSelectionValue: (val) => val, buildOSFilterConfig: (obj) => obj }
- ])
+ useLoadModule: jest
+ .fn()
+ .mockImplementation(() => [
+ { toGroupSelectionValue: (val) => val, buildOSFilterConfig: (obj) => obj },
+ ]),
}));
beforeEach(() => {
- useSelector.mockImplementation(callback => {
- return callback({ entities: mockEntities });
- });
+ useSelector.mockImplementation((callback) => callback({ entities: mockEntities }));
});
describe('OsVersionFilter', () => {
- it('has nothing selected', () => {
- const response = osVersionFilter('', apply);
- expect(response[0].value).toEqual([]);
- });
- it('has one selected as a string', () => {
- const response = osVersionFilter('RHEL 9.0', apply);
- expect(response[0].value).toEqual(['9.0']);
- });
- it('has two selected as a string', () => {
- const response = osVersionFilter('RHEL 8.9, RHEL 9.0', apply);
- expect(response[0].value).toEqual(['8.9', ' 9.0']);
- });
- it('has one selected as an array', () => {
- const response = osVersionFilter(['RHEL 8.7'], apply);
- expect(response[0].value).toEqual(['8.7']);
- });
- it('has one selected as an array', () => {
- const response = osVersionFilter(['RHEL 8.8', 'RHEL 8.9'], apply);
- expect(response[0].value).toEqual(['8.8', '8.9']);
- });
+ it('has nothing selected', () => {
+ const response = osVersionFilter('', apply);
+ expect(response[0].value).toEqual([]);
+ });
+ it('has one selected as a string', () => {
+ const response = osVersionFilter('RHEL 9.0', apply);
+ expect(response[0].value).toEqual(['9.0']);
+ });
+ it('has two selected as a string', () => {
+ const response = osVersionFilter('RHEL 8.9, RHEL 9.0', apply);
+ expect(response[0].value).toEqual(['8.9', ' 9.0']);
+ });
+ it('has one selected as an array', () => {
+ const response = osVersionFilter(['RHEL 8.7'], apply);
+ expect(response[0].value).toEqual(['8.7']);
+ });
+ it('has one selected as an array', () => {
+ const response = osVersionFilter(['RHEL 8.8', 'RHEL 8.9'], apply);
+ expect(response[0].value).toEqual(['8.8', '8.9']);
+ });
});
diff --git a/src/PresentationalComponents/Filters/PackagesListStatusFilter.js b/src/PresentationalComponents/Filters/PackagesListStatusFilter.js
index 2d501c87f..8f808bca0 100644
--- a/src/PresentationalComponents/Filters/PackagesListStatusFilter.js
+++ b/src/PresentationalComponents/Filters/PackagesListStatusFilter.js
@@ -4,25 +4,24 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const packagesListStatusFilter = (apply, currentFilter = {}) => {
+ let { systems_applicable: currentValue } = currentFilter;
- let { systems_applicable: currentValue } = currentFilter;
+ const filterByType = (value) => {
+ apply({ filter: { systems_applicable: value } });
+ };
- const filterByType = value => {
- apply({ filter: { systems_applicable: value } });
- };
-
- return {
- label: intl.formatMessage(messages.labelsFiltersUpdatable),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterByType(value);
- },
- items: packagesListUpdatableTypes,
- value: currentValue,
- placeholder: intl.formatMessage(messages.labelsFiltersUpdatablePlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersUpdatable),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByType(value);
+ },
+ items: packagesListUpdatableTypes,
+ value: currentValue,
+ placeholder: intl.formatMessage(messages.labelsFiltersUpdatablePlaceholder),
+ },
+ };
};
export default packagesListStatusFilter;
diff --git a/src/PresentationalComponents/Filters/PackagesListStatusFilter.test.js b/src/PresentationalComponents/Filters/PackagesListStatusFilter.test.js
index 0ede61267..fc7b36442 100644
--- a/src/PresentationalComponents/Filters/PackagesListStatusFilter.test.js
+++ b/src/PresentationalComponents/Filters/PackagesListStatusFilter.test.js
@@ -4,23 +4,22 @@ const apply = jest.fn();
const currentFilter = { systems_applicable: 'filter' };
describe('PackageListStatusFilter', () => {
- it('Should set currentValue to zero and init', () => {
- const response = packageListStatusFilter(apply, currentFilter);
- expect(response.filterValues.value).toEqual('filter');
- expect(response.label).toEqual('Patch status');
- expect(response.type).toEqual('checkbox');
- });
+ it('Should set currentValue to zero and init', () => {
+ const response = packageListStatusFilter(apply, currentFilter);
+ expect(response.filterValues.value).toEqual('filter');
+ expect(response.label).toEqual('Patch status');
+ expect(response.type).toEqual('checkbox');
+ });
- it('Should call apply with a date', () => {
- const response = packageListStatusFilter(apply, currentFilter);
- response.filterValues.onChange('event', 'testValue');
- expect(apply).toHaveBeenCalledWith({ filter: { systems_applicable: 'testValue' } });
- });
+ it('Should call apply with a date', () => {
+ const response = packageListStatusFilter(apply, currentFilter);
+ response.filterValues.onChange('event', 'testValue');
+ expect(apply).toHaveBeenCalledWith({ filter: { systems_applicable: 'testValue' } });
+ });
- it('Should call apply with empty string ', () => {
- const response = packageListStatusFilter(apply);
- response.filterValues.onChange();
- expect(apply).toHaveBeenCalledWith({ filter: { systems_applicable: 'testValue' } });
- });
+ it('Should call apply with empty string ', () => {
+ const response = packageListStatusFilter(apply);
+ response.filterValues.onChange();
+ expect(apply).toHaveBeenCalledWith({ filter: { systems_applicable: 'testValue' } });
+ });
});
-
diff --git a/src/PresentationalComponents/Filters/PublishDateFilter.js b/src/PresentationalComponents/Filters/PublishDateFilter.js
index ea04e91a5..060bf1670 100644
--- a/src/PresentationalComponents/Filters/PublishDateFilter.js
+++ b/src/PresentationalComponents/Filters/PublishDateFilter.js
@@ -4,24 +4,24 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const publishDateFilter = (apply, currentFilter = {}) => {
- let { public_date: currentValue } = currentFilter;
+ let { public_date: currentValue } = currentFilter;
- const filterByPublicDate = value => {
- apply({ filter: { public_date: value === 'all' ? '' : value } });
- };
+ const filterByPublicDate = (value) => {
+ apply({ filter: { public_date: value === 'all' ? '' : value } });
+ };
- return {
- label: intl.formatMessage(messages.labelsFiltersPublishDate),
- type: conditionalFilterType.singleSelect,
- filterValues: {
- onChange: (event, value) => {
- filterByPublicDate(value);
- },
- items: publicDateOptions,
- value: currentValue ?? 'all',
- placeholder: intl.formatMessage(messages.labelsFiltersPublishDatePlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersPublishDate),
+ type: conditionalFilterType.singleSelect,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByPublicDate(value);
+ },
+ items: publicDateOptions,
+ value: currentValue ?? 'all',
+ placeholder: intl.formatMessage(messages.labelsFiltersPublishDatePlaceholder),
+ },
+ };
};
export default publishDateFilter;
diff --git a/src/PresentationalComponents/Filters/PublishDateFilter.test.js b/src/PresentationalComponents/Filters/PublishDateFilter.test.js
index feb180802..6913bab71 100644
--- a/src/PresentationalComponents/Filters/PublishDateFilter.test.js
+++ b/src/PresentationalComponents/Filters/PublishDateFilter.test.js
@@ -1,26 +1,25 @@
import publishDateFilter from './PublishDateFilter';
-/* eslint-disable */
+
const apply = jest.fn();
const currentFilter = { public_date: 'filter' };
describe('PublishDateFilter', () => {
- it('Should set currentValue to "all" by default', () => {
- const response = publishDateFilter(apply);
- expect(response.filterValues.value).toEqual('all');
- expect(response.label).toEqual('Publish date');
- expect(response.type).toEqual('singleSelect');
- });
+ it('Should set currentValue to "all" by default', () => {
+ const response = publishDateFilter(apply);
+ expect(response.filterValues.value).toEqual('all');
+ expect(response.label).toEqual('Publish date');
+ expect(response.type).toEqual('singleSelect');
+ });
- it('Should call apply with a date', () => {
- const response = publishDateFilter(apply, currentFilter);
- response.filterValues.onChange('event', 'testValue');
- expect(apply).toHaveBeenCalledWith({ filter: { public_date: 'testValue' } });
- });
+ it('Should call apply with a date', () => {
+ const response = publishDateFilter(apply, currentFilter);
+ response.filterValues.onChange('event', 'testValue');
+ expect(apply).toHaveBeenCalledWith({ filter: { public_date: 'testValue' } });
+ });
- it('Should call apply with undefined', () => {
- const response = publishDateFilter(apply);
- response.filterValues.onChange();
- expect(apply).toHaveBeenCalledWith({ filter: { public_date: undefined } });
- });
+ it('Should call apply with undefined', () => {
+ const response = publishDateFilter(apply);
+ response.filterValues.onChange();
+ expect(apply).toHaveBeenCalledWith({ filter: { public_date: undefined } });
+ });
});
-/* eslint-enable */
diff --git a/src/PresentationalComponents/Filters/RebootFilter.js b/src/PresentationalComponents/Filters/RebootFilter.js
index d8b2d097e..1774a0543 100644
--- a/src/PresentationalComponents/Filters/RebootFilter.js
+++ b/src/PresentationalComponents/Filters/RebootFilter.js
@@ -5,42 +5,39 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const rebootFilter = (apply, currentFilter = {}) => {
- let { reboot_required: currentValue } = currentFilter;
+ let { reboot_required: currentValue } = currentFilter;
- const rebootMap = React.useMemo(
- () =>
- rebootRequired.map(({ value, label }) => ({
- label,
- value: value.toString()
- })),
- []
- );
+ const rebootMap = React.useMemo(
+ () =>
+ rebootRequired.map(({ value, label }) => ({
+ label,
+ value: value.toString(),
+ })),
+ [],
+ );
- const currentValueStringType = (
- currentValue
- && (
- Array.isArray(currentValue)
- && currentValue.map(value => value.toString())
- || [currentValue.toString()]
- )
- );
+ const currentValueStringType =
+ currentValue &&
+ ((Array.isArray(currentValue) && currentValue.map((value) => value.toString())) || [
+ currentValue.toString(),
+ ]);
- const filterByReboot = value => {
- apply({ filter: { reboot_required: value } });
- };
+ const filterByReboot = (value) => {
+ apply({ filter: { reboot_required: value } });
+ };
- return {
- label: intl.formatMessage(messages.labelsFiltersReboot),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterByReboot(value);
- },
- items: rebootMap,
- value: currentValueStringType,
- placeholder: intl.formatMessage(messages.labelsFiltersRebootPlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersReboot),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByReboot(value);
+ },
+ items: rebootMap,
+ value: currentValueStringType,
+ placeholder: intl.formatMessage(messages.labelsFiltersRebootPlaceholder),
+ },
+ };
};
export default rebootFilter;
diff --git a/src/PresentationalComponents/Filters/SearchFilter.js b/src/PresentationalComponents/Filters/SearchFilter.js
index c767b78c7..2a2d4e375 100644
--- a/src/PresentationalComponents/Filters/SearchFilter.js
+++ b/src/PresentationalComponents/Filters/SearchFilter.js
@@ -3,27 +3,27 @@ import debounce from 'lodash/debounce';
import { useState, useEffect, useCallback } from 'react';
const searchFilter = (apply, search, title, placeholder) => {
- const [searchValue, setSearchValue] = useState(search);
- const debouncedRequest = useCallback(
- debounce(value => apply({ search: value }), 400),
- []
- );
+ const [searchValue, setSearchValue] = useState(search);
+ const debouncedRequest = useCallback(
+ debounce((value) => apply({ search: value }), 400),
+ [],
+ );
- useEffect(() => setSearchValue(search), [search]);
+ useEffect(() => setSearchValue(search), [search]);
- return {
- type: conditionalFilterType.text,
- label: title,
- filterValues: {
- 'aria-label': 'search-field',
- onChange: (event, value) => {
- setSearchValue(value);
- debouncedRequest(value);
- },
- placeholder,
- value: searchValue
- }
- };
+ return {
+ type: conditionalFilterType.text,
+ label: title,
+ filterValues: {
+ 'aria-label': 'search-field',
+ onChange: (event, value) => {
+ setSearchValue(value);
+ debouncedRequest(value);
+ },
+ placeholder,
+ value: searchValue,
+ },
+ };
};
export default searchFilter;
diff --git a/src/PresentationalComponents/Filters/SearchFilter.test.js b/src/PresentationalComponents/Filters/SearchFilter.test.js
index 331c46b0e..0ab303f83 100644
--- a/src/PresentationalComponents/Filters/SearchFilter.test.js
+++ b/src/PresentationalComponents/Filters/SearchFilter.test.js
@@ -6,28 +6,28 @@ const mockSetState = jest.fn();
const currentFilter = { search: 'filter' };
jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useState: jest.fn().mockReturnValueOnce(['testSearch', () => {}]),
- useEffect: jest.fn(),
- useCallback: jest.fn()
+ ...jest.requireActual('react'),
+ useState: jest.fn().mockReturnValueOnce(['testSearch', () => {}]),
+ useEffect: jest.fn(),
+ useCallback: jest.fn(),
}));
describe('SearchFilter', () => {
- it('Should set currentValue to zero and init', () => {
- const response = searchFilter(apply, currentFilter, 'title', 'placeholder');
- expect(response.filterValues.value).toEqual('testSearch');
- expect(response.filterValues.placeholder).toEqual('placeholder');
- expect(response.label).toEqual('title');
- expect(response.type).toEqual('text');
- });
+ it('Should set currentValue to zero and init', () => {
+ const response = searchFilter(apply, currentFilter, 'title', 'placeholder');
+ expect(response.filterValues.value).toEqual('testSearch');
+ expect(response.filterValues.placeholder).toEqual('placeholder');
+ expect(response.label).toEqual('title');
+ expect(response.type).toEqual('text');
+ });
- it('Should call apply with a date', () => {
- useCallback.mockReturnValue(() => apply('testValue'));
- useState.mockClear().mockReturnValue([null, mockSetState]);
+ it('Should call apply with a date', () => {
+ useCallback.mockReturnValue(() => apply('testValue'));
+ useState.mockClear().mockReturnValue([null, mockSetState]);
- const response = searchFilter(apply, currentFilter, 'title', 'placeholder');
- response.filterValues.onChange('event', 'testValue');
- expect(mockSetState).toHaveBeenCalledWith('testValue');
- expect(apply).toHaveBeenCalledWith('testValue');
- });
+ const response = searchFilter(apply, currentFilter, 'title', 'placeholder');
+ response.filterValues.onChange('event', 'testValue');
+ expect(mockSetState).toHaveBeenCalledWith('testValue');
+ expect(apply).toHaveBeenCalledWith('testValue');
+ });
});
diff --git a/src/PresentationalComponents/Filters/SeverityFilter.js b/src/PresentationalComponents/Filters/SeverityFilter.js
index 8858b9805..15d855dfa 100644
--- a/src/PresentationalComponents/Filters/SeverityFilter.js
+++ b/src/PresentationalComponents/Filters/SeverityFilter.js
@@ -9,67 +9,65 @@ import { conditionalFilterType } from '@redhat-cloud-services/frontend-component
// `[null]` to bare `null` before dispatching so the API stays on the supported code path
const severityFilter = (apply, currentFilter = {}) => {
- const advisorySeverityMap = React.useMemo(
- () =>
- advisorySeverities.map(({ value, label }) => ({
- label,
- value: String(value)
- })),
- []
- );
+ const advisorySeverityMap = React.useMemo(
+ () =>
+ advisorySeverities.map(({ value, label }) => ({
+ label,
+ value: String(value),
+ })),
+ [],
+ );
- const currentSeverityValue = (() => {
- const { severity } = currentFilter ?? {};
+ const currentSeverityValue = (() => {
+ const { severity } = currentFilter ?? {};
- if (severity === undefined) {
- return undefined;
- }
+ if (severity === undefined) {
+ return undefined;
+ }
- // Treat "None" as an array too (for consistency in the UI), even though the API requires it to be `null`
- if (severity === null) {
- return ['null'];
- }
+ // Treat "None" as an array too (for consistency in the UI), even though the API requires it to be `null`
+ if (severity === null) {
+ return ['null'];
+ }
- const severityArray = Array.isArray(severity) ? severity : [severity];
+ const severityArray = Array.isArray(severity) ? severity : [severity];
- return severityArray.map((value) => String(value));
- })();
+ return severityArray.map((value) => String(value));
+ })();
- const filterBySeverity = (severityStrings = []) => {
- if (severityStrings.length === 0) {
- apply({ filter: { severity: undefined } });
- return;
- }
+ const filterBySeverity = (severityStrings = []) => {
+ if (severityStrings.length === 0) {
+ apply({ filter: { severity: undefined } });
+ return;
+ }
- // Convert each string into its respective raw value before passing it to the API
- // The engine expects a scalar `null` for the "None" case and integer arrays for actual severities
- const mappedSeverities = severityStrings.map((item) =>
- item === 'null' ? null : parseInt(item, 10)
- );
+ // Convert each string into its respective raw value before passing it to the API
+ // The engine expects a scalar `null` for the "None" case and integer arrays for actual severities
+ const mappedSeverities = severityStrings.map((item) =>
+ item === 'null' ? null : parseInt(item, 10),
+ );
- // Send a bare `null` so we use the API's `IS NULL` path instead of an unsupported `IN (NULL)` clause
- if (mappedSeverities.length === 1 && mappedSeverities[0] === null) {
- apply({ filter: { severity: null } });
- return;
- }
+ // Send a bare `null` so we use the API's `IS NULL` path instead of an unsupported `IN (NULL)` clause
+ if (mappedSeverities.length === 1 && mappedSeverities[0] === null) {
+ apply({ filter: { severity: null } });
+ return;
+ }
- apply({ filter: { severity: mappedSeverities } });
- };
+ apply({ filter: { severity: mappedSeverities } });
+ };
- return {
- label: intl.formatMessage(messages.labelsFiltersSeverity),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterBySeverity(value);
- },
- items: advisorySeverityMap,
- value: currentSeverityValue,
- placeholder: intl.formatMessage(
- messages.labelsFiltersSeverityPlaceholder
- )
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersSeverity),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterBySeverity(value);
+ },
+ items: advisorySeverityMap,
+ value: currentSeverityValue,
+ placeholder: intl.formatMessage(messages.labelsFiltersSeverityPlaceholder),
+ },
+ };
};
export default severityFilter;
diff --git a/src/PresentationalComponents/Filters/SeverityFilter.test.js b/src/PresentationalComponents/Filters/SeverityFilter.test.js
index 7341599b9..67acfa3e8 100644
--- a/src/PresentationalComponents/Filters/SeverityFilter.test.js
+++ b/src/PresentationalComponents/Filters/SeverityFilter.test.js
@@ -1,8 +1,8 @@
import severityFilter from './SeverityFilter';
jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useMemo: jest.fn((callback) => callback())
+ ...jest.requireActual('react'),
+ useMemo: jest.fn((callback) => callback()),
}));
const currentFilterInteger = { severity: [2] };
@@ -11,52 +11,52 @@ const currentFilterEmpty = { severity: [] };
let apply;
const renderFilter = (filter = {}) => severityFilter(apply, filter);
const rehydrateFilter = (value) =>
- severityFilter(apply, value === undefined ? {} : { severity: value });
+ severityFilter(apply, value === undefined ? {} : { severity: value });
describe('SeverityFilter', () => {
- beforeEach(() => {
- apply = jest.fn();
- });
-
- it('returns checkbox metadata seeded from existing severities', () => {
- const response = renderFilter(currentFilterInteger);
- expect(response.filterValues.value).toEqual(['2']);
- expect(response.label).toEqual('Severity');
- expect(response.type).toEqual('checkbox');
- });
-
- it('converts selected integer severities into raw values before dispatch', () => {
- const response = renderFilter(currentFilterInteger);
- response.filterValues.onChange('event', ['2']);
- expect(apply).toHaveBeenCalledWith({ filter: { severity: [2] } });
- // Rehydrate with the store snapshot that would come back after dispatching `[2]`
- const rehydratedResponse = rehydrateFilter([2]);
- // ConditionalFilter checkboxes compare option ids as strings
- expect(rehydratedResponse.filterValues.value).toEqual(['2']);
- });
-
- it('converts the "None" selection into a null severity', () => {
- const response = renderFilter(currentFilterEmpty);
- response.filterValues.onChange('event', ['null']);
- expect(apply).toHaveBeenCalledWith({ filter: { severity: null } });
- // Rehydrate with the store snapshot that would come back after dispatching `null`
- const rehydratedResponse = rehydrateFilter(null);
- expect(rehydratedResponse.filterValues.value).toEqual(['null']);
- });
-
- it('dispatches undefined severity when onChange receives no payload', () => {
- const response = renderFilter(currentFilterEmpty);
- response.filterValues.onChange();
- expect(apply).toHaveBeenCalledWith({ filter: { severity: undefined } });
- const rehydratedResponse = rehydrateFilter(undefined);
- expect(rehydratedResponse.filterValues.value).toBeUndefined();
- });
-
- it('dispatches undefined severity when the selection is cleared explicitly', () => {
- const response = renderFilter(currentFilterEmpty);
- response.filterValues.onChange('event', []); // Clear the filter
- expect(apply).toHaveBeenCalledWith({ filter: { severity: undefined } });
- const rehydratedResponse = rehydrateFilter(undefined);
- expect(rehydratedResponse.filterValues.value).toBeUndefined();
- });
+ beforeEach(() => {
+ apply = jest.fn();
+ });
+
+ it('returns checkbox metadata seeded from existing severities', () => {
+ const response = renderFilter(currentFilterInteger);
+ expect(response.filterValues.value).toEqual(['2']);
+ expect(response.label).toEqual('Severity');
+ expect(response.type).toEqual('checkbox');
+ });
+
+ it('converts selected integer severities into raw values before dispatch', () => {
+ const response = renderFilter(currentFilterInteger);
+ response.filterValues.onChange('event', ['2']);
+ expect(apply).toHaveBeenCalledWith({ filter: { severity: [2] } });
+ // Rehydrate with the store snapshot that would come back after dispatching `[2]`
+ const rehydratedResponse = rehydrateFilter([2]);
+ // ConditionalFilter checkboxes compare option ids as strings
+ expect(rehydratedResponse.filterValues.value).toEqual(['2']);
+ });
+
+ it('converts the "None" selection into a null severity', () => {
+ const response = renderFilter(currentFilterEmpty);
+ response.filterValues.onChange('event', ['null']);
+ expect(apply).toHaveBeenCalledWith({ filter: { severity: null } });
+ // Rehydrate with the store snapshot that would come back after dispatching `null`
+ const rehydratedResponse = rehydrateFilter(null);
+ expect(rehydratedResponse.filterValues.value).toEqual(['null']);
+ });
+
+ it('dispatches undefined severity when onChange receives no payload', () => {
+ const response = renderFilter(currentFilterEmpty);
+ response.filterValues.onChange();
+ expect(apply).toHaveBeenCalledWith({ filter: { severity: undefined } });
+ const rehydratedResponse = rehydrateFilter(undefined);
+ expect(rehydratedResponse.filterValues.value).toBeUndefined();
+ });
+
+ it('dispatches undefined severity when the selection is cleared explicitly', () => {
+ const response = renderFilter(currentFilterEmpty);
+ response.filterValues.onChange('event', []); // Clear the filter
+ expect(apply).toHaveBeenCalledWith({ filter: { severity: undefined } });
+ const rehydratedResponse = rehydrateFilter(undefined);
+ expect(rehydratedResponse.filterValues.value).toBeUndefined();
+ });
});
diff --git a/src/PresentationalComponents/Filters/StatusFilter.js b/src/PresentationalComponents/Filters/StatusFilter.js
index 705977948..779839778 100644
--- a/src/PresentationalComponents/Filters/StatusFilter.js
+++ b/src/PresentationalComponents/Filters/StatusFilter.js
@@ -5,33 +5,32 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const statusFilter = (apply, currentFilter = {}) => {
+ let { update_status: currentValue } = currentFilter;
- let { update_status: currentValue } = currentFilter;
+ const updatableTypesMap = React.useMemo(
+ () =>
+ updatableTypes.map(({ value, label }) => ({
+ label,
+ value: value.toString(),
+ })),
+ [],
+ );
+ const filterByType = (value) => {
+ apply({ filter: { update_status: value } });
+ };
- const updatableTypesMap = React.useMemo(
- () =>
- updatableTypes.map(({ value, label }) => ({
- label,
- value: value.toString()
- })),
- []
- );
- const filterByType = value => {
- apply({ filter: { update_status: value } });
- };
-
- return {
- label: intl.formatMessage(messages.labelsFiltersStatus),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterByType(value);
- },
- items: updatableTypesMap,
- value: currentValue,
- placeholder: intl.formatMessage(messages.labelsColumnsStatusPlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersStatus),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByType(value);
+ },
+ items: updatableTypesMap,
+ value: currentValue,
+ placeholder: intl.formatMessage(messages.labelsColumnsStatusPlaceholder),
+ },
+ };
};
export default statusFilter;
diff --git a/src/PresentationalComponents/Filters/StatusFilter.test.js b/src/PresentationalComponents/Filters/StatusFilter.test.js
index 374cbf7f8..dca169a86 100644
--- a/src/PresentationalComponents/Filters/StatusFilter.test.js
+++ b/src/PresentationalComponents/Filters/StatusFilter.test.js
@@ -4,27 +4,27 @@ const apply = jest.fn();
const currentFilter = { update_status: 'filter' };
jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useMemo: jest.fn(callback => callback())
+ ...jest.requireActual('react'),
+ useMemo: jest.fn((callback) => callback()),
}));
describe('StatusFilter', () => {
- it('Should set currentValue to zero and init', () => {
- const response = statusFilter(apply, currentFilter);
- expect(response.filterValues.value).toEqual('filter');
- expect(response.label).toEqual('Status');
- expect(response.type).toEqual('checkbox');
- });
+ it('Should set currentValue to zero and init', () => {
+ const response = statusFilter(apply, currentFilter);
+ expect(response.filterValues.value).toEqual('filter');
+ expect(response.label).toEqual('Status');
+ expect(response.type).toEqual('checkbox');
+ });
- it('Should call apply with a date', () => {
- const response = statusFilter(apply, currentFilter);
- response.filterValues.onChange('event', 'testValue');
- expect(apply).toHaveBeenCalledWith({ filter: { update_status: 'testValue' } });
- });
+ it('Should call apply with a date', () => {
+ const response = statusFilter(apply, currentFilter);
+ response.filterValues.onChange('event', 'testValue');
+ expect(apply).toHaveBeenCalledWith({ filter: { update_status: 'testValue' } });
+ });
- it('Should call apply with empty string ', () => {
- const response = statusFilter(apply);
- response.filterValues.onChange();
- expect(apply).toHaveBeenCalledWith({ filter: { update_status: 'testValue' } });
- });
+ it('Should call apply with empty string ', () => {
+ const response = statusFilter(apply);
+ response.filterValues.onChange();
+ expect(apply).toHaveBeenCalledWith({ filter: { update_status: 'testValue' } });
+ });
});
diff --git a/src/PresentationalComponents/Filters/SystemStaleFilter.js b/src/PresentationalComponents/Filters/SystemStaleFilter.js
index c10f0698b..9a89ebee3 100644
--- a/src/PresentationalComponents/Filters/SystemStaleFilter.js
+++ b/src/PresentationalComponents/Filters/SystemStaleFilter.js
@@ -5,43 +5,39 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const systemsStaleFilter = (apply, currentFilter = {}) => {
+ let { stale: currentValue } = currentFilter;
- let { stale: currentValue } = currentFilter;
+ const staleMap = React.useMemo(
+ () =>
+ staleSystems.map(({ value, label }) => ({
+ label,
+ value: value.toString(),
+ })),
+ [],
+ );
- const staleMap = React.useMemo(
- () =>
- staleSystems.map(({ value, label }) => ({
- label,
- value: value.toString()
- })),
- []
- );
+ const currentValueStringType =
+ currentValue &&
+ ((Array.isArray(currentValue) && currentValue.map((value) => value.toString())) || [
+ currentValue.toString(),
+ ]);
- const currentValueStringType = (
- currentValue
- && (
- Array.isArray(currentValue)
- && currentValue.map(value => value.toString())
- || [currentValue.toString()]
- )
- );
+ const filterByStale = (value) => {
+ apply({ filter: { stale: value } });
+ };
- const filterByStale = value => {
- apply({ filter: { stale: value } });
- };
-
- return {
- label: intl.formatMessage(messages.labelsFiltersStale),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterByStale(value);
- },
- items: staleMap,
- value: currentValueStringType,
- placeholder: intl.formatMessage(messages.labelsFiltersStalePlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersStale),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByStale(value);
+ },
+ items: staleMap,
+ value: currentValueStringType,
+ placeholder: intl.formatMessage(messages.labelsFiltersStalePlaceholder),
+ },
+ };
};
export default systemsStaleFilter;
diff --git a/src/PresentationalComponents/Filters/SystemStaleFilter.test.js b/src/PresentationalComponents/Filters/SystemStaleFilter.test.js
index 7be1e6fb6..b2f3717d7 100644
--- a/src/PresentationalComponents/Filters/SystemStaleFilter.test.js
+++ b/src/PresentationalComponents/Filters/SystemStaleFilter.test.js
@@ -1,31 +1,30 @@
import systemStaleFilter from './SystemStaleFilter';
jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useMemo: jest.fn(callback => callback())
+ ...jest.requireActual('react'),
+ useMemo: jest.fn((callback) => callback()),
}));
const apply = jest.fn();
const currentFilter = { stale: 'filter' };
describe('SystemStaleFilter', () => {
- it('Should set currentValue to zero and init', () => {
- const response = systemStaleFilter(apply, currentFilter);
- expect(response.filterValues.value).toEqual(['filter']);
- expect(response.label).toEqual('Status');
- expect(response.type).toEqual('checkbox');
- });
+ it('Should set currentValue to zero and init', () => {
+ const response = systemStaleFilter(apply, currentFilter);
+ expect(response.filterValues.value).toEqual(['filter']);
+ expect(response.label).toEqual('Status');
+ expect(response.type).toEqual('checkbox');
+ });
- it('Should call apply with a test value', () => {
- const response = systemStaleFilter(apply, currentFilter);
- response.filterValues.onChange('event', 'testValue');
- expect(apply).toHaveBeenCalledWith({ filter: { stale: 'testValue' } });
- });
+ it('Should call apply with a test value', () => {
+ const response = systemStaleFilter(apply, currentFilter);
+ response.filterValues.onChange('event', 'testValue');
+ expect(apply).toHaveBeenCalledWith({ filter: { stale: 'testValue' } });
+ });
- it('Should call apply with empty string ', () => {
- const response = systemStaleFilter(apply);
- response.filterValues.onChange();
- expect(apply).toHaveBeenCalledWith({ filter: { stale: 'testValue' } });
- });
+ it('Should call apply with empty string ', () => {
+ const response = systemStaleFilter(apply);
+ response.filterValues.onChange();
+ expect(apply).toHaveBeenCalledWith({ filter: { stale: 'testValue' } });
+ });
});
-
diff --git a/src/PresentationalComponents/Filters/SystemsUpdatableFilter.js b/src/PresentationalComponents/Filters/SystemsUpdatableFilter.js
index 95aacb6d8..2a5870db5 100644
--- a/src/PresentationalComponents/Filters/SystemsUpdatableFilter.js
+++ b/src/PresentationalComponents/Filters/SystemsUpdatableFilter.js
@@ -1,28 +1,27 @@
-
import { conditionalFilterType } from '@redhat-cloud-services/frontend-components/ConditionalFilter';
import { packagesListUpdatableTypes } from '../../Utilities/constants';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const systemsUpdatableFilter = (apply, currentFilter = {}) => {
- let { packages_updatable: currentValue } = currentFilter;
+ let { packages_updatable: currentValue } = currentFilter;
- const filterByUpdatableSystems = value => {
- apply({ filter: { packages_updatable: value } });
- };
+ const filterByUpdatableSystems = (value) => {
+ apply({ filter: { packages_updatable: value } });
+ };
- return {
- label: intl.formatMessage(messages.labelsFiltersUpdatable),
- type: conditionalFilterType.singleSelect,
- filterValues: {
- onChange: (event, value) => {
- filterByUpdatableSystems(value);
- },
- items: packagesListUpdatableTypes,
- value: currentValue,
- placeholder: intl.formatMessage(messages.labelsFiltersUpdatablePlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersUpdatable),
+ type: conditionalFilterType.singleSelect,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByUpdatableSystems(value);
+ },
+ items: packagesListUpdatableTypes,
+ value: currentValue,
+ placeholder: intl.formatMessage(messages.labelsFiltersUpdatablePlaceholder),
+ },
+ };
};
export default systemsUpdatableFilter;
diff --git a/src/PresentationalComponents/Filters/SystemsUpdatableFilter.test.js b/src/PresentationalComponents/Filters/SystemsUpdatableFilter.test.js
index abbce70cd..3f39a74de 100644
--- a/src/PresentationalComponents/Filters/SystemsUpdatableFilter.test.js
+++ b/src/PresentationalComponents/Filters/SystemsUpdatableFilter.test.js
@@ -4,23 +4,22 @@ const apply = jest.fn();
const currentFilter = { packages_updatable: 'filter' };
describe('SystemsUpdatableFilter', () => {
- it('Should set currentValue to zero and init', () => {
- const response = systemsUpdatableFilter(apply, currentFilter);
- expect(response.filterValues.value).toEqual('filter');
- expect(response.label).toEqual('Patch status');
- expect(response.type).toEqual('singleSelect');
- });
+ it('Should set currentValue to zero and init', () => {
+ const response = systemsUpdatableFilter(apply, currentFilter);
+ expect(response.filterValues.value).toEqual('filter');
+ expect(response.label).toEqual('Patch status');
+ expect(response.type).toEqual('singleSelect');
+ });
- it('Should call apply with a test value', () => {
- const response = systemsUpdatableFilter(apply, currentFilter);
- response.filterValues.onChange('event', 'testValue');
- expect(apply).toHaveBeenCalledWith({ filter: { packages_updatable: 'testValue' } });
- });
+ it('Should call apply with a test value', () => {
+ const response = systemsUpdatableFilter(apply, currentFilter);
+ response.filterValues.onChange('event', 'testValue');
+ expect(apply).toHaveBeenCalledWith({ filter: { packages_updatable: 'testValue' } });
+ });
- it('Should call apply with empty string ', () => {
- const response = systemsUpdatableFilter(apply);
- response.filterValues.onChange();
- expect(apply).toHaveBeenCalledWith({ filter: { packages_updatable: 'testValue' } });
- });
+ it('Should call apply with empty string ', () => {
+ const response = systemsUpdatableFilter(apply);
+ response.filterValues.onChange();
+ expect(apply).toHaveBeenCalledWith({ filter: { packages_updatable: 'testValue' } });
+ });
});
-
diff --git a/src/PresentationalComponents/Filters/TypeFilter.js b/src/PresentationalComponents/Filters/TypeFilter.js
index 42829f36e..1eff0f477 100644
--- a/src/PresentationalComponents/Filters/TypeFilter.js
+++ b/src/PresentationalComponents/Filters/TypeFilter.js
@@ -5,30 +5,30 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const typeFilter = (apply, currentFilter = {}) => {
- const advisoryTypesMap = React.useMemo(
- () =>
- advisoryTypes.map(({ value, label }) => ({
- label,
- value: value.toString()
- })),
- []
- );
- const filterByType = value => {
- apply({ filter: { advisory_type_name: value } });
- };
+ const advisoryTypesMap = React.useMemo(
+ () =>
+ advisoryTypes.map(({ value, label }) => ({
+ label,
+ value: value.toString(),
+ })),
+ [],
+ );
+ const filterByType = (value) => {
+ apply({ filter: { advisory_type_name: value } });
+ };
- return {
- label: intl.formatMessage(messages.labelsFiltersType),
- type: conditionalFilterType.checkbox,
- filterValues: {
- onChange: (event, value) => {
- filterByType(value);
- },
- items: advisoryTypesMap,
- value: currentFilter.advisory_type_name,
- placeholder: intl.formatMessage(messages.labelsFiltersTypePlaceholder)
- }
- };
+ return {
+ label: intl.formatMessage(messages.labelsFiltersType),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ onChange: (event, value) => {
+ filterByType(value);
+ },
+ items: advisoryTypesMap,
+ value: currentFilter.advisory_type_name,
+ placeholder: intl.formatMessage(messages.labelsFiltersTypePlaceholder),
+ },
+ };
};
export default typeFilter;
diff --git a/src/PresentationalComponents/Filters/TypeFilter.test.js b/src/PresentationalComponents/Filters/TypeFilter.test.js
index 73ca811c1..278bb758e 100644
--- a/src/PresentationalComponents/Filters/TypeFilter.test.js
+++ b/src/PresentationalComponents/Filters/TypeFilter.test.js
@@ -1,31 +1,30 @@
import typeFilter from './TypeFilter';
jest.mock('react', () => ({
- ...jest.requireActual('react'),
- useMemo: jest.fn(callback => callback())
+ ...jest.requireActual('react'),
+ useMemo: jest.fn((callback) => callback()),
}));
const apply = jest.fn();
const currentFilter = { advisory_type_name: 'bugfix' };
describe('TypeFilter', () => {
- it('Should set currentValue to zero and init', () => {
- const response = typeFilter(apply, currentFilter);
- expect(response.filterValues.value).toEqual('bugfix');
- expect(response.label).toEqual('Type');
- expect(response.type).toEqual('checkbox');
- });
+ it('Should set currentValue to zero and init', () => {
+ const response = typeFilter(apply, currentFilter);
+ expect(response.filterValues.value).toEqual('bugfix');
+ expect(response.label).toEqual('Type');
+ expect(response.type).toEqual('checkbox');
+ });
- it('Should call apply with a test value', () => {
- const response = typeFilter(apply, currentFilter);
- response.filterValues.onChange('event', 'bugfix');
- expect(apply).toHaveBeenCalledWith({ filter: { advisory_type_name: 'bugfix' } });
- });
+ it('Should call apply with a test value', () => {
+ const response = typeFilter(apply, currentFilter);
+ response.filterValues.onChange('event', 'bugfix');
+ expect(apply).toHaveBeenCalledWith({ filter: { advisory_type_name: 'bugfix' } });
+ });
- it('Should call apply with empty string ', () => {
- const response = typeFilter(apply);
- response.filterValues.onChange();
- expect(apply).toHaveBeenCalledWith({ filter: { advisory_type_name: 'bugfix' } });
- });
+ it('Should call apply with empty string ', () => {
+ const response = typeFilter(apply);
+ response.filterValues.onChange();
+ expect(apply).toHaveBeenCalledWith({ filter: { advisory_type_name: 'bugfix' } });
+ });
});
-
diff --git a/src/PresentationalComponents/Filters/VersionFilter.js b/src/PresentationalComponents/Filters/VersionFilter.js
index 55c022ac8..035645297 100644
--- a/src/PresentationalComponents/Filters/VersionFilter.js
+++ b/src/PresentationalComponents/Filters/VersionFilter.js
@@ -3,35 +3,39 @@ import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
const VersionFilter = (apply, filter = {}, packageVersions) => {
- const current = Array.isArray(filter?.installed_evra)
- ? filter.installed_evra.map(String)
- : (filter.installed_evra ? String(filter.installed_evra).split(',').filter(Boolean) : []);
+ const current = Array.isArray(filter?.installed_evra)
+ ? filter.installed_evra.map(String)
+ : filter.installed_evra
+ ? String(filter.installed_evra).split(',').filter(Boolean)
+ : [];
- const items = packageVersions && packageVersions.data
- ? packageVersions.data.sort().map(version => ({ value: version.evra, label: version.evra }))
- : [
- {
- value: intl.formatMessage(messages.textNoVersionAvailable),
- label: intl.formatMessage(messages.textNoVersionAvailable),
- disabled: true
- }
+ const items =
+ packageVersions && packageVersions.data
+ ? packageVersions.data.sort().map((version) => ({ value: version.evra, label: version.evra }))
+ : [
+ {
+ value: intl.formatMessage(messages.textNoVersionAvailable),
+ label: intl.formatMessage(messages.textNoVersionAvailable),
+ disabled: true,
+ },
];
- return {
- label: intl.formatMessage(messages.labelsFiltersPackageVersionTitle),
- type: conditionalFilterType.checkbox,
- filterValues: {
- items,
- onChange: (_event, value) => {
- const arr = Array.isArray(value) ? value : [value];
- const cleaned = arr.filter((v) => v && v !== intl.formatMessage(messages.textNoVersionAvailable));
- apply({ filter: { installed_evra: cleaned.length ? cleaned.join(',') : undefined } });
- },
- value: current,
- placeholder: intl.formatMessage(messages.labelsFiltersPackageVersionPlaceholder)
- }
- };
-
+ return {
+ label: intl.formatMessage(messages.labelsFiltersPackageVersionTitle),
+ type: conditionalFilterType.checkbox,
+ filterValues: {
+ items,
+ onChange: (_event, value) => {
+ const arr = Array.isArray(value) ? value : [value];
+ const cleaned = arr.filter(
+ (v) => v && v !== intl.formatMessage(messages.textNoVersionAvailable),
+ );
+ apply({ filter: { installed_evra: cleaned.length ? cleaned.join(',') : undefined } });
+ },
+ value: current,
+ placeholder: intl.formatMessage(messages.labelsFiltersPackageVersionPlaceholder),
+ },
+ };
};
export default VersionFilter;
diff --git a/src/PresentationalComponents/Filters/VersionFilter.test.js b/src/PresentationalComponents/Filters/VersionFilter.test.js
index babc23d23..d0da7d97e 100644
--- a/src/PresentationalComponents/Filters/VersionFilter.test.js
+++ b/src/PresentationalComponents/Filters/VersionFilter.test.js
@@ -1,4 +1,3 @@
-/* eslint-disable no-unused-vars */
import versionFilter from './VersionFilter';
import { packageVersions } from '../../Utilities/RawDataForTesting';
import { intl } from '../../Utilities/IntlProvider';
@@ -8,49 +7,57 @@ const apply = jest.fn();
const currentFilter = { installed_evra: undefined };
describe('Version filter', () => {
- it('should initialize the filter', () => {
- const response = versionFilter(apply, currentFilter, packageVersions);
- expect(response.label).toEqual(intl.formatMessage(messages.labelsFiltersPackageVersionTitle));
- expect(response.type).toEqual('checkbox');
- expect(Array.isArray(response.filterValues.items)).toBe(true);
- expect(response.filterValues.value).toEqual([]);
- expect(response.filterValues.items).toHaveLength(packageVersions.data.length);
+ it('should initialize the filter', () => {
+ const response = versionFilter(apply, currentFilter, packageVersions);
+ expect(response.label).toEqual(intl.formatMessage(messages.labelsFiltersPackageVersionTitle));
+ expect(response.type).toEqual('checkbox');
+ expect(Array.isArray(response.filterValues.items)).toBe(true);
+ expect(response.filterValues.value).toEqual([]);
+ expect(response.filterValues.items).toHaveLength(packageVersions.data.length);
+ });
+
+ it('should call apply when selecting a single version', () => {
+ const response = versionFilter(apply, currentFilter, packageVersions);
+ response.filterValues.onChange(null, packageVersions.data[0].evra);
+
+ expect(apply).toHaveBeenCalledWith({
+ filter: { installed_evra: packageVersions.data[0].evra },
});
+ });
- it('should call apply when selecting a single version', () => {
- const response = versionFilter(apply, currentFilter, packageVersions);
- response.filterValues.onChange(null, packageVersions.data[0].evra);
+ it('should call apply when onChange is fired and append previously selected versions into new selection', () => {
+ const existing = 'testVersions';
- expect(apply).toHaveBeenCalledWith({ filter: { installed_evra: packageVersions.data[0].evra } });
- });
-
- it('should call apply when onChange is fired and append previously selected versions into new selection', () => {
- const existing = 'testVersions';
-
- const response = versionFilter(apply, { installed_evra: existing }, packageVersions);
- response.filterValues.onChange(null, [existing, packageVersions.data[0].evra]);
-
- expect(apply).toHaveBeenCalledWith({ filter: { installed_evra: `${existing},${packageVersions.data[0].evra}` } });
- });
-
- it('should send installed_evra: undefined when previously selected version and new version are the same', () => {
- const response = versionFilter(apply, { installed_evra: packageVersions.data[1].evra }, packageVersions);
- response.filterValues.onChange(null, []);
+ const response = versionFilter(apply, { installed_evra: existing }, packageVersions);
+ response.filterValues.onChange(null, [existing, packageVersions.data[0].evra]);
- expect(apply).toHaveBeenCalledWith({ filter: { installed_evra: undefined } });
+ expect(apply).toHaveBeenCalledWith({
+ filter: { installed_evra: `${existing},${packageVersions.data[0].evra}` },
});
-
- it('should call apply when onChange is fired and deselect the version', () => {
- const package1 = packageVersions.data[0].evra;
- const package2 = packageVersions.data[1].evra;
-
- const response = versionFilter(apply,
- { installed_evra: `${package1},${package2}` }, packageVersions);
- response.filterValues.onChange(null, [package1]);
-
- expect(apply).toHaveBeenCalledWith({ filter:
- { installed_evra: package1 }
- });
- });
-
+ });
+
+ it('should send installed_evra: undefined when previously selected version and new version are the same', () => {
+ const response = versionFilter(
+ apply,
+ { installed_evra: packageVersions.data[1].evra },
+ packageVersions,
+ );
+ response.filterValues.onChange(null, []);
+
+ expect(apply).toHaveBeenCalledWith({ filter: { installed_evra: undefined } });
+ });
+
+ it('should call apply when onChange is fired and deselect the version', () => {
+ const package1 = packageVersions.data[0].evra;
+ const package2 = packageVersions.data[1].evra;
+
+ const response = versionFilter(
+ apply,
+ { installed_evra: `${package1},${package2}` },
+ packageVersions,
+ );
+ response.filterValues.onChange(null, [package1]);
+
+ expect(apply).toHaveBeenCalledWith({ filter: { installed_evra: package1 } });
+ });
});
diff --git a/src/PresentationalComponents/Filters/__mocks__/OsVersionFilter.js b/src/PresentationalComponents/Filters/__mocks__/OsVersionFilter.js
index 559c27ecc..d5ee5bab3 100644
--- a/src/PresentationalComponents/Filters/__mocks__/OsVersionFilter.js
+++ b/src/PresentationalComponents/Filters/__mocks__/OsVersionFilter.js
@@ -1,63 +1,63 @@
export default () => [
- {
- label: 'Operating System',
- type: 'group',
- id: 'rhel_version',
- value: 'os-filter',
- placeholder: 'Filter by operating system',
- filterValues: {
- selected: {},
- groups: [
- {
- groupSelectable: true,
- noFilter: true,
- label: 'RHEL 9',
- value: '9.0',
- items: [
- {
- label: 'RHEL 9.0',
- value: '9.0',
- type: 'checkbox'
- }
- ]
- },
- {
- groupSelectable: true,
- noFilter: true,
- label: 'RHEL 8',
- value: '8.0',
- items: [
- {
- label: 'RHEL 8.6',
- value: '8.6',
- type: 'checkbox'
- },
- {
- label: 'RHEL 8.5',
- value: '8.5',
- type: 'checkbox'
- },
- {
- label: 'RHEL 8.0',
- value: '8.0',
- type: 'checkbox'
- }
- ]
- },
- {
- groupSelectable: true,
- noFilter: true,
- label: 'RHEL 6',
- value: '6.0',
- items: [
- {
- label: 'RHEL 6.7',
- value: '6.7',
- type: 'checkbox'
- }
- ]
- }
- ]
- }
- }
+ {
+ label: 'Operating System',
+ type: 'group',
+ id: 'rhel_version',
+ value: 'os-filter',
+ placeholder: 'Filter by operating system',
+ filterValues: {
+ selected: {},
+ groups: [
+ {
+ groupSelectable: true,
+ noFilter: true,
+ label: 'RHEL 9',
+ value: '9.0',
+ items: [
+ {
+ label: 'RHEL 9.0',
+ value: '9.0',
+ type: 'checkbox',
+ },
+ ],
+ },
+ {
+ groupSelectable: true,
+ noFilter: true,
+ label: 'RHEL 8',
+ value: '8.0',
+ items: [
+ {
+ label: 'RHEL 8.6',
+ value: '8.6',
+ type: 'checkbox',
+ },
+ {
+ label: 'RHEL 8.5',
+ value: '8.5',
+ type: 'checkbox',
+ },
+ {
+ label: 'RHEL 8.0',
+ value: '8.0',
+ type: 'checkbox',
+ },
+ ],
+ },
+ {
+ groupSelectable: true,
+ noFilter: true,
+ label: 'RHEL 6',
+ value: '6.0',
+ items: [
+ {
+ label: 'RHEL 6.7',
+ value: '6.7',
+ type: 'checkbox',
+ },
+ ],
+ },
+ ],
+ },
+ },
];
diff --git a/src/PresentationalComponents/Header/Header.js b/src/PresentationalComponents/Header/Header.js
index df12bdca9..f8e06e6ad 100644
--- a/src/PresentationalComponents/Header/Header.js
+++ b/src/PresentationalComponents/Header/Header.js
@@ -1,43 +1,34 @@
import { Split, SplitItem } from '@patternfly/react-core';
-import {
- PageHeader,
- PageHeaderTitle
-} from '@redhat-cloud-services/frontend-components/PageHeader';
+import { PageHeader, PageHeaderTitle } from '@redhat-cloud-services/frontend-components/PageHeader';
import PropTypes from 'prop-types';
import React from 'react';
import HeaderBreadcrumbs from './HeaderBreadcrumbs';
import HeaderTabs from './HeaderTabs';
-const Header = ({ title, showTabs, breadcrumbs, children, headerOUIA, actions }) => {
- return (
-
-
- {breadcrumbs && }
-
-
-
-
-
-
- {actions}
-
-
- {children}
-
- {showTabs && }
-
- );
-};
+const Header = ({ title, showTabs, breadcrumbs, children, headerOUIA, actions }) => (
+
+
+ {breadcrumbs && }
+
+
+
+
+
+ {actions}
+
+ {children}
+
+ {showTabs && }
+
+);
Header.propTypes = {
- title: PropTypes.node,
- showTabs: PropTypes.bool,
- breadcrumbs: PropTypes.array,
- children: PropTypes.any,
- headerOUIA: PropTypes.string,
- actions: PropTypes.node
+ title: PropTypes.node,
+ showTabs: PropTypes.bool,
+ breadcrumbs: PropTypes.array,
+ children: PropTypes.any,
+ headerOUIA: PropTypes.string,
+ actions: PropTypes.node,
};
export default Header;
diff --git a/src/PresentationalComponents/Header/Header.scss b/src/PresentationalComponents/Header/Header.scss
index 0e0f209d7..6547f71d8 100644
--- a/src/PresentationalComponents/Header/Header.scss
+++ b/src/PresentationalComponents/Header/Header.scss
@@ -1,5 +1,5 @@
.pf-v6-c-tabs.patchman-tabs {
- background-color: var(--pf-t--global--background--color--primary--default);
- padding-left: var(--pf-v6-c-page__main-section--md--PaddingLeft);
- display: block;
+ background-color: var(--pf-t--global--background--color--primary--default);
+ padding-left: var(--pf-v6-c-page__main-section--md--PaddingLeft);
+ display: block;
}
diff --git a/src/PresentationalComponents/Header/Header.test.js b/src/PresentationalComponents/Header/Header.test.js
index 4886e4159..8c619a26d 100644
--- a/src/PresentationalComponents/Header/Header.test.js
+++ b/src/PresentationalComponents/Header/Header.test.js
@@ -3,112 +3,109 @@ import Header from './Header';
import { mountWithRouter } from '../../../config/rtlwrapper';
describe('Header component', () => {
- it('should render with header as empty string', () => {
- const header = { title: '' };
- const { asFragment } = mountWithRouter();
- expect(asFragment()).toMatchSnapshot();
- });
+ it('should render with header as empty string', () => {
+ const header = { title: '' };
+ const { asFragment } = mountWithRouter();
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('should render with header Hello world', () => {
- const header = { title: 'Hello world' };
- const { asFragment } = mountWithRouter();
- expect(asFragment()).toMatchSnapshot();
- });
+ it('should render with header Hello world', () => {
+ const header = { title: 'Hello world' };
+ const { asFragment } = mountWithRouter();
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('should render with empty breadcrumb', () => {
- const header = {
- breadcrumbs: [],
- title: ''
- };
- const { asFragment } = mountWithRouter();
- expect(asFragment()).toMatchSnapshot();
- });
+ it('should render with empty breadcrumb', () => {
+ const header = {
+ breadcrumbs: [],
+ title: '',
+ };
+ const { asFragment } = mountWithRouter();
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('should render with 1 breadcrumb item and last is active', () => {
- const header = {
- title: '',
- breadcrumbs: [
- {
- title: 'First item',
- to: '#',
- isActive: true
- }
- ]
- };
- const { asFragment } = mountWithRouter();
- expect(asFragment()).toMatchSnapshot();
- });
+ it('should render with 1 breadcrumb item and last is active', () => {
+ const header = {
+ title: '',
+ breadcrumbs: [
+ {
+ title: 'First item',
+ to: '#',
+ isActive: true,
+ },
+ ],
+ };
+ const { asFragment } = mountWithRouter();
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('should render without to attribute', () => {
- const header = {
- title: '',
- breadcrumbs: [
- {
- title: 'First item',
- isActive: true
- }
- ]
- };
- const { asFragment } = mountWithRouter();
- expect(asFragment()).toMatchSnapshot();
- });
+ it('should render without to attribute', () => {
+ const header = {
+ title: '',
+ breadcrumbs: [
+ {
+ title: 'First item',
+ isActive: true,
+ },
+ ],
+ };
+ const { asFragment } = mountWithRouter();
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('should render with 2 breadcrumb items and last is active', () => {
- const header = {
- title: '',
- breadcrumbs: [
- {
- title: 'First item',
- to: '#',
- isActive: false
- },
- {
- title: 'Second item',
- to: '#',
- isActive: true
- }
- ]
- };
- const { asFragment } = mountWithRouter();
- expect(asFragment()).toMatchSnapshot();
- });
+ it('should render with 2 breadcrumb items and last is active', () => {
+ const header = {
+ title: '',
+ breadcrumbs: [
+ {
+ title: 'First item',
+ to: '#',
+ isActive: false,
+ },
+ {
+ title: 'Second item',
+ to: '#',
+ isActive: true,
+ },
+ ],
+ };
+ const { asFragment } = mountWithRouter();
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('should render with 3 breadcrumb items and last is active', () => {
- const header = {
- showTabs: false,
- title: '',
- breadcrumbs: [
- {
- title: 'First item',
- to: '#',
- isActive: false
- },
- {
- title: 'Second item',
- to: '#',
- isActive: false
- },
- {
- title: 'Third item',
- to: '#',
- isActive: true
- }
- ]
- };
- const { asFragment } = mountWithRouter();
- expect(asFragment()).toMatchSnapshot();
- });
- //NOTE: Should be rewritten because of how RTL testing approaches testing the router
- //something like this could be ok
- //https://stackoverflow.com/questions/70313688/how-i-could-test-location-with-memoryrouter-on-react-router-dom-v6
- it.skip('should render with tabs only, click a tab', () => {
- const wrapper = mountWithRouter();
- let history = wrapper.find('Router').props().navigator;
- const spy = jest.spyOn(history, 'push');
- wrapper
- .find('Tabs.patchman-tabs')
- .props()
- .onSelect();
- expect(spy).toBeCalled();
- });
+ it('should render with 3 breadcrumb items and last is active', () => {
+ const header = {
+ showTabs: false,
+ title: '',
+ breadcrumbs: [
+ {
+ title: 'First item',
+ to: '#',
+ isActive: false,
+ },
+ {
+ title: 'Second item',
+ to: '#',
+ isActive: false,
+ },
+ {
+ title: 'Third item',
+ to: '#',
+ isActive: true,
+ },
+ ],
+ };
+ const { asFragment } = mountWithRouter();
+ expect(asFragment()).toMatchSnapshot();
+ });
+ // NOTE: Should be rewritten because of how RTL testing approaches testing the router
+ // something like this could be ok
+ // https://stackoverflow.com/questions/70313688/how-i-could-test-location-with-memoryrouter-on-react-router-dom-v6
+ it.skip('should render with tabs only, click a tab', () => {
+ const wrapper = mountWithRouter();
+ let history = wrapper.find('Router').props().navigator;
+ const spy = jest.spyOn(history, 'push');
+ wrapper.find('Tabs.patchman-tabs').props().onSelect();
+ expect(spy).toBeCalled();
+ });
});
diff --git a/src/PresentationalComponents/Header/HeaderBreadcrumbs.cy.js b/src/PresentationalComponents/Header/HeaderBreadcrumbs.cy.js
index 861a6d1a4..6ae7ff937 100644
--- a/src/PresentationalComponents/Header/HeaderBreadcrumbs.cy.js
+++ b/src/PresentationalComponents/Header/HeaderBreadcrumbs.cy.js
@@ -5,48 +5,48 @@ import HeaderBreadcrumbs from './HeaderBreadcrumbs';
import { MemoryRouter } from 'react-router-dom';
describe('HeaderBreadcrumbs', () => {
- it('renders two breadcrumbs', () => {
- mount(
-
- );
- cy.get('.pf-v6-c-breadcrumb__list').children().should('have.length', 2);
- });
+ it('renders two breadcrumbs', () => {
+ mount(
+ ,
+ );
+ cy.get('.pf-v6-c-breadcrumb__list').children().should('have.length', 2);
+ });
- it('renders one breadcrumb with link', () => {
- mount(
- // Router wrapper is needed since one of the child components render Route
-
-
-
- );
- cy.get('.pf-v6-c-breadcrumb__list').children().should('have.length', 2);
- cy.get('.pf-v6-c-breadcrumb__list')
- .children()
- .eq(0)
- .find('a')
- .should('have.attr', 'href', '/test');
- });
+ it('renders one breadcrumb with link', () => {
+ mount(
+ // Router wrapper is needed since one of the child components render Route
+
+
+ ,
+ );
+ cy.get('.pf-v6-c-breadcrumb__list').children().should('have.length', 2);
+ cy.get('.pf-v6-c-breadcrumb__list')
+ .children()
+ .eq(0)
+ .find('a')
+ .should('have.attr', 'href', '/test');
+ });
});
diff --git a/src/PresentationalComponents/Header/HeaderBreadcrumbs.js b/src/PresentationalComponents/Header/HeaderBreadcrumbs.js
index 7ff622b19..5185e16bf 100644
--- a/src/PresentationalComponents/Header/HeaderBreadcrumbs.js
+++ b/src/PresentationalComponents/Header/HeaderBreadcrumbs.js
@@ -1,38 +1,37 @@
-import {
- Breadcrumb,
- BreadcrumbItem
-} from '@patternfly/react-core';
+import { Breadcrumb, BreadcrumbItem } from '@patternfly/react-core';
import PropTypes from 'prop-types';
import React from 'react';
import { InsightsLink } from '@redhat-cloud-services/frontend-components/InsightsLink';
-const HeaderBreadcrumbs = ({ items, headerOUIA }) => {
- return (
-
- {items.filter(Boolean).map(item => (
-
- {item.to
- ? {item.title}
- : item.title
- }
-
- ))}
-
- );
-};
+const HeaderBreadcrumbs = ({ items, headerOUIA }) => (
+
+ {items.filter(Boolean).map((item) => (
+
+ {item.to ? (
+
+ {item.title}
+
+ ) : (
+ item.title
+ )}
+
+ ))}
+
+);
HeaderBreadcrumbs.propTypes = {
- items: PropTypes.arrayOf(
- PropTypes.shape({
- isActive: PropTypes.bool,
- to: PropTypes.string,
- title: PropTypes.node
- })
- ),
- headerOUIA: PropTypes.string
+ items: PropTypes.arrayOf(
+ PropTypes.shape({
+ isActive: PropTypes.bool,
+ to: PropTypes.string,
+ title: PropTypes.node,
+ }),
+ ),
+ headerOUIA: PropTypes.string,
};
export default HeaderBreadcrumbs;
diff --git a/src/PresentationalComponents/Header/HeaderTabs.js b/src/PresentationalComponents/Header/HeaderTabs.js
index 82ea5b776..d027f9a11 100644
--- a/src/PresentationalComponents/Header/HeaderTabs.js
+++ b/src/PresentationalComponents/Header/HeaderTabs.js
@@ -5,37 +5,33 @@ import './Header.scss';
import { useLocation, useNavigate } from 'react-router-dom';
const HeaderTabs = ({ headerOUIA }) => {
- const location = useLocation();
- const navigate = useNavigate();
+ const location = useLocation();
+ const navigate = useNavigate();
- const handleRedirect = (event, tabString) => {
- navigate(tabString);
- };
+ const handleRedirect = (event, tabString) => {
+ navigate(tabString);
+ };
- return (
-
-
-
-
- );
+ return (
+
+
+
+
+ );
};
HeaderTabs.propTypes = {
- headerOUIA: propTypes.string
+ headerOUIA: propTypes.string,
};
export default HeaderTabs;
diff --git a/src/PresentationalComponents/InfoBox/InfoBox.js b/src/PresentationalComponents/InfoBox/InfoBox.js
index 63c8729db..21aa7566b 100644
--- a/src/PresentationalComponents/InfoBox/InfoBox.js
+++ b/src/PresentationalComponents/InfoBox/InfoBox.js
@@ -4,34 +4,28 @@ import React from 'react';
import WithLoader, { WithLoaderVariants } from '../WithLoader/WithLoader';
import './InfoBox.scss';
-const InfoBox = ({ title, text, isLoading, content, color }) => {
- return (
-
-
-
- {content}
-
-
-
- {title}
- {text}
-
-
-
-
- );
-};
+const InfoBox = ({ title, text, isLoading, content, color }) => (
+
+
+
+ {content}
+
+
+
+ {title}
+ {text}
+
+
+
+
+);
InfoBox.propTypes = {
- title: propTypes.string,
- text: propTypes.any,
- isLoading: propTypes.bool,
- content: propTypes.any,
- color: propTypes.string
+ title: propTypes.string,
+ text: propTypes.any,
+ isLoading: propTypes.bool,
+ content: propTypes.any,
+ color: propTypes.string,
};
export default InfoBox;
diff --git a/src/PresentationalComponents/InfoBox/InfoBox.scss b/src/PresentationalComponents/InfoBox/InfoBox.scss
index 6316136a0..5af9ce397 100644
--- a/src/PresentationalComponents/InfoBox/InfoBox.scss
+++ b/src/PresentationalComponents/InfoBox/InfoBox.scss
@@ -1,22 +1,22 @@
.infobox {
- background-color: var(--pf-t--global--background--color--primary-default);
- border: var(--pf-t--global--border--color--control--read-only) var(--pf-t--global--border--width--regular)
- solid;
- height: 65px;
- > .pf-v6-l-split__item:first-child {
- width: 65px;
- color: black;
- background-color: var(--pf-t--global--color--status--warning--100);
- > div.pf-v6-l-bullseye svg {
- color: white;
- }
- }
- .pf-v6-c-content h6 {
- margin: 0;
- }
- > .pf-v6-l-split__item:nth-child(2) {
- display: flex;
- justify-content: flex-start;
- align-items: center;
+ background-color: var(--pf-t--global--background--color--primary-default);
+ border: var(--pf-t--global--border--color--control--read-only)
+ var(--pf-t--global--border--width--regular) solid;
+ height: 65px;
+ > .pf-v6-l-split__item:first-child {
+ width: 65px;
+ color: black;
+ background-color: var(--pf-t--global--color--status--warning--100);
+ > div.pf-v6-l-bullseye svg {
+ color: white;
}
+ }
+ .pf-v6-c-content h6 {
+ margin: 0;
+ }
+ > .pf-v6-l-split__item:nth-child(2) {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ }
}
diff --git a/src/PresentationalComponents/InfoBox/InfoBox.test.js b/src/PresentationalComponents/InfoBox/InfoBox.test.js
index b398a355b..62f1b3fd3 100644
--- a/src/PresentationalComponents/InfoBox/InfoBox.test.js
+++ b/src/PresentationalComponents/InfoBox/InfoBox.test.js
@@ -2,18 +2,16 @@ import InfoBox from './InfoBox';
import { render } from '@testing-library/react';
const props = {
- title: 'testTitle',
- text: 'testText',
- isLoading: false,
- content: 'testContent',
- color: 'testColor'
+ title: 'testTitle',
+ text: 'testText',
+ isLoading: false,
+ content: 'testContent',
+ color: 'testColor',
};
describe('InfoBox', () => {
- it('Should match to snapshots', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match to snapshots', () => {
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/PresentationalComponents/PackageHeader/PackageHeader.js b/src/PresentationalComponents/PackageHeader/PackageHeader.js
index a74bbb079..605e47cfe 100644
--- a/src/PresentationalComponents/PackageHeader/PackageHeader.js
+++ b/src/PresentationalComponents/PackageHeader/PackageHeader.js
@@ -1,36 +1,33 @@
import { Grid, GridItem, Stack, StackItem } from '@patternfly/react-core';
import propTypes from 'prop-types';
-import React from 'react';
-import { Fragment } from 'react';
+import React, { Fragment } from 'react';
import { truncateDescription } from '../../Utilities/Helpers';
import WithLoader, { WithLoaderVariants } from '../WithLoader/WithLoader';
const PackageHeader = ({ attributes: { description }, isLoading }) => {
- const [wordLength, setWordLength] = React.useState(1000);
+ const [wordLength, setWordLength] = React.useState(1000);
- return description && (
+ return (
+ (description && (
+
-
-
-
-
- {
- description && truncateDescription(description, wordLength, setWordLength)
- }
-
-
-
+
+
+
+
+ {description && truncateDescription(description, wordLength, setWordLength)}
+
+
+
- ) || ;
+
+ )) ||
+ );
};
PackageHeader.propTypes = {
- attributes: propTypes.object,
- isLoading: propTypes.bool
+ attributes: propTypes.object,
+ isLoading: propTypes.bool,
};
export default PackageHeader;
diff --git a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js
index 532c5a8a8..7d5ad5e17 100644
--- a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js
+++ b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.js
@@ -5,28 +5,31 @@ import PatchSetWizard from '../../SmartComponents/PatchSetWizard/PatchSetWizard'
import UnassignSystemsModal from '../../SmartComponents/Modals/UnassignSystemsModal';
import AssignSystemsModal from '../../SmartComponents/Modals/AssignSystemsModal';
-const PatchSetWrapper = ({ patchSetState, setPatchSetState, totalItems }) => {
- return (<>
- {(patchSetState.isUnassignSystemsModalOpen) && }
-
- {(patchSetState.isPatchSetWizardOpen) &&
- }
- >);
-};
+const PatchSetWrapper = ({ patchSetState, setPatchSetState, totalItems }) => (
+ <>
+ {patchSetState.isUnassignSystemsModalOpen && (
+
+ )}
+
+ {patchSetState.isPatchSetWizardOpen && (
+
+ )}
+ >
+);
PatchSetWrapper.propTypes = {
- patchSetState: propTypes.object,
- setPatchSetState: propTypes.func,
- totalItems: propTypes.number
+ patchSetState: propTypes.object,
+ setPatchSetState: propTypes.func,
+ totalItems: propTypes.number,
};
export default PatchSetWrapper;
diff --git a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js
index 0cddd0d41..0d8ce8cd6 100644
--- a/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js
+++ b/src/PresentationalComponents/PatchSetWrapper/PatchSetWrapper.test.js
@@ -3,62 +3,77 @@ import { useSelector } from 'react-redux';
import configureStore from 'redux-mock-store';
import { mountWithRouterAndProviderAndIntl } from '../../../config/rtlwrapper';
-jest.mock('../../SmartComponents/PatchSetWizard/PatchSetWizard', () => () => );
-jest.mock('../../SmartComponents/Modals/UnassignSystemsModal', () => () => );
-jest.mock('../../SmartComponents/Modals/AssignSystemsModal', () => () => );
+jest.mock('../../SmartComponents/PatchSetWizard/PatchSetWizard', () => () => (
+
+));
+jest.mock('../../SmartComponents/Modals/UnassignSystemsModal', () => () => (
+
+));
+jest.mock('../../SmartComponents/Modals/AssignSystemsModal', () => () => (
+
+));
const mockState = {};
const initStore = (state) => {
- const customMiddleWare = () => next => action => {
- useSelector.mockImplementation(callback => {
- return callback({ SpecificPatchSetReducer: state });
- });
- next(action);
- };
+ const customMiddleWare = () => (next) => (action) => {
+ useSelector.mockImplementation((callback) => callback({ SpecificPatchSetReducer: state }));
+ next(action);
+ };
- const mockStore = configureStore([customMiddleWare]);
- return mockStore({ });
+ const mockStore = configureStore([customMiddleWare]);
+ return mockStore({});
};
let store = initStore(mockState);
const testProps = {
- patchSetState: {
- isUnassignSystemsModalOpen: true,
- isPatchSetWizardOpen: true,
- systemsIDs: ['system-1', 'system-2']
- },
- setPatchSetState: jest.fn(),
- totalItems: 101
+ patchSetState: {
+ isUnassignSystemsModalOpen: true,
+ isPatchSetWizardOpen: true,
+ systemsIDs: ['system-1', 'system-2'],
+ },
+ setPatchSetState: jest.fn(),
+ totalItems: 101,
};
describe('PatchSetWrapper', () => {
- it('should display PatchSetWizard when isPatchSetWizardOpen prop is true', () => {
- const { container } = mountWithRouterAndProviderAndIntl(, store);
- expect(container.querySelector('#test-patch-set-wizard')).toBeTruthy();
- });
+ it('should display PatchSetWizard when isPatchSetWizardOpen prop is true', () => {
+ const { container } = mountWithRouterAndProviderAndIntl(
+ ,
+ store,
+ );
+ expect(container.querySelector('#test-patch-set-wizard')).toBeTruthy();
+ });
- it('should hide PatchSetWizard when isPatchSetWizardOpen prop is false', () => {
- const testHiddenState = {
- patchSetState: { ...testProps.patchSetState, isPatchSetWizardOpen: false },
- ...testProps.setPatchSetState
- };
- const { container } = mountWithRouterAndProviderAndIntl(
- , store);
- expect(container.querySelector('#test-patch-set-wizard')).toBeFalsy();
- });
+ it('should hide PatchSetWizard when isPatchSetWizardOpen prop is false', () => {
+ const testHiddenState = {
+ patchSetState: { ...testProps.patchSetState, isPatchSetWizardOpen: false },
+ ...testProps.setPatchSetState,
+ };
+ const { container } = mountWithRouterAndProviderAndIntl(
+ ,
+ store,
+ );
+ expect(container.querySelector('#test-patch-set-wizard')).toBeFalsy();
+ });
- it('should display UnassignSystemsModal when isUnassignSystemsModalOpen prop is true', () => {
- const { container } = mountWithRouterAndProviderAndIntl(, store);
- expect(container.querySelector('#test-unassign-systems-modal')).toBeTruthy();
- });
+ it('should display UnassignSystemsModal when isUnassignSystemsModalOpen prop is true', () => {
+ const { container } = mountWithRouterAndProviderAndIntl(
+ ,
+ store,
+ );
+ expect(container.querySelector('#test-unassign-systems-modal')).toBeTruthy();
+ });
- it('should hide UnassignSystemsModal when isUnassignSystemsModalOpen prop is false', () => {
- const testHiddenState = {
- patchSetState: { ...testProps.patchSetState, isUnassignSystemsModalOpen: false },
- ...testProps.setPatchSetState
- };
- const { container } = mountWithRouterAndProviderAndIntl(, store);
- expect(container.querySelector('#test-unassign-systems-modal')).toBeFalsy();
- });
+ it('should hide UnassignSystemsModal when isUnassignSystemsModalOpen prop is false', () => {
+ const testHiddenState = {
+ patchSetState: { ...testProps.patchSetState, isUnassignSystemsModalOpen: false },
+ ...testProps.setPatchSetState,
+ };
+ const { container } = mountWithRouterAndProviderAndIntl(
+ ,
+ store,
+ );
+ expect(container.querySelector('#test-unassign-systems-modal')).toBeFalsy();
+ });
});
diff --git a/src/PresentationalComponents/Snippets/AdvisoriesIcon.js b/src/PresentationalComponents/Snippets/AdvisoriesIcon.js
index a0aa758fc..3cd93cb52 100644
--- a/src/PresentationalComponents/Snippets/AdvisoriesIcon.js
+++ b/src/PresentationalComponents/Snippets/AdvisoriesIcon.js
@@ -2,25 +2,23 @@ import React from 'react';
import { Flex, FlexItem, Tooltip, Icon as PfIcon } from '@patternfly/react-core';
import propTypes from 'prop-types';
-const AdvisoriesIcon = ({ count, tooltipText, Icon }) =>(
-
-
-
-
-
-
-
-
- {count && count.toString() || 0}
-
-
-
+const AdvisoriesIcon = ({ count, tooltipText, Icon }) => (
+
+
+
+
+
+
+
+ {(count && count.toString()) || 0}
+
+
);
AdvisoriesIcon.propTypes = {
- Icon: propTypes.func,
- count: propTypes.any,
- tooltipText: propTypes.string
+ Icon: propTypes.func,
+ count: propTypes.any,
+ tooltipText: propTypes.string,
};
export default AdvisoriesIcon;
diff --git a/src/PresentationalComponents/Snippets/AdvisorySeverityInfo.js b/src/PresentationalComponents/Snippets/AdvisorySeverityInfo.js
index e51b8eb7d..247c2ba6f 100644
--- a/src/PresentationalComponents/Snippets/AdvisorySeverityInfo.js
+++ b/src/PresentationalComponents/Snippets/AdvisorySeverityInfo.js
@@ -1,41 +1,34 @@
-import { Icon, Split, SplitItem, Title } from '@patternfly/react-core';
+import { Icon, Split, SplitItem, Title, Flex, FlexItem } from '@patternfly/react-core';
import { SecurityIcon } from '@patternfly/react-icons';
import propTypes from 'prop-types';
import React from 'react';
-import { Flex, FlexItem } from '@patternfly/react-core';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
-const AdvisorySeverityInfo = ({ severity }) => {
- return (
-
-
-
-
-
- {intl.formatMessage(messages.labelsColumnsSeverity)}
-
-
-
-
-
-
-
-
-
-
- {severity.label}
-
-
-
-
-
-
- );
-};
+const AdvisorySeverityInfo = ({ severity }) => (
+
+
+
+
+ {intl.formatMessage(messages.labelsColumnsSeverity)}
+
+
+
+
+
+
+
+
+ {severity.label}
+
+
+
+
+
+);
AdvisorySeverityInfo.propTypes = {
- severity: propTypes.object
+ severity: propTypes.object,
};
export default AdvisorySeverityInfo;
diff --git a/src/PresentationalComponents/Snippets/DescriptionWithLink.js b/src/PresentationalComponents/Snippets/DescriptionWithLink.js
index b51b8ff7c..f9b615b21 100644
--- a/src/PresentationalComponents/Snippets/DescriptionWithLink.js
+++ b/src/PresentationalComponents/Snippets/DescriptionWithLink.js
@@ -4,54 +4,68 @@ import propTypes from 'prop-types';
import React from 'react';
import messages from '../../Messages';
import { entityTypes } from '../../Utilities/constants';
-import { getSeverityByValue, handlePatchLink, isRHAdvisory, truncate } from '../../Utilities/Helpers';
+import {
+ getSeverityByValue,
+ handlePatchLink,
+ isRHAdvisory,
+ truncate,
+} from '../../Utilities/Helpers';
import { intl } from '../../Utilities/IntlProvider';
import ExternalLink from './ExternalLink';
import Label from './Label';
import RebootRequired from '../Snippets/RebootRequired';
export const DescriptionWithLink = ({ row }) => {
- const severityObject = getSeverityByValue(row.attributes?.severity);
- return (
-
- {
- row.attributes.cve_count > 0 &&
- (
-
- {intl.formatMessage(messages.labelsSeverity)}
-
-
-
-
- {severityObject.label}
-
-
- {intl.formatMessage(messages.labelsCves)}
-
-
- {row.attributes.cve_count}
-
- )
- }
-
-
- {truncate(row.attributes.description.replace(
- new RegExp('\\n(?=[^\\n])', 'g'),
- ''
- ), 570, handlePatchLink(entityTypes.advisories, row.id, intl.formatMessage(messages.linksReadMore)))}
-
- {
- row.attributes.reboot_required &&
- }
- {isRHAdvisory(row.id) && }
- );
+ const severityObject = getSeverityByValue(row.attributes?.severity);
+ return (
+
+ {row.attributes.cve_count > 0 && (
+
+
+ {intl.formatMessage(messages.labelsSeverity)}
+
+
+
+
+ {' '}
+ {severityObject.label}
+
+
+ {intl.formatMessage(messages.labelsCves)}
+
+ {row.attributes.cve_count}
+
+ )}
+
+
+ {truncate(
+ row.attributes.description.replace(new RegExp('\\n(?=[^\\n])', 'g'), ''),
+ 570,
+ handlePatchLink(
+ entityTypes.advisories,
+ row.id,
+ intl.formatMessage(messages.linksReadMore),
+ ),
+ )}
+
+ {row.attributes.reboot_required && }
+ {isRHAdvisory(row.id) && (
+
+ )}
+
+ );
};
DescriptionWithLink.propTypes = {
- row: propTypes.shape({
- id: propTypes.string,
- attributes: propTypes.object,
- reboot_required: propTypes.bool
- })
+ row: propTypes.shape({
+ id: propTypes.string,
+ attributes: propTypes.object,
+ reboot_required: propTypes.bool,
+ }),
};
diff --git a/src/PresentationalComponents/Snippets/EmptyStates.js b/src/PresentationalComponents/Snippets/EmptyStates.js
index 48f057e9e..29eaae1d5 100644
--- a/src/PresentationalComponents/Snippets/EmptyStates.js
+++ b/src/PresentationalComponents/Snippets/EmptyStates.js
@@ -1,123 +1,113 @@
import {
- Button,
- EmptyState,
- EmptyStateBody,
- EmptyStateVariant,
- Tooltip
+ Button,
+ EmptyState,
+ EmptyStateBody,
+ EmptyStateVariant,
+ Tooltip,
} from '@patternfly/react-core';
-import { SearchIcon } from '@patternfly/react-icons';
+import { SearchIcon, PlusCircleIcon } from '@patternfly/react-icons';
import React from 'react';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
-import { PlusCircleIcon } from '@patternfly/react-icons';
import PropTypes from 'prop-types';
export const EmptyAdvisoryList = () => (
-
-
- {intl.formatMessage(messages.textEmptyStateBody)}
-
-
+
+ {intl.formatMessage(messages.textEmptyStateBody)}
+
);
export const EmptyPackagesList = () => (
-
-
- {intl.formatMessage(messages.textEmptyStateBody)}
-
-
+
+ {intl.formatMessage(messages.textEmptyStateBody)}
+
);
export const EmptyCvesList = () => (
-
-
- {intl.formatMessage(messages.textEmptyStateBody)}
-
-
+
+ {intl.formatMessage(messages.textEmptyStateBody)}
+
);
export const EmptySystemsList = () => (
-
-
- {intl.formatMessage(messages.textEmptyStateBody)}
-
-
+
+ {intl.formatMessage(messages.textEmptyStateBody)}
+
);
export const EmptyPatchSetList = () => (
-
-
- {intl.formatMessage(messages.textEmptyStateBody)}
-
-
+
+ {intl.formatMessage(messages.textEmptyStateBody)}
+
);
export const NoPatchSetList = ({ Button }) => (
-
-
- {intl.formatMessage(messages.statesNoTemplateBody)}
-
-
-
-
-
+
+
+ {intl.formatMessage(messages.statesNoTemplateBody)}
+
+
+
+
+
);
NoPatchSetList.propTypes = {
- Button: PropTypes.node
+ Button: PropTypes.node,
};
export const NoAppliedSystems = ({ onButtonClick, hasAccess }) => (
-
-
- {hasAccess
- ?
- :
-
-
- }
-
-
+
+
+ {hasAccess ? (
+
+ ) : (
+
+
+
+ )}
+
+
);
NoAppliedSystems.propTypes = {
- onButtonClick: PropTypes.func,
- hasAccess: PropTypes.bool
+ onButtonClick: PropTypes.func,
+ hasAccess: PropTypes.bool,
};
diff --git a/src/PresentationalComponents/Snippets/EmptyStates.test.js b/src/PresentationalComponents/Snippets/EmptyStates.test.js
index 558d02c0f..1742fa250 100644
--- a/src/PresentationalComponents/Snippets/EmptyStates.test.js
+++ b/src/PresentationalComponents/Snippets/EmptyStates.test.js
@@ -1,23 +1,16 @@
-import {
- EmptyAdvisoryList,
- EmptyPackagesList
-} from './EmptyStates';
+import { EmptyAdvisoryList, EmptyPackagesList } from './EmptyStates';
import { render } from '@testing-library/react';
describe('EmptyAdvisoryList', () => {
- it('Should match the snapshot', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshot', () => {
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
});
describe('EmptyPackagesList', () => {
- it('Should match the snapshot', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshot', () => {
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/PresentationalComponents/Snippets/Error.js b/src/PresentationalComponents/Snippets/Error.js
index 1ae4b9c62..2b4baa5ea 100644
--- a/src/PresentationalComponents/Snippets/Error.js
+++ b/src/PresentationalComponents/Snippets/Error.js
@@ -1,25 +1,25 @@
-import { Card, EmptyState, EmptyStateBody, EmptyStateVariant } from '@patternfly/react-core';
+import { Card, EmptyState, EmptyStateBody, EmptyStateVariant } from '@patternfly/react-core';
import { FrownOpenIcon } from '@patternfly/react-icons';
import propTypes from 'prop-types';
import React from 'react';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
-const Error = ({ message }) =>
-
-
-
- {message}
-
- ;
+const Error = ({ message }) => (
+
+
+ {message}
+
+
+);
export default Error;
Error.propTypes = {
- message: propTypes.string
+ message: propTypes.string,
};
diff --git a/src/PresentationalComponents/Snippets/Error.test.js b/src/PresentationalComponents/Snippets/Error.test.js
index 23b209719..138523df2 100644
--- a/src/PresentationalComponents/Snippets/Error.test.js
+++ b/src/PresentationalComponents/Snippets/Error.test.js
@@ -2,10 +2,8 @@ import Error from './Error';
import { render } from '@testing-library/react';
describe('Error.js', () => {
- it('Should match the snapshot', () => {
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshot', () => {
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/PresentationalComponents/Snippets/ErrorHandler.js b/src/PresentationalComponents/Snippets/ErrorHandler.js
index 0cf0a3b36..c7b44f731 100644
--- a/src/PresentationalComponents/Snippets/ErrorHandler.js
+++ b/src/PresentationalComponents/Snippets/ErrorHandler.js
@@ -9,58 +9,65 @@ import { LockIcon } from '@patternfly/react-icons';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
-//TODO: use the shared component from platform
+// TODO: use the shared component from platform
import NoRegisteredSystems from './NoRegisteredSystems';
-//import { NoRegisteredSystems } from '@redhat-cloud-services/frontend-components/NoRegisteredSystems';
+// import { NoRegisteredSystems } from '@redhat-cloud-services/frontend-components/NoRegisteredSystems';
const ErrorHandler = ({ code, ErrorState, EmptyState, metadata = {} }) => {
- switch (code) {
- case 204:
- return ;
+ switch (code) {
+ case 204:
+ return ;
- case 400:
- return ;
+ case 400:
+ return ;
- case 401:
- return ;
+ case 401:
+ return (
+
+ );
- case 403:
- return ;
+ case 403:
+ return (
+
+ );
- case 404:
- return ;
+ case 404:
+ return ;
- case 500:
- case 502:
- case 503:
- case 504:
- return ;
+ case 500:
+ case 502:
+ case 503:
+ case 504:
+ return ;
- default:
- return ErrorState
- || EmptyState
- || !metadata.has_systems &&
- || ;
- }
+ default:
+ return (
+ ErrorState ||
+ EmptyState ||
+ (!metadata.has_systems && ) || (
+
+ )
+ );
+ }
};
ErrorHandler.propTypes = {
- code: propTypes.number,
- ErrorState: propTypes.element,
- EmptyState: propTypes.element,
- metadata: propTypes.object.isRequired
+ code: propTypes.number,
+ ErrorState: propTypes.element,
+ EmptyState: propTypes.element,
+ metadata: propTypes.object.isRequired,
};
export default ErrorHandler;
diff --git a/src/PresentationalComponents/Snippets/ExternalLink.js b/src/PresentationalComponents/Snippets/ExternalLink.js
index 961e34b3b..1b3a0c3da 100644
--- a/src/PresentationalComponents/Snippets/ExternalLink.js
+++ b/src/PresentationalComponents/Snippets/ExternalLink.js
@@ -3,19 +3,15 @@ import propTypes from 'prop-types';
import React from 'react';
const ExternalLink = ({ link, text }) => (
-
- {text}
-
-
+
+ {text}
+
+
);
ExternalLink.propTypes = {
- link: propTypes.string,
- text: propTypes.string
+ link: propTypes.string,
+ text: propTypes.string,
};
export default ExternalLink;
diff --git a/src/PresentationalComponents/Snippets/Label.js b/src/PresentationalComponents/Snippets/Label.js
index 956710545..e3f4afdc9 100644
--- a/src/PresentationalComponents/Snippets/Label.js
+++ b/src/PresentationalComponents/Snippets/Label.js
@@ -2,12 +2,10 @@ import propTypes from 'prop-types';
import React from 'react';
import './Label.scss';
-const Label = ({ children }) => {
- return {children};
-};
+const Label = ({ children }) => {children};
Label.propTypes = {
- children: propTypes.any
+ children: propTypes.any,
};
export default Label;
diff --git a/src/PresentationalComponents/Snippets/Label.scss b/src/PresentationalComponents/Snippets/Label.scss
index df44b0688..0234133a9 100644
--- a/src/PresentationalComponents/Snippets/Label.scss
+++ b/src/PresentationalComponents/Snippets/Label.scss
@@ -1,9 +1,9 @@
span {
- &.patchman-label {
- display: inline-block;
- font-size: var(--pf-t--global--font--size--body--default);
- font-weight: var(--pf-t--global--font--weight--heading--bold);
- line-height: var(--pf-t--global--font--line-height--heading);
- color: var(--pf-t--global--text--color--regular);
- }
+ &.patchman-label {
+ display: inline-block;
+ font-size: var(--pf-t--global--font--size--body--default);
+ font-weight: var(--pf-t--global--font--weight--heading--bold);
+ line-height: var(--pf-t--global--font--line-height--heading);
+ color: var(--pf-t--global--text--color--regular);
+ }
}
diff --git a/src/PresentationalComponents/Snippets/Label.test.js b/src/PresentationalComponents/Snippets/Label.test.js
index 30a7098a9..45d29664d 100644
--- a/src/PresentationalComponents/Snippets/Label.test.js
+++ b/src/PresentationalComponents/Snippets/Label.test.js
@@ -2,10 +2,8 @@ import Label from './Label';
import { render } from '@testing-library/react';
describe('Label.js', () => {
- it('Should match the snapshot', () => {
- const { asFragment } = render(
-
- }
- >
-
-
-
-
-
- }
- headerOUIA={'advisories'}
- />
-
-
-
+ dispatch(
+ expandAdvisoryRow({
+ rowId: getRowIdByIndexExpandable(advisories, rowId),
+ value,
+ }),
+ ),
+ );
+
+ const onSelect = useOnSelect(rows, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.advisories,
+ queryParams,
+ selectionDispatcher: selectAdvisoryRow,
+ totalItems: metadata?.total_items,
+ });
+
+ const onSort = useSortColumn(advisoriesColumns, apply, 2);
+ const sortBy = React.useMemo(
+ () => createSortBy(advisoriesColumns, metadata.sort, 2),
+ [metadata.sort],
+ );
+
+ const onExport = useOnExport(
+ 'advisories',
+ queryParams,
+ {
+ csv: exportAdvisoriesCSV,
+ json: exportAdvisoriesJSON,
+ },
+ dispatch,
+ );
+
+ const onSetPage = useSetPage(metadata.limit, apply);
+ const onPerPageSelect = usePerPageSelect(apply);
+
+ function apply(params) {
+ dispatch(changeAdvisoryListParams(params));
+ }
+
+ const remediationDataProvider = useRemediationDataProvider(
+ selectedRows,
+ setRemediationLoading,
+ 'advisories',
+ areAllSelected,
+ );
+
+ return (
+
+
+ {intl.formatMessage(messages.titlesPatchAdvisories)}
+
+
+
+ Advisories allow to see all of the applicable Red Hat and Extra Packages for
+ Enterprise Linux (EPEL) advisories for your RHEL systems checking into{' '}
+ {isLightspeedEnabled ? 'Red Hat Lightspeed' : 'Insights'}.
+
+
+
+
+
+
+ }
+ >
+
+
-
-
- );
+
+
+
+ }
+ headerOUIA='advisories'
+ />
+
+
+
+
+
+ );
};
export default Advisories;
diff --git a/src/SmartComponents/Advisories/Advisories.test.js b/src/SmartComponents/Advisories/Advisories.test.js
index 74debde5e..692c86712 100644
--- a/src/SmartComponents/Advisories/Advisories.test.js
+++ b/src/SmartComponents/Advisories/Advisories.test.js
@@ -3,122 +3,138 @@ import { advisoryRows } from '../../Utilities/RawDataForTesting';
import configureStore from 'redux-mock-store';
import { initMocks } from '../../Utilities/unitTestingUtilities.js';
import { storeListDefaults } from '../../Utilities/constants';
-import {
- exportAdvisoriesCSV, exportAdvisoriesJSON, fetchIDs
-} from '../../Utilities/api';
+import { exportAdvisoriesCSV, exportAdvisoriesJSON, fetchIDs } from '../../Utilities/api';
import AsyncRemediationButton from '../Remediation/AsyncRemediationButton';
-import { ComponentWithContext, testBulkSelection, testExport } from '../../Utilities/TestingUtilities.js';
+import {
+ ComponentWithContext,
+ testBulkSelection,
+ testExport,
+} from '../../Utilities/TestingUtilities.js';
import '@testing-library/jest-dom';
import { waitFor, render, screen } from '@testing-library/react';
initMocks();
jest.mock('@redhat-cloud-services/frontend-components-utilities/helpers', () => ({
- ...jest.requireActual('@redhat-cloud-services/frontend-components-utilities/helpers'),
- downloadFile: jest.fn()
+ ...jest.requireActual('@redhat-cloud-services/frontend-components-utilities/helpers'),
+ downloadFile: jest.fn(),
}));
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- exportAdvisoriesJSON: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- exportAdvisoriesCSV: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- fetchSystems: jest.fn(() => Promise.resolve({ data: { id: 'testId' } }).catch((err) => console.log(err))),
- fetchViewAdvisoriesSystems: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test_id-1' }] }).catch((err) => console.log(err))),
- fetchApplicableAdvisoriesApi: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err)))
+ ...jest.requireActual('../../Utilities/api'),
+ exportAdvisoriesJSON: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ exportAdvisoriesCSV: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ fetchSystems: jest.fn(() =>
+ Promise.resolve({ data: { id: 'testId' } }).catch((err) => console.log(err)),
+ ),
+ fetchViewAdvisoriesSystems: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ fetchIDs: jest.fn(() =>
+ Promise.resolve({ data: [{ id: 'test_id-1' }] }).catch((err) => console.log(err)),
+ ),
+ fetchApplicableAdvisoriesApi: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
}));
jest.mock('../../Utilities/constants', () => ({
- ...jest.requireActual('../../Utilities/constants'),
- publicDateOptions: jest.fn().mockReturnValue([]),
- advisorySeverities: [{
- value: null,
- label: 'None',
- color: 'var(--pf-t--global--icon--color--severity--minor--default'
- }]
+ ...jest.requireActual('../../Utilities/constants'),
+ publicDateOptions: jest.fn().mockReturnValue([]),
+ advisorySeverities: [
+ {
+ value: null,
+ label: 'None',
+ color: 'var(--pf-t--global--icon--color--severity--minor--default',
+ },
+ ],
}));
jest.mock('../Remediation/AsyncRemediationButton', () => ({
- __esModule: true,
- default: jest.fn((props) => (
-
- Remediation
-
- ))
+ __esModule: true,
+ default: jest.fn((props) => (
+
+ Remediation
+
+ )),
}));
const mockState = {
- ...storeListDefaults,
- rows: advisoryRows,
- status: { isLoading: false, code: 200, hasError: false },
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 101
- }
+ ...storeListDefaults,
+ rows: advisoryRows,
+ status: { isLoading: false, code: 200, hasError: false },
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 101,
+ },
};
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore({ AdvisoryListStore: state });
+ const mockStore = configureStore([]);
+ return mockStore({ AdvisoryListStore: state });
};
let store = initStore(mockState);
beforeEach(() => {
- render(
-
- );
+ render(
+
+
+ ,
+ );
});
describe('Advisories.js', () => {
- testExport(exportAdvisoriesCSV, exportAdvisoriesJSON, 'advisories');
-
- testBulkSelection(
- fetchIDs,
- '/ids/advisories',
- 'selectAdvisoryRow',
- [{
- id: 'RHEA-2020:2743',
- selected: 'RHEA-2020:2743'
- }]
+ testExport(exportAdvisoriesCSV, exportAdvisoriesJSON, 'advisories');
+
+ testBulkSelection(fetchIDs, '/ids/advisories', 'selectAdvisoryRow', [
+ {
+ id: 'RHEA-2020:2743',
+ selected: 'RHEA-2020:2743',
+ },
+ ]);
+
+ it('Should display error page when status is rejected', async () => {
+ const rejectedState = {
+ ...mockState,
+ status: { isLoading: false, code: 400, hasError: true },
+ error: {},
+ };
+ const tempStore = initStore(rejectedState);
+ render(
+
+
+ ,
);
- it('Should display error page when status is rejected', async () => {
- const rejectedState = {
- ...mockState,
- status: { isLoading: false, code: 400, hasError: true },
- error: {}
- };
- const tempStore = initStore(rejectedState);
- render(
-
- );
-
- await waitFor(
- () => expect(screen.queryByText('This page is temporarily unavailable')).toBeVisible()
- );
- });
-
- it('should load remediation button with proper props', () => {
- const selectedState = {
- ...mockState,
- selectedRows: { 'RHEA-2020:2743': true }
- };
-
- const tempStore = initStore(selectedState);
- render(
-
-
-
- );
+ await waitFor(() =>
+ expect(screen.queryByText('This page is temporarily unavailable')).toBeVisible(),
+ );
+ });
+
+ it('should load remediation button with proper props', () => {
+ const selectedState = {
+ ...mockState,
+ selectedRows: { 'RHEA-2020:2743': true },
+ };
+
+ const tempStore = initStore(selectedState);
+ render(
+
+
+ ,
+ );
- waitFor(() => {
- expect(AsyncRemediationButton).toHaveBeenCalledWith({
- isDisabled: false,
- isLoading: false,
- remediationProvider: expect.any(Function)
- });
- });
+ waitFor(() => {
+ expect(AsyncRemediationButton).toHaveBeenCalledWith({
+ isDisabled: false,
+ isLoading: false,
+ remediationProvider: expect.any(Function),
+ });
});
+ });
});
-
diff --git a/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.js b/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.js
index be8cd3c92..580e48a8a 100644
--- a/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.js
+++ b/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.js
@@ -7,78 +7,85 @@ import messages from '../../Messages';
import AdvisoryHeader from '../../PresentationalComponents/AdvisoryHeader/AdvisoryHeader';
import Header from '../../PresentationalComponents/Header/Header';
import { Unavailable } from '@redhat-cloud-services/frontend-components/Unavailable';
-import { clearAdvisoryDetailStore, clearEntitiesStore, fetchAvisoryDetails } from '../../store/Actions/Actions';
+import {
+ clearAdvisoryDetailStore,
+ clearEntitiesStore,
+ fetchAvisoryDetails,
+} from '../../store/Actions/Actions';
import { intl } from '../../Utilities/IntlProvider';
import AdvisorySystems from '../AdvisorySystems/AdvisorySystems';
import { clearNotifications } from '@redhat-cloud-services/frontend-components-notifications/redux';
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
const AdvisoryDetail = () => {
- const dispatch = useDispatch();
- const chrome = useChrome();
- const { advisoryId: advisoryName } = useParams();
+ const dispatch = useDispatch();
+ const chrome = useChrome();
+ const { advisoryId: advisoryName } = useParams();
- useEffect(()=>{
- advisoryName &&
- chrome.updateDocumentTitle(`${advisoryName} - Advisories - Content | RHEL`, true);
- }, [chrome, advisoryName]);
+ useEffect(() => {
+ advisoryName &&
+ chrome.updateDocumentTitle(`${advisoryName} - Advisories - Content | RHEL`, true);
+ }, [chrome, advisoryName]);
- const advisoryDetails = useSelector(
- ({ AdvisoryDetailStore }) => AdvisoryDetailStore
- );
- const status = useSelector(
- ({ AdvisoryDetailStore }) => AdvisoryDetailStore.status
- );
+ const advisoryDetails = useSelector(({ AdvisoryDetailStore }) => AdvisoryDetailStore);
+ const status = useSelector(({ AdvisoryDetailStore }) => AdvisoryDetailStore.status);
- React.useEffect(() => {
- dispatch(fetchAvisoryDetails({ advisoryName }));
- }, []);
+ React.useEffect(() => {
+ dispatch(fetchAvisoryDetails({ advisoryName }));
+ }, []);
- React.useEffect(() => {
- return () => {
- dispatch(clearEntitiesStore());
- dispatch(clearAdvisoryDetailStore());
- dispatch(clearNotifications());
- };
- }, []);
+ React.useEffect(
+ () => () => {
+ dispatch(clearEntitiesStore());
+ dispatch(clearAdvisoryDetailStore());
+ dispatch(clearNotifications());
+ },
+ [],
+ );
- const { attributes } = advisoryDetails.data;
- return (
-
- {status.hasError ? :
- }
-
-
-
-
-
- {intl.formatMessage(messages.titlesAffectedSystems)}
-
-
-
-
-
-
-
-
- );
+ const { attributes } = advisoryDetails.data;
+ return (
+
+
+ {status.hasError ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ {intl.formatMessage(messages.titlesAffectedSystems)}
+
+
+
+
+
+
+
+
+
+ );
};
export default AdvisoryDetail;
diff --git a/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.test.js b/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.test.js
index db1ed9666..93591c350 100644
--- a/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.test.js
+++ b/src/SmartComponents/AdvisoryDetail/AdvisoryDetail.test.js
@@ -10,84 +10,85 @@ import { render, screen } from '@testing-library/react';
initMocks();
-jest.mock('../../PresentationalComponents/AdvisoryHeader/AdvisoryHeader', () =>
- () => hello
-);
+jest.mock('../../PresentationalComponents/AdvisoryHeader/AdvisoryHeader', () => () => (
+ hello
+));
jest.mock('react-redux', () => ({
- ...jest.requireActual('react-redux'),
- useSelector: jest.fn()
+ ...jest.requireActual('react-redux'),
+ useSelector: jest.fn(),
}));
-jest.mock('../AdvisorySystems/AdvisorySystems', () =>
- () => hello
-);
+jest.mock('../AdvisorySystems/AdvisorySystems', () => () => hello
);
const mockState = { ...storeListDefaults, ...advisoryDetailRows };
const initStore = (state) => {
- const customMiddleWare = () => next => action => {
- useSelector.mockImplementation(callback => {
- return callback({ AdvisoryDetailStore: state });
- });
- next(action);
- };
-
- const mockStore = configureStore([customMiddleWare]);
- return mockStore({ AdvisoryDetailStore: state });
+ const customMiddleWare = () => (next) => (action) => {
+ useSelector.mockImplementation((callback) => callback({ AdvisoryDetailStore: state }));
+ next(action);
+ };
+
+ const mockStore = configureStore([customMiddleWare]);
+ return mockStore({ AdvisoryDetailStore: state });
};
let store = initStore(mockState);
beforeEach(() => {
- store.clearActions();
- useSelector.mockImplementation(callback => {
- return callback({ AdvisoryDetailStore: mockState });
- });
+ store.clearActions();
+ useSelector.mockImplementation((callback) => callback({ AdvisoryDetailStore: mockState }));
});
afterEach(() => {
- useSelector.mockClear();
+ useSelector.mockClear();
});
describe('AdvisoryDetail.js', () => {
- it('Should match the snapshots', () => {
- const { asFragment } = mountWithRouterAndProvider(, store);
- expect(asFragment()).toMatchSnapshot();
- });
-
- it('Should clear store on unmount', async () => {
- const { unmount } = await render(
-
-
-
- );
- unmount();
-
- const dispatchedActions = store.getActions();
- expect(dispatchedActions.filter(item => item.type === 'CLEAR_ENTITIES')).toHaveLength(1);
- expect(dispatchedActions.filter(item => item.type === 'CLEAR_ADVISORY_DETAILS')).toHaveLength(1);
- });
-
- it('Should display error page when status is rejected', () => {
-
- const rejectedState = { ...mockState, status: { hasError: true }, error: { detail: 'test' } };
-
- useSelector.mockImplementation(callback => {
- return callback({ AdvisoryDetailStore: rejectedState });
- });
-
- const tempStore = initStore(rejectedState);
- render(
-
- );
- expect(screen.getByRole('heading', {
- name: /this page is temporarily unavailable/i
- })).toBeTruthy();
- expect(screen.getByText(
- // eslint-disable-next-line max-len
- /try refreshing the page\. if the problem persists, contact your organization administrator or visit our status page for known outages\./i
- )).toBeTruthy();
- });
-
+ it('Should match the snapshots', () => {
+ const { asFragment } = mountWithRouterAndProvider(, store);
+ expect(asFragment()).toMatchSnapshot();
+ });
+
+ it('Should clear store on unmount', async () => {
+ const { unmount } = await render(
+
+
+
+
+ ,
+ );
+ unmount();
+
+ const dispatchedActions = store.getActions();
+ expect(dispatchedActions.filter((item) => item.type === 'CLEAR_ENTITIES')).toHaveLength(1);
+ expect(dispatchedActions.filter((item) => item.type === 'CLEAR_ADVISORY_DETAILS')).toHaveLength(
+ 1,
+ );
+ });
+
+ it('Should display error page when status is rejected', () => {
+ const rejectedState = { ...mockState, status: { hasError: true }, error: { detail: 'test' } };
+
+ useSelector.mockImplementation((callback) => callback({ AdvisoryDetailStore: rejectedState }));
+
+ const tempStore = initStore(rejectedState);
+ render(
+
+
+
+
+ ,
+ );
+ expect(
+ screen.getByRole('heading', {
+ name: /this page is temporarily unavailable/i,
+ }),
+ ).toBeTruthy();
+ expect(
+ screen.getByText(
+ /try refreshing the page\. if the problem persists, contact your organization administrator or visit our status page for known outages\./i,
+ ),
+ ).toBeTruthy();
+ });
});
diff --git a/src/SmartComponents/AdvisoryDetail/CveModal.test.js b/src/SmartComponents/AdvisoryDetail/CveModal.test.js
index 0f4a7916b..41a0e266f 100644
--- a/src/SmartComponents/AdvisoryDetail/CveModal.test.js
+++ b/src/SmartComponents/AdvisoryDetail/CveModal.test.js
@@ -10,92 +10,94 @@ import { ComponentWithContext } from '../../Utilities/TestingUtilities.js';
initMocks();
jest.mock('../../Utilities/DataMappers', () => ({
- ...jest.requireActual('../../Utilities/DataMappers'),
- createCvesRows: jest.fn()
+ ...jest.requireActual('../../Utilities/DataMappers'),
+ createCvesRows: jest.fn(),
}));
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- fetchCvesInfo: jest.fn(() => Promise.resolve('success').catch((err) => console.log(err)))
+ ...jest.requireActual('../../Utilities/api'),
+ fetchCvesInfo: jest.fn(() => Promise.resolve('success').catch((err) => console.log(err))),
}));
const mockState = { ...storeListDefaults, rows: cveRows };
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore({ CvesListStore: state });
+ const mockStore = configureStore([]);
+ return mockStore({ CvesListStore: state });
};
let store = initStore(mockState);
beforeEach(() => {
- createCvesRows.mockImplementation(() => readyCveRows);
+ createCvesRows.mockImplementation(() => readyCveRows);
- render(
-
- );
+ render(
+
+
+ ,
+ );
});
-//TODO: convert disabled tests to RTL after react&paterrnfly migration
+// TODO: convert disabled tests to RTL after react&paterrnfly migration
describe('CveModal.js', () => {
- it('should render the CVEs modal', async () => {
- await waitFor(() => screen.getByText('CVEs'));
- });
- // it('should set rows to undefined to close the modal', () => {
- // screen.debug(undefined, 30000);
- // // const handleClose = wrapper.find('Modal').props().onClose;
- // // handleClose();
- // // wrapper.update();
- // // expect(wrapper.find('TableView').exists()).toBeFalsy();
- // });
-
- // it('should handle page change', () => {
- // let tempWrapper;
- // tempWrapper = mount(
- //
- //
- //
- // );
-
- // const handlePageChange = tempWrapper.find('TableView').props().onSetPage;
- // act(() => handlePageChange('', 2));
- // act(() => tempWrapper.update());
- // expect(tempWrapper.find('TableView').props().store.rows).toEqual(
- // [{ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' },
- // { title: '7.3' }], id: 'CVE-2021-29931', key: 'CVE-2021-29931' },
- // { cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' },
- // { title: '7.3' }], id: 'CVE-2021-29932', key: 'CVE-2021-29932' }]
- // );
- // });
-
- // it('should handle perPage change', () => {
- // let tempWrapper;
- // tempWrapper = mount(
- //
- //
- //
- // );
-
- // const handlePerPageChange = tempWrapper.find('TableView').props().onPerPageSelect;
- // act(() => handlePerPageChange('', 20));
- // act(() => tempWrapper.update());
- // expect(tempWrapper.find('TableView').props().store.rows).toEqual(readyCveRows);
- // });
-
- // it('should handle sorting', () => {
- // let tempWrapper;
- // tempWrapper = mount(
- //
- //
- // );
-
- // const handleSort = tempWrapper.find('TableView').props().onSort;
- // act(() => handleSort('', 0, 'desc'));
- // act(() => tempWrapper.update());
-
- // expect(tempWrapper.find('TableView').props().store.rows).
- // toEqual(readyCveRows.slice(0, 10).sort(({ id: aId }, { id: bId }) => {
- // return !aId.localeCompare(bId);
- // }));
- // });
+ it('should render the CVEs modal', async () => {
+ await waitFor(() => screen.getByText('CVEs'));
+ });
+ // it('should set rows to undefined to close the modal', () => {
+ // screen.debug(undefined, 30000);
+ // // const handleClose = wrapper.find('Modal').props().onClose;
+ // // handleClose();
+ // // wrapper.update();
+ // // expect(wrapper.find('TableView').exists()).toBeFalsy();
+ // });
+
+ // it('should handle page change', () => {
+ // let tempWrapper;
+ // tempWrapper = mount(
+ //
+ //
+ //
+ // );
+
+ // const handlePageChange = tempWrapper.find('TableView').props().onSetPage;
+ // act(() => handlePageChange('', 2));
+ // act(() => tempWrapper.update());
+ // expect(tempWrapper.find('TableView').props().store.rows).toEqual(
+ // [{ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' },
+ // { title: '7.3' }], id: 'CVE-2021-29931', key: 'CVE-2021-29931' },
+ // { cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' },
+ // { title: '7.3' }], id: 'CVE-2021-29932', key: 'CVE-2021-29932' }]
+ // );
+ // });
+
+ // it('should handle perPage change', () => {
+ // let tempWrapper;
+ // tempWrapper = mount(
+ //
+ //
+ //
+ // );
+
+ // const handlePerPageChange = tempWrapper.find('TableView').props().onPerPageSelect;
+ // act(() => handlePerPageChange('', 20));
+ // act(() => tempWrapper.update());
+ // expect(tempWrapper.find('TableView').props().store.rows).toEqual(readyCveRows);
+ // });
+
+ // it('should handle sorting', () => {
+ // let tempWrapper;
+ // tempWrapper = mount(
+ //
+ //
+ // );
+
+ // const handleSort = tempWrapper.find('TableView').props().onSort;
+ // act(() => handleSort('', 0, 'desc'));
+ // act(() => tempWrapper.update());
+
+ // expect(tempWrapper.find('TableView').props().store.rows).
+ // toEqual(readyCveRows.slice(0, 10).sort(({ id: aId }, { id: bId }) => {
+ // return !aId.localeCompare(bId);
+ // }));
+ // });
});
diff --git a/src/SmartComponents/AdvisoryDetail/CvesModal.js b/src/SmartComponents/AdvisoryDetail/CvesModal.js
index 33d5d53cf..5113de20e 100644
--- a/src/SmartComponents/AdvisoryDetail/CvesModal.js
+++ b/src/SmartComponents/AdvisoryDetail/CvesModal.js
@@ -1,7 +1,5 @@
import React, { useState, useMemo } from 'react';
-import {
- Modal
-} from '@patternfly/react-core/deprecated';
+import { Modal } from '@patternfly/react-core/deprecated';
import messages from '../../Messages';
import { intl } from '../../Utilities/IntlProvider';
import TableView from '../../PresentationalComponents/TableView/TableView';
@@ -14,106 +12,115 @@ import { createCvesRows } from '../../Utilities/DataMappers';
import { sortCves } from '..//../Utilities/Helpers';
import { SortByDirection } from '@patternfly/react-table';
-const CvesModal = ({ cveIds }) =>{
- const dispatch = useDispatch();
- const [cves, setCves] = useState([]);
- const [rows, setRows] = useState([]);
- const [page, setPage] = useState(1);
- const [perPage, setPerPage] = useState(10);
- const [search, setSearch] = useState(undefined);
- const [sortBy, setSortBy] = useState({
- direction: SortByDirection.asc,
- index: 0
- });
-
- const data = useSelector(({ CvesListStore }) => CvesListStore.rows);
-
- const status = useSelector(
- ({ CvesListStore }) => CvesListStore.status
- );
-
- React.useEffect(() => {
- dispatch(fetchCves({ cveIds }));
- }, []);
-
- React.useMemo(() => {
- setRows(cves.slice((page - 1) * perPage, page * perPage));
- }, [cves, page, perPage, sortBy]);
-
- useMemo(() => {
- const sortedCves = (search !== undefined && search !== '')
- && data.filter(
- cve => {
- const { attributes: { synopsis } } = cve;
- return synopsis && search && (synopsis.toLowerCase().includes(search.toLowerCase()));
- }
- ) || data;
-
- setCves(createCvesRows((sortedCves.length !== 0 || search) && sortedCves || data));
- }, [search, data]);
-
- const handleClose = () => {
- setRows(undefined);
- };
-
- const handleFilter = ({ search }) =>{
- setPage(page);
- setSearch(search);
- };
-
- const handlePageChange = (_, page) => {
- setPage(page);
- };
-
- const handlePerPageChange = (_, perPage) => {
- setPage(1);
- setPerPage(perPage);
- };
-
- const handleSort = (_, index, direction) => {
- const { sortBy, sortedCves } = sortCves(cves, index, direction);
-
- setSortBy(sortBy);
- setCves(sortedCves);
- };
-
- return (
-
-
-
-
-
- );
-
+const CvesModal = ({ cveIds }) => {
+ const dispatch = useDispatch();
+ const [cves, setCves] = useState([]);
+ const [rows, setRows] = useState([]);
+ const [page, setPage] = useState(1);
+ const [perPage, setPerPage] = useState(10);
+ const [search, setSearch] = useState(undefined);
+ const [sortBy, setSortBy] = useState({
+ direction: SortByDirection.asc,
+ index: 0,
+ });
+
+ const data = useSelector(({ CvesListStore }) => CvesListStore.rows);
+
+ const status = useSelector(({ CvesListStore }) => CvesListStore.status);
+
+ React.useEffect(() => {
+ dispatch(fetchCves({ cveIds }));
+ }, []);
+
+ React.useMemo(() => {
+ setRows(cves.slice((page - 1) * perPage, page * perPage));
+ }, [cves, page, perPage, sortBy]);
+
+ useMemo(() => {
+ const sortedCves =
+ (search !== undefined &&
+ search !== '' &&
+ data.filter((cve) => {
+ const {
+ attributes: { synopsis },
+ } = cve;
+ return synopsis && search && synopsis.toLowerCase().includes(search.toLowerCase());
+ })) ||
+ data;
+
+ setCves(createCvesRows(((sortedCves.length !== 0 || search) && sortedCves) || data));
+ }, [search, data]);
+
+ const handleClose = () => {
+ setRows(undefined);
+ };
+
+ const handleFilter = ({ search }) => {
+ setPage(page);
+ setSearch(search);
+ };
+
+ const handlePageChange = (_, page) => {
+ setPage(page);
+ };
+
+ const handlePerPageChange = (_, perPage) => {
+ setPage(1);
+ setPerPage(perPage);
+ };
+
+ const handleSort = (_, index, direction) => {
+ const { sortBy, sortedCves } = sortCves(cves, index, direction);
+
+ setSortBy(sortBy);
+ setCves(sortedCves);
+ };
+
+ return (
+
+
+
+
+
+ );
};
CvesModal.propTypes = {
- cveIds: propTypes.array
+ cveIds: propTypes.array,
};
export default CvesModal;
diff --git a/src/SmartComponents/AdvisorySystems/AdvisorySystems.js b/src/SmartComponents/AdvisorySystems/AdvisorySystems.js
index 806219e4f..567c1e42f 100644
--- a/src/SmartComponents/AdvisorySystems/AdvisorySystems.js
+++ b/src/SmartComponents/AdvisorySystems/AdvisorySystems.js
@@ -1,80 +1,74 @@
-
import propTypes from 'prop-types';
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import ErrorHandler from '../../PresentationalComponents/Snippets/ErrorHandler';
-import { changeAffectedSystemsParams, clearAdvisorySystemsReducer,
- clearInventoryReducer } from '../../store/Actions/Actions';
-import {
- decodeQueryparams
-} from '../../Utilities/Helpers';
import {
- osParamParser
-} from '../../Utilities/SystemsHelpers';
+ changeAffectedSystemsParams,
+ clearAdvisorySystemsReducer,
+ clearInventoryReducer,
+} from '../../store/Actions/Actions';
+import { decodeQueryparams } from '../../Utilities/Helpers';
+import { osParamParser } from '../../Utilities/SystemsHelpers';
import RemediationWizard from '../Remediation/RemediationWizard';
import { useSearchParams } from 'react-router-dom';
import { useActivateRemediationModal } from '../Systems/SystemsListAssets';
import AdvisorySystemsTable from './AdvisorySystemsTable';
const AdvisorySystems = ({ advisoryName }) => {
- const dispatch = useDispatch();
- const [searchParams, setSearchParams] = useSearchParams();
+ const dispatch = useDispatch();
+ const [searchParams, setSearchParams] = useSearchParams();
- const [isRemediationOpen, setRemediationOpen] = useState(false);
- const [remediationIssues, setRemediationIssues] = useState([]);
+ const [isRemediationOpen, setRemediationOpen] = useState(false);
+ const [remediationIssues, setRemediationIssues] = useState([]);
- const decodedParams = decodeQueryparams('?' + searchParams.toString(), { os: osParamParser });
- const status = useSelector(
- ({ entities }) => entities?.status || {}
- );
- const metadata = useSelector(
- ({ AdvisorySystemsStore }) => AdvisorySystemsStore?.metadata || {}
- );
+ const decodedParams = decodeQueryparams('?' + searchParams.toString(), { os: osParamParser });
+ const status = useSelector(({ entities }) => entities?.status || {});
+ const metadata = useSelector(({ AdvisorySystemsStore }) => AdvisorySystemsStore?.metadata || {});
- useEffect(() => {
- apply(decodedParams);
- return () => {
- dispatch(clearInventoryReducer());
- dispatch(clearAdvisorySystemsReducer());
- };
- }, []);
+ useEffect(() => {
+ apply(decodedParams);
+ return () => {
+ dispatch(clearInventoryReducer());
+ dispatch(clearAdvisorySystemsReducer());
+ };
+ }, []);
- function apply(params) {
- dispatch(changeAffectedSystemsParams(params));
- }
+ function apply(params) {
+ dispatch(changeAffectedSystemsParams(params));
+ }
- const activateRemediationModal = useActivateRemediationModal(
- setRemediationIssues,
- setRemediationOpen
- );
+ const activateRemediationModal = useActivateRemediationModal(
+ setRemediationIssues,
+ setRemediationOpen,
+ );
- if (status.hasError || metadata?.has_systems === false) {
- return ;
- }
+ if (status.hasError || metadata?.has_systems === false) {
+ return ;
+ }
- return (
-
- {isRemediationOpen &&
-
- || null
- }
-
-
- );
+ return (
+
+ {(isRemediationOpen && (
+
+ )) ||
+ null}
+
+
+ );
};
AdvisorySystems.propTypes = {
- advisoryName: propTypes.string
+ advisoryName: propTypes.string,
};
export default AdvisorySystems;
diff --git a/src/SmartComponents/AdvisorySystems/AdvisorySystems.test.js b/src/SmartComponents/AdvisorySystems/AdvisorySystems.test.js
index e37105857..de1c12e31 100644
--- a/src/SmartComponents/AdvisorySystems/AdvisorySystems.test.js
+++ b/src/SmartComponents/AdvisorySystems/AdvisorySystems.test.js
@@ -9,118 +9,118 @@ import userEvent from '@testing-library/user-event';
initMocks();
jest.mock('./AdvisorySystemsTable', () => ({
- __esModule: true,
- default: jest.fn(({ activateRemediationModal, ...props }) => {
- return (
-
-
- );
- })
+ __esModule: true,
+ default: jest.fn(({ activateRemediationModal, ...props }) => (
+
+
+ Systems table
+
+ )),
}));
-jest.mock(
- '../../PresentationalComponents/Filters/OsVersionFilter'
-);
+jest.mock('../../PresentationalComponents/Filters/OsVersionFilter');
jest.mock('../Remediation/RemediationWizard', () => ({
- __esModule: true,
- default: jest.fn((props) => (
-
- Remediation wizard
-
- ))
+ __esModule: true,
+ default: jest.fn((props) => (
+
+ Remediation wizard
+
+ )),
}));
jest.mock('../../Utilities/api', () => ({
- fetchSystems: jest.fn(() => Promise.resolve({
- meta: {
- subtotals: { patched: 10, unpatched: 5, stale: 20 }
- }
- })),
- fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test-system-id-1' }] })),
- fetchApplicableSystemAdvisoriesApi: jest.fn(() => Promise.resolve({
- data: [{
- attributes: {
- advisory_type: 2,
- description: 'The tzdata penhancements.',
- public_date: '2020-10-19T15:02:38Z',
- synopsis: 'tzdata enhancement update'
- },
- id: 'RHBA-2020:4282',
- type: 'advisory'
- }]
- }))
+ fetchSystems: jest.fn(() =>
+ Promise.resolve({
+ meta: {
+ subtotals: { patched: 10, unpatched: 5, stale: 20 },
+ },
+ }),
+ ),
+ fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test-system-id-1' }] })),
+ fetchApplicableSystemAdvisoriesApi: jest.fn(() =>
+ Promise.resolve({
+ data: [
+ {
+ attributes: {
+ advisory_type: 2,
+ description: 'The tzdata penhancements.',
+ public_date: '2020-10-19T15:02:38Z',
+ synopsis: 'tzdata enhancement update',
+ },
+ id: 'RHBA-2020:4282',
+ type: 'advisory',
+ },
+ ],
+ }),
+ ),
}));
const mockState = {
- entities: {
- metadata: {
- has_systems: true
- },
- selectedRows: [{ 'test-system-id-1': true }],
- status: { hasError: false, code: 200 }
+ entities: {
+ metadata: {
+ has_systems: true,
},
- GlobalFilterStore: { selectedTags: [], selectedGlobalTags: [] },
- AdvisorySystemsStore: {
- queryParams: {}
- }
+ selectedRows: [{ 'test-system-id-1': true }],
+ status: { hasError: false, code: 200 },
+ },
+ GlobalFilterStore: { selectedTags: [], selectedGlobalTags: [] },
+ AdvisorySystemsStore: {
+ queryParams: {},
+ },
};
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore(state);
+ const mockStore = configureStore([]);
+ return mockStore(state);
};
const renderComponent = async (mockedStore) => {
- render(
-
- );
+ render(
+
+
+ ,
+ );
};
const user = userEvent.setup();
describe('AdvisorySystems', () => {
- it('Should display systems table when there are no errors', async () => {
- renderComponent(mockState);
- expect(screen.getByTestId('systems-table-mock')).toBeVisible();
- });
+ it('Should display systems table when there are no errors', async () => {
+ renderComponent(mockState);
+ expect(screen.getByTestId('systems-table-mock')).toBeVisible();
+ });
- it('Should display unauthorised component when status is rejected', () => {
- const noAccessState = {
- ...mockState,
- entities: {
- metadata: {
- has_systems: true
- },
- status: { hasError: true, code: 403 }
- }
- };
- renderComponent(noAccessState);
- expect(
- screen.getByText('You do not have permissions to view or manage Patch')
- ).toBeTruthy();
- });
+ it('Should display unauthorised component when status is rejected', () => {
+ const noAccessState = {
+ ...mockState,
+ entities: {
+ metadata: {
+ has_systems: true,
+ },
+ status: { hasError: true, code: 403 },
+ },
+ };
+ renderComponent(noAccessState);
+ expect(screen.getByText('You do not have permissions to view or manage Patch')).toBeTruthy();
+ });
- it('Should display NoRegisteredSystems component if there are no systems registered', () => {
- const noSystemState = {
- ...mockState,
- AdvisorySystemsStore: {
- metadata: {
- has_systems: false
- }
- }
- };
+ it('Should display NoRegisteredSystems component if there are no systems registered', () => {
+ const noSystemState = {
+ ...mockState,
+ AdvisorySystemsStore: {
+ metadata: {
+ has_systems: false,
+ },
+ },
+ };
- renderComponent(noSystemState);
- expect(
- screen.getByText(`Do more with your Red Hat Enterprise Linux environment`)
- ).toBeTruthy();
- });
+ renderComponent(noSystemState);
+ expect(screen.getByText(`Do more with your Red Hat Enterprise Linux environment`)).toBeTruthy();
+ });
- it('Should display remediation wizard', async () => {
- renderComponent(mockState);
- await user.click(screen.getByTestId('active-remediation-modal'));
- expect(screen.getByTestId('remediation-wizard-mock')).toBeVisible();
- });
+ it('Should display remediation wizard', async () => {
+ renderComponent(mockState);
+ await user.click(screen.getByTestId('active-remediation-modal'));
+ expect(screen.getByTestId('remediation-wizard-mock')).toBeVisible();
+ });
});
diff --git a/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.js b/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.js
index e3b05b4dc..1eadf7592 100644
--- a/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.js
+++ b/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.js
@@ -7,19 +7,31 @@ import { combineReducers } from 'redux';
import messages from '../../Messages';
import searchFilter from '../../PresentationalComponents/Filters/SearchFilter';
import { defaultReducers } from '../../store';
+import { systemSelectAction } from '../../store/Actions/Actions';
import {
- systemSelectAction
-} from '../../store/Actions/Actions';
-import { inventoryEntitiesReducer, modifyAdvisorySystems } from '../../store/Reducers/InventoryEntitiesReducer';
-import { exportAdvisorySystemsCSV, exportAdvisorySystemsJSON, fetchAdvisorySystems } from '../../Utilities/api';
+ inventoryEntitiesReducer,
+ modifyAdvisorySystems,
+} from '../../store/Reducers/InventoryEntitiesReducer';
+import {
+ exportAdvisorySystemsCSV,
+ exportAdvisorySystemsJSON,
+ fetchAdvisorySystems,
+} from '../../Utilities/api';
import { remediationIdentifiers } from '../../Utilities/constants';
import {
- arrayFromObj, persistantParams,
- remediationProvider, removeUndefinedObjectKeys
+ arrayFromObj,
+ persistantParams,
+ remediationProvider,
+ removeUndefinedObjectKeys,
} from '../../Utilities/Helpers';
import {
- useBulkSelectConfig, useGetEntities, useOnExport, useRemoveFilter, useOnSelect, ID_API_ENDPOINTS,
- useColumnManagement
+ useBulkSelectConfig,
+ useGetEntities,
+ useOnExport,
+ useRemoveFilter,
+ useOnSelect,
+ ID_API_ENDPOINTS,
+ useColumnManagement,
} from '../../Utilities/hooks';
import { intl } from '../../Utilities/IntlProvider';
import { ADVISORY_SYSTEMS_COLUMNS, systemsRowActions } from '../Systems/SystemsListAssets';
@@ -28,154 +40,170 @@ import { buildActiveFiltersConfig, mergeInventoryColumns } from '../../Utilities
import advisoryStatusFilter from '../../PresentationalComponents/Filters/AdvisoryStatusFilter';
const AdvisorySystemsTable = ({
- advisoryName,
+ advisoryName,
+ apply,
+ setSearchParams,
+ activateRemediationModal,
+ decodedParams,
+}) => {
+ const dispatch = useDispatch();
+ const store = useStore();
+
+ const systems = useSelector(({ entities }) => entities?.rows || [], shallowEqual);
+ const totalItems = useSelector(({ entities }) => entities?.total || 0);
+ const queryParams = useSelector(
+ ({ AdvisorySystemsStore }) => AdvisorySystemsStore?.queryParams || {},
+ );
+ const selectedRows = useSelector(({ entities }) => entities?.selectedRows || []);
+
+ const { systemProfile, selectedTags, filter, search, page, perPage, sort } = queryParams;
+
+ const [appliedColumns, setAppliedColumns] = React.useState(ADVISORY_SYSTEMS_COLUMNS);
+ const [ColumnManagementModal, setColumnManagementModalOpen] = useColumnManagement(
+ appliedColumns,
+ (newColumns) => setAppliedColumns(newColumns),
+ );
+
+ const [deleteFilters] = useRemoveFilter({ search, ...filter }, apply);
+
+ const filterConfig = {
+ items: [
+ searchFilter(
+ apply,
+ search,
+ intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
+ intl.formatMessage(messages.labelsFiltersSystemsSearchPlaceholder),
+ ),
+ advisoryStatusFilter(apply, filter),
+ ],
+ };
+
+ const activeFiltersConfig = buildActiveFiltersConfig(filter, search, deleteFilters);
+
+ const onSelect = useOnSelect(systems, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.advisorySystems(advisoryName),
+ queryParams,
+ selectionDispatcher: systemSelectAction,
+ totalItems,
+ });
+
+ const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
+
+ const getEntites = useGetEntities(
+ fetchAdvisorySystems,
apply,
+ { id: advisoryName },
setSearchParams,
- activateRemediationModal,
- decodedParams
-}) => {
- const dispatch = useDispatch();
- const store = useStore();
+ );
- const systems = useSelector(({ entities }) => entities?.rows || [], shallowEqual);
- const totalItems = useSelector(
- ({ entities }) => entities?.total || 0
- );
- const queryParams = useSelector(
- ({ AdvisorySystemsStore }) => AdvisorySystemsStore?.queryParams || {}
- );
- const selectedRows = useSelector(
- ({ entities }) => entities?.selectedRows || []
+ const onExport = useOnExport(
+ advisoryName,
+ queryParams,
+ {
+ csv: exportAdvisorySystemsCSV,
+ json: exportAdvisorySystemsJSON,
+ },
+ dispatch,
+ );
+
+ const remediationDataProvider = () =>
+ remediationProvider(
+ advisoryName,
+ removeUndefinedObjectKeys(selectedRows),
+ remediationIdentifiers.advisory,
);
- const { systemProfile, selectedTags,
- filter, search, page, perPage, sort } = queryParams;
-
- const [appliedColumns, setAppliedColumns] = React.useState(ADVISORY_SYSTEMS_COLUMNS);
- const [ColumnManagementModal, setColumnManagementModalOpen] =
- useColumnManagement(appliedColumns, newColumns => setAppliedColumns(newColumns));
-
- const [deleteFilters] = useRemoveFilter({ search, ...filter }, apply);
-
- const filterConfig = {
- items: [
- searchFilter(apply, search,
- intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
- intl.formatMessage(messages.labelsFiltersSystemsSearchPlaceholder)
- ),
- advisoryStatusFilter(apply, filter)
- ]
- };
-
- const activeFiltersConfig = buildActiveFiltersConfig(filter, search, deleteFilters);
-
- const onSelect = useOnSelect(
- systems,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.advisorySystems(advisoryName),
- queryParams,
- selectionDispatcher: systemSelectAction,
- totalItems
+ const bulkSelectConfig = useBulkSelectConfig(
+ selectedCount,
+ onSelect,
+ { total_items: totalItems },
+ systems,
+ null,
+ queryParams,
+ );
+
+ return (
+
+ {ColumnManagementModal}
+
+
+ mergeInventoryColumns(
+ appliedColumns.filter((column) => column.isShown),
+ inventoryColumns,
+ )
}
- );
-
- const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
-
- const getEntites = useGetEntities(fetchAdvisorySystems, apply, { id: advisoryName }, setSearchParams);
-
- const onExport = useOnExport(advisoryName, queryParams, {
- csv: exportAdvisorySystemsCSV,
- json: exportAdvisorySystemsJSON
- }, dispatch);
-
- const remediationDataProvider = () => remediationProvider(
- advisoryName,
- removeUndefinedObjectKeys(selectedRows),
- remediationIdentifiers.advisory
- );
-
- const bulkSelectConfig = useBulkSelectConfig(
- selectedCount, onSelect, { total_items: totalItems }, systems, null, queryParams
- );
-
- return (
-
- {ColumnManagementModal}
-
-
- mergeInventoryColumns(appliedColumns.filter(column => column.isShown), inventoryColumns)
- }
- showTags
- customFilters={{
- patchParams: {
- search,
- filter,
- systemProfile,
- selectedTags
- }
- }}
- paginationProps={{
- isDisabled: totalItems === 0
- }}
- onLoad={({ mergeWithEntities }) => {
- store.replaceReducer(combineReducers({
- ...defaultReducers,
- ...mergeWithEntities(
- inventoryEntitiesReducer(ADVISORY_SYSTEMS_COLUMNS, modifyAdvisorySystems),
- persistantParams({ page, perPage, sort, search }, decodedParams)
- )
- }));
- }}
- getEntities={getEntites}
- actionsConfig={{
- actions: [
- null, // first item of actions will be a big button, but we want "Manage columns" in kebab menu
- {
- label: 'Manage columns',
- onClick: () => setColumnManagementModalOpen(true)
- }
- ]
- }}
- tableProps={{
- actionResolver: (row) => systemsRowActions(activateRemediationModal, undefined, undefined, row),
- canSelectAll: false,
- variant: TableVariant.compact, className: 'patchCompactInventory', isStickyHeader: true
- }}
- filterConfig={filterConfig}
- activeFiltersConfig={activeFiltersConfig}
- exportConfig={{
- isDisabled: totalItems === 0,
- onSelect: onExport
- }}
- bulkSelect={onSelect && bulkSelectConfig}
- dedicatedAction={(
- 0}
- />
- )}
-
- />
-
- );
+ showTags
+ customFilters={{
+ patchParams: {
+ search,
+ filter,
+ systemProfile,
+ selectedTags,
+ },
+ }}
+ paginationProps={{
+ isDisabled: totalItems === 0,
+ }}
+ onLoad={({ mergeWithEntities }) => {
+ store.replaceReducer(
+ combineReducers({
+ ...defaultReducers,
+ ...mergeWithEntities(
+ inventoryEntitiesReducer(ADVISORY_SYSTEMS_COLUMNS, modifyAdvisorySystems),
+ persistantParams({ page, perPage, sort, search }, decodedParams),
+ ),
+ }),
+ );
+ }}
+ getEntities={getEntites}
+ actionsConfig={{
+ actions: [
+ null, // first item of actions will be a big button, but we want "Manage columns" in kebab menu
+ {
+ label: 'Manage columns',
+ onClick: () => setColumnManagementModalOpen(true),
+ },
+ ],
+ }}
+ tableProps={{
+ actionResolver: (row) =>
+ systemsRowActions(activateRemediationModal, undefined, undefined, row),
+ canSelectAll: false,
+ variant: TableVariant.compact,
+ className: 'patchCompactInventory',
+ isStickyHeader: true,
+ }}
+ filterConfig={filterConfig}
+ activeFiltersConfig={activeFiltersConfig}
+ exportConfig={{
+ isDisabled: totalItems === 0,
+ onSelect: onExport,
+ }}
+ bulkSelect={onSelect && bulkSelectConfig}
+ dedicatedAction={
+ 0}
+ />
+ }
+ />
+
+ );
};
AdvisorySystemsTable.propTypes = {
- advisoryName: propTypes.string,
- apply: propTypes.func,
- setSearchParams: propTypes.func,
- activateRemediationModal: propTypes.func,
- decodedParams: propTypes.object
+ advisoryName: propTypes.string,
+ apply: propTypes.func,
+ setSearchParams: propTypes.func,
+ activateRemediationModal: propTypes.func,
+ decodedParams: propTypes.object,
};
export default AdvisorySystemsTable;
diff --git a/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.test.js b/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.test.js
index ed9212034..fa18068a7 100644
--- a/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.test.js
+++ b/src/SmartComponents/AdvisorySystems/AdvisorySystemsTable.test.js
@@ -8,237 +8,242 @@ import { render, screen, waitFor } from '@testing-library/react';
initMocks();
const mockState = {
- entities: {
- rows: systemRows,
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 10
- },
- expandedRows: {},
- selectedRows: { 'test-system-1': true },
- error: {},
- status: 'resolved',
- total: 101
+ entities: {
+ rows: systemRows,
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 10,
},
- AdvisorySystemsStore: {
- queryParams: {}
- }
+ expandedRows: {},
+ selectedRows: { 'test-system-1': true },
+ error: {},
+ status: 'resolved',
+ total: 101,
+ },
+ AdvisorySystemsStore: {
+ queryParams: {},
+ },
};
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore(state);
+ const mockStore = configureStore([]);
+ return mockStore(state);
};
const renderComponent = async (mockedStore) => {
- render(
-
- );
-
- await waitFor(() => {
- expect(
- screen.getByTestId('inventory-mock-component')
- ).toBeInTheDocument();
- });
+ render(
+
+
+ ,
+ );
+
+ await waitFor(() => {
+ expect(screen.getByTestId('inventory-mock-component')).toBeInTheDocument();
+ });
};
describe('AdvisorySystemsTable.js', () => {
- it('Should render inventory table', async () => {
- await renderComponent(mockState);
- expect(screen.getByTestId('inventory-mock-component')).toBeVisible();
- });
-
- it('Should provide customFilters prop', async () => {
- const filteredState = {
- ...mockState,
- AdvisorySystemsStore: {
- queryParams: {
- filter: { status: ['Installable'] },
- search: 'test-search',
- selectedTags: ['tags=test-tag'],
- systemProfile: { ansible: { controller_version: 'not_nil' } }
- }
- }
- };
-
- await renderComponent(filteredState);
- await waitFor(() =>
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- customFilters: {
- patchParams: {
- filter: { status: ['Installable'] },
- search: 'test-search',
- selectedTags: ['tags=test-tag'],
- systemProfile: { ansible: { controller_version: 'not_nil' } }
- }
- }
- }),
- {}
- )
- );
- });
-
- it('should use os and tag filter from Inventory', async () => {
- await renderComponent(mockState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- hideFilters: {
- all: true,
- tags: false,
- operatingSystem: false
- }
- }),
- {}
- );
- });
-
- it('should disable pagination and export when there are no rows', async () => {
- const emptyStateState = {
- ...mockState,
- entities: {
- ...mockState.entities,
- total: 0
- }
- };
-
- await renderComponent(emptyStateState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- paginationProps: {
- isDisabled: true
- }
- }),
- {}
- );
-
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- exportConfig: {
- isDisabled: true,
- onSelect: expect.any(Function)
- }
- }),
- {}
- );
- });
-
- it('should provide filterConfig', async () => {
- await renderComponent(mockState);
- await waitFor(() => expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- filterConfig: {
- items:
- [
- {
- filterValues: {
- 'aria-label': 'search-field',
- onChange: expect.any(Function),
- placeholder: 'Filter by name',
- value: undefined
- },
- label: 'System',
- type: 'text'
- },
- {
- filterValues: {
- items: [
- { label: 'Installable', value: 'Installable' },
- { label: 'Applicable', value: 'Applicable' }
- ],
- onChange: expect.any(Function),
- placeholder: 'Filter by status',
- value: undefined
- },
- label: 'Status',
- type: 'checkbox'
- }
- ]
- }
- }),
- {}
- ));
- });
-
- it('should provide tableProps', async () => {
- await renderComponent(mockState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- tableProps: {
- actionResolver: expect.any(Function),
- canSelectAll: false,
- className: 'patchCompactInventory',
- isStickyHeader: true,
- variant: 'compact'
- }
- }),
- {}
- );
- });
-
- it('should provide activeFilters config', async () => {
- const filteredState = {
- ...mockState,
- AdvisorySystemsStore: {
- queryParams: {
- filter: { status: ['Installable'] }
- }
- }
- };
-
- await renderComponent(filteredState);
-
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- activeFiltersConfig: {
- deleteTitle: 'Reset filters',
- filters: [{
- category: 'Status',
- chips: [{
- id: 'status',
- name: 'Installable',
- value: 'Installable'
- }],
- id: 'status'
- }],
- onDelete: expect.any(Function)
- }
- }),
- {}
- );
- });
-
- it('should provide bulkSelect config', async () => {
- await renderComponent(mockState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- bulkSelect: {
- checked: null,
- isDisabled: false,
- count: 1,
- items: [
- {
- onClick: expect.any(Function),
- title: 'Select none (0)'
- },
- {
- onClick: expect.any(Function),
- title: 'Select page (2)'
- },
- {
- onClick: expect.any(Function),
- title: 'Select all (101)'
- }
- ],
- onSelect: expect.any(Function),
- toggleProps: {
- 'aria-label': 'Select',
- 'data-ouia-component-type': 'bulk-select-toggle-button'
- }
- }
- }),
- {}
- );
- });
+ it('Should render inventory table', async () => {
+ await renderComponent(mockState);
+ expect(screen.getByTestId('inventory-mock-component')).toBeVisible();
+ });
+
+ it('Should provide customFilters prop', async () => {
+ const filteredState = {
+ ...mockState,
+ AdvisorySystemsStore: {
+ queryParams: {
+ filter: { status: ['Installable'] },
+ search: 'test-search',
+ selectedTags: ['tags=test-tag'],
+ systemProfile: { ansible: { controller_version: 'not_nil' } },
+ },
+ },
+ };
+
+ await renderComponent(filteredState);
+ await waitFor(() =>
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ customFilters: {
+ patchParams: {
+ filter: { status: ['Installable'] },
+ search: 'test-search',
+ selectedTags: ['tags=test-tag'],
+ systemProfile: { ansible: { controller_version: 'not_nil' } },
+ },
+ },
+ }),
+ {},
+ ),
+ );
+ });
+
+ it('should use os and tag filter from Inventory', async () => {
+ await renderComponent(mockState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ hideFilters: {
+ all: true,
+ tags: false,
+ operatingSystem: false,
+ },
+ }),
+ {},
+ );
+ });
+
+ it('should disable pagination and export when there are no rows', async () => {
+ const emptyStateState = {
+ ...mockState,
+ entities: {
+ ...mockState.entities,
+ total: 0,
+ },
+ };
+
+ await renderComponent(emptyStateState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ paginationProps: {
+ isDisabled: true,
+ },
+ }),
+ {},
+ );
+
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ exportConfig: {
+ isDisabled: true,
+ onSelect: expect.any(Function),
+ },
+ }),
+ {},
+ );
+ });
+
+ it('should provide filterConfig', async () => {
+ await renderComponent(mockState);
+ await waitFor(() =>
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ filterConfig: {
+ items: [
+ {
+ filterValues: {
+ 'aria-label': 'search-field',
+ onChange: expect.any(Function),
+ placeholder: 'Filter by name',
+ value: undefined,
+ },
+ label: 'System',
+ type: 'text',
+ },
+ {
+ filterValues: {
+ items: [
+ { label: 'Installable', value: 'Installable' },
+ { label: 'Applicable', value: 'Applicable' },
+ ],
+ onChange: expect.any(Function),
+ placeholder: 'Filter by status',
+ value: undefined,
+ },
+ label: 'Status',
+ type: 'checkbox',
+ },
+ ],
+ },
+ }),
+ {},
+ ),
+ );
+ });
+
+ it('should provide tableProps', async () => {
+ await renderComponent(mockState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ tableProps: {
+ actionResolver: expect.any(Function),
+ canSelectAll: false,
+ className: 'patchCompactInventory',
+ isStickyHeader: true,
+ variant: 'compact',
+ },
+ }),
+ {},
+ );
+ });
+
+ it('should provide activeFilters config', async () => {
+ const filteredState = {
+ ...mockState,
+ AdvisorySystemsStore: {
+ queryParams: {
+ filter: { status: ['Installable'] },
+ },
+ },
+ };
+
+ await renderComponent(filteredState);
+
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ activeFiltersConfig: {
+ deleteTitle: 'Reset filters',
+ filters: [
+ {
+ category: 'Status',
+ chips: [
+ {
+ id: 'status',
+ name: 'Installable',
+ value: 'Installable',
+ },
+ ],
+ id: 'status',
+ },
+ ],
+ onDelete: expect.any(Function),
+ },
+ }),
+ {},
+ );
+ });
+
+ it('should provide bulkSelect config', async () => {
+ await renderComponent(mockState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ bulkSelect: {
+ checked: null,
+ isDisabled: false,
+ count: 1,
+ items: [
+ {
+ onClick: expect.any(Function),
+ title: 'Select none (0)',
+ },
+ {
+ onClick: expect.any(Function),
+ title: 'Select page (2)',
+ },
+ {
+ onClick: expect.any(Function),
+ title: 'Select all (101)',
+ },
+ ],
+ onSelect: expect.any(Function),
+ toggleProps: {
+ 'aria-label': 'Select',
+ 'data-ouia-component-type': 'bulk-select-toggle-button',
+ },
+ },
+ }),
+ {},
+ );
+ });
});
diff --git a/src/SmartComponents/Modals/AssignSystemsModal.js b/src/SmartComponents/Modals/AssignSystemsModal.js
index f42bf9fc2..9361bd4f4 100644
--- a/src/SmartComponents/Modals/AssignSystemsModal.js
+++ b/src/SmartComponents/Modals/AssignSystemsModal.js
@@ -1,15 +1,7 @@
import React, { useEffect, useState } from 'react';
import propTypes from 'prop-types';
-import {
- Button,
- Stack,
- StackItem,
- Form,
- Spinner
-} from '@patternfly/react-core';
-import {
- Modal
-} from '@patternfly/react-core/deprecated';
+import { Button, Stack, StackItem, Form, Spinner } from '@patternfly/react-core';
+import { Modal } from '@patternfly/react-core/deprecated';
import { injectIntl } from 'react-intl';
import SelectExistingSets from '../PatchSetWizard/InputFields/SelectExistingSets';
import messages from '../../Messages';
@@ -23,144 +15,143 @@ import { useFetchBatched } from '../../Utilities/hooks';
import isEmpty from 'lodash/isEmpty';
const AssignSystemsModal = ({ patchSetState = {}, setPatchSetState, intl, totalItems }) => {
- const dispatch = useDispatch();
+ const dispatch = useDispatch();
- const { systemsIDs, isAssignSystemsModalOpen } = patchSetState;
- const [selectedPatchSet, setSelectedPatchSet] = useState([]);
- const [selectedPatchSetDetails, setSelectedPatchSetDetails] = useState({});
+ const { systemsIDs, isAssignSystemsModalOpen } = patchSetState;
+ const [selectedPatchSet, setSelectedPatchSet] = useState([]);
+ const [selectedPatchSetDetails, setSelectedPatchSetDetails] = useState({});
- const [systemsNotManagedBySatellite, setSystemsNotManagedBySatellite] = useState([]);
- const [systemsLoading, setSystemsLoading] = useState(true);
- const { fetchBatched } = useFetchBatched();
+ const [systemsNotManagedBySatellite, setSystemsNotManagedBySatellite] = useState([]);
+ const [systemsLoading, setSystemsLoading] = useState(true);
+ const { fetchBatched } = useFetchBatched();
- const closeModal = () => {
- setPatchSetState({
- isAssignSystemsModalOpen: !isAssignSystemsModalOpen,
- systemsIDs: []
- });
- setSelectedPatchSet([]);
- setSelectedPatchSetDetails({});
- };
+ const closeModal = () => {
+ setPatchSetState({
+ isAssignSystemsModalOpen: !isAssignSystemsModalOpen,
+ systemsIDs: [],
+ });
+ setSelectedPatchSet([]);
+ setSelectedPatchSetDetails({});
+ };
- const submitModal = () => {
- const systems = systemsNotManagedBySatellite.reduce((obj, item) => {
- obj[item] = true;
- return obj;
- }, {});
+ const submitModal = () => {
+ const systems = systemsNotManagedBySatellite.reduce((obj, item) => {
+ obj[item] = true;
+ return obj;
+ }, {});
- updatePatchSets({ inventory_ids: systemsIDs }, selectedPatchSetDetails.id)
- .then(() => {
- dispatch(addNotification(patchSetAssignSystemsNotifications(Object.keys(systems).length).success));
- setPatchSetState({
- ...patchSetState,
- shouldRefresh: true,
- isAssignSystemsModalOpen: false,
- systemsIDs: []
- });
- })
- .catch(() => {
- dispatch(addNotification(patchSetAssignSystemsNotifications().failure));
+ updatePatchSets({ inventory_ids: systemsIDs }, selectedPatchSetDetails.id)
+ .then(() => {
+ dispatch(
+ addNotification(patchSetAssignSystemsNotifications(Object.keys(systems).length).success),
+ );
+ setPatchSetState({
+ ...patchSetState,
+ shouldRefresh: true,
+ isAssignSystemsModalOpen: false,
+ systemsIDs: [],
});
+ })
+ .catch(() => {
+ dispatch(addNotification(patchSetAssignSystemsNotifications().failure));
+ });
- closeModal();
- };
+ closeModal();
+ };
- const openWizard = () => {
- setPatchSetState({
- ...patchSetState,
- isPatchSetWizardOpen: true,
- systemsIDs: filterSelectedActiveSystemIDs(systemsIDs),
- shouldRefresh: false
- });
- setSelectedPatchSet([]);
- setSelectedPatchSetDetails({});
- setSystemsLoading(true);
- };
+ const openWizard = () => {
+ setPatchSetState({
+ ...patchSetState,
+ isPatchSetWizardOpen: true,
+ systemsIDs: filterSelectedActiveSystemIDs(systemsIDs),
+ shouldRefresh: false,
+ });
+ setSelectedPatchSet([]);
+ setSelectedPatchSetDetails({});
+ setSystemsLoading(true);
+ };
- useEffect(() => {
- if (systemsIDs && !isEmpty(systemsIDs)) {
- setSystemsLoading(true);
- filterSatelliteManagedSystems(
- Object.keys(systemsIDs),
- fetchBatched,
- totalItems
- ).then(result => {
- setSystemsNotManagedBySatellite(result);
- setSystemsLoading(false);
- });
- }
- }, [systemsIDs]);
+ useEffect(() => {
+ if (systemsIDs && !isEmpty(systemsIDs)) {
+ setSystemsLoading(true);
+ filterSatelliteManagedSystems(Object.keys(systemsIDs), fetchBatched, totalItems).then(
+ (result) => {
+ setSystemsNotManagedBySatellite(result);
+ setSystemsLoading(false);
+ },
+ );
+ }
+ }, [systemsIDs]);
- const systemsManagedBySatelliteCount = Object.keys(systemsIDs).length - systemsNotManagedBySatellite.length;
+ const systemsManagedBySatelliteCount =
+ Object.keys(systemsIDs).length - systemsNotManagedBySatellite.length;
- return (
-
- {intl.formatMessage(messages.templateApply)}
- ,
-
- ]}
- data-testid='assign-systems-modal'
- >
- {systemsLoading
- ?
- : systemsNotManagedBySatellite.length === 0
- ? systemsNotManagedBySatellite.length === 1
- ? 'Template cannot be applied to the selected system.'
- : 'Template cannot be applied to any of the selected systems.'
- :
-
- {intl.formatMessage(messages.templateSelect, {
- systemCount: systemsNotManagedBySatellite.length,
- b: (...chunks) => {chunks}
- })}
-
- {systemsManagedBySatelliteCount > 0 && {
- intl.formatMessage(messages.templateSelectSatellite, {
- systemCount: systemsManagedBySatelliteCount,
- b: (...chunks) => {chunks}
- })}
-
- }
-
-
-
-
- {intl.formatMessage(messages.templateOr)}
-
-
-
-
-
- }
-
- );
+ return (
+
+ {intl.formatMessage(messages.templateApply)}
+ ,
+ ,
+ ]}
+ data-testid='assign-systems-modal'
+ >
+ {systemsLoading ? (
+
+ ) : systemsNotManagedBySatellite.length === 0 ? (
+ systemsNotManagedBySatellite.length === 1 ? (
+ 'Template cannot be applied to the selected system.'
+ ) : (
+ 'Template cannot be applied to any of the selected systems.'
+ )
+ ) : (
+
+
+ {intl.formatMessage(messages.templateSelect, {
+ systemCount: systemsNotManagedBySatellite.length,
+ b: (...chunks) => {chunks},
+ })}
+
+ {systemsManagedBySatelliteCount > 0 && (
+
+ {intl.formatMessage(messages.templateSelectSatellite, {
+ systemCount: systemsManagedBySatelliteCount,
+ b: (...chunks) => {chunks},
+ })}
+
+ )}
+
+
+
+ {intl.formatMessage(messages.templateOr)}
+
+
+
+
+ )}
+
+ );
};
AssignSystemsModal.propTypes = {
- intl: propTypes.any,
- setPatchSetState: propTypes.func,
- patchSetState: propTypes.object,
- totalItems: propTypes.number
+ intl: propTypes.any,
+ setPatchSetState: propTypes.func,
+ patchSetState: propTypes.object,
+ totalItems: propTypes.number,
};
export default injectIntl(AssignSystemsModal);
diff --git a/src/SmartComponents/Modals/DeleteSetModal.js b/src/SmartComponents/Modals/DeleteSetModal.js
index e595b192e..720de77db 100644
--- a/src/SmartComponents/Modals/DeleteSetModal.js
+++ b/src/SmartComponents/Modals/DeleteSetModal.js
@@ -1,57 +1,63 @@
import React, { useState } from 'react';
import propTypes from 'prop-types';
-import {
- Button,
- Checkbox
-} from '@patternfly/react-core';
-import {
- Modal
-} from '@patternfly/react-core/deprecated';
+import { Button, Checkbox } from '@patternfly/react-core';
+import { Modal } from '@patternfly/react-core/deprecated';
import messages from '../../Messages';
import { intl } from '../../Utilities/IntlProvider';
const DeleteSetModal = ({ isModalOpen, setModalOpen, templateName, onConfirm }) => {
- const [isCheckboxChecked, setCheckboxChecked] = useState(false);
+ const [isCheckboxChecked, setCheckboxChecked] = useState(false);
- const onClose = () => {
- setModalOpen(false);
- setCheckboxChecked(false);
- };
+ const onClose = () => {
+ setModalOpen(false);
+ setCheckboxChecked(false);
+ };
- return (
- {onClose(); onConfirm();}} isDisabled={!isCheckboxChecked}>
- {intl.formatMessage(messages.labelsDelete)}
- ,
-
- ]}
+ return (
+ {
+ onClose();
+ onConfirm();
+ }}
+ isDisabled={!isCheckboxChecked}
>
- {intl.formatMessage(messages.titlesTemplateDeleteModalText, { templateName, b: (...chunks) => {chunks} })}
- setCheckboxChecked(value)}
- label={intl.formatMessage(messages.titlesTemplateDeleteModalCheckbox)}
- id="template-delete-modal-checkbox"
- />
-
- );
+ {intl.formatMessage(messages.labelsDelete)}
+ ,
+ ,
+ ]}
+ >
+ {intl.formatMessage(messages.titlesTemplateDeleteModalText, {
+ templateName,
+ b: (...chunks) => {chunks},
+ })}
+ setCheckboxChecked(value)}
+ label={intl.formatMessage(messages.titlesTemplateDeleteModalCheckbox)}
+ id='template-delete-modal-checkbox'
+ />
+
+ );
};
DeleteSetModal.propTypes = {
- isModalOpen: propTypes.bool,
- setModalOpen: propTypes.func,
- templateName: propTypes.string,
- onConfirm: propTypes.func
+ isModalOpen: propTypes.bool,
+ setModalOpen: propTypes.func,
+ templateName: propTypes.string,
+ onConfirm: propTypes.func,
};
export default DeleteSetModal;
diff --git a/src/SmartComponents/Modals/Helpers.js b/src/SmartComponents/Modals/Helpers.js
index 07daae761..dcf958fe7 100644
--- a/src/SmartComponents/Modals/Helpers.js
+++ b/src/SmartComponents/Modals/Helpers.js
@@ -4,41 +4,34 @@ import { GridItem } from '@patternfly/react-core';
import messages from '../../Messages';
import { fetchIDs } from '../../Utilities/api';
-const filterChosenSystems = (urlFilter, systemsIDs, fetchBatched, totalItems) => {
- return fetchBatched(
- (filter) => fetchIDs(
- '/ids/systems',
- filter
- ),
- {
- ...urlFilter,
- filter: { stale: [true, false] }
- },
- totalItems,
- 100
- ).then((systemsNotManagedBySatellite) => {
- const aggregatedResult = systemsNotManagedBySatellite.flatMap(({ data }) => data);
- return systemsIDs.filter(systemID =>{
- return aggregatedResult?.some(system => system.id === systemID);
- }
- );
- });
-};
+const filterChosenSystems = (urlFilter, systemsIDs, fetchBatched, totalItems) =>
+ fetchBatched(
+ (filter) => fetchIDs('/ids/systems', filter),
+ {
+ ...urlFilter,
+ filter: { stale: [true, false] },
+ },
+ totalItems,
+ 100,
+ ).then((systemsNotManagedBySatellite) => {
+ const aggregatedResult = systemsNotManagedBySatellite.flatMap(({ data }) => data);
+ return systemsIDs.filter((systemID) =>
+ aggregatedResult?.some((system) => system.id === systemID),
+ );
+ });
-export const filterSystemsWithoutTemplates = (systemsIDs, fetchBatched, totalItems) => {
- const urlFilter = { [`filter[template_name]`]: 'neq:' };
- return filterChosenSystems(urlFilter, systemsIDs, fetchBatched, totalItems);
+export const filterSystemsWithoutTemplates = (systemsIDs, fetchBatched, totalItems) => {
+ const urlFilter = { [`filter[template_name]`]: 'neq:' };
+ return filterChosenSystems(urlFilter, systemsIDs, fetchBatched, totalItems);
};
-export const filterSatelliteManagedSystems = (systemsIDs, fetchBatched, totalItems) => {
- const urlFilter = { 'filter[satellite_managed]': 'false' };
- return filterChosenSystems(urlFilter, systemsIDs, fetchBatched, totalItems);
+export const filterSatelliteManagedSystems = (systemsIDs, fetchBatched, totalItems) => {
+ const urlFilter = { 'filter[satellite_managed]': 'false' };
+ return filterChosenSystems(urlFilter, systemsIDs, fetchBatched, totalItems);
};
-export const renderUnassignModalMessages = (bodyMessage, systemsCount, intl) => (
- {intl.formatMessage(
- messages[bodyMessage],
- { systemsCount, b: (...chunks) => {chunks} }
- )}
-);
-
+export const renderUnassignModalMessages = (bodyMessage, systemsCount, intl) => (
+
+ {intl.formatMessage(messages[bodyMessage], { systemsCount, b: (...chunks) => {chunks} })}
+
+);
diff --git a/src/SmartComponents/Modals/UnassignSystemsModal.js b/src/SmartComponents/Modals/UnassignSystemsModal.js
index a7cdae3a9..bb836d46a 100644
--- a/src/SmartComponents/Modals/UnassignSystemsModal.js
+++ b/src/SmartComponents/Modals/UnassignSystemsModal.js
@@ -1,13 +1,7 @@
import React, { Fragment, useEffect, useState } from 'react';
import propTypes from 'prop-types';
-import {
- Button,
- Grid,
- Skeleton
-} from '@patternfly/react-core';
-import {
- Modal
-} from '@patternfly/react-core/deprecated';
+import { Button, Grid, Skeleton } from '@patternfly/react-core';
+import { Modal } from '@patternfly/react-core/deprecated';
import { injectIntl } from 'react-intl';
import messages from '../../Messages';
@@ -15,88 +9,99 @@ import { useUnassignSystemsHook } from './useUnassignSystemsHook';
import { renderUnassignModalMessages, filterSystemsWithoutTemplates } from './Helpers';
import { useFetchBatched } from '../../Utilities/hooks';
-const UnassignSystemsModal = ({ unassignSystemsModalState = {}, setUnassignSystemsModalOpen, intl, totalItems }) => {
- const { systemsIDs, isUnassignSystemsModalOpen } = unassignSystemsModalState;
- const [systemsWithPatchSet, setSystemWithPatchSet] = useState([]);
- const [systemsLoading, setSystemsLoading] = useState(true);
- const { fetchBatched } = useFetchBatched();
+const UnassignSystemsModal = ({
+ unassignSystemsModalState = {},
+ setUnassignSystemsModalOpen,
+ intl,
+ totalItems,
+}) => {
+ const { systemsIDs, isUnassignSystemsModalOpen } = unassignSystemsModalState;
+ const [systemsWithPatchSet, setSystemWithPatchSet] = useState([]);
+ const [systemsLoading, setSystemsLoading] = useState(true);
+ const { fetchBatched } = useFetchBatched();
- const handleModalToggle = (shouldRefresh) => {
- setUnassignSystemsModalOpen({
- isUnassignSystemsModalOpen: !isUnassignSystemsModalOpen,
- systemsIDs: [],
- shouldRefresh
- });
- };
+ const handleModalToggle = (shouldRefresh) => {
+ setUnassignSystemsModalOpen({
+ isUnassignSystemsModalOpen: !isUnassignSystemsModalOpen,
+ systemsIDs: [],
+ shouldRefresh,
+ });
+ };
- const handleModalClose = () => {
- handleModalToggle(false);
- };
+ const handleModalClose = () => {
+ handleModalToggle(false);
+ };
- const handleUnassignment = useUnassignSystemsHook(handleModalToggle, systemsWithPatchSet);
+ const handleUnassignment = useUnassignSystemsHook(handleModalToggle, systemsWithPatchSet);
- useEffect(() => {
- setSystemsLoading(true);
+ useEffect(() => {
+ setSystemsLoading(true);
- filterSystemsWithoutTemplates(
- systemsIDs,
- fetchBatched,
- totalItems
- )
- .then(result => {
- setSystemWithPatchSet(result);
- setSystemsLoading(false);
- });
- }, [systemsIDs]);
+ filterSystemsWithoutTemplates(systemsIDs, fetchBatched, totalItems).then((result) => {
+ setSystemWithPatchSet(result);
+ setSystemsLoading(false);
+ });
+ }, [systemsIDs]);
- const systemsWithoutPatchSetCount = systemsIDs.length - systemsWithPatchSet.length;
+ const systemsWithoutPatchSetCount = systemsIDs.length - systemsWithPatchSet.length;
- return (
-
- {intl.formatMessage(messages.labelsRemove)}
- ,
-
- ]}
- data-testid='unassign-systems-modal'
+ return (
+
-
- {systemsLoading
- ?
- :
- {systemsWithPatchSet.length === 0 &&
- renderUnassignModalMessages('textUnassignSystemsNoAssignedSystems', systemsWithPatchSet.length, intl)
- }
- {systemsWithPatchSet.length > 0 &&
- renderUnassignModalMessages('textUnassignSystemsStatement', systemsWithPatchSet.length, intl)
- }
- {systemsWithPatchSet.length > 0 && systemsWithoutPatchSetCount > 0 &&
- renderUnassignModalMessages('textUnassignSystemsWarning', systemsWithoutPatchSetCount, intl)
- }
-
- }
-
-
- );
+ {intl.formatMessage(messages.labelsRemove)}
+ ,
+ ,
+ ]}
+ data-testid='unassign-systems-modal'
+ >
+
+ {systemsLoading ? (
+
+ ) : (
+
+ {systemsWithPatchSet.length === 0 &&
+ renderUnassignModalMessages(
+ 'textUnassignSystemsNoAssignedSystems',
+ systemsWithPatchSet.length,
+ intl,
+ )}
+ {systemsWithPatchSet.length > 0 &&
+ renderUnassignModalMessages(
+ 'textUnassignSystemsStatement',
+ systemsWithPatchSet.length,
+ intl,
+ )}
+ {systemsWithPatchSet.length > 0 &&
+ systemsWithoutPatchSetCount > 0 &&
+ renderUnassignModalMessages(
+ 'textUnassignSystemsWarning',
+ systemsWithoutPatchSetCount,
+ intl,
+ )}
+
+ )}
+
+
+ );
};
UnassignSystemsModal.propTypes = {
- intl: propTypes.any,
- setUnassignSystemsModalOpen: propTypes.func,
- unassignSystemsModalState: propTypes.object,
- totalItems: propTypes.number
+ intl: propTypes.any,
+ setUnassignSystemsModalOpen: propTypes.func,
+ unassignSystemsModalState: propTypes.object,
+ totalItems: propTypes.number,
};
export default injectIntl(UnassignSystemsModal);
diff --git a/src/SmartComponents/Modals/UnassignSystemsModal.test.js b/src/SmartComponents/Modals/UnassignSystemsModal.test.js
index 693aac090..e5f0cde5e 100644
--- a/src/SmartComponents/Modals/UnassignSystemsModal.test.js
+++ b/src/SmartComponents/Modals/UnassignSystemsModal.test.js
@@ -10,85 +10,87 @@ import userEvent from '@testing-library/user-event';
initMocks();
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- unassignSystemFromPatchSet: jest.fn(),
- fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test_1' }] }))
+ ...jest.requireActual('../../Utilities/api'),
+ unassignSystemFromPatchSet: jest.fn(),
+ fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test_1' }] })),
}));
jest.mock('react-redux', () => ({
- useDispatch: jest.fn(() => () => {})
+ useDispatch: jest.fn(() => () => {}),
}));
jest.mock('@redhat-cloud-services/frontend-components-notifications/redux', () => ({
- addNotification: jest.fn(() => {})
+ addNotification: jest.fn(() => {}),
}));
let unassignSystemsModalState = {
- isUnassignSystemsModalOpen: true,
- systemsIDs: ['test_1', 'test_2', 'test_3']
+ isUnassignSystemsModalOpen: true,
+ systemsIDs: ['test_1', 'test_2', 'test_3'],
};
const setUnassignSystemsModalOpen = (modalState) => {
- unassignSystemsModalState = modalState;
+ unassignSystemsModalState = modalState;
};
beforeEach(() => {
- unassignSystemsModalState.isUnassignSystemsModalOpen = true;
- render(
-
-
-
- );
+ unassignSystemsModalState.isUnassignSystemsModalOpen = true;
+ render(
+
+
+ ,
+ );
});
const user = userEvent.setup();
describe('UnassignSystemsModal', () => {
- it('Should remove systems from a patch set and handle success notification', async () => {
- unassignSystemsModalState.isUnassignSystemsModalOpen = true;
- unassignSystemFromPatchSet.mockReturnValueOnce(
- new Promise((resolve) => {
- resolve({ status: 200 });
- })
- );
+ it('Should remove systems from a patch set and handle success notification', async () => {
+ unassignSystemsModalState.isUnassignSystemsModalOpen = true;
+ unassignSystemFromPatchSet.mockReturnValueOnce(
+ new Promise((resolve) => {
+ resolve({ status: 200 });
+ }),
+ );
- await user.click(screen.getByText('Remove'));
+ await user.click(screen.getByText('Remove'));
- await waitFor(() => {
- expect(addNotification).toHaveBeenCalledWith(
- patchSetUnassignSystemsNotifications(1).success
- );
- expect(unassignSystemsModalState).toEqual({ isUnassignSystemsModalOpen: false, shouldRefresh: true, systemsIDs: [] });
- expect(unassignSystemFromPatchSet).toHaveBeenCalledWith({ inventory_ids: ['test_1'] });
- });
+ await waitFor(() => {
+ expect(addNotification).toHaveBeenCalledWith(patchSetUnassignSystemsNotifications(1).success);
+ expect(unassignSystemsModalState).toEqual({
+ isUnassignSystemsModalOpen: false,
+ shouldRefresh: true,
+ systemsIDs: [],
+ });
+ expect(unassignSystemFromPatchSet).toHaveBeenCalledWith({ inventory_ids: ['test_1'] });
});
+ });
- it('should close the modal', async () => {
- unassignSystemsModalState.isUnassignSystemsModalOpen = true;
- await user.click(screen.getByLabelText('Close'));
+ it('should close the modal', async () => {
+ unassignSystemsModalState.isUnassignSystemsModalOpen = true;
+ await user.click(screen.getByLabelText('Close'));
- await waitFor(() => {
- expect(unassignSystemsModalState.isUnassignSystemsModalOpen).toBeFalsy();
- });
+ await waitFor(() => {
+ expect(unassignSystemsModalState.isUnassignSystemsModalOpen).toBeFalsy();
});
+ });
- it('Should return correct notification text with 1 system', () => {
- const result = patchSetUnassignSystemsNotifications(1);
- expect(result.success).toEqual({
- title: `Systems succesfully removed from this Patch template.`,
- description: `1 system removed from Patch template(s)`,
- variant: 'success'
- });
+ it('Should return correct notification text with 1 system', () => {
+ const result = patchSetUnassignSystemsNotifications(1);
+ expect(result.success).toEqual({
+ title: `Systems succesfully removed from this Patch template.`,
+ description: `1 system removed from Patch template(s)`,
+ variant: 'success',
});
+ });
- it('Should return correct notification text with multiple systems', () => {
- const result = patchSetUnassignSystemsNotifications(2);
- expect(result.success).toEqual({
- title: `Systems succesfully removed from this Patch template.`,
- description: `2 systems removed from Patch template(s)`,
- variant: 'success'
- });
+ it('Should return correct notification text with multiple systems', () => {
+ const result = patchSetUnassignSystemsNotifications(2);
+ expect(result.success).toEqual({
+ title: `Systems succesfully removed from this Patch template.`,
+ description: `2 systems removed from Patch template(s)`,
+ variant: 'success',
});
+ });
});
diff --git a/src/SmartComponents/Modals/useUnassignSystemsHook.js b/src/SmartComponents/Modals/useUnassignSystemsHook.js
index 1f0788e7b..e2a3e9972 100644
--- a/src/SmartComponents/Modals/useUnassignSystemsHook.js
+++ b/src/SmartComponents/Modals/useUnassignSystemsHook.js
@@ -5,32 +5,27 @@ import { unassignSystemFromPatchSet } from '../../Utilities/api';
import { patchSetUnassignSystemsNotifications } from '../PatchSet/PatchSetAssets';
/**
-*Handles removing one or more systems from different patch sets.
-* @param {Function} [handleModalToggle] function to close the modal on callback
-* @param {Array} [systemsWithPatchSet] array of systems to be removed
-* @returns {handleSystemsRemoval}
-*/
+ *Handles removing one or more systems from different patch sets.
+ * @param {Function} [handleModalToggle] function to close the modal on callback
+ * @param {Array} [systemsWithPatchSet] array of systems to be removed
+ * @returns {handleSystemsRemoval}
+ */
export const useUnassignSystemsHook = (handleModalToggle, systemsWithPatchSet) => {
- const dispatch = useDispatch();
- const handleSystemsRemoval = async () => {
- const result = await unassignSystemFromPatchSet({ inventory_ids: systemsWithPatchSet });
- handleModalToggle(true);
+ const dispatch = useDispatch();
+ const handleSystemsRemoval = async () => {
+ const result = await unassignSystemFromPatchSet({ inventory_ids: systemsWithPatchSet });
+ handleModalToggle(true);
- if (result.status === 200) {
- dispatch(
- addNotification(
- patchSetUnassignSystemsNotifications(systemsWithPatchSet?.length || 0).success
- )
- );
- }
- else {
- dispatch(
- addNotification(
- patchSetUnassignSystemsNotifications().failure
- )
- );
- }
- };
+ if (result.status === 200) {
+ dispatch(
+ addNotification(
+ patchSetUnassignSystemsNotifications(systemsWithPatchSet?.length || 0).success,
+ ),
+ );
+ } else {
+ dispatch(addNotification(patchSetUnassignSystemsNotifications().failure));
+ }
+ };
- return handleSystemsRemoval;
+ return handleSystemsRemoval;
};
diff --git a/src/SmartComponents/PackageDetail/PackageDetail.js b/src/SmartComponents/PackageDetail/PackageDetail.js
index 5cceaa03b..5a7323543 100644
--- a/src/SmartComponents/PackageDetail/PackageDetail.js
+++ b/src/SmartComponents/PackageDetail/PackageDetail.js
@@ -15,73 +15,74 @@ import ErrorHandler from '../../PresentationalComponents/Snippets/ErrorHandler';
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
const PackageDetail = () => {
- const dispatch = useDispatch();
- const { packageName } = useParams();
- const chrome = useChrome();
+ const dispatch = useDispatch();
+ const { packageName } = useParams();
+ const chrome = useChrome();
- useEffect(()=>{
- packageName && chrome.updateDocumentTitle(`${packageName} - Packages - Content | RHEL`, true);
- }, [chrome, packageName]);
+ useEffect(() => {
+ packageName && chrome.updateDocumentTitle(`${packageName} - Packages - Content | RHEL`, true);
+ }, [chrome, packageName]);
- const packageDetails = useSelector(
- ({ PackageDetailStore }) => PackageDetailStore
- );
- const status = useSelector(
- ({ PackageDetailStore }) => PackageDetailStore.status
- );
+ const packageDetails = useSelector(({ PackageDetailStore }) => PackageDetailStore);
+ const status = useSelector(({ PackageDetailStore }) => PackageDetailStore.status);
- React.useEffect(() => {
- dispatch(fetchPackageDetails({ packageName }));
- }, []);
+ React.useEffect(() => {
+ dispatch(fetchPackageDetails({ packageName }));
+ }, []);
- React.useEffect(() => {
- return () => {
- dispatch(clearNotifications());
- dispatch(clearPackageDetailStore());
- };
- }, []);
+ React.useEffect(
+ () => () => {
+ dispatch(clearNotifications());
+ dispatch(clearPackageDetailStore());
+ },
+ [],
+ );
- const { attributes } = packageDetails.data;
+ const { attributes } = packageDetails.data;
- return (
-
- {status.hasError ? :
- }
-
-
-
-
-
- {intl.formatMessage(messages.titlesAffectedSystems)}
-
-
-
- {status.hasError
- && < ErrorHandler />
- || (!status.isLoading && )
- }
-
-
-
-
- );
+ return (
+
+
+ {status.hasError ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ {intl.formatMessage(messages.titlesAffectedSystems)}
+
+
+
+
+ {(status.hasError && ) ||
+ (!status.isLoading && )}
+
+
+
+
+ );
};
export default PackageDetail;
diff --git a/src/SmartComponents/PackageDetail/PackageDetail.test.js b/src/SmartComponents/PackageDetail/PackageDetail.test.js
index 3fb2f4729..b0fbdf485 100644
--- a/src/SmartComponents/PackageDetail/PackageDetail.test.js
+++ b/src/SmartComponents/PackageDetail/PackageDetail.test.js
@@ -11,76 +11,76 @@ import { queryByText } from '@testing-library/dom';
initMocks();
jest.mock('react-redux', () => ({
- ...jest.requireActual('react-redux'),
- useSelector: jest.fn()
+ ...jest.requireActual('react-redux'),
+ useSelector: jest.fn(),
}));
-jest.mock('../../SmartComponents/PackageSystems/PackageSystems', () => () =>
-);
+jest.mock('../../SmartComponents/PackageSystems/PackageSystems', () => () => );
const mockState = {
- ...storeListDefaults,
- data: packageDetailData,
- status: { isLoading: false, code: 200, hasError: false }
+ ...storeListDefaults,
+ data: packageDetailData,
+ status: { isLoading: false, code: 200, hasError: false },
};
const initStore = (state) => {
- const customMiddleWare = () => next => action => {
- useSelector.mockImplementation(callback => {
- return callback({ PackageDetailStore: state });
- });
- next(action);
- };
+ const customMiddleWare = () => (next) => (action) => {
+ useSelector.mockImplementation((callback) => callback({ PackageDetailStore: state }));
+ next(action);
+ };
- const mockStore = configureStore([customMiddleWare]);
- return mockStore({ PackageDetailStore: state });
+ const mockStore = configureStore([customMiddleWare]);
+ return mockStore({ PackageDetailStore: state });
};
let store = initStore(mockState);
beforeEach(() => {
- store.clearActions();
- useSelector.mockImplementation(callback => {
- return callback({ PackageDetailStore: mockState });
- });
+ store.clearActions();
+ useSelector.mockImplementation((callback) => callback({ PackageDetailStore: mockState }));
});
afterEach(() => {
- useSelector.mockClear();
+ useSelector.mockClear();
});
describe('PackageDetail.js', () => {
- it('should render the Header', () => {
- const { container } = render(
-
-
- );
- expect(queryByText(container, 'Packages')).not.toBeNull();
- });
+ it('should render the Header', () => {
+ const { container } = render(
+
+
+
+
+ ,
+ );
+ expect(queryByText(container, 'Packages')).not.toBeNull();
+ });
- it('should render the Text', () => {
- const { container } = render(
-
-
- );
- expect(queryByText(container, 'Systems')).not.toBeNull();
- });
+ it('should render the Text', () => {
+ const { container } = render(
+
+
+
+
+ ,
+ );
+ expect(queryByText(container, 'Systems')).not.toBeNull();
+ });
- it('should display Unavailable component on error', () => {
- const rejectedState = { ...mockState, status: { isLoading: false, code: 200, hasError: true } };
- const tempStore = initStore(rejectedState);
- useSelector.mockImplementation(callback => {
- return callback({ PackageDetailStore: rejectedState });
- });
- render(
-
-
-
-
- );
- const heading = screen.getByRole('heading', {
- name: /this page is temporarily unavailable/i
- });
- expect(heading).toBeTruthy();
+ it('should display Unavailable component on error', () => {
+ const rejectedState = { ...mockState, status: { isLoading: false, code: 200, hasError: true } };
+ const tempStore = initStore(rejectedState);
+ useSelector.mockImplementation((callback) => callback({ PackageDetailStore: rejectedState }));
+ render(
+
+
+
+
+ ,
+ );
+ const heading = screen.getByRole('heading', {
+ name: /this page is temporarily unavailable/i,
});
+ expect(heading).toBeTruthy();
+ });
});
diff --git a/src/SmartComponents/PackageSystems/PackageSystems.js b/src/SmartComponents/PackageSystems/PackageSystems.js
index e5926a1e7..a607f02f1 100644
--- a/src/SmartComponents/PackageSystems/PackageSystems.js
+++ b/src/SmartComponents/PackageSystems/PackageSystems.js
@@ -10,31 +10,41 @@ import statusFilter from '../../PresentationalComponents/Filters/StatusFilter';
import versionFilter from '../../PresentationalComponents/Filters/VersionFilter';
import ErrorHandler from '../../PresentationalComponents/Snippets/ErrorHandler';
import { defaultReducers } from '../../store';
-import { changePackageSystemsParams, clearInventoryReducer,
- clearPackageSystemsReducer, systemSelectAction } from '../../store/Actions/Actions';
-import { inventoryEntitiesReducer, modifyPackageSystems } from '../../store/Reducers/InventoryEntitiesReducer';
import {
- exportPackageSystemsCSV,
- exportPackageSystemsJSON, fetchPackageSystems,
- fetchPackageVersions
+ changePackageSystemsParams,
+ clearInventoryReducer,
+ clearPackageSystemsReducer,
+ systemSelectAction,
+} from '../../store/Actions/Actions';
+import {
+ inventoryEntitiesReducer,
+ modifyPackageSystems,
+} from '../../store/Reducers/InventoryEntitiesReducer';
+import {
+ exportPackageSystemsCSV,
+ exportPackageSystemsJSON,
+ fetchPackageSystems,
+ fetchPackageVersions,
} from '../../Utilities/api';
import { remediationIdentifiers } from '../../Utilities/constants';
import {
- arrayFromObj, buildFilterChips, decodeQueryparams, filterRemediatablePackageSystems,
- persistantParams, remediationProviderWithPairs, removeUndefinedObjectKeys
+ arrayFromObj,
+ buildFilterChips,
+ decodeQueryparams,
+ filterRemediatablePackageSystems,
+ persistantParams,
+ remediationProviderWithPairs,
+ removeUndefinedObjectKeys,
} from '../../Utilities/Helpers';
+import { mergeInventoryColumns, osParamParser } from '../../Utilities/SystemsHelpers';
import {
- mergeInventoryColumns,
- osParamParser
-} from '../../Utilities/SystemsHelpers';
-import {
- useBulkSelectConfig,
- useGetEntities,
- useOnExport,
- useRemoveFilter,
- useOnSelect,
- ID_API_ENDPOINTS,
- useColumnManagement
+ useBulkSelectConfig,
+ useGetEntities,
+ useOnExport,
+ useRemoveFilter,
+ useOnSelect,
+ ID_API_ENDPOINTS,
+ useColumnManagement,
} from '../../Utilities/hooks';
import { intl } from '../../Utilities/IntlProvider';
import AsyncRemediationButton from '../Remediation/AsyncRemediationButton';
@@ -42,194 +52,213 @@ import { PACKAGE_SYSTEMS_COLUMNS } from '../Systems/SystemsListAssets';
import { combineReducers } from 'redux';
const PackageSystems = ({ packageName }) => {
- const dispatch = useDispatch();
- const store = useStore();
- const [packageVersions, setPackageVersions] = React.useState([]);
-
- const [searchParams, setSearchParams] = useSearchParams();
- const decodedParams = decodeQueryparams('?' + searchParams.toString(), { os: osParamParser });
- const systems = useSelector(({ entities }) => entities?.rows || [], shallowEqual);
- const status = useSelector(
- ({ entities }) => entities?.status || {}
- );
- const totalItems = useSelector(
- ({ entities }) => entities?.total || 0
- );
- const selectedRows = useSelector(
- ({ entities }) => entities?.selectedRows || []
- );
- const queryParams = useSelector(
- ({ PackageSystemsStore }) => PackageSystemsStore?.queryParams || {}
- );
+ const dispatch = useDispatch();
+ const store = useStore();
+ const [packageVersions, setPackageVersions] = React.useState([]);
+
+ const [searchParams, setSearchParams] = useSearchParams();
+ const decodedParams = decodeQueryparams('?' + searchParams.toString(), { os: osParamParser });
+ const systems = useSelector(({ entities }) => entities?.rows || [], shallowEqual);
+ const status = useSelector(({ entities }) => entities?.status || {});
+ const totalItems = useSelector(({ entities }) => entities?.total || 0);
+ const selectedRows = useSelector(({ entities }) => entities?.selectedRows || []);
+ const queryParams = useSelector(
+ ({ PackageSystemsStore }) => PackageSystemsStore?.queryParams || {},
+ );
+
+ const { systemProfile, selectedTags, filter, search, sort, page, perPage } = queryParams;
+
+ const apply = useCallback((params) => {
+ dispatch(changePackageSystemsParams(params));
+ }, []);
+
+ useEffect(() => {
+ apply(decodedParams);
+ fetchPackageVersions({ package_name: packageName }).then(setPackageVersions);
+ }, []);
+
+ useEffect(
+ () => () => {
+ dispatch(clearInventoryReducer());
+ dispatch(clearPackageSystemsReducer());
+ },
+ [],
+ );
+
+ const [appliedColumns, setAppliedColumns] = React.useState(PACKAGE_SYSTEMS_COLUMNS);
+ const [ColumnManagementModal, setColumnManagementModalOpen] = useColumnManagement(
+ appliedColumns,
+ (newColumns) => setAppliedColumns(newColumns),
+ );
+
+ const [deleteFilters] = useRemoveFilter({ ...filter, search }, apply);
- const { systemProfile, selectedTags,
- filter, search, sort, page, perPage } = queryParams;
-
- const apply = useCallback((params) => {
- dispatch(changePackageSystemsParams(params));
- }, []);
-
- useEffect(() => {
- apply(decodedParams);
- fetchPackageVersions({ package_name: packageName }).then(setPackageVersions);
- }, []);
-
- useEffect(() => {
- return () => {
- dispatch(clearInventoryReducer());
- dispatch(clearPackageSystemsReducer());
- };
- }, []);
-
- const [appliedColumns, setAppliedColumns] = React.useState(PACKAGE_SYSTEMS_COLUMNS);
- const [ColumnManagementModal, setColumnManagementModalOpen] =
- useColumnManagement(appliedColumns, newColumns => setAppliedColumns(newColumns));
-
- const [deleteFilters] = useRemoveFilter({ ...filter, search }, apply);
-
- const filterConfig = {
- items: [
- searchFilter(apply, search,
- intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
- intl.formatMessage(messages.labelsFiltersSystemsSearchPlaceholder)
- ),
- statusFilter(apply, filter),
- versionFilter(apply, filter, packageVersions)
- ]
- };
-
- const activeFiltersConfig = useMemo(() => ({
- filters: buildFilterChips(filter, search, intl.formatMessage(messages.labelsFiltersSystemsSearchTitle)),
- onDelete: deleteFilters
- }), [filter, search]);
-
- const constructFilename = (system) => {
- return `${system.available_evra}`;
- };
-
- const onSelect = useOnSelect(
- systems,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.packageSystems(packageName),
- queryParams,
- selectionDispatcher: systemSelectAction,
- constructFilename,
- apiResponseTransformer: filterRemediatablePackageSystems,
- totalItems
+ const filterConfig = {
+ items: [
+ searchFilter(
+ apply,
+ search,
+ intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
+ intl.formatMessage(messages.labelsFiltersSystemsSearchPlaceholder),
+ ),
+ statusFilter(apply, filter),
+ versionFilter(apply, filter, packageVersions),
+ ],
+ };
+
+ const activeFiltersConfig = useMemo(
+ () => ({
+ filters: buildFilterChips(
+ filter,
+ search,
+ intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
+ ),
+ onDelete: deleteFilters,
+ }),
+ [filter, search],
+ );
+
+ const constructFilename = (system) => `${system.available_evra}`;
+
+ const onSelect = useOnSelect(systems, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.packageSystems(packageName),
+ queryParams,
+ selectionDispatcher: systemSelectAction,
+ constructFilename,
+ apiResponseTransformer: filterRemediatablePackageSystems,
+ totalItems,
+ });
+
+ const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
+
+ const onExport = useOnExport(
+ packageName,
+ queryParams,
+ {
+ csv: exportPackageSystemsCSV,
+ json: exportPackageSystemsJSON,
+ },
+ dispatch,
+ );
+
+ const prepareRemediationPairs = useCallback(
+ (systemIDs) => {
+ const pairs = [];
+
+ systemIDs.forEach((id) => {
+ const packageEvra = packageName + '-' + selectedRows[id];
+ const issueID = `patch-package:${packageEvra}`;
+ const index = pairs.findIndex((pair) => pair.id === issueID);
+
+ if (index !== -1) {
+ pairs[index].systems.push(id);
+ } else if (packageEvra) {
+ pairs.push({
+ id: issueID,
+ description: packageEvra,
+ systems: [id],
+ });
}
- );
+ });
- const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
-
- const onExport = useOnExport(packageName, queryParams, {
- csv: exportPackageSystemsCSV,
- json: exportPackageSystemsJSON
- }, dispatch);
-
- const prepareRemediationPairs = useCallback((systemIDs) => {
- const pairs = [];
-
- systemIDs.forEach(id => {
- const packageEvra = packageName + '-' + selectedRows[id];
- const issueID = `patch-package:${packageEvra}`;
- const index = pairs.findIndex(pair => pair.id === issueID);
-
- if (index !== -1) {
- pairs[index].systems.push(id);
- } else if (packageEvra) {
- pairs.push({
- id: issueID,
- description: packageEvra,
- systems: [id]
- });
- }
- });
-
- return pairs.length ? { issues: pairs } : false;
- }, [selectedRows]);
-
- const getEntites = useGetEntities(fetchPackageSystems, apply, { packageName }, setSearchParams);
-
- const remediationDataProvider = () => remediationProviderWithPairs(
- removeUndefinedObjectKeys(selectedRows),
- prepareRemediationPairs,
- remediationIdentifiers.package
- );
+ return pairs.length ? { issues: pairs } : false;
+ },
+ [selectedRows],
+ );
+
+ const getEntites = useGetEntities(fetchPackageSystems, apply, { packageName }, setSearchParams);
- const bulkSelectConfig = useBulkSelectConfig(selectedCount, onSelect, { total_items: totalItems }, systems);
-
- return (
-
- {ColumnManagementModal}
-
- {status.hasError && || (
-
- mergeInventoryColumns(appliedColumns.filter(column => column.isShown), inventoryColumns)
- }
- showTags
- getEntities={getEntites}
- customFilters={{
- patchParams: {
- search,
- filter,
- systemProfile,
- selectedTags
- }
- }}
- paginationProps={{
- isDisabled: totalItems === 0
- }}
- onLoad={({ mergeWithEntities }) => {
- store.replaceReducer(combineReducers({
- ...defaultReducers,
- ...mergeWithEntities(
- inventoryEntitiesReducer(PACKAGE_SYSTEMS_COLUMNS, modifyPackageSystems),
- persistantParams({ page, perPage, sort, search }, decodedParams)
- )
- }));
-
- }}
- actionsConfig={{
- actions: [
- null, // first item of actions will be a big button, but we want "Manage columns" in kebab menu
- {
- label: 'Manage columns',
- onClick: () => setColumnManagementModalOpen(true)
- }
- ]
- }}
- tableProps={{
- canSelectAll: false,
- variant: TableVariant.compact, className: 'patchCompactInventory', isStickyHeader: true
- }}
- filterConfig={filterConfig}
- activeFiltersConfig={activeFiltersConfig}
- bulkSelect={onSelect && bulkSelectConfig}
- exportConfig={{
- isDisabled: totalItems === 0,
- onSelect: onExport
- }}
- dedicatedAction={(
-
- )}
- />
- )}
-
+ const remediationDataProvider = () =>
+ remediationProviderWithPairs(
+ removeUndefinedObjectKeys(selectedRows),
+ prepareRemediationPairs,
+ remediationIdentifiers.package,
);
+
+ const bulkSelectConfig = useBulkSelectConfig(
+ selectedCount,
+ onSelect,
+ { total_items: totalItems },
+ systems,
+ );
+
+ return (
+
+ {ColumnManagementModal}
+
+ {(status.hasError && ) || (
+
+ mergeInventoryColumns(
+ appliedColumns.filter((column) => column.isShown),
+ inventoryColumns,
+ )
+ }
+ showTags
+ getEntities={getEntites}
+ customFilters={{
+ patchParams: {
+ search,
+ filter,
+ systemProfile,
+ selectedTags,
+ },
+ }}
+ paginationProps={{
+ isDisabled: totalItems === 0,
+ }}
+ onLoad={({ mergeWithEntities }) => {
+ store.replaceReducer(
+ combineReducers({
+ ...defaultReducers,
+ ...mergeWithEntities(
+ inventoryEntitiesReducer(PACKAGE_SYSTEMS_COLUMNS, modifyPackageSystems),
+ persistantParams({ page, perPage, sort, search }, decodedParams),
+ ),
+ }),
+ );
+ }}
+ actionsConfig={{
+ actions: [
+ null, // first item of actions will be a big button, but we want "Manage columns" in kebab menu
+ {
+ label: 'Manage columns',
+ onClick: () => setColumnManagementModalOpen(true),
+ },
+ ],
+ }}
+ tableProps={{
+ canSelectAll: false,
+ variant: TableVariant.compact,
+ className: 'patchCompactInventory',
+ isStickyHeader: true,
+ }}
+ filterConfig={filterConfig}
+ activeFiltersConfig={activeFiltersConfig}
+ bulkSelect={onSelect && bulkSelectConfig}
+ exportConfig={{
+ isDisabled: totalItems === 0,
+ onSelect: onExport,
+ }}
+ dedicatedAction={
+
+ }
+ />
+ )}
+
+ );
};
PackageSystems.propTypes = {
- packageName: propTypes.string
+ packageName: propTypes.string,
};
export default PackageSystems;
diff --git a/src/SmartComponents/PackageSystems/PackageSystems.test.js b/src/SmartComponents/PackageSystems/PackageSystems.test.js
index f9ed8ce35..6bc989f02 100644
--- a/src/SmartComponents/PackageSystems/PackageSystems.test.js
+++ b/src/SmartComponents/PackageSystems/PackageSystems.test.js
@@ -8,138 +8,146 @@ import { render, screen } from '@testing-library/react';
initMocks();
jest.mock('@redhat-cloud-services/frontend-components-utilities/helpers', () => ({
- ...jest.requireActual('@redhat-cloud-services/frontend-components-utilities/helpers'),
- downloadFile: jest.fn()
+ ...jest.requireActual('@redhat-cloud-services/frontend-components-utilities/helpers'),
+ downloadFile: jest.fn(),
}));
-jest.mock(
- '../../PresentationalComponents/Filters/OsVersionFilter'
-);
+jest.mock('../../PresentationalComponents/Filters/OsVersionFilter');
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- exportPackageSystemsCSV: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- exportPackageSystemsJSON: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- fetchPackageVersions: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- fetchIDs: jest.fn(() => Promise.resolve({
- data: [{
- advisory_type: 2,
- description: 'The tzdata penhancements.',
- public_date: '2020-10-19T15:02:38Z',
- synopsis: 'tzdata enhancement update',
- updatable: true,
- id: 'RHBA-2020:4282',
- type: 'advisory'
- }]
- }).catch((err) => console.log(err)))
+ ...jest.requireActual('../../Utilities/api'),
+ exportPackageSystemsCSV: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ exportPackageSystemsJSON: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ fetchPackageVersions: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ fetchIDs: jest.fn(() =>
+ Promise.resolve({
+ data: [
+ {
+ advisory_type: 2,
+ description: 'The tzdata penhancements.',
+ public_date: '2020-10-19T15:02:38Z',
+ synopsis: 'tzdata enhancement update',
+ updatable: true,
+ id: 'RHBA-2020:4282',
+ type: 'advisory',
+ },
+ ],
+ }).catch((err) => console.log(err)),
+ ),
}));
const mockState = {
- entities: {
- rows: systemRows,
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 10
- },
- expandedRows: {},
- selectedRows: { 'test-system-1': 'packageEvra' },
- error: {},
- status: 'resolved',
- total: 101
+ entities: {
+ rows: systemRows,
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 10,
},
- PackageSystemsStore: {
- queryParams: {}
- }
+ expandedRows: {},
+ selectedRows: { 'test-system-1': 'packageEvra' },
+ error: {},
+ status: 'resolved',
+ total: 101,
+ },
+ PackageSystemsStore: {
+ queryParams: {},
+ },
};
const initStore = () => {
- const mockStore = configureStore([]);
- return mockStore(mockState);
+ const mockStore = configureStore([]);
+ return mockStore(mockState);
};
const store = initStore(mockState);
beforeEach(() => {
- render(
-
- );
+ render(
+
+
+ ,
+ );
});
-//TODO: find a meaningful way of testing InventoryTable fed module
+// TODO: find a meaningful way of testing InventoryTable fed module
describe('PackageSystems.js', () => {
- it('Should render inventory table', () => {
- expect(screen.getByTestId('inventory-mock-component')).toBeVisible();
- });
- // it('Should dispatch change package systems params action once only', () => {
- // const dispatchedActions = store.getActions();
- // expect(dispatchedActions.filter(item => item.type === 'CHANGE_PACKAGE_SYSTEMS_PARAMS')).toHaveLength(1);
- // });
-
- // it('Should open remediation modal', () => {
- // const { dedicatedAction } = wrapper.find('.testInventroyComponentChild').parent().props();
- // const remediationPairs = dedicatedAction.props.remediationProvider('test-system-1');
- // expect(remediationPairs).toEqual({
- // issues: [
- // {
- // id: 'patch-package:testName-packageEvra',
- // description: 'testName-packageEvra',
- // systems: ['test-system-1']
- // }
- // ]
- // });
- // expect(dedicatedAction).toMatchSnapshot();
- // });
-
- // describe('test exports', () => {
-
- // global.Headers = jest.fn();
- // global.fetch = jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err)));
-
- // it('Should download csv file', () => {
- // const { exportConfig } = wrapper.find('.testInventroyComponentChild').parent().props();
- // exportConfig.onSelect(null, 'csv');
- // expect(exportPackageSystemsCSV).toHaveBeenCalledWith({}, 'testName');
- // });
-
- // it('Should download json file', () => {
- // const { exportConfig } = wrapper.find('.testInventroyComponentChild').parent().props();
- // exportConfig.onSelect(null, 'json');
- // expect(exportPackageSystemsJSON).toHaveBeenCalledWith({}, 'testName');
- // });
- // });
-
- // describe('test entity selecting', () => {
- // it('Should unselect all', () => {
- // const { bulkSelect } = wrapper.find('.testInventroyComponentChild').parent().props();
-
- // bulkSelect.items[0].onClick();
- // const dispatchedActions = store.getActions();
-
- // expect(dispatchedActions[1].type).toEqual('SELECT_ENTITY');
- // expect(bulkSelect.items[0].title).toEqual('Select none (0)');
- // expect(dispatchedActions[1].payload).toEqual([{ id: 'test-system-1', selected: false }]);
- // });
-
- // it('Should select a page', async () => {
-
- // const { bulkSelect } = wrapper.find('.testInventroyComponentChild').parent().props();
-
- // bulkSelect.items[1].onClick();
- // const dispatchedActions = store.getActions();
- // expect(dispatchedActions[1].type).toEqual('SELECT_ENTITY');
- // expect(bulkSelect.items[1].title).toEqual('Select page (2)');
- // });
-
- // it('Should select all', async () => {
-
- // const { bulkSelect } = wrapper.find('.testInventroyComponentChild').parent().props();
-
- // bulkSelect.items[2].onClick();
- // expect(fetchIDs).toHaveBeenCalledWith('/packages/testName/systems', { limit: -1, offset: 0 });
- // expect(bulkSelect.items[2].title).toEqual('Select all (2)');
- // });
- // });
-
+ it('Should render inventory table', () => {
+ expect(screen.getByTestId('inventory-mock-component')).toBeVisible();
+ });
+ // it('Should dispatch change package systems params action once only', () => {
+ // const dispatchedActions = store.getActions();
+ // expect(dispatchedActions.filter(item => item.type === 'CHANGE_PACKAGE_SYSTEMS_PARAMS')).toHaveLength(1);
+ // });
+
+ // it('Should open remediation modal', () => {
+ // const { dedicatedAction } = wrapper.find('.testInventroyComponentChild').parent().props();
+ // const remediationPairs = dedicatedAction.props.remediationProvider('test-system-1');
+ // expect(remediationPairs).toEqual({
+ // issues: [
+ // {
+ // id: 'patch-package:testName-packageEvra',
+ // description: 'testName-packageEvra',
+ // systems: ['test-system-1']
+ // }
+ // ]
+ // });
+ // expect(dedicatedAction).toMatchSnapshot();
+ // });
+
+ // describe('test exports', () => {
+
+ // global.Headers = jest.fn();
+ // global.fetch = jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err)));
+
+ // it('Should download csv file', () => {
+ // const { exportConfig } = wrapper.find('.testInventroyComponentChild').parent().props();
+ // exportConfig.onSelect(null, 'csv');
+ // expect(exportPackageSystemsCSV).toHaveBeenCalledWith({}, 'testName');
+ // });
+
+ // it('Should download json file', () => {
+ // const { exportConfig } = wrapper.find('.testInventroyComponentChild').parent().props();
+ // exportConfig.onSelect(null, 'json');
+ // expect(exportPackageSystemsJSON).toHaveBeenCalledWith({}, 'testName');
+ // });
+ // });
+
+ // describe('test entity selecting', () => {
+ // it('Should unselect all', () => {
+ // const { bulkSelect } = wrapper.find('.testInventroyComponentChild').parent().props();
+
+ // bulkSelect.items[0].onClick();
+ // const dispatchedActions = store.getActions();
+
+ // expect(dispatchedActions[1].type).toEqual('SELECT_ENTITY');
+ // expect(bulkSelect.items[0].title).toEqual('Select none (0)');
+ // expect(dispatchedActions[1].payload).toEqual([{ id: 'test-system-1', selected: false }]);
+ // });
+
+ // it('Should select a page', async () => {
+
+ // const { bulkSelect } = wrapper.find('.testInventroyComponentChild').parent().props();
+
+ // bulkSelect.items[1].onClick();
+ // const dispatchedActions = store.getActions();
+ // expect(dispatchedActions[1].type).toEqual('SELECT_ENTITY');
+ // expect(bulkSelect.items[1].title).toEqual('Select page (2)');
+ // });
+
+ // it('Should select all', async () => {
+
+ // const { bulkSelect } = wrapper.find('.testInventroyComponentChild').parent().props();
+
+ // bulkSelect.items[2].onClick();
+ // expect(fetchIDs).toHaveBeenCalledWith('/packages/testName/systems', { limit: -1, offset: 0 });
+ // expect(bulkSelect.items[2].title).toEqual('Select all (2)');
+ // });
+ // });
});
-
diff --git a/src/SmartComponents/Packages/Packages.js b/src/SmartComponents/Packages/Packages.js
index cf34d77c8..78dbf6e63 100644
--- a/src/SmartComponents/Packages/Packages.js
+++ b/src/SmartComponents/Packages/Packages.js
@@ -12,96 +12,100 @@ import { exportPackagesCSV, exportPackagesJSON } from '../../Utilities/api';
import { packagesListDefaultFilters } from '../../Utilities/constants';
import { createPackagesRows } from '../../Utilities/DataMappers';
import { createSortBy, decodeQueryparams, encodeURLParams } from '../../Utilities/Helpers';
-import { useOnExport, usePerPageSelect,
- useSetPage, useSortColumn, useDeepCompareEffect } from '../../Utilities/hooks';
+import {
+ useOnExport,
+ usePerPageSelect,
+ useSetPage,
+ useSortColumn,
+ useDeepCompareEffect,
+} from '../../Utilities/hooks';
import { intl } from '../../Utilities/IntlProvider';
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
import { useSearchParams } from 'react-router-dom';
const Packages = () => {
- const dispatch = useDispatch();
- const [firstMount, setFirstMount] = React.useState(true);
- const chrome = useChrome();
- useEffect(()=>{
- chrome.updateDocumentTitle(`Packages - Content | RHEL`, true);
- }, [chrome]);
+ const dispatch = useDispatch();
+ const [firstMount, setFirstMount] = React.useState(true);
+ const chrome = useChrome();
+ useEffect(() => {
+ chrome.updateDocumentTitle(`Packages - Content | RHEL`, true);
+ }, [chrome]);
- const [searchParams, setSearchParams] = useSearchParams();
- const packageRows = useSelector(
- ({ PackagesListStore }) => PackagesListStore.rows
- );
- const rows = React.useMemo(() => createPackagesRows(packageRows), [packageRows]);
+ const [searchParams, setSearchParams] = useSearchParams();
+ const packageRows = useSelector(({ PackagesListStore }) => PackagesListStore.rows);
+ const rows = React.useMemo(() => createPackagesRows(packageRows), [packageRows]);
- const status = useSelector(
- ({ PackagesListStore }) => PackagesListStore.status
- );
- const metadata = useSelector(
- ({ PackagesListStore }) => PackagesListStore.metadata
- );
- const queryParams = useSelector(
- ({ PackagesListStore }) => PackagesListStore.queryParams
- );
+ const status = useSelector(({ PackagesListStore }) => PackagesListStore.status);
+ const metadata = useSelector(({ PackagesListStore }) => PackagesListStore.metadata);
+ const queryParams = useSelector(({ PackagesListStore }) => PackagesListStore.queryParams);
- useDeepCompareEffect(() => {
- if (firstMount) {
- apply(decodeQueryparams('?' + searchParams.toString()));
- setFirstMount(false);
- } else {
- setSearchParams(encodeURLParams(queryParams));
- dispatch(fetchPackagesAction(queryParams));
- }
- }, [queryParams, firstMount]);
-
- function apply(params) {
- dispatch(changePackagesListParams(params));
+ useDeepCompareEffect(() => {
+ if (firstMount) {
+ apply(decodeQueryparams('?' + searchParams.toString()));
+ setFirstMount(false);
+ } else {
+ setSearchParams(encodeURLParams(queryParams));
+ dispatch(fetchPackagesAction(queryParams));
}
+ }, [queryParams, firstMount]);
+
+ function apply(params) {
+ dispatch(changePackagesListParams(params));
+ }
- const onExport = useOnExport('packages', queryParams, {
- csv: exportPackagesCSV,
- json: exportPackagesJSON
- }, dispatch);
+ const onExport = useOnExport(
+ 'packages',
+ queryParams,
+ {
+ csv: exportPackagesCSV,
+ json: exportPackagesJSON,
+ },
+ dispatch,
+ );
- const onSort = useSortColumn(packagesColumns, apply);
- const sortBy = React.useMemo(
- () => createSortBy(packagesColumns, metadata.sort, 0),
- [metadata.sort]
- );
- const onSetPage = useSetPage(metadata.limit, apply);
- const onPerPageSelect = usePerPageSelect(apply);
+ const onSort = useSortColumn(packagesColumns, apply);
+ const sortBy = React.useMemo(
+ () => createSortBy(packagesColumns, metadata.sort, 0),
+ [metadata.sort],
+ );
+ const onSetPage = useSetPage(metadata.limit, apply);
+ const onPerPageSelect = usePerPageSelect(apply);
- return (
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+ );
};
export default Packages;
diff --git a/src/SmartComponents/Packages/Packages.test.js b/src/SmartComponents/Packages/Packages.test.js
index d59405f75..b589b2316 100644
--- a/src/SmartComponents/Packages/Packages.test.js
+++ b/src/SmartComponents/Packages/Packages.test.js
@@ -14,57 +14,70 @@ import '@testing-library/jest-dom';
initMocks();
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- exportPackagesCSV: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- exportPackagesJSON: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err))),
- fetchPackagesList: jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err)))
+ ...jest.requireActual('../../Utilities/api'),
+ exportPackagesCSV: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ exportPackagesJSON: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
+ fetchPackagesList: jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ ),
}));
const mockState = {
- ...storeListDefaults,
- rows: systemPackages,
- status: { isLoading: false, code: 200, hasError: false },
- metadata: { total_items: 1 }
+ ...storeListDefaults,
+ rows: systemPackages,
+ status: { isLoading: false, code: 200, hasError: false },
+ metadata: { total_items: 1 },
};
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore({ PackagesListStore: state });
+ const mockStore = configureStore([]);
+ return mockStore({ PackagesListStore: state });
};
let store = initStore(mockState);
beforeEach(() => {
- store.clearActions();
- render(
-
- );
+ store.clearActions();
+ render(
+
+
+ ,
+ );
});
describe('Packages.js', () => {
+ it('should render the packages names correctly', () => {
+ const { container } = render(
+
+
+
+
+ ,
+ );
+ expect(queryByText(container, 'test-name')).not.toBeNull();
+ });
- it('should render the packages names correctly', () => {
- const { container } = render(
-
-
-
- );
- expect(queryByText(container, 'test-name')).not.toBeNull();
- });
+ it('should render the packages summary', () => {
+ const { container } = render(
+
+
+
+
+ ,
+ );
+ expect(queryAllByText(container, 'Access control list utilities')).not.toBeNull();
+ });
- it('should render the packages summary', () => {
- const { container } = render(
-
-
-
- );
- expect(queryAllByText(container, 'Access control list utilities')).not.toBeNull();
- });
+ it('should fetch packages only once on load', () => {
+ const dispatchedActions = store.getActions();
+ expect(
+ dispatchedActions.filter((item) => item.type === 'CHANGE_PACKAGES_LIST_PARAMS'),
+ ).toHaveLength(1);
+ expect(dispatchedActions.filter((item) => item.type === 'FETCH_PACKAGES_LIST')).toHaveLength(1);
+ });
- it('should fetch packages only once on load', () => {
- const dispatchedActions = store.getActions();
- expect(dispatchedActions.filter(item => item.type === 'CHANGE_PACKAGES_LIST_PARAMS')).toHaveLength(1);
- expect(dispatchedActions.filter(item => item.type === 'FETCH_PACKAGES_LIST')).toHaveLength(1);
- });
-
- testExport(exportPackagesCSV, exportPackagesJSON, 'packages');
+ testExport(exportPackagesCSV, exportPackagesJSON, 'packages');
});
diff --git a/src/SmartComponents/PatchSet/PatchSet.js b/src/SmartComponents/PatchSet/PatchSet.js
index 16dea38e0..fc3d7f509 100644
--- a/src/SmartComponents/PatchSet/PatchSet.js
+++ b/src/SmartComponents/PatchSet/PatchSet.js
@@ -8,20 +8,33 @@ import searchFilter from '../../PresentationalComponents/Filters/SearchFilter';
import creatorFilter from '../../PresentationalComponents/Filters/CreatorFilter';
import TableView from '../../PresentationalComponents/TableView/TableView';
import {
- fetchPatchSetsAction, changePatchSetsParams,
- selectPatchSetRow, clearPatchSetsAction
+ fetchPatchSetsAction,
+ changePatchSetsParams,
+ selectPatchSetRow,
+ clearPatchSetsAction,
} from '../../store/Actions/Actions';
import { deletePatchSet } from '../../Utilities/api';
import { createPatchSetRows } from '../../Utilities/DataMappers';
import { createSortBy, decodeQueryparams, encodeURLParams } from '../../Utilities/Helpers';
-import { useDeepCompareEffect, usePerPageSelect, useSetPage, useSortColumn,
- usePatchSetState, useOnSelect, ID_API_ENDPOINTS
+import {
+ useDeepCompareEffect,
+ usePerPageSelect,
+ useSetPage,
+ useSortColumn,
+ usePatchSetState,
+ useOnSelect,
+ ID_API_ENDPOINTS,
} from '../../Utilities/hooks';
import { intl } from '../../Utilities/IntlProvider';
-import { clearNotifications, addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
import {
- patchSetColumns, CreatePatchSetButton as createPatchSetButton,
- patchSetRowActions, CustomActionsToggle
+ clearNotifications,
+ addNotification,
+} from '@redhat-cloud-services/frontend-components-notifications/redux';
+import {
+ patchSetColumns,
+ CreatePatchSetButton as createPatchSetButton,
+ patchSetRowActions,
+ CustomActionsToggle,
} from './PatchSetAssets';
import PatchSetWizard from '../PatchSetWizard/PatchSetWizard';
import { patchSetDeleteNotifications } from '../../Utilities/constants';
@@ -33,194 +46,184 @@ import { NoPatchSetList } from '../../PresentationalComponents/Snippets/EmptySta
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
const PatchSet = () => {
- const IS_SELECTION_ENABLED = false;
- const chrome = useChrome();
- useEffect(()=>{
- chrome.updateDocumentTitle(`Templates - Patch | RHEL`, true);
- }, [chrome]);
-
- const dispatch = useDispatch();
- const [searchParams, setSearchParams] = useSearchParams();
- const [firstMount, setFirstMount] = React.useState(true);
- const [isDeleteConfirmModalOpen, setDeleteConfirmModalOpen] = React.useState(false);
- const [patchSetToDelete, setPatchSetToDelete] = React.useState(null);
-
- const patchSets = useSelector(
- ({ PatchSetsStore }) => PatchSetsStore.rows
- );
-
- const queryParams = useSelector(
- ({ PatchSetsStore }) => PatchSetsStore.queryParams
- );
- const selectedRows = useSelector(
- ({ PatchSetsStore }) => PatchSetsStore.selectedRows
- );
- const metadata = useSelector(
- ({ PatchSetsStore }) => PatchSetsStore.metadata
- );
- const status = useSelector(
- ({ PatchSetsStore }) => PatchSetsStore.status
- );
-
- const rows = useMemo(
- () => createPatchSetRows(patchSets, selectedRows, queryParams),
- [patchSets, selectedRows]
- );
-
- function apply(params) {
- dispatch(changePatchSetsParams(params));
+ const IS_SELECTION_ENABLED = false;
+ const chrome = useChrome();
+ useEffect(() => {
+ chrome.updateDocumentTitle(`Templates - Patch | RHEL`, true);
+ }, [chrome]);
+
+ const dispatch = useDispatch();
+ const [searchParams, setSearchParams] = useSearchParams();
+ const [firstMount, setFirstMount] = React.useState(true);
+ const [isDeleteConfirmModalOpen, setDeleteConfirmModalOpen] = React.useState(false);
+ const [patchSetToDelete, setPatchSetToDelete] = React.useState(null);
+
+ const patchSets = useSelector(({ PatchSetsStore }) => PatchSetsStore.rows);
+
+ const queryParams = useSelector(({ PatchSetsStore }) => PatchSetsStore.queryParams);
+ const selectedRows = useSelector(({ PatchSetsStore }) => PatchSetsStore.selectedRows);
+ const metadata = useSelector(({ PatchSetsStore }) => PatchSetsStore.metadata);
+ const status = useSelector(({ PatchSetsStore }) => PatchSetsStore.status);
+
+ const rows = useMemo(
+ () => createPatchSetRows(patchSets, selectedRows, queryParams),
+ [patchSets, selectedRows],
+ );
+
+ function apply(params) {
+ dispatch(changePatchSetsParams(params));
+ }
+
+ const refreshTable = () => {
+ dispatch(fetchPatchSetsAction({ ...queryParams, page: 1, offset: 0 }));
+ };
+
+ useEffect(
+ () => () => {
+ dispatch(clearPatchSetsAction());
+ dispatch(clearNotifications());
+ },
+ [],
+ );
+
+ const { patchSetState, setPatchSetState, openPatchSetEditModal } = usePatchSetState(selectedRows);
+
+ useEffect(() => {
+ if (patchSetState.shouldRefresh === true) {
+ refreshTable();
}
-
- const refreshTable = () => {
- dispatch(fetchPatchSetsAction({ ...queryParams, page: 1, offset: 0 }));
- };
-
- useEffect(() => {
- return () => {
- dispatch(clearPatchSetsAction());
- dispatch(clearNotifications());
- };
- }, []);
-
- const { patchSetState, setPatchSetState, openPatchSetEditModal } = usePatchSetState(selectedRows);
-
- useEffect(() => {
- if (patchSetState.shouldRefresh === true) {
- refreshTable();
- }
- }, [patchSetState.shouldRefresh]);
-
- useDeepCompareEffect(() => {
- if (firstMount) {
- apply(decodeQueryparams('?' + searchParams.toString()));
- setFirstMount(false);
- } else {
- setSearchParams(encodeURLParams(queryParams));
- dispatch(fetchPatchSetsAction(queryParams));
- }
- }, [queryParams, firstMount]);
-
- const onSelect = useOnSelect(
- rows,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.templates,
- queryParams,
- selectionDispatcher: selectPatchSetRow,
- totalItems: metadata.total_items
+ }, [patchSetState.shouldRefresh]);
+
+ useDeepCompareEffect(() => {
+ if (firstMount) {
+ apply(decodeQueryparams('?' + searchParams.toString()));
+ setFirstMount(false);
+ } else {
+ setSearchParams(encodeURLParams(queryParams));
+ dispatch(fetchPatchSetsAction(queryParams));
+ }
+ }, [queryParams, firstMount]);
+
+ const onSelect = useOnSelect(rows, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.templates,
+ queryParams,
+ selectionDispatcher: selectPatchSetRow,
+ totalItems: metadata.total_items,
+ });
+
+ const onSort = useSortColumn(patchSetColumns, apply, 0);
+ const sortBy = React.useMemo(
+ () => createSortBy(patchSetColumns, metadata.sort, 0),
+ [metadata.sort],
+ );
+
+ const onSetPage = useSetPage(metadata.limit, apply);
+ const onPerPageSelect = usePerPageSelect(apply);
+
+ const openPatchDeleteModal = (rowData) => {
+ setDeleteConfirmModalOpen(true);
+ setPatchSetToDelete(rowData);
+ };
+
+ const handlePatchSetDelete = () => {
+ deletePatchSet(patchSetToDelete.id)
+ .then(() => {
+ dispatch(
+ addNotification(patchSetDeleteNotifications(patchSetToDelete.displayName).success),
+ );
+ refreshTable();
+ })
+ .catch(() => {
+ dispatch(addNotification(patchSetDeleteNotifications(patchSetToDelete.displayName).error));
+ });
+ };
+
+ const { hasAccess } = usePermissionsWithContext(['patch:*:*', 'patch:template:write']);
+ const CreatePatchSetButton = createPatchSetButton(setPatchSetState, hasAccess);
+ const actionsConfig = patchSetRowActions(openPatchSetEditModal, openPatchDeleteModal);
+
+ // TODO: refactor search filter to be able to wrap this into useMemo
+ const filterConfig = {
+ items: [
+ searchFilter(
+ apply,
+ queryParams.search,
+ intl.formatMessage(messages.labelsFiltersSearchTemplateTitle),
+ intl.formatMessage(messages.labelsFiltersSearchTemplatePlaceholder),
+ ),
+ creatorFilter(apply, queryParams.filter, metadata.creators),
+ ],
+ };
+
+ return (
+
+
+
+ {intl.formatMessage(messages.titlesTemplate)}
+
+
}
- );
-
- const onSort = useSortColumn(patchSetColumns, apply, 0);
- const sortBy = React.useMemo(
- () => createSortBy(patchSetColumns, metadata.sort, 0),
- [metadata.sort]
- );
-
- const onSetPage = useSetPage(metadata.limit, apply);
- const onPerPageSelect = usePerPageSelect(apply);
-
- const openPatchDeleteModal = (rowData) => {
- setDeleteConfirmModalOpen(true);
- setPatchSetToDelete(rowData);
- };
-
- const handlePatchSetDelete = () => {
- deletePatchSet(patchSetToDelete.id).then(() => {
- dispatch(addNotification(patchSetDeleteNotifications(patchSetToDelete.displayName).success));
- refreshTable();
- }).catch(() => {
- dispatch(addNotification(patchSetDeleteNotifications(patchSetToDelete.displayName).error));
- });
- };
-
- const { hasAccess } = usePermissionsWithContext([
- 'patch:*:*',
- 'patch:template:write'
- ]);
- const CreatePatchSetButton = createPatchSetButton(setPatchSetState, hasAccess);
- const actionsConfig = patchSetRowActions(openPatchSetEditModal, openPatchDeleteModal);
-
- //TODO: refactor search filter to be able to wrap this into useMemo
- const filterConfig = {
- items: [
- searchFilter(apply, queryParams.search,
- intl.formatMessage(messages.labelsFiltersSearchTemplateTitle),
- intl.formatMessage(messages.labelsFiltersSearchTemplatePlaceholder)
- ),
- creatorFilter(apply, queryParams.filter, metadata.creators)
- ]
- };
-
- return (
-
-
-
- {intl.formatMessage(messages.titlesTemplate)}
-
- }
- />
- {patchSetState.isPatchSetWizardOpen &&
- }
-
- {(rows.length === 0 && !status.isLoading)
- ?
- : 0 ? actionsConfig : []}
- filterConfig={filterConfig}
- searchChipLabel={intl.formatMessage(messages.labelsFiltersSearchTemplateTitle)}
- ToolbarButton={CreatePatchSetButton}
- actionsToggle={!hasAccess ? CustomActionsToggle : null}
- />
- }
-
-
- );
+ />
+ {patchSetState.isPatchSetWizardOpen && (
+
+ )}
+
+ {rows.length === 0 && !status.isLoading ? (
+
+ ) : (
+ 0 ? actionsConfig : []}
+ filterConfig={filterConfig}
+ searchChipLabel={intl.formatMessage(messages.labelsFiltersSearchTemplateTitle)}
+ ToolbarButton={CreatePatchSetButton}
+ actionsToggle={!hasAccess ? CustomActionsToggle : null}
+ />
+ )}
+
+
+ );
};
export default PatchSet;
diff --git a/src/SmartComponents/PatchSet/PatchSet.test.js b/src/SmartComponents/PatchSet/PatchSet.test.js
index 012f9e1c7..7c0a58c60 100644
--- a/src/SmartComponents/PatchSet/PatchSet.test.js
+++ b/src/SmartComponents/PatchSet/PatchSet.test.js
@@ -11,64 +11,61 @@ import { initMocks } from '../../Utilities/unitTestingUtilities.js';
import PatchSet from './PatchSet';
jest.mock('react-redux', () => ({
- ...jest.requireActual('react-redux'),
- useSelector: jest.fn()
+ ...jest.requireActual('react-redux'),
+ useSelector: jest.fn(),
}));
jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useHistory: jest.fn(() => ({ location: { search: 'test-search' }, push: () => {} }))
+ ...jest.requireActual('react-router-dom'),
+ useHistory: jest.fn(() => ({ location: { search: 'test-search' }, push: () => {} })),
}));
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
- useChrome: jest.fn(() => ({
- auth: {
- getUser: () => new Promise(
- (resolve) => resolve({ entitlements: { 'test-entitelement': true } })
- )
- }
- }))
+ useChrome: jest.fn(() => ({
+ auth: {
+ getUser: () =>
+ new Promise((resolve) => resolve({ entitlements: { 'test-entitelement': true } })),
+ },
+ })),
}));
initMocks();
const mockState = {
- ...storeListDefaults,
- rows: createPatchSetRows(patchSets.data, {}, {}),
- status: { isLoading: false, code: 200, hasError: false },
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 10
- }
+ ...storeListDefaults,
+ rows: createPatchSetRows(patchSets.data, {}, {}),
+ status: { isLoading: false, code: 200, hasError: false },
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 10,
+ },
};
const initStore = (state) => {
- const customMiddleWare = () => next => action => {
- useSelector.mockImplementation(callback => {
- return callback({ PatchSetsStore: state });
- });
- next(action);
- };
+ const customMiddleWare = () => (next) => (action) => {
+ useSelector.mockImplementation((callback) => callback({ PatchSetsStore: state }));
+ next(action);
+ };
- const mockStore = configureStore([customMiddleWare]);
- return mockStore({ PatchSetsStore: state });
+ const mockStore = configureStore([customMiddleWare]);
+ return mockStore({ PatchSetsStore: state });
};
let store = initStore(mockState);
beforeEach(() => {
- store.clearActions();
- useSelector.mockImplementation(callback => {
- return callback({ PatchSetsStore: mockState });
- });
+ store.clearActions();
+ useSelector.mockImplementation((callback) => callback({ PatchSetsStore: mockState }));
});
describe('HeaderBreadcrumbs', () => {
- it('Should render correctly', () => {
- const { asFragment } = render(
-
- {} }}/>
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should render correctly', () => {
+ const { asFragment } = render(
+
+
+ {} }} />
+
+ ,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/SmartComponents/PatchSet/PatchSetAssets.js b/src/SmartComponents/PatchSet/PatchSetAssets.js
index b85ed2b84..1b6cb5e29 100644
--- a/src/SmartComponents/PatchSet/PatchSetAssets.js
+++ b/src/SmartComponents/PatchSet/PatchSetAssets.js
@@ -1,107 +1,110 @@
import React from 'react';
import { Button, Icon, Tooltip } from '@patternfly/react-core';
import { sortable } from '@patternfly/react-table';
-import {
- EllipsisVIcon
-} from '@patternfly/react-icons';
+import { EllipsisVIcon } from '@patternfly/react-icons';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
export const CreatePatchSetButton = (setPatchSetState, hasAccess) => () =>
- !hasAccess ?
-
-
-
- :
- ();
+ !hasAccess ? (
+
+
+
+ ) : (
+
+ );
export const patchSetColumns = [
- {
- key: 'name',
- title: 'Name',
- transforms: [sortable]
- },
- {
- key: 'systems',
- title: 'Systems applied',
- transforms: [sortable]
- },
- {
- key: 'last_edited',
- title: 'Last edited',
- transforms: [sortable]
- },
- {
- key: 'published',
- title: 'Published',
- transforms: [sortable]
- },
- {
- key: 'creator',
- title: 'Created by',
- transforms: [sortable]
- }
+ {
+ key: 'name',
+ title: 'Name',
+ transforms: [sortable],
+ },
+ {
+ key: 'systems',
+ title: 'Systems applied',
+ transforms: [sortable],
+ },
+ {
+ key: 'last_edited',
+ title: 'Last edited',
+ transforms: [sortable],
+ },
+ {
+ key: 'published',
+ title: 'Published',
+ transforms: [sortable],
+ },
+ {
+ key: 'creator',
+ title: 'Created by',
+ transforms: [sortable],
+ },
];
export const patchSetRowActions = (openPatchSetEditModal, handlePatchSetDelete) => [
- {
- title: intl.formatMessage(messages.labelsButtonEditTemplate),
- onClick: (_event, _rowId, rowData) => {
- openPatchSetEditModal(rowData?.id);
- }
+ {
+ title: intl.formatMessage(messages.labelsButtonEditTemplate),
+ onClick: (_event, _rowId, rowData) => {
+ openPatchSetEditModal(rowData?.id);
+ },
+ },
+ {
+ title: intl.formatMessage(messages.labelsButtonRemoveTemplate),
+ onClick: (_event, _rowId, rowData) => {
+ handlePatchSetDelete(rowData);
},
- {
- title: intl.formatMessage(messages.labelsButtonRemoveTemplate),
- onClick: (_event, _rowId, rowData) => {
- handlePatchSetDelete(rowData);
- }
- }
+ },
];
export const patchSetDetailRowActions = (handleSystemUnassign) => [
- {
- title: intl.formatMessage(messages.titlesTemplateRemoveFromSystems, { systemsCount: 1 }),
- onClick: (_event, _rowId, rowData) => {
- handleSystemUnassign([rowData.id]);
- }
- }
-
+ {
+ title: intl.formatMessage(messages.titlesTemplateRemoveFromSystems, { systemsCount: 1 }),
+ onClick: (_event, _rowId, rowData) => {
+ handleSystemUnassign([rowData.id]);
+ },
+ },
];
-export const CustomActionsToggle = () =>
-
+);
export const patchSetUnassignSystemsNotifications = (systemsCount) => ({
- success: {
- title: `Systems succesfully removed from this Patch template.`,
- description: `${systemsCount} ${systemsCount > 1 ? 'systems' : 'system'} removed from Patch template(s)`,
- variant: 'success'
- },
- failure: {
- title: `Failed to remove systems from this Patch template.`,
- variant: 'danger'
- }
+ success: {
+ title: `Systems succesfully removed from this Patch template.`,
+ description: `${systemsCount} ${systemsCount > 1 ? 'systems' : 'system'} removed from Patch template(s)`,
+ variant: 'success',
+ },
+ failure: {
+ title: `Failed to remove systems from this Patch template.`,
+ variant: 'danger',
+ },
});
export const patchSetAssignSystemsNotifications = (systemsCount) => ({
- success: {
- title: `Systems succesfully applied to this Patch template.`,
- description: `${systemsCount} ${systemsCount > 1 ? 'systems' : 'system'} added to Patch template(s)`,
- variant: 'success'
- },
- failure: {
- title: `Failed to apply systems to this Patch template.`,
- variant: 'danger'
- }
+ success: {
+ title: `Systems succesfully applied to this Patch template.`,
+ description: `${systemsCount} ${systemsCount > 1 ? 'systems' : 'system'} added to Patch template(s)`,
+ variant: 'success',
+ },
+ failure: {
+ title: `Failed to apply systems to this Patch template.`,
+ variant: 'danger',
+ },
});
diff --git a/src/SmartComponents/PatchSetDetail/PatchSetDetail.js b/src/SmartComponents/PatchSetDetail/PatchSetDetail.js
index f7adfaa54..83ff58cc5 100644
--- a/src/SmartComponents/PatchSetDetail/PatchSetDetail.js
+++ b/src/SmartComponents/PatchSetDetail/PatchSetDetail.js
@@ -6,28 +6,34 @@ import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import messages from '../../Messages';
import Header from '../../PresentationalComponents/Header/Header';
import { NoAppliedSystems } from '../../PresentationalComponents/Snippets/EmptyStates';
-import { useBulkSelectConfig, useDeepCompareEffect, useGetEntities, useRemoveFilter } from '../../Utilities/hooks';
import {
- changePatchSetDetailsSystemsMetadata,
- changePatchSetDetailsSystemsParams,
- changeTags,
- clearInventoryReducer,
- clearTemplateDetail,
- fetchPatchSetSystemsNoFiltersAction,
- fetchTemplateDetail
-} from '../../store/Actions/Actions';
+ useBulkSelectConfig,
+ useDeepCompareEffect,
+ useGetEntities,
+ useRemoveFilter,
+ ID_API_ENDPOINTS,
+ useOnSelect,
+} from '../../Utilities/hooks';
import {
- Bullseye,
- Skeleton,
- Spinner,
- Content,
- Tooltip
-} from '@patternfly/react-core';
+ changePatchSetDetailsSystemsMetadata,
+ changePatchSetDetailsSystemsParams,
+ changeTags,
+ clearInventoryReducer,
+ clearTemplateDetail,
+ fetchPatchSetSystemsNoFiltersAction,
+ fetchTemplateDetail,
+ systemSelectAction,
+} from '../../store/Actions/Actions';
import {
- Dropdown,
- DropdownItem,
- DropdownPosition,
- DropdownToggle
+ Bullseye,
+ Skeleton,
+ Spinner,
+ Content,
+ Tooltip,
+ Dropdown,
+ DropdownItem,
+ DropdownPosition,
+ DropdownToggle,
} from '@patternfly/react-core';
import DeleteSetModal from '../Modals/DeleteSetModal';
import { deletePatchSet, fetchPatchSetSystems } from '../../Utilities/api';
@@ -35,11 +41,11 @@ import { addNotification } from '@redhat-cloud-services/frontend-components-noti
import { patchSetDeleteNotifications } from '../../Utilities/constants';
import ErrorHandler from '../../PresentationalComponents/Snippets/ErrorHandler';
import {
- arrayFromObj,
- decodeQueryparams,
- encodeURLParams,
- filterSelectedActiveSystemIDs,
- persistantParams
+ arrayFromObj,
+ decodeQueryparams,
+ encodeURLParams,
+ filterSelectedActiveSystemIDs,
+ persistantParams,
} from '../../Utilities/Helpers';
import PatchSetWizard from '../PatchSetWizard/PatchSetWizard';
import { patchSetDetailRowActions } from '../PatchSet/PatchSetAssets';
@@ -48,403 +54,413 @@ import UnassignSystemsModal from '../Modals/UnassignSystemsModal';
import { TableVariant } from '@patternfly/react-table';
import { InventoryTable } from '@redhat-cloud-services/frontend-components/Inventory';
import {
- buildActiveFiltersConfig,
- buildTemplateFilterConfig,
- templateSystemsColumnsMerger
+ buildActiveFiltersConfig,
+ buildTemplateFilterConfig,
+ templateSystemsColumnsMerger,
} from '../../Utilities/SystemsHelpers';
import { combineReducers } from 'redux';
import { defaultReducers } from '../../store';
-import { inventoryEntitiesReducer, modifyTemplateDetailSystems } from '../../store/Reducers/InventoryEntitiesReducer';
+import {
+ inventoryEntitiesReducer,
+ modifyTemplateDetailSystems,
+} from '../../store/Reducers/InventoryEntitiesReducer';
import { SYSTEMS_LIST_COLUMNS } from '../Systems/SystemsListAssets';
import { processDate } from '@redhat-cloud-services/frontend-components-utilities/helpers';
-import { ID_API_ENDPOINTS, useOnSelect } from '../../Utilities/hooks';
-import { systemSelectAction } from '../../store/Actions/Actions';
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
const PatchSetDetail = () => {
- const intl = useIntl();
- const dispatch = useDispatch();
- const chrome = useChrome();
- const [searchParams, setSearchParams] = useSearchParams();
- const navigate = useNavigate();
-
- const store = useStore();
- const inventory = useRef(null);
-
- const { templateName: patchSetId } = useParams();
-
- const [firstMount, setFirstMount] = React.useState(true);
- const [isHeaderDropdownOpen, setHeaderDropdownOpen] = useState(false);
- const [isDeleteConfirmModalOpen, setDeleteConfirmModalOpen] = useState(false);
- const [patchSetState, setPatchSetState] = useState({
- isPatchSetWizardOpen: false,
- isUnassignSystemsModalOpen: false,
- systemsIDs: [],
- shouldRefresh: false
- });
+ const intl = useIntl();
+ const dispatch = useDispatch();
+ const chrome = useChrome();
+ const [searchParams, setSearchParams] = useSearchParams();
+ const navigate = useNavigate();
- const templateDetails = useSelector(
- ({ PatchSetDetailStore }) => PatchSetDetailStore
- );
-
- const isHeaderLoading = useSelector(
- ({ PatchSetDetailStore }) => PatchSetDetailStore?.status?.isLoading ?? true
- );
-
- const detailStatus = useSelector(
- ({ PatchSetDetailStore }) => PatchSetDetailStore.status
- );
-
- const systems = useSelector(
- ({ entities }) => entities?.rows || [], shallowEqual
- );
-
- const selectedRows = useSelector(
- ({ entities }) => entities?.selectedRows || []
- );
-
- const systemStatus = useSelector(
- ({ entities }) => entities?.status || {}
- );
-
- const totalItems = useSelector(
- ({ entities }) => entities?.total || 0
- );
-
- const queryParams = useSelector(
- ({ PatchSetDetailSystemsStore }) => PatchSetDetailSystemsStore?.queryParams || {}
- );
-
- const templateHasSystemsLoading = useSelector(
- ({ PatchSetDetailSystemsStore }) => PatchSetDetailSystemsStore?.templateHasSystemsLoading
- );
-
- const templateHasSystems = useSelector(
- ({ PatchSetDetailSystemsStore }) => PatchSetDetailSystemsStore?.templateHasSystems
- );
-
- const { hasAccess } = usePermissionsWithContext([
- 'patch:*:*',
- 'patch:template:write'
- ]);
-
- const patchSetName = templateDetails.data.attributes.name;
-
- useEffect(() => {
- patchSetName && chrome.updateDocumentTitle(`${patchSetName} - Templates - Patch | RHEL`, true);
- }, [chrome, patchSetName]);
-
- const onSelect = useOnSelect(
- systems,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.templateSystems(patchSetId),
- queryParams,
- selectionDispatcher: systemSelectAction,
- totalItems
- }
- );
+ const store = useStore();
+ const inventory = useRef(null);
- const apply = (params) => {
- dispatch(changePatchSetDetailsSystemsParams(params));
- };
+ const { templateName: patchSetId } = useParams();
- const openPatchSetAssignWizard = () => {
- setPatchSetState({
- ...patchSetState,
- isPatchSetWizardOpen: true
- });
- };
+ const [firstMount, setFirstMount] = React.useState(true);
+ const [isHeaderDropdownOpen, setHeaderDropdownOpen] = useState(false);
+ const [isDeleteConfirmModalOpen, setDeleteConfirmModalOpen] = useState(false);
+ const [patchSetState, setPatchSetState] = useState({
+ isPatchSetWizardOpen: false,
+ isUnassignSystemsModalOpen: false,
+ systemsIDs: [],
+ shouldRefresh: false,
+ });
- const refreshTable = () => {
- // timestamp is used to force inventory to refresh
- // if it wasn't there inventory might ignore request to refresh because parameters are the same
- inventory?.current?.onRefreshData({ timestamp: Date.now() });
+ const templateDetails = useSelector(({ PatchSetDetailStore }) => PatchSetDetailStore);
- onSelect('none');
+ const isHeaderLoading = useSelector(
+ ({ PatchSetDetailStore }) => PatchSetDetailStore?.status?.isLoading ?? true,
+ );
- dispatch(fetchTemplateDetail(patchSetId));
- };
+ const detailStatus = useSelector(({ PatchSetDetailStore }) => PatchSetDetailStore.status);
- useEffect(() => {
- dispatch(fetchPatchSetSystemsNoFiltersAction({ id: patchSetId, limit: 1 }));
+ const systems = useSelector(({ entities }) => entities?.rows || [], shallowEqual);
- return () => {
- dispatch(clearTemplateDetail());
- dispatch(clearInventoryReducer());
- };
- }, []);
+ const selectedRows = useSelector(({ entities }) => entities?.selectedRows || []);
- useEffect(() => {
- if (patchSetState.shouldRefresh === true) {
- refreshTable();
- setPatchSetState({ ...patchSetState, shouldRefresh: false });
- dispatch(fetchPatchSetSystemsNoFiltersAction({ id: patchSetId, limit: 1 }));
- }
- }, [patchSetState.shouldRefresh]);
+ const systemStatus = useSelector(({ entities }) => entities?.status || {});
- useDeepCompareEffect(() => {
- if (firstMount) {
- apply(decodeQueryparams('?' + searchParams.toString()));
+ const totalItems = useSelector(({ entities }) => entities?.total || 0);
- dispatch(fetchTemplateDetail(patchSetId));
+ const queryParams = useSelector(
+ ({ PatchSetDetailSystemsStore }) => PatchSetDetailSystemsStore?.queryParams || {},
+ );
- setFirstMount(false);
- } else {
- setSearchParams(encodeURLParams(queryParams));
- }
- }, [queryParams, firstMount]);
+ const templateHasSystemsLoading = useSelector(
+ ({ PatchSetDetailSystemsStore }) => PatchSetDetailSystemsStore?.templateHasSystemsLoading,
+ );
- const openSystemUnassignModal = ids => {
- setPatchSetState({ ...patchSetState, isUnassignSystemsModalOpen: true, systemsIDs: ids });
- };
+ const templateHasSystems = useSelector(
+ ({ PatchSetDetailSystemsStore }) => PatchSetDetailSystemsStore?.templateHasSystems,
+ );
- const deleteSet = () => {
- deletePatchSet(patchSetId).then(() => {
- dispatch(addNotification(patchSetDeleteNotifications(patchSetName).success));
- navigate('../templates');
- }).catch(() => {
- dispatch(addNotification(patchSetDeleteNotifications(patchSetName).error));
- });
- };
+ const { hasAccess } = usePermissionsWithContext(['patch:*:*', 'patch:template:write']);
- const applyMetadata = (metadata) => {
- dispatch(changePatchSetDetailsSystemsMetadata(metadata));
- };
+ const patchSetName = templateDetails.data.attributes.name;
- const applyGlobalFilter = (tags) => {
- dispatch(changeTags(tags));
- };
+ useEffect(() => {
+ patchSetName && chrome.updateDocumentTitle(`${patchSetName} - Templates - Patch | RHEL`, true);
+ }, [chrome, patchSetName]);
+
+ const onSelect = useOnSelect(systems, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.templateSystems(patchSetId),
+ queryParams,
+ selectionDispatcher: systemSelectAction,
+ totalItems,
+ });
+
+ const apply = (params) => {
+ dispatch(changePatchSetDetailsSystemsParams(params));
+ };
+
+ const openPatchSetAssignWizard = () => {
+ setPatchSetState({
+ ...patchSetState,
+ isPatchSetWizardOpen: true,
+ });
+ };
- const getEntities = useGetEntities(
- fetchPatchSetSystems,
- apply,
- { id: patchSetId },
- setSearchParams,
- applyMetadata,
- applyGlobalFilter
- );
-
- const addTooltip = (children, key) => (
-
- {children}
-
- );
-
- const editTemplateButton = (
- openPatchSetAssignWizard()}
- isDisabled={!hasAccess}
- >
- {intl.formatMessage(messages.labelsButtonEditTemplate)}
-
- );
-
- const deleteTemplateButton = (
- setDeleteConfirmModalOpen(true)}
- isDisabled={!hasAccess}
- >
- {intl.formatMessage(messages.labelsButtonRemoveTemplate)}
-
- );
-
- const dropdownItems = [
- hasAccess ? editTemplateButton : addTooltip(editTemplateButton, 'edit-template'),
- hasAccess ? deleteTemplateButton : addTooltip(deleteTemplateButton, 'delete-template')
- ];
-
- const decodedParams = decodeQueryparams('?' + searchParams.toString());
-
- const { systemProfile, selectedTags, filter, search, page, perPage, sort } = queryParams;
-
- const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
-
- const bulkSelectConfig = useBulkSelectConfig(selectedCount, onSelect, { total_items: totalItems }, systems);
-
- const [deleteFilters] = useRemoveFilter({ search, ...filter }, apply);
-
- const filterConfig = buildTemplateFilterConfig(search, apply);
-
- const activeFiltersConfig = buildActiveFiltersConfig(filter, search, deleteFilters);
-
- return (
- detailStatus?.hasError
- ?
- :
-
- {patchSetState.isPatchSetWizardOpen &&
- }
-
- : patchSetName}
- headerOUIA={'template-details'}
- breadcrumbs={[
- {
- title: intl.formatMessage(messages.templateDetailHeaderBreadcrumb),
- to: '/templates',
- isActive: false
- },
- {
- title: isHeaderLoading ? : patchSetName,
- isActive: true
- }
- ]}
- actions={
- {
- setHeaderDropdownOpen(false);
- document.getElementById('patch-set-detail-header-kebab').focus();
- }}
- toggle={
-
- }
- isOpen={isHeaderDropdownOpen}
- dropdownItems={dropdownItems}
- />
- }
- >
-
-
-
- | {intl.formatMessage(messages.templateDetailTableDescription)} |
-
- {isHeaderLoading
- ?
- : templateDetails.data.attributes.description
- || intl.formatMessage(messages.titlesTemplateNoDescription)}
- |
-
-
- | {intl.formatMessage(messages.templateDetailTableUpToDate)} |
-
- {isHeaderLoading
- ?
- : processDate(templateDetails.data.attributes.config.to_time)}
- |
-
-
- | {intl.formatMessage(messages.templateDetailTableCreatedBy)} |
-
- {isHeaderLoading
- ?
- : templateDetails.data.attributes.creator}
- |
-
-
- | {intl.formatMessage(messages.templateDetailTablePublished)} |
-
- {isHeaderLoading
- ?
- : processDate(templateDetails.data.attributes.published)}
- |
-
-
- | {intl.formatMessage(messages.templateDetailTableLastEdited)} |
-
- {isHeaderLoading
- ?
- : processDate(templateDetails.data.attributes.last_edited)}
- |
-
-
-
-
-
-
-
- {intl.formatMessage(messages.templateDetailTableTitle)}
-
-
- {templateHasSystemsLoading
- ? (
-
-
-
- ) : templateHasSystems
- ? systemStatus.hasError
- ?
- : templateSystemsColumnsMerger(defaultColumns)}
- showTags
- onLoad={({ mergeWithEntities }) => {
- store.replaceReducer(combineReducers({
- ...defaultReducers,
- ...mergeWithEntities(
- inventoryEntitiesReducer(SYSTEMS_LIST_COLUMNS, modifyTemplateDetailSystems),
- persistantParams({ page, perPage, sort, search }, decodedParams)
- )
- }));
- }}
- customFilters={{
- patchParams: {
- search,
- filter,
- systemProfile,
- selectedTags
- }
- }}
- paginationProps={{
- isDisabled: totalItems === 0
- }}
- getEntities={getEntities}
- bulkSelect={bulkSelectConfig}
- tableProps={{
- canSelectAll: false,
- variant: TableVariant.compact,
- className: 'patchCompactInventory',
- isStickyHeader: true,
- actionResolver: () => hasAccess ? patchSetDetailRowActions(openSystemUnassignModal) : []
- }}
- actionsConfig={{
- actions: [
- '', // intentionally empty, remediation button placeholder
- {
- key: 'remove-multiple-systems',
- label: intl.formatMessage(
- messages.titlesTemplateRemoveFromSystems,
- { systemsCount: selectedCount }
- ),
- onClick: () =>
- openSystemUnassignModal(filterSelectedActiveSystemIDs(selectedRows)),
- props: { isDisabled: selectedCount === 0 }
- }
- ]
- }}
- filterConfig={filterConfig}
- activeFiltersConfig={activeFiltersConfig}
- />
- : openPatchSetAssignWizard()} />}
-
-
- );
+ const refreshTable = () => {
+ // timestamp is used to force inventory to refresh
+ // if it wasn't there inventory might ignore request to refresh because parameters are the same
+ inventory?.current?.onRefreshData({ timestamp: Date.now() });
+
+ onSelect('none');
+
+ dispatch(fetchTemplateDetail(patchSetId));
+ };
+
+ useEffect(() => {
+ dispatch(fetchPatchSetSystemsNoFiltersAction({ id: patchSetId, limit: 1 }));
+
+ return () => {
+ dispatch(clearTemplateDetail());
+ dispatch(clearInventoryReducer());
+ };
+ }, []);
+
+ useEffect(() => {
+ if (patchSetState.shouldRefresh === true) {
+ refreshTable();
+ setPatchSetState({ ...patchSetState, shouldRefresh: false });
+ dispatch(fetchPatchSetSystemsNoFiltersAction({ id: patchSetId, limit: 1 }));
+ }
+ }, [patchSetState.shouldRefresh]);
+
+ useDeepCompareEffect(() => {
+ if (firstMount) {
+ apply(decodeQueryparams('?' + searchParams.toString()));
+
+ dispatch(fetchTemplateDetail(patchSetId));
+
+ setFirstMount(false);
+ } else {
+ setSearchParams(encodeURLParams(queryParams));
+ }
+ }, [queryParams, firstMount]);
+
+ const openSystemUnassignModal = (ids) => {
+ setPatchSetState({ ...patchSetState, isUnassignSystemsModalOpen: true, systemsIDs: ids });
+ };
+
+ const deleteSet = () => {
+ deletePatchSet(patchSetId)
+ .then(() => {
+ dispatch(addNotification(patchSetDeleteNotifications(patchSetName).success));
+ navigate('../templates');
+ })
+ .catch(() => {
+ dispatch(addNotification(patchSetDeleteNotifications(patchSetName).error));
+ });
+ };
+
+ const applyMetadata = (metadata) => {
+ dispatch(changePatchSetDetailsSystemsMetadata(metadata));
+ };
+
+ const applyGlobalFilter = (tags) => {
+ dispatch(changeTags(tags));
+ };
+
+ const getEntities = useGetEntities(
+ fetchPatchSetSystems,
+ apply,
+ { id: patchSetId },
+ setSearchParams,
+ applyMetadata,
+ applyGlobalFilter,
+ );
+
+ const addTooltip = (children, key) => (
+
+ {children}
+
+ );
+
+ const editTemplateButton = (
+ openPatchSetAssignWizard()}
+ isDisabled={!hasAccess}
+ >
+ {intl.formatMessage(messages.labelsButtonEditTemplate)}
+
+ );
+
+ const deleteTemplateButton = (
+ setDeleteConfirmModalOpen(true)}
+ isDisabled={!hasAccess}
+ >
+ {intl.formatMessage(messages.labelsButtonRemoveTemplate)}
+
+ );
+
+ const dropdownItems = [
+ hasAccess ? editTemplateButton : addTooltip(editTemplateButton, 'edit-template'),
+ hasAccess ? deleteTemplateButton : addTooltip(deleteTemplateButton, 'delete-template'),
+ ];
+
+ const decodedParams = decodeQueryparams('?' + searchParams.toString());
+
+ const { systemProfile, selectedTags, filter, search, page, perPage, sort } = queryParams;
+
+ const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
+
+ const bulkSelectConfig = useBulkSelectConfig(
+ selectedCount,
+ onSelect,
+ { total_items: totalItems },
+ systems,
+ );
+
+ const [deleteFilters] = useRemoveFilter({ search, ...filter }, apply);
+
+ const filterConfig = buildTemplateFilterConfig(search, apply);
+
+ const activeFiltersConfig = buildActiveFiltersConfig(filter, search, deleteFilters);
+
+ return detailStatus?.hasError ? (
+
+ ) : (
+
+
+ {patchSetState.isPatchSetWizardOpen && (
+
+ )}
+
+ : patchSetName}
+ headerOUIA='template-details'
+ breadcrumbs={[
+ {
+ title: intl.formatMessage(messages.templateDetailHeaderBreadcrumb),
+ to: '/templates',
+ isActive: false,
+ },
+ {
+ title: isHeaderLoading ? : patchSetName,
+ isActive: true,
+ },
+ ]}
+ actions={
+ {
+ setHeaderDropdownOpen(false);
+ document.getElementById('patch-set-detail-header-kebab').focus();
+ }}
+ toggle={
+
+ }
+ isOpen={isHeaderDropdownOpen}
+ dropdownItems={dropdownItems}
+ />
+ }
+ >
+
+
+
+ |
+ {intl.formatMessage(messages.templateDetailTableDescription)}
+ |
+
+ {isHeaderLoading ? (
+
+ ) : (
+ templateDetails.data.attributes.description ||
+ intl.formatMessage(messages.titlesTemplateNoDescription)
+ )}
+ |
+
+
+ | {intl.formatMessage(messages.templateDetailTableUpToDate)} |
+
+ {isHeaderLoading ? (
+
+ ) : (
+ processDate(templateDetails.data.attributes.config.to_time)
+ )}
+ |
+
+
+ | {intl.formatMessage(messages.templateDetailTableCreatedBy)} |
+
+ {isHeaderLoading ? (
+
+ ) : (
+ templateDetails.data.attributes.creator
+ )}
+ |
+
+
+ | {intl.formatMessage(messages.templateDetailTablePublished)} |
+
+ {isHeaderLoading ? (
+
+ ) : (
+ processDate(templateDetails.data.attributes.published)
+ )}
+ |
+
+
+ | {intl.formatMessage(messages.templateDetailTableLastEdited)} |
+
+ {isHeaderLoading ? (
+
+ ) : (
+ processDate(templateDetails.data.attributes.last_edited)
+ )}
+ |
+
+
+
+
+
+
+
+ {intl.formatMessage(messages.templateDetailTableTitle)}
+
+
+ {templateHasSystemsLoading ? (
+
+
+
+ ) : templateHasSystems ? (
+ systemStatus.hasError ? (
+
+ ) : (
+ templateSystemsColumnsMerger(defaultColumns)}
+ showTags
+ onLoad={({ mergeWithEntities }) => {
+ store.replaceReducer(
+ combineReducers({
+ ...defaultReducers,
+ ...mergeWithEntities(
+ inventoryEntitiesReducer(SYSTEMS_LIST_COLUMNS, modifyTemplateDetailSystems),
+ persistantParams({ page, perPage, sort, search }, decodedParams),
+ ),
+ }),
+ );
+ }}
+ customFilters={{
+ patchParams: {
+ search,
+ filter,
+ systemProfile,
+ selectedTags,
+ },
+ }}
+ paginationProps={{
+ isDisabled: totalItems === 0,
+ }}
+ getEntities={getEntities}
+ bulkSelect={bulkSelectConfig}
+ tableProps={{
+ canSelectAll: false,
+ variant: TableVariant.compact,
+ className: 'patchCompactInventory',
+ isStickyHeader: true,
+ actionResolver: () =>
+ hasAccess ? patchSetDetailRowActions(openSystemUnassignModal) : [],
+ }}
+ actionsConfig={{
+ actions: [
+ '', // intentionally empty, remediation button placeholder
+ {
+ key: 'remove-multiple-systems',
+ label: intl.formatMessage(messages.titlesTemplateRemoveFromSystems, {
+ systemsCount: selectedCount,
+ }),
+ onClick: () =>
+ openSystemUnassignModal(filterSelectedActiveSystemIDs(selectedRows)),
+ props: { isDisabled: selectedCount === 0 },
+ },
+ ],
+ }}
+ filterConfig={filterConfig}
+ activeFiltersConfig={activeFiltersConfig}
+ />
+ )
+ ) : (
+ openPatchSetAssignWizard()}
+ />
+ )}
+
+
+ );
};
export default PatchSetDetail;
diff --git a/src/SmartComponents/PatchSetDetail/PatchSetDetailAssets.js b/src/SmartComponents/PatchSetDetail/PatchSetDetailAssets.js
index 01054d374..8dd67edd8 100644
--- a/src/SmartComponents/PatchSetDetail/PatchSetDetailAssets.js
+++ b/src/SmartComponents/PatchSetDetail/PatchSetDetailAssets.js
@@ -2,32 +2,37 @@ import { sortable } from '@patternfly/react-table/dist/js';
import { createAdvisoriesIcons, createOSColumn } from '../../Utilities/Helpers';
export const patchSetDetailColumns = [
- {
- key: 'os',
- title: 'OS',
- renderFunc: value => createOSColumn(value),
- transforms: [sortable]
- },
- {
- key: 'installable_rhsa_count',
- title: 'Installable advisories',
- renderFunc: (_a, _b, row) => createAdvisoriesIcons([
- row.installable_rhea_count,
- row.installable_rhba_count,
- row.installable_rhsa_count,
- row.installable_other_count
- ], 'installable'),
- transforms: [sortable]
- },
- {
- key: 'applicable_rhsa_count',
- title: 'Applicable advisories',
- transforms: [sortable],
- renderFunc: (_a, _b, row) => createAdvisoriesIcons([
- row.applicable_rhea_count,
- row.applicable_rhba_count,
- row.applicable_rhsa_count,
- row.applicable_other_count
- ])
- }
+ {
+ key: 'os',
+ title: 'OS',
+ renderFunc: (value) => createOSColumn(value),
+ transforms: [sortable],
+ },
+ {
+ key: 'installable_rhsa_count',
+ title: 'Installable advisories',
+ renderFunc: (_a, _b, row) =>
+ createAdvisoriesIcons(
+ [
+ row.installable_rhea_count,
+ row.installable_rhba_count,
+ row.installable_rhsa_count,
+ row.installable_other_count,
+ ],
+ 'installable',
+ ),
+ transforms: [sortable],
+ },
+ {
+ key: 'applicable_rhsa_count',
+ title: 'Applicable advisories',
+ transforms: [sortable],
+ renderFunc: (_a, _b, row) =>
+ createAdvisoriesIcons([
+ row.applicable_rhea_count,
+ row.applicable_rhba_count,
+ row.applicable_rhsa_count,
+ row.applicable_other_count,
+ ]),
+ },
];
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.js b/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.js
index 841e0ebf5..9a600aa2c 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.js
@@ -5,26 +5,30 @@ import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { nameComponent, descriptionComponent } from '../WizardAssets';
const ConfigurationFields = ({ isLoading }) => {
- const { renderForm } = useFormApi();
+ const { renderForm } = useFormApi();
- return (
-
- {/* The form element always need to be rendered in order to correctly disable "Next" button,
+ return (
+
+ {/* The form element always need to be rendered in order to correctly disable "Next" button,
that's why these are hidden using "display: none" instead of not rendering */}
-
-
-
- {renderForm(nameComponent)}
-
-
- {renderForm(descriptionComponent)}
-
-
-
- );
+
+
+
+ {renderForm(nameComponent)}
+
+
+ {renderForm(descriptionComponent)}
+
+
+
+ );
};
ConfigurationFields.propTypes = {
- isLoading: propTypes.bool
+ isLoading: propTypes.bool,
};
export default ConfigurationFields;
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.test.js b/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.test.js
index 8f0f1ca06..e572ad8f0 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.test.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/ConfigurationFields.test.js
@@ -1,22 +1,21 @@
import ConfigurationFields from './ConfigurationFields';
import { render } from '@testing-library/react';
-jest.mock('@data-driven-forms/react-form-renderer/use-form-api',
- () => jest.fn(() => ({
- renderForm: () => test form
- }))
+jest.mock('@data-driven-forms/react-form-renderer/use-form-api', () =>
+ jest.fn(() => ({
+ renderForm: () => test form
,
+ })),
);
describe('ConfigurationFields.js', () => {
- it('Should display Spinner on patch-set loading', () => {
- const { container } = render();
- expect(container.querySelector('#test-config-fields-spinner')).toBeTruthy();
- });
+ it('Should display Spinner on patch-set loading', () => {
+ const { container } = render();
+ expect(container.querySelector('#test-config-fields-spinner')).toBeTruthy();
+ });
- it('Should display configuration fields', () => {
- const { container } = render();
- const text = container.querySelector('#test-configuration-fields');
- expect(text).toBeTruthy();
- });
+ it('Should display configuration fields', () => {
+ const { container } = render();
+ const text = container.querySelector('#test-configuration-fields');
+ expect(text).toBeTruthy();
+ });
});
-
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.js b/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.js
index 36331ec61..57bfabf90 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.js
@@ -6,30 +6,30 @@ import { intl } from '../../../Utilities/IntlProvider';
import messages from '../../../Messages';
const DescriptionField = (props) => {
- const { input } = useFieldApi(props);
- const formOptions = useFormApi();
- const values = formOptions.getState()?.values;
+ const { input } = useFieldApi(props);
+ const formOptions = useFormApi();
+ const values = formOptions.getState()?.values;
- const [description, setDescription] = useState(values?.description);
+ const [description, setDescription] = useState(values?.description);
- useEffect(() => {
- setDescription(values.description);
- }, [values.description]);
+ useEffect(() => {
+ setDescription(values.description);
+ }, [values.description]);
- return (
-
- {
- input.onChange(val);
- setDescription(val);
- }}
- aria-label="description"
- />
-
- );
+ return (
+
+ {
+ input.onChange(val);
+ setDescription(val);
+ }}
+ aria-label='description'
+ />
+
+ );
};
export default DescriptionField;
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.test.js b/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.test.js
index 4c6633c04..a59c611f1 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.test.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/DescriptionField.test.js
@@ -2,51 +2,43 @@ import DescriptionField from './DescriptionField';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { render, screen } from '@testing-library/react';
-jest.mock('@data-driven-forms/react-form-renderer/use-form-api',
- () => ({
- __esModule: true,
- default: jest.fn()
- })
-);
+jest.mock('@data-driven-forms/react-form-renderer/use-form-api', () => ({
+ __esModule: true,
+ default: jest.fn(),
+}));
-jest.mock('@data-driven-forms/react-form-renderer/use-field-api',
- () => jest.fn(() =>({
- input: {
- onChange: jest.fn()
- }
- }))
+jest.mock('@data-driven-forms/react-form-renderer/use-field-api', () =>
+ jest.fn(() => ({
+ input: {
+ onChange: jest.fn(),
+ },
+ })),
);
describe('ConfigurationFields.js', () => {
- it('Should description field have default value', () => {
- useFormApi.mockReturnValue(({
- getState: () => ({
- values: { description: 'testDescription' }
- })
- })
- );
+ it('Should description field have default value', () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({
+ values: { description: 'testDescription' },
+ }),
+ });
- render(
-
- );
- const input = screen.getByRole('textbox', {
- name: /description/i
- });
- expect(input.value).toBe('testDescription');
+ render();
+ const input = screen.getByRole('textbox', {
+ name: /description/i,
});
+ expect(input.value).toBe('testDescription');
+ });
- it('Should display configuration fields', () => {
- useFormApi.mockReturnValue(({
- getState: () => ({ values: { } })
- })
- );
+ it('Should display configuration fields', () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({ values: {} }),
+ });
- render(
-
- );
- const input = screen.getByRole('textbox', {
- name: /description/i
- });
- expect(input.value).toBe('');
+ render();
+ const input = screen.getByRole('textbox', {
+ name: /description/i,
});
+ expect(input.value).toBe('');
+ });
});
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/NameField.js b/src/SmartComponents/PatchSetWizard/InputFields/NameField.js
index adc6e443b..d1c0dcf86 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/NameField.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/NameField.js
@@ -1,11 +1,11 @@
import React, { useState, useEffect } from 'react';
import {
- FormGroup,
- FormHelperText,
- HelperText,
- HelperTextItem,
- TextInput,
- Spinner
+ FormGroup,
+ FormHelperText,
+ HelperText,
+ HelperTextItem,
+ TextInput,
+ Spinner,
} from '@patternfly/react-core';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
@@ -15,86 +15,78 @@ import { useFetchAllTemplateData } from '../WizardAssets';
import { fetchPatchSets } from '../../../Utilities/api';
const NameField = (props) => {
- const { input } = useFieldApi(props);
- const formOptions = useFormApi();
- const values = formOptions.getState()?.values;
+ const { input } = useFieldApi(props);
+ const formOptions = useFormApi();
+ const values = formOptions.getState()?.values;
- const [name, setName] = useState(values?.name);
- const [validated, setValidated] = useState();
- const [takenTemplateNames, setTakenTemplateNames] = useState([]);
- const [areTakenTemplateNamesLoading, setAreTakenTemplateNamesLoading] = useState(true);
+ const [name, setName] = useState(values?.name);
+ const [validated, setValidated] = useState();
+ const [takenTemplateNames, setTakenTemplateNames] = useState([]);
+ const [areTakenTemplateNamesLoading, setAreTakenTemplateNamesLoading] = useState(true);
- const fetchTemplateNames = useFetchAllTemplateData(
- fetchPatchSets,
- ({ attributes }) => attributes.name
- );
+ const fetchTemplateNames = useFetchAllTemplateData(
+ fetchPatchSets,
+ ({ attributes }) => attributes.name,
+ );
- useEffect(() => {
- fetchTemplateNames().then(({ data, isLoading }) => {
- setTakenTemplateNames(data);
- setAreTakenTemplateNamesLoading(isLoading);
- });
- }, []);
+ useEffect(() => {
+ fetchTemplateNames().then(({ data, isLoading }) => {
+ setTakenTemplateNames(data);
+ setAreTakenTemplateNamesLoading(isLoading);
+ });
+ }, []);
- useEffect(() => {
- const validateName = () => {
- if (
- values.name === undefined ||
- values.name === values.previousName
- ) {
- return 'default';
- }
+ useEffect(() => {
+ const validateName = () => {
+ if (values.name === undefined || values.name === values.previousName) {
+ return 'default';
+ }
- if (takenTemplateNames.includes(values.name)) {
- return 'error';
- }
+ if (takenTemplateNames.includes(values.name)) {
+ return 'error';
+ }
- return 'success';
- };
+ return 'success';
+ };
- setName(values.name);
- setValidated(validateName());
- }, [values.name, takenTemplateNames]);
+ setName(values.name);
+ setValidated(validateName());
+ }, [values.name, takenTemplateNames]);
- useEffect(() => {
- formOptions.change('takenTemplateNames', takenTemplateNames);
- formOptions.change('areTakenTemplateNamesLoading', areTakenTemplateNamesLoading);
- }, [takenTemplateNames, areTakenTemplateNamesLoading]);
+ useEffect(() => {
+ formOptions.change('takenTemplateNames', takenTemplateNames);
+ formOptions.change('areTakenTemplateNamesLoading', areTakenTemplateNamesLoading);
+ }, [takenTemplateNames, areTakenTemplateNamesLoading]);
- return (
-
- {
- input.onChange(val);
- setName(val);
- }}
- aria-label="name"
- autoFocus
- validated={validated}
- />
- {(validated === 'error' || areTakenTemplateNamesLoading) && (
-
-
- {areTakenTemplateNamesLoading
- ?
- :
- {intl.formatMessage(
- messages.templateWizardValidateNameTaken
- )}
-
- }
-
-
+ return (
+
+ {
+ input.onChange(val);
+ setName(val);
+ }}
+ aria-label='name'
+ autoFocus
+ validated={validated}
+ />
+ {(validated === 'error' || areTakenTemplateNamesLoading) && (
+
+
+ {areTakenTemplateNamesLoading ? (
+
+ ) : (
+
+ {intl.formatMessage(messages.templateWizardValidateNameTaken)}
+
)}
-
- );
+
+
+ )}
+
+ );
};
export default NameField;
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/NameField.test.js b/src/SmartComponents/PatchSetWizard/InputFields/NameField.test.js
index 1e5885e18..b58390e0d 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/NameField.test.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/NameField.test.js
@@ -3,73 +3,69 @@ import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { render, screen, waitFor, queryByLabelText } from '@testing-library/react';
import '@testing-library/jest-dom';
-jest.mock('@data-driven-forms/react-form-renderer/use-form-api',
- () => ({
- __esModule: true,
- default: jest.fn()
- })
-);
+jest.mock('@data-driven-forms/react-form-renderer/use-form-api', () => ({
+ __esModule: true,
+ default: jest.fn(),
+}));
-jest.mock('@data-driven-forms/react-form-renderer/use-field-api',
- () => jest.fn(() => ({
- input: {
- onChange: jest.fn()
- }
- }))
+jest.mock('@data-driven-forms/react-form-renderer/use-field-api', () =>
+ jest.fn(() => ({
+ input: {
+ onChange: jest.fn(),
+ },
+ })),
);
jest.mock('../../../Utilities/api', () => ({
- ...jest.requireActual('../../../Utilities/api'),
- fetchPatchSets: jest.fn(
- () => Promise.resolve({ data: [{ attributes: { name: 'taken-template-name' } }] })
- )
+ ...jest.requireActual('../../../Utilities/api'),
+ fetchPatchSets: jest.fn(() =>
+ Promise.resolve({ data: [{ attributes: { name: 'taken-template-name' } }] }),
+ ),
}));
describe('NameField.js', () => {
- it('Should description field have default value and fire input onChange', () => {
- useFormApi.mockReturnValue(({
- getState: () => ({
- values: { name: 'testName' }
- }),
- change: () => { }
- }));
-
- render(
-
- );
- expect(screen.getByRole('textbox', {
- name: /name/i
- })).toBeTruthy();
+ it('Should description field have default value and fire input onChange', () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({
+ values: { name: 'testName' },
+ }),
+ change: () => {},
});
- it('Should display configuration fields', () => {
- useFormApi.mockReturnValue(({
- getState: () => ({ values: {} }),
- change: () => { }
- }));
+ render();
+ expect(
+ screen.getByRole('textbox', {
+ name: /name/i,
+ }),
+ ).toBeTruthy();
+ });
- render(
-
- );
- const input = screen.getByRole('textbox', {
- name: /name/i
- });
- expect(input.value).toBe('');
+ it('Should display configuration fields', () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({ values: {} }),
+ change: () => {},
});
- it('Should invalidate taken template names', async () => {
- useFormApi.mockReturnValue(({
- getState: () => ({ values: { name: 'taken-template-name' } }),
- change: () => { }
- }));
+ render();
+ const input = screen.getByRole('textbox', {
+ name: /name/i,
+ });
+ expect(input.value).toBe('');
+ });
+
+ it('Should invalidate taken template names', async () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({ values: { name: 'taken-template-name' } }),
+ change: () => {},
+ });
- const { container } = render(
-
- );
+ const { container } = render();
- await waitFor(() => {
- expect(queryByLabelText(container, 'Contents')).not.toBeInTheDocument();
- });
- await waitFor(() => expect(screen.getByText('Template name already exists. Try a different name.')).toBeVisible());
+ await waitFor(() => {
+ expect(queryByLabelText(container, 'Contents')).not.toBeInTheDocument();
});
+ await waitFor(() =>
+ expect(screen.getByText('Template name already exists. Try a different name.')).toBeVisible(),
+ );
+ });
});
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.js b/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.js
index 313748b67..8f1dbfddd 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.js
@@ -4,153 +4,189 @@ import propTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { AngleLeftIcon, AngleRightIcon } from '@patternfly/react-icons';
import {
- FormGroup,
- Spinner,
- Flex,
- FlexItem,
- Button,
- Icon
-} from '@patternfly/react-core';
-import {
- Select,
- SelectOption,
- MenuToggle,
- SelectList
+ FormGroup,
+ Spinner,
+ Flex,
+ FlexItem,
+ Button,
+ Icon,
+ Select,
+ SelectOption,
+ MenuToggle,
+ SelectList,
} from '@patternfly/react-core';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
-import { fetchPatchSetsAction, changePatchSetsParams, clearPatchSetsAction } from '../../../store/Actions/Actions';
+import {
+ fetchPatchSetsAction,
+ changePatchSetsParams,
+ clearPatchSetsAction,
+} from '../../../store/Actions/Actions';
import { intl } from '../../../Utilities/IntlProvider';
import messages from '../../../Messages';
-const SelectPagination = ({ changePage, page, perPage, totalItems }) =>{
- const openNextPage = () => changePage(page + 1);
- const openPrevPage = () => changePage(page - 1);
-
- return (
-
-
-
-
- } variant="plain" aria-label="prev" isDisabled={page === 1} onClick={openPrevPage} />
-
-
-
-
- } variant="plain" aria-label="next"
- isDisabled={totalItems < page * perPage}
- onClick={openNextPage} />
-
-
- );
+const SelectPagination = ({ changePage, page, perPage, totalItems }) => {
+ const openNextPage = () => changePage(page + 1);
+ const openPrevPage = () => changePage(page - 1);
+
+ return (
+
+
+
+
+
+ }
+ variant='plain'
+ aria-label='prev'
+ isDisabled={page === 1}
+ onClick={openPrevPage}
+ />
+
+
+
+
+
+ }
+ variant='plain'
+ aria-label='next'
+ isDisabled={totalItems < page * perPage}
+ onClick={openNextPage}
+ />
+
+
+ );
};
-const SelectExistingSets = ({ setSelectedPatchSet, selectedSets, systems, selectCallback = () => {} }) => {
- const dispatch = useDispatch();
- const formOptions = useFormApi();
- const [isOpen, setOpen] = useState(false);
-
- const rows = useSelector(({ PatchSetsStore }) => PatchSetsStore.rows);
- const queryParams = useSelector(({ PatchSetsStore }) => PatchSetsStore.queryParams);
- const status = useSelector(({ PatchSetsStore }) => PatchSetsStore.status);
- const metadata = useSelector(({ PatchSetsStore }) => PatchSetsStore.metadata);
-
- useEffect(() => () => {
- dispatch(clearPatchSetsAction());
- }, []);
-
- const { search } = queryParams || {};
- const searchDependency = typeof search === 'string' && search !== '' ? search : Boolean(search);
-
- useEffect(() => {
- dispatch(fetchPatchSetsAction({ ...queryParams, offset:
- queryParams.offset + ((queryParams.page - 1) * queryParams.perPage) }));
- }, [queryParams.page, searchDependency]);
-
- const patchOptions = useMemo(() =>{
- if (status.isLoading) {
- return [];
- }
-
- return rows?.map(set =>
- {set.name}
- );
- }, [rows, status.isLoading]);
-
- const handleOpen = () => {
- setOpen(!isOpen);
- };
-
- const handleSelect = (_, selected) => {
- setOpen(false);
- setSelectedPatchSet(selected);
-
- const selectedSet = rows.filter(set => set.name === selected);
-
- if (selectedSet.length === 1) {
- selectCallback(selectedSet[0]);
- formOptions?.change?.('existing_patch_set', { name: selectedSet[0]?.name, systems, id: selectedSet[0]?.id });
- }
- };
-
- const changePage = (page) => {
- dispatch(changePatchSetsParams({ ...queryParams, page }));
- };
-
- const toggle = (toggleRef) => (
- setOpen(open => !open)}
- isExpanded={isOpen}
- isFullWidth
- aria-label={intl.formatMessage(messages.labelsFiltersSearchTemplatePlaceholder)}
- >
- {intl.formatMessage(messages.templateSelectExisting)}
-
- );
-
- return (
-
-
- }
- >
-
- {patchOptions}
-
-
-
+const SelectExistingSets = ({
+ setSelectedPatchSet,
+ selectedSets,
+ systems,
+ selectCallback = () => {},
+}) => {
+ const dispatch = useDispatch();
+ const formOptions = useFormApi();
+ const [isOpen, setOpen] = useState(false);
+
+ const rows = useSelector(({ PatchSetsStore }) => PatchSetsStore.rows);
+ const queryParams = useSelector(({ PatchSetsStore }) => PatchSetsStore.queryParams);
+ const status = useSelector(({ PatchSetsStore }) => PatchSetsStore.status);
+ const metadata = useSelector(({ PatchSetsStore }) => PatchSetsStore.metadata);
+
+ useEffect(
+ () => () => {
+ dispatch(clearPatchSetsAction());
+ },
+ [],
+ );
+
+ const { search } = queryParams || {};
+ const searchDependency = typeof search === 'string' && search !== '' ? search : Boolean(search);
+
+ useEffect(() => {
+ dispatch(
+ fetchPatchSetsAction({
+ ...queryParams,
+ offset: queryParams.offset + (queryParams.page - 1) * queryParams.perPage,
+ }),
);
+ }, [queryParams.page, searchDependency]);
+
+ const patchOptions = useMemo(() => {
+ if (status.isLoading) {
+ return [
+
+
+ ,
+ ];
+ }
+
+ return rows?.map((set) => (
+
+ {set.name}
+
+ ));
+ }, [rows, status.isLoading]);
+
+ const handleOpen = () => {
+ setOpen(!isOpen);
+ };
+
+ const handleSelect = (_, selected) => {
+ setOpen(false);
+ setSelectedPatchSet(selected);
+
+ const selectedSet = rows.filter((set) => set.name === selected);
+
+ if (selectedSet.length === 1) {
+ selectCallback(selectedSet[0]);
+ formOptions?.change?.('existing_patch_set', {
+ name: selectedSet[0]?.name,
+ systems,
+ id: selectedSet[0]?.id,
+ });
+ }
+ };
+
+ const changePage = (page) => {
+ dispatch(changePatchSetsParams({ ...queryParams, page }));
+ };
+
+ const toggle = (toggleRef) => (
+ setOpen((open) => !open)}
+ isExpanded={isOpen}
+ isFullWidth
+ aria-label={intl.formatMessage(messages.labelsFiltersSearchTemplatePlaceholder)}
+ >
+ {intl.formatMessage(messages.templateSelectExisting)}
+
+ );
+
+ return (
+
+
+ }
+ >
+ {patchOptions}
+
+
+ );
};
SelectPagination.propTypes = {
- changePage: propTypes.func,
- page: propTypes.number,
- perPage: propTypes.number,
- totalItems: propTypes.number
+ changePage: propTypes.func,
+ page: propTypes.number,
+ perPage: propTypes.number,
+ totalItems: propTypes.number,
};
SelectExistingSets.propTypes = {
- setSelectedPatchSet: propTypes.func,
- selectedSets: propTypes.array,
- systems: propTypes.array,
- selectCallback: propTypes.func
+ setSelectedPatchSet: propTypes.func,
+ selectedSets: propTypes.array,
+ systems: propTypes.array,
+ selectCallback: propTypes.func,
};
export default SelectExistingSets;
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.test.js b/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.test.js
index 35eaf145a..b5a424e71 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.test.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/SelectExistingSets.test.js
@@ -10,47 +10,42 @@ import userEvent from '@testing-library/user-event';
initMocks();
-const mockChage = jest.fn((payload) => { return payload; });
+const mockChage = jest.fn((payload) => payload);
jest.mock('@data-driven-forms/react-form-renderer/use-form-api', () => () => ({
- change: mockChage
-})
-);
+ change: mockChage,
+}));
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore({ PatchSetsStore: state });
+ const mockStore = configureStore([]);
+ return mockStore({ PatchSetsStore: state });
};
let store = initStore({
- ...initialState,
- rows: patchSets,
- status: { ...initialState, isLoading: false }
-
+ ...initialState,
+ rows: patchSets,
+ status: { ...initialState, isLoading: false },
});
beforeEach(() => {
- store.clearActions();
- render(
-
- );
+ store.clearActions();
+ render(
+
+
+ ,
+ );
});
describe('SelectExistingSets', () => {
- it('Should render the select existing sets component', () => {
-
- expect(screen.getByText('Select an existing template')).toBeVisible();
- expect(screen.getByText('Template')).toBeVisible();
- });
- it('Should render the select with options', async () => {
- await userEvent.click(screen.getByRole('button', { name: /filter by template name/i }));
- await waitFor(() => {
- expect(screen.getByText('test-set-1')).toBeInTheDocument();
- expect(screen.getAllByLabelText('patch-set-option')).toHaveLength(patchSets.length);
- });
-
+ it('Should render the select existing sets component', () => {
+ expect(screen.getByText('Select an existing template')).toBeVisible();
+ expect(screen.getByText('Template')).toBeVisible();
+ });
+ it('Should render the select with options', async () => {
+ await userEvent.click(screen.getByRole('button', { name: /filter by template name/i }));
+ await waitFor(() => {
+ expect(screen.getByText('test-set-1')).toBeInTheDocument();
+ expect(screen.getAllByLabelText('patch-set-option')).toHaveLength(patchSets.length);
});
+ });
});
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.js b/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.js
index 6cab8af6c..aa0aa7885 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.js
@@ -1,10 +1,5 @@
import React, { useState, useEffect } from 'react';
-import {
- FormGroup,
- DatePicker,
- Flex,
- FlexItem
-} from '@patternfly/react-core';
+import { FormGroup, DatePicker, Flex, FlexItem } from '@patternfly/react-core';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
import dateValidator from '../../../Utilities/dateValidator';
@@ -12,39 +7,39 @@ import { intl } from '../../../Utilities/IntlProvider';
import messages from '../../../Messages';
const ToDateField = (props) => {
- const { input } = useFieldApi(props);
- const formOptions = useFormApi();
- const values = formOptions.getState()?.values;
+ const { input } = useFieldApi(props);
+ const formOptions = useFormApi();
+ const values = formOptions.getState()?.values;
- const [toDate, setToDate] = useState(values?.toDate);
+ const [toDate, setToDate] = useState(values?.toDate);
- useEffect(() => {
- setToDate(values.toDate);
- }, [values.toDate]);
+ useEffect(() => {
+ setToDate(values.toDate);
+ }, [values.toDate]);
- return (
-
-
-
- {intl.formatMessage(messages.templateDateUpto)}
-
-
- {
- input.onChange(val);
- setToDate(val);
- }}
- popoverProps={{ position: 'right' }}
- aria-label="toDate"
- validators={[dateValidator]}
- invalidFormatText={intl.formatMessage(messages.labelsErrorInvalidDate)}
- />
-
-
-
- );
+ return (
+
+
+
+ {intl.formatMessage(messages.templateDateUpto)}
+
+
+ {
+ input.onChange(val);
+ setToDate(val);
+ }}
+ popoverProps={{ position: 'right' }}
+ aria-label='toDate'
+ validators={[dateValidator]}
+ invalidFormatText={intl.formatMessage(messages.labelsErrorInvalidDate)}
+ />
+
+
+
+ );
};
export default ToDateField;
diff --git a/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.test.js b/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.test.js
index 565b3ad92..abfd83c97 100644
--- a/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.test.js
+++ b/src/SmartComponents/PatchSetWizard/InputFields/ToDateField.test.js
@@ -2,35 +2,31 @@ import ToDateField from './ToDateField';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { render, screen } from '@testing-library/react';
-jest.mock('@data-driven-forms/react-form-renderer/use-form-api',
- () => ({
- __esModule: true,
- default: jest.fn()
- })
-);
+jest.mock('@data-driven-forms/react-form-renderer/use-form-api', () => ({
+ __esModule: true,
+ default: jest.fn(),
+}));
-jest.mock('@data-driven-forms/react-form-renderer/use-field-api',
- () => jest.fn(() => ({
- input: {
- onChange: jest.fn()
- }
- }))
+jest.mock('@data-driven-forms/react-form-renderer/use-field-api', () =>
+ jest.fn(() => ({
+ input: {
+ onChange: jest.fn(),
+ },
+ })),
);
describe('ConfigurationFields.js', () => {
- it('Should description field have default value', () => {
- useFormApi.mockReturnValue(({
- getState: () => ({
- values: { toDate: 'testToDate' }
- })
- })
- );
- render();
- expect(screen.getByRole('textbox', {
- name: /todate/i
- }).value).toEqual(
- 'testToDate'
- );
+ it('Should description field have default value', () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({
+ values: { toDate: 'testToDate' },
+ }),
});
+ render();
+ expect(
+ screen.getByRole('textbox', {
+ name: /todate/i,
+ }).value,
+ ).toEqual('testToDate');
+ });
});
-
diff --git a/src/SmartComponents/PatchSetWizard/PatchSetWizard.js b/src/SmartComponents/PatchSetWizard/PatchSetWizard.js
index 0b9c105ce..580c4d6fa 100644
--- a/src/SmartComponents/PatchSetWizard/PatchSetWizard.js
+++ b/src/SmartComponents/PatchSetWizard/PatchSetWizard.js
@@ -1,4 +1,3 @@
-
import React, { Fragment, useState, memo, useEffect } from 'react';
import propTypes from 'prop-types';
import FormRenderer from '@data-driven-forms/react-form-renderer/form-renderer';
@@ -8,10 +7,7 @@ import WizardMapper from '@data-driven-forms/pf4-component-mapper/wizard';
import TextField from '@data-driven-forms/pf4-component-mapper/text-field';
import DatePicker from '@data-driven-forms/pf4-component-mapper/date-picker';
-import {
- Wizard,
- Modal
-} from '@patternfly/react-core/deprecated';
+import { Wizard, Modal } from '@patternfly/react-core/deprecated';
import { useDispatch } from 'react-redux';
import ConfigurationStepFields from './steps/ConfigurationStepFields';
@@ -26,135 +22,128 @@ import RequestProgress from './steps/RequestProgress';
import { usePatchSetApi } from '../../Utilities/hooks';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
-import {
- fetchPatchSetAction,
- clearPatchSetAction
-} from '../../store/Actions/Actions';
+import { fetchPatchSetAction, clearPatchSetAction } from '../../store/Actions/Actions';
export const PatchSetWizard = ({ systemsIDs, setBaselineState, patchSetID }) => {
- //if system ids exist, those are being assigned. Likewise if patchSetID exists, it is being edited
- const wizardType = patchSetID ? 'edit' : 'create';
- const [wizardState, setWizardState] = useState({
- submitted: false,
- formValues: {},
- requestPending: true,
- failed: false,
- shouldRefresh: false
- });
+ // if system ids exist, those are being assigned. Likewise if patchSetID exists, it is being edited
+ const wizardType = patchSetID ? 'edit' : 'create';
+ const [wizardState, setWizardState] = useState({
+ submitted: false,
+ formValues: {},
+ requestPending: true,
+ failed: false,
+ shouldRefresh: false,
+ });
- const dispatch = useDispatch();
- useEffect(() => {
- if (patchSetID) {
- dispatch(fetchPatchSetAction(patchSetID));
- }
+ const dispatch = useDispatch();
+ useEffect(() => {
+ if (patchSetID) {
+ dispatch(fetchPatchSetAction(patchSetID));
+ }
- return () => dispatch(clearPatchSetAction());
- }, []);
+ return () => dispatch(clearPatchSetAction());
+ }, []);
- const onSubmit = usePatchSetApi(wizardState, setWizardState, patchSetID);
+ const onSubmit = usePatchSetApi(wizardState, setWizardState, patchSetID);
- const handleWizardClose = () => {
- const shouldRefresh = !wizardState.failed && wizardState.submitted;
+ const handleWizardClose = () => {
+ const shouldRefresh = !wizardState.failed && wizardState.submitted;
- setBaselineState({ isPatchSetWizardOpen: false, systemsIDs: [], patchSetID: undefined, shouldRefresh });
- setWizardState({ formValues: {}, submitted: false });
- };
+ setBaselineState({
+ isPatchSetWizardOpen: false,
+ systemsIDs: [],
+ patchSetID: undefined,
+ shouldRefresh,
+ });
+ setWizardState({ formValues: {}, submitted: false });
+ };
- const mapperExtensions = {
- nameField: {
- component: NameField
- },
- descriptionField: {
- component: DescriptionField
- },
- toDateField: {
- component: ToDateField
- },
- contentStep: {
- component: ContentStep,
- patchSetID
- },
- configurationStep: {
- component: ConfigurationStepFields,
- patchSetID
- },
- reviewSystems: {
- component: ReviewSystems,
- systemsIDs: systemsIDs || [],
- patchSetID
- },
- reviewPatchSet: {
- component: ReviewPatchSet,
- systemsIDs: systemsIDs || []
- }
- };
+ const mapperExtensions = {
+ nameField: {
+ component: NameField,
+ },
+ descriptionField: {
+ component: DescriptionField,
+ },
+ toDateField: {
+ component: ToDateField,
+ },
+ contentStep: {
+ component: ContentStep,
+ patchSetID,
+ },
+ configurationStep: {
+ component: ConfigurationStepFields,
+ patchSetID,
+ },
+ reviewSystems: {
+ component: ReviewSystems,
+ systemsIDs: systemsIDs || [],
+ patchSetID,
+ },
+ reviewPatchSet: {
+ component: ReviewPatchSet,
+ systemsIDs: systemsIDs || [],
+ },
+ };
- return (
-
- {!wizardState.submitted && (
- (
-
- )}
- componentMapper={{
- [componentTypes.WIZARD]: {
- component: WizardMapper,
- className: 'patch-set',
- 'data-ouia-component-id': 'patch-set-wizard'
- },
- [componentTypes.TEXT_FIELD]: TextField,
- [componentTypes.DATE_PICKER]: DatePicker,
- ...mapperExtensions
- }}
- validatorMapper={validatorMapper}
- onSubmit={onSubmit}
- onCancel={handleWizardClose} />
- ) || (
-
-
- {intl.formatMessage(messages.templateDescription)}
-
- }
- steps={[
- {
- name: 'progress',
- component: (
-
- ),
- isFinishedStep: true
- }
- ]}
- onClose={handleWizardClose}
- />
-
- )}
-
- );
+ return (
+
+ {(!wizardState.submitted && (
+ }
+ componentMapper={{
+ [componentTypes.WIZARD]: {
+ component: WizardMapper,
+ className: 'patch-set',
+ 'data-ouia-component-id': 'patch-set-wizard',
+ },
+ [componentTypes.TEXT_FIELD]: TextField,
+ [componentTypes.DATE_PICKER]: DatePicker,
+ ...mapperExtensions,
+ }}
+ validatorMapper={validatorMapper}
+ onSubmit={onSubmit}
+ onCancel={handleWizardClose}
+ />
+ )) || (
+
+ {intl.formatMessage(messages.templateDescription)}}
+ steps={[
+ {
+ name: 'progress',
+ component: ,
+ isFinishedStep: true,
+ },
+ ]}
+ onClose={handleWizardClose}
+ />
+
+ )}
+
+ );
};
PatchSetWizard.propTypes = {
- setBaselineState: propTypes.func,
- systemsIDs: propTypes.array,
- patchSetID: propTypes.string
+ setBaselineState: propTypes.func,
+ systemsIDs: propTypes.array,
+ patchSetID: propTypes.string,
};
-export default memo(PatchSetWizard, (prevProps, nextProps) => {
- return JSON.stringify(prevProps) === JSON.stringify(nextProps);
-});
+export default memo(
+ PatchSetWizard,
+ (prevProps, nextProps) => JSON.stringify(prevProps) === JSON.stringify(nextProps),
+);
diff --git a/src/SmartComponents/PatchSetWizard/WizardAssets.js b/src/SmartComponents/PatchSetWizard/WizardAssets.js
index e37927bbf..b18aeb6ab 100644
--- a/src/SmartComponents/PatchSetWizard/WizardAssets.js
+++ b/src/SmartComponents/PatchSetWizard/WizardAssets.js
@@ -8,186 +8,176 @@ import { sortable } from '@patternfly/react-table/dist/js';
import React, { Fragment } from 'react';
import { useFetchBatched } from '../../Utilities/hooks';
-export const REVIEW_SYSTEM_COLUMNS = [{
+export const REVIEW_SYSTEM_COLUMNS = [
+ {
key: 'display_name',
title: 'Name',
props: {
- width: 40
+ width: 40,
},
- transforms: [sortable]
-},
-{
+ transforms: [sortable],
+ },
+ {
title: 'OS',
key: 'operating_system',
props: {
- width: 20
+ width: 20,
},
- transforms: [sortable]
-},
-{
+ transforms: [sortable],
+ },
+ {
key: 'template_name',
title: 'Template',
props: {
- width: 20
+ width: 20,
},
- transforms: [sortable]
-},
-{
+ transforms: [sortable],
+ },
+ {
key: 'last_upload',
title: 'Last seen',
props: {
- width: 20
+ width: 20,
},
- transforms: [sortable]
-}
+ transforms: [sortable],
+ },
];
export const configurationFields = [
- {
- name: 'configurationStep',
- component: 'configurationStep'
- },
- {
- name: 'existing_patch_set',
- component: componentTypes.TEXT_FIELD,
- hidden: true
- }
+ {
+ name: 'configurationStep',
+ component: 'configurationStep',
+ },
+ {
+ name: 'existing_patch_set',
+ component: componentTypes.TEXT_FIELD,
+ hidden: true,
+ },
];
export const contentStep = [
- {
- name: 'contentStep',
- component: 'contentStep'
- }
+ {
+ name: 'contentStep',
+ component: 'contentStep',
+ },
];
-export const nameComponent = [{
+export const nameComponent = [
+ {
name: 'name',
component: 'nameField',
- validate: [
- { type: validatorTypes.REQUIRED },
- { type: 'validate-name' }
- ]
-}];
+ validate: [{ type: validatorTypes.REQUIRED }, { type: 'validate-name' }],
+ },
+];
-export const descriptionComponent = [{
+export const descriptionComponent = [
+ {
name: 'description',
- component: 'descriptionField'
-}];
+ component: 'descriptionField',
+ },
+];
-export const toDateComponent = [{
+export const toDateComponent = [
+ {
name: 'toDate',
component: 'toDateField',
- validate: [
- { type: validatorTypes.REQUIRED },
- { type: 'validate-date' }
- ]
-}];
+ validate: [{ type: validatorTypes.REQUIRED }, { type: 'validate-date' }],
+ },
+];
-export const getWizardTitle = (wizardType) => {
- return (wizardType === 'edit')
- ? intl.formatMessage(messages.templateEdit)
- : intl.formatMessage(messages.templateTitle);
-};
+export const getWizardTitle = (wizardType) =>
+ wizardType === 'edit'
+ ? intl.formatMessage(messages.templateEdit)
+ : intl.formatMessage(messages.templateTitle);
-export const schema = (wizardType) => {
- return ({
- fields: [
+export const schema = (wizardType) => ({
+ fields: [
+ {
+ component: componentTypes.WIZARD,
+ name: 'patch-set-wizard',
+ isDynamic: true,
+ inModal: true,
+ title: getWizardTitle(wizardType),
+ description: {intl.formatMessage(messages.templateDescription)},
+ fields: [
+ {
+ name: 'template-content',
+ title: intl.formatMessage(messages.templateContentStepSidebarName),
+ fields: contentStep,
+ nextStep: 'template-details',
+ },
+ {
+ name: 'template-details',
+ title: intl.formatMessage(messages.templateDetailStepSidebarName),
+ fields: configurationFields,
+ nextStep: 'template-systems',
+ },
+ {
+ name: 'template-systems',
+ title: intl.formatMessage(messages.templateStepSystems),
+ fields: [
{
- component: componentTypes.WIZARD,
- name: 'patch-set-wizard',
- isDynamic: true,
- inModal: true,
- title: getWizardTitle(wizardType),
- description:
- {intl.formatMessage(messages.templateDescription)}
- ,
- fields: [
- {
- name: 'template-content',
- title: intl.formatMessage(messages.templateContentStepSidebarName),
- fields: contentStep,
- nextStep: 'template-details'
- },
- {
- name: 'template-details',
- title: intl.formatMessage(messages.templateDetailStepSidebarName),
- fields: configurationFields,
- nextStep: 'template-systems'
- },
- {
- name: 'template-systems',
- title: intl.formatMessage(messages.templateStepSystems),
- fields: [
- {
- name: 'systems',
- component: 'reviewSystems'
- //We can use this later in case UX wantes to prevent patch template s without zero systems
- //validate: [{ type: 'validate-systems' }]
- }
- ],
- nextStep: 'template-review'
- },
- {
- name: 'template-review',
- title: intl.formatMessage(messages.templateReview),
- fields: [
- {
- name: 'review',
- component: 'reviewPatchSet'
- }
- ]
- }
- ]
- }
- ]
- });
-};
+ name: 'systems',
+ component: 'reviewSystems',
+ // We can use this later in case UX wantes to prevent patch template s without zero systems
+ // validate: [{ type: 'validate-systems' }]
+ },
+ ],
+ nextStep: 'template-review',
+ },
+ {
+ name: 'template-review',
+ title: intl.formatMessage(messages.templateReview),
+ fields: [
+ {
+ name: 'review',
+ component: 'reviewPatchSet',
+ },
+ ],
+ },
+ ],
+ },
+ ],
+});
export const validatorMapper = {
- 'validate-systems': () => (formValueSystems) => {
- const systems = filterSelectedActiveSystemIDs(formValueSystems);
+ 'validate-systems': () => (formValueSystems) => {
+ const systems = filterSelectedActiveSystemIDs(formValueSystems);
- if (systems === undefined) {
- return;
- }
- else if (systems.length > 0) {
- return;
- } else {
- return intl.formatMessage(messages.templateNoSystemSelected);
- }
- },
- 'validate-date': () => dateValidator,
- 'validate-name': () => (name, formValues) => {
- if (formValues.areTakenTemplateNamesLoading || formValues.templateDetailLoading) {
- return intl.formatMessage(messages.templateWizardValidateLoading);
- }
+ if (systems === undefined) {
+ return;
+ } else if (systems.length > 0) {
+ return;
+ } else {
+ return intl.formatMessage(messages.templateNoSystemSelected);
+ }
+ },
+ 'validate-date': () => dateValidator,
+ 'validate-name': () => (name, formValues) => {
+ if (formValues.areTakenTemplateNamesLoading || formValues.templateDetailLoading) {
+ return intl.formatMessage(messages.templateWizardValidateLoading);
+ }
- if (formValues.previousName !== name && formValues.takenTemplateNames?.includes(name)) {
- return intl.formatMessage(messages.templateWizardValidateNameTaken);
- }
+ if (formValues.previousName !== name && formValues.takenTemplateNames?.includes(name)) {
+ return intl.formatMessage(messages.templateWizardValidateNameTaken);
}
+ },
};
export const apiFailedNotification = (description) => ({
- title: 'There was an error while processing your request',
- description,
- variant: 'danger'
+ title: 'There was an error while processing your request',
+ description,
+ variant: 'danger',
});
export const useFetchAllTemplateData = (fetchFunction, mapFunction) => {
- const { fetchBatched, isLoading } = useFetchBatched();
- return async (params = {}) => {
- const result = await fetchBatched(
- fetchFunction,
- params,
- undefined,
- 100
- );
+ const { fetchBatched, isLoading } = useFetchBatched();
+ return async (params = {}) => {
+ const result = await fetchBatched(fetchFunction, params, undefined, 100);
- return {
- isLoading,
- data: result.flatMap(({ data }) => data).map(mapFunction)
- };
+ return {
+ isLoading,
+ data: result.flatMap(({ data }) => data).map(mapFunction),
};
+ };
};
diff --git a/src/SmartComponents/PatchSetWizard/steps/ConfigurationStepFields.js b/src/SmartComponents/PatchSetWizard/steps/ConfigurationStepFields.js
index a95a1cae2..e0a554cba 100644
--- a/src/SmartComponents/PatchSetWizard/steps/ConfigurationStepFields.js
+++ b/src/SmartComponents/PatchSetWizard/steps/ConfigurationStepFields.js
@@ -2,52 +2,46 @@ import React, { useEffect } from 'react';
import propTypes from 'prop-types';
import { useSelector, shallowEqual } from 'react-redux';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
-import {
- Content,
- Stack,
- StackItem
-} from '@patternfly/react-core';
+import { Content, Stack, StackItem } from '@patternfly/react-core';
import { intl } from '../../../Utilities/IntlProvider';
import messages from '../../../Messages';
import ConfigurationFields from '../InputFields/ConfigurationFields';
const ConfigurationStepFields = ({ patchSetID }) => {
- const formOptions = useFormApi();
+ const formOptions = useFormApi();
- const { patchSet, status, areTakenTemplateNamesLoading } =
- useSelector(({ SpecificPatchSetReducer }) => SpecificPatchSetReducer, shallowEqual);
+ const { patchSet, status, areTakenTemplateNamesLoading } = useSelector(
+ ({ SpecificPatchSetReducer }) => SpecificPatchSetReducer,
+ shallowEqual,
+ );
- useEffect(() => {
- if (patchSetID) {
- const { name, description } = patchSet;
+ useEffect(() => {
+ if (patchSetID) {
+ const { name, description } = patchSet;
- formOptions.change('name', name);
- formOptions.change('description', description);
- }
- }, [patchSet]);
+ formOptions.change('name', name);
+ formOptions.change('description', description);
+ }
+ }, [patchSet]);
- return (
-
-
-
-
- {intl.formatMessage(messages.templateDetailStepTitle)}
-
-
-
-
- {intl.formatMessage(messages.templateDetailStepText)}
-
-
-
-
-
- );
+ return (
+
+
+
+ {intl.formatMessage(messages.templateDetailStepTitle)}
+
+
+ {intl.formatMessage(messages.templateDetailStepText)}
+
+
+
+
+ );
};
ConfigurationStepFields.propTypes = {
- patchSetID: propTypes.string
+ patchSetID: propTypes.string,
};
export default ConfigurationStepFields;
diff --git a/src/SmartComponents/PatchSetWizard/steps/ContentStep.js b/src/SmartComponents/PatchSetWizard/steps/ContentStep.js
index e6f6c4533..df2a37432 100644
--- a/src/SmartComponents/PatchSetWizard/steps/ContentStep.js
+++ b/src/SmartComponents/PatchSetWizard/steps/ContentStep.js
@@ -2,59 +2,56 @@ import React, { useEffect } from 'react';
import propTypes from 'prop-types';
import { useSelector, shallowEqual } from 'react-redux';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
-import {
- Content,
- Stack,
- StackItem,
- ExpandableSection
-} from '@patternfly/react-core';
+import { Content, Stack, StackItem, ExpandableSection } from '@patternfly/react-core';
import { intl } from '../../../Utilities/IntlProvider';
import messages from '../../../Messages';
import { convertIsoToDate } from '../../../Utilities/Helpers';
import { toDateComponent } from '../WizardAssets';
const ContentStep = ({ patchSetID }) => {
- const formOptions = useFormApi();
-
- const { patchSet, status } = useSelector(({ SpecificPatchSetReducer }) => SpecificPatchSetReducer, shallowEqual);
-
- useEffect(() => {
- if (patchSetID) {
- const { config: { to_time: toDate }, name: previousName } = patchSet;
-
- formOptions.change('toDate', convertIsoToDate(toDate));
- formOptions.change('previousName', previousName);
- formOptions.change('templateDetailLoading', status.isLoading);
- }
- }, [patchSet, status]);
-
- return (
-
-
-
-
- {intl.formatMessage(messages.templateContentStepTitle)}
-
-
-
-
- {intl.formatMessage(messages.templateContentStepText)}
-
-
-
- {formOptions.renderForm(toDateComponent)}
-
-
-
-
- {intl.formatMessage(messages.templateContentStepExpandable)}
-
-
-
- );
+ const formOptions = useFormApi();
+
+ const { patchSet, status } = useSelector(
+ ({ SpecificPatchSetReducer }) => SpecificPatchSetReducer,
+ shallowEqual,
+ );
+
+ useEffect(() => {
+ if (patchSetID) {
+ const {
+ config: { to_time: toDate },
+ name: previousName,
+ } = patchSet;
+
+ formOptions.change('toDate', convertIsoToDate(toDate));
+ formOptions.change('previousName', previousName);
+ formOptions.change('templateDetailLoading', status.isLoading);
+ }
+ }, [patchSet, status]);
+
+ return (
+
+
+
+ {intl.formatMessage(messages.templateContentStepTitle)}
+
+
+ {intl.formatMessage(messages.templateContentStepText)}
+
+ {formOptions.renderForm(toDateComponent)}
+
+
+
+ {intl.formatMessage(messages.templateContentStepExpandable)}
+
+
+
+ );
};
ContentStep.propTypes = {
- patchSetID: propTypes.string
+ patchSetID: propTypes.string,
};
export default ContentStep;
diff --git a/src/SmartComponents/PatchSetWizard/steps/RequestProgress.js b/src/SmartComponents/PatchSetWizard/steps/RequestProgress.js
index 92e52f8eb..79b1894fc 100644
--- a/src/SmartComponents/PatchSetWizard/steps/RequestProgress.js
+++ b/src/SmartComponents/PatchSetWizard/steps/RequestProgress.js
@@ -1,21 +1,16 @@
import React from 'react';
import propTypes from 'prop-types';
import {
- EmptyState,
- EmptyStateVariant,
- EmptyStateBody,
- Grid,
- GridItem,
- HelperText,
- HelperTextItem,
- Button
-
+ EmptyState,
+ EmptyStateVariant,
+ EmptyStateBody,
+ Grid,
+ GridItem,
+ HelperText,
+ HelperTextItem,
+ Button,
} from '@patternfly/react-core';
-import {
- CheckCircleIcon,
- ExclamationCircleIcon,
- InProgressIcon
-} from '@patternfly/react-icons';
+import { CheckCircleIcon, ExclamationCircleIcon, InProgressIcon } from '@patternfly/react-icons';
import { intl } from '../../../Utilities/IntlProvider';
import messages from '../../../Messages';
import { useDispatch } from 'react-redux';
@@ -23,79 +18,81 @@ import { apiFailedNotification } from '../WizardAssets';
import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
const RequestProgress = ({ onClose, state }) => {
- const { requestPending, failed, error } = state;
- const dispatch = useDispatch();
-
- if (failed) {
- dispatch(
- addNotification(
- apiFailedNotification(error.detail)
- )
- );
- }
+ const { requestPending, failed, error } = state;
+ const dispatch = useDispatch();
- return (
-
-
-
- {(requestPending) && (
- <>
-
-
- {intl.formatMessage(messages.textPatchTemplatePending)}
-
-
-
-
- {intl.formatMessage(messages.labelsCancel)}
- {' '}
- >
- )}
- {(!requestPending && !failed) && (
-
-
- {intl.formatMessage(messages.textReturnToApp)}
-
-
- )}
- {(!requestPending && failed) && (
- <>
-
-
- {intl.formatMessage(
- messages.templateError,
- { a: (chunks) => {chunks} })}
-
-
-
-
- {intl.formatMessage(messages.textReturnToApp)}
-
- >
- )}
-
+ if (failed) {
+ dispatch(addNotification(apiFailedNotification(error.detail)));
+ }
-
-
- );
+ return (
+
+
+
+ {requestPending && (
+ <>
+
+
+
+ {intl.formatMessage(messages.textPatchTemplatePending)}
+
+
+
+
+
+ {intl.formatMessage(messages.labelsCancel)}
+ {' '}
+
+ >
+ )}
+ {!requestPending && !failed && (
+
+
+ {intl.formatMessage(messages.textReturnToApp)}
+
+
+ )}
+ {!requestPending && failed && (
+ <>
+
+
+
+ {intl.formatMessage(messages.templateError, {
+ a: (chunks) => (
+ {chunks}
+ ),
+ })}
+
+
+
+
+
+ {intl.formatMessage(messages.textReturnToApp)}
+
+
+ >
+ )}
+
+
+
+ );
};
RequestProgress.propTypes = {
- onClose: propTypes.func,
- state: propTypes.object
+ onClose: propTypes.func,
+ state: propTypes.object,
};
export default RequestProgress;
diff --git a/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.js b/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.js
index e16bbf6f6..cc210b0a5 100644
--- a/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.js
+++ b/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.js
@@ -1,88 +1,80 @@
import React, { Fragment } from 'react';
-import {
- Content,
- Stack,
- StackItem,
- ContentVariants
-
-} from '@patternfly/react-core';
+import { Content, Stack, StackItem, ContentVariants } from '@patternfly/react-core';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { intl } from '../../../Utilities/IntlProvider';
import messages from '../../../Messages';
import { templateDateFormat } from '../../../Utilities/Helpers';
const renderTextListItem = (label, text) => (
-
-
- {intl.formatMessage(messages[label])}
-
-
- {text}
-
-
+
+
+ {intl.formatMessage(messages[label])}
+
+ {text}
+
);
const ReviewPatchSet = () => {
- const formOptions = useFormApi();
- const { values } = formOptions.getState();
- const { name, description, toDate } = values.existing_patch_set || values;
- const { systems } = values;
+ const formOptions = useFormApi();
+ const { values } = formOptions.getState();
+ const { name, description, toDate } = values.existing_patch_set || values;
+ const { systems } = values;
- return (
-
-
-
-
- {intl.formatMessage(messages.templateReview)}
-
-
-
-
-
-
- {intl.formatMessage(messages.textPatchTemplateReview)}
-
-
-
-
-
-
- {intl.formatMessage(messages.textPatchTemplateContent)}
-
-
- {renderTextListItem('labelsColumnsUpToDate', templateDateFormat(toDate))}
-
-
-
-
-
-
- {intl.formatMessage(messages.textPatchTemplateDetails)}
-
-
- {renderTextListItem('labelsColumnsName', name)}
- {renderTextListItem('labelsDescription', description
- || intl.formatMessage(messages.titlesTemplateNoDescriptionProvided))}
-
-
-
-
-
-
- {intl.formatMessage(messages.textPatchTemplateSystems)}
-
-
- {renderTextListItem(
- 'labelsSelectedSystems',
- intl.formatMessage(messages.labelsSystem, {
- systemsCount: Object.values(systems).filter(system => system).length
- })
- )}
-
-
-
-
- );
+ return (
+
+
+
+ {intl.formatMessage(messages.templateReview)}
+
+
+
+
+
+ {intl.formatMessage(messages.textPatchTemplateReview)}
+
+
+
+
+
+
+ {intl.formatMessage(messages.textPatchTemplateContent)}
+
+
+ {renderTextListItem('labelsColumnsUpToDate', templateDateFormat(toDate))}
+
+
+
+
+
+
+ {intl.formatMessage(messages.textPatchTemplateDetails)}
+
+
+ {renderTextListItem('labelsColumnsName', name)}
+ {renderTextListItem(
+ 'labelsDescription',
+ description || intl.formatMessage(messages.titlesTemplateNoDescriptionProvided),
+ )}
+
+
+
+
+
+
+ {intl.formatMessage(messages.textPatchTemplateSystems)}
+
+
+ {renderTextListItem(
+ 'labelsSelectedSystems',
+ intl.formatMessage(messages.labelsSystem, {
+ systemsCount: Object.values(systems).filter((system) => system).length,
+ }),
+ )}
+
+
+
+
+ );
};
export default ReviewPatchSet;
diff --git a/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.test.js b/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.test.js
index 7061b5e21..4c79328e3 100644
--- a/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.test.js
+++ b/src/SmartComponents/PatchSetWizard/steps/ReviewPatchSet.test.js
@@ -2,49 +2,43 @@ import ReviewPatchSet from './ReviewPatchSet';
import { render } from '@testing-library/react';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
-jest.mock('@data-driven-forms/react-form-renderer/use-form-api',
- () => ({
- __esModule: true,
- default: jest.fn()
- })
-);
+jest.mock('@data-driven-forms/react-form-renderer/use-form-api', () => ({
+ __esModule: true,
+ default: jest.fn(),
+}));
describe('ReviewPatchSet.js', () => {
- it('Should display all Patch Template configuration', () => {
- useFormApi.mockReturnValue(({
- getState: () => ({
- values: {
- name: 'test-name',
- description: 'test-description',
- toDate: '2022-06-14',
- systems: {
- 'test-system-id-1': true,
- 'test-system-id-2': true
- }
- }
- })
- }));
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
+ it('Should display all Patch Template configuration', () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({
+ values: {
+ name: 'test-name',
+ description: 'test-description',
+ toDate: '2022-06-14',
+ systems: {
+ 'test-system-id-1': true,
+ 'test-system-id-2': true,
+ },
+ },
+ }),
});
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('Should display available configuration fields only', () => {
- useFormApi.mockReturnValue(({
- getState: () => ({
- values: {
- name: 'test-name',
- systems: {
- 'test-system-id-1': true,
- 'test-system-id-2': true
- }
- }
- })
- }));
- const { asFragment } = render(
-
- );
- expect(asFragment()).toMatchSnapshot();
+ it('Should display available configuration fields only', () => {
+ useFormApi.mockReturnValue({
+ getState: () => ({
+ values: {
+ name: 'test-name',
+ systems: {
+ 'test-system-id-1': true,
+ 'test-system-id-2': true,
+ },
+ },
+ }),
});
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
});
diff --git a/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js b/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js
index 72c71d7b3..86f292e8c 100644
--- a/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js
+++ b/src/SmartComponents/PatchSetWizard/steps/ReviewSystems.js
@@ -7,204 +7,201 @@ import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { createSortBy, buildSelectedSystemsObj } from '../../../Utilities/Helpers';
import { createSystemsRowsReview } from '../../../Utilities/DataMappers';
-import { usePerPageSelect, useSetPage, useSortColumn, useOnSelect, ID_API_ENDPOINTS } from '../../../Utilities/hooks';
+import {
+ usePerPageSelect,
+ useSetPage,
+ useSortColumn,
+ useOnSelect,
+ ID_API_ENDPOINTS,
+} from '../../../Utilities/hooks';
import TableView from '../../../PresentationalComponents/TableView/TableView';
import staleFilter from '../../../PresentationalComponents/Filters/SystemStaleFilter';
import systemsUpdatableFilter from '../../../PresentationalComponents/Filters/SystemsUpdatableFilter';
import { fetchSystems, fetchPatchSetSystems } from '../../../Utilities/api';
-import { REVIEW_SYSTEM_COLUMNS } from '../WizardAssets';
+import { REVIEW_SYSTEM_COLUMNS, useFetchAllTemplateData } from '../WizardAssets';
import messages from '../../../Messages';
import { intl } from '../../../Utilities/IntlProvider';
import { systemsListDefaultFilters } from '../../../Utilities/constants';
import useOsVersionFilter from '../../../PresentationalComponents/Filters/OsVersionFilter';
-import { useFetchAllTemplateData } from '../WizardAssets';
export const ReviewSystems = ({ systemsIDs = [], patchSetID, ...props }) => {
- const { input } = useFieldApi(props);
- const formOptions = useFormApi();
- const { values } = formOptions.getState();
- const defaultSelectedSystems = buildSelectedSystemsObj(systemsIDs, values?.systems);
-
- const [isLoading, setLoading] = useState(true);
- const [rawData, setRawData] = useState([]);
- const [systems, setSystems] = useState([]);
- const [selectedRows, setSelectedRows] = useState(defaultSelectedSystems);
- const [metadata, setMetada] = useState({
- limit: 20,
- offset: 0,
- total_items: 0
+ const { input } = useFieldApi(props);
+ const formOptions = useFormApi();
+ const { values } = formOptions.getState();
+ const defaultSelectedSystems = buildSelectedSystemsObj(systemsIDs, values?.systems);
+
+ const [isLoading, setLoading] = useState(true);
+ const [rawData, setRawData] = useState([]);
+ const [systems, setSystems] = useState([]);
+ const [selectedRows, setSelectedRows] = useState(defaultSelectedSystems);
+ const [metadata, setMetada] = useState({
+ limit: 20,
+ offset: 0,
+ total_items: 0,
+ });
+ const [assignedSystems, setAssignedSystems] = useState([]);
+ const [areAssignedSystemsLoading, setAssignedSystemsLoading] = useState(true);
+
+ const [queryParams, setQueryParams] = useState({
+ page: 1,
+ perPage: 20,
+ filter: {
+ stale: [true, false],
+ },
+ });
+
+ const fetchAssignedSystems = useFetchAllTemplateData(
+ fetchPatchSetSystems,
+ (system) => system?.inventory_id,
+ );
+
+ useEffect(() => {
+ if (patchSetID) {
+ fetchAssignedSystems({ id: patchSetID }).then(({ isLoading, data }) => {
+ setAssignedSystems(data);
+ setAssignedSystemsLoading(isLoading);
+ });
+ }
+ }, [patchSetID]);
+
+ useEffect(() => {
+ fetchSystems({
+ ...queryParams,
+ filter: {
+ ...queryParams.filter,
+ id: systemsIDs.length > 0 ? `in:${systemsIDs.join(',')}` : undefined,
+ satellite_managed: false,
+ },
+ }).then((result) => {
+ setSystems(
+ createSystemsRowsReview(result.data, {
+ ...buildSelectedSystemsObj([...assignedSystems, ...systemsIDs]),
+ ...selectedRows,
+ }),
+ );
+ setMetada(result.meta);
+ setRawData(result.data);
+ setLoading(false);
});
- const [assignedSystems, setAssignedSystems] = useState([]);
- const [areAssignedSystemsLoading, setAssignedSystemsLoading] = useState(true);
+ }, [queryParams.filter, queryParams, assignedSystems]);
- const [queryParams, setQueryParams] = useState({
- page: 1,
- perPage: 20,
- filter: {
- stale: [true, false]
- }
- });
+ useEffect(() => {
+ input.onChange(selectedRows);
+
+ setSystems(createSystemsRowsReview(rawData, selectedRows));
+ }, [selectedRows]);
- const fetchAssignedSystems = useFetchAllTemplateData(
- fetchPatchSetSystems,
- system => system?.inventory_id
- );
-
- useEffect(() => {
- if (patchSetID) {
- fetchAssignedSystems({ id: patchSetID }).then(
- ({ isLoading, data }) => {
- setAssignedSystems(data);
- setAssignedSystemsLoading(isLoading);
- }
- );
- }
- }, [patchSetID]);
-
- useEffect(() => {
- fetchSystems({
- ...queryParams,
- filter: {
- ...queryParams.filter,
- id: systemsIDs.length > 0 ? `in:${systemsIDs.join(',')}` : undefined,
- satellite_managed: false
- }
- }).then(result => {
- setSystems(
- createSystemsRowsReview(
- result.data,
- { ...buildSelectedSystemsObj([...assignedSystems, ...systemsIDs]), ...selectedRows }
- )
- );
- setMetada(result.meta);
- setRawData(result.data);
- setLoading(false);
- });
- }, [queryParams.filter, queryParams, assignedSystems]);
-
- useEffect(() => {
- input.onChange(selectedRows);
-
- setSystems(
- createSystemsRowsReview(rawData, selectedRows)
- );
- }, [selectedRows]);
-
- useEffect(() => {
- setSelectedRows({ ...selectedRows, ...buildSelectedSystemsObj(assignedSystems) });
- }, [assignedSystems]);
-
- const apply = (params, shouldReset = true) => {
- setLoading(true);
- setQueryParams((prevQueryParams) => ({
- ...prevQueryParams,
- ...params,
- filter: { ...prevQueryParams.filter, ...params.filter },
- ...shouldReset && {
- page: 1,
- offset: 0
- }
- }));
- };
-
- const osFilterConfig = useOsVersionFilter(queryParams.filter.os, apply);
- const onSort = useSortColumn(REVIEW_SYSTEM_COLUMNS, apply, 1);
- const sortBy = React.useMemo(
- () => createSortBy(REVIEW_SYSTEM_COLUMNS, metadata.sort, 1),
- [metadata.sort]
- );
-
- const onSetPage = useSetPage(metadata.limit, params => apply(params, false));
-
- const onPerPageSelect = usePerPageSelect(apply);
-
- const selectRows = (toSelect) => {
- const newSelections = toSelect.reduce((object, system) => {
- object[system.id] = system.selected ? true : undefined;
- return object;
- }, {});
-
- setSelectedRows({ ...selectedRows, ...newSelections });
- };
-
- const onSelect = useOnSelect(
- systems,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.systems,
- queryParams: {
- ...queryParams,
- filter: {
- ...queryParams.filter,
- ...systemsIDs.length > 0 && { id: `in:${systemsIDs.join(',')}` },
- satellite_managed: false
- }
- },
- customSelector: selectRows,
- totalItems: metadata.total_items
- }
- );
-
- const isTableLoading = isLoading || (patchSetID && areAssignedSystemsLoading);
- return (
-
-
-
-
- {intl.formatMessage(messages.templateApplySystems)}
-
-
-
-
-
-
- Select systems to apply the new template to. The list of systems does not contain systems
- managed by Satellite.
-
-
-
-
-
-
-
-
- );
+ useEffect(() => {
+ setSelectedRows({ ...selectedRows, ...buildSelectedSystemsObj(assignedSystems) });
+ }, [assignedSystems]);
+
+ const apply = (params, shouldReset = true) => {
+ setLoading(true);
+ setQueryParams((prevQueryParams) => ({
+ ...prevQueryParams,
+ ...params,
+ filter: { ...prevQueryParams.filter, ...params.filter },
+ ...(shouldReset && {
+ page: 1,
+ offset: 0,
+ }),
+ }));
+ };
+
+ const osFilterConfig = useOsVersionFilter(queryParams.filter.os, apply);
+ const onSort = useSortColumn(REVIEW_SYSTEM_COLUMNS, apply, 1);
+ const sortBy = React.useMemo(
+ () => createSortBy(REVIEW_SYSTEM_COLUMNS, metadata.sort, 1),
+ [metadata.sort],
+ );
+
+ const onSetPage = useSetPage(metadata.limit, (params) => apply(params, false));
+
+ const onPerPageSelect = usePerPageSelect(apply);
+
+ const selectRows = (toSelect) => {
+ const newSelections = toSelect.reduce((object, system) => {
+ object[system.id] = system.selected ? true : undefined;
+ return object;
+ }, {});
+
+ setSelectedRows({ ...selectedRows, ...newSelections });
+ };
+
+ const onSelect = useOnSelect(systems, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.systems,
+ queryParams: {
+ ...queryParams,
+ filter: {
+ ...queryParams.filter,
+ ...(systemsIDs.length > 0 && { id: `in:${systemsIDs.join(',')}` }),
+ satellite_managed: false,
+ },
+ },
+ customSelector: selectRows,
+ totalItems: metadata.total_items,
+ });
+
+ const isTableLoading = isLoading || (patchSetID && areAssignedSystemsLoading);
+ return (
+
+
+
+ {intl.formatMessage(messages.templateApplySystems)}
+
+
+
+
+
+ Select systems to apply the new template to. The list of systems does not contain{' '}
+ systems managed by Satellite.
+
+
+
+
+
+
+
+
+ );
};
ReviewSystems.propTypes = {
- systemsIDs: propTypes.array,
- patchSetID: propTypes.string
+ systemsIDs: propTypes.array,
+ patchSetID: propTypes.string,
};
export default ReviewSystems;
diff --git a/src/SmartComponents/Remediation/AsyncRemediationButton.js b/src/SmartComponents/Remediation/AsyncRemediationButton.js
index 11c98d0dd..155146aba 100644
--- a/src/SmartComponents/Remediation/AsyncRemediationButton.js
+++ b/src/SmartComponents/Remediation/AsyncRemediationButton.js
@@ -7,35 +7,41 @@ import { Spinner } from '@patternfly/react-core';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
-const AsyncRemediationButton = ({ remediationProvider, isDisabled, isLoading, patchNoAdvisoryText, hasSelected }) => {
- const dispatch = useDispatch();
- const handleRemediationSuccess = res => {
- dispatch(addNotification(res.getNotification()));
- };
+const AsyncRemediationButton = ({
+ remediationProvider,
+ isDisabled,
+ isLoading,
+ patchNoAdvisoryText,
+ hasSelected,
+}) => {
+ const dispatch = useDispatch();
+ const handleRemediationSuccess = (res) => {
+ dispatch(addNotification(res.getNotification()));
+ };
- return (
- }
- dataProvider={remediationProvider}
- onRemediationCreated={handleRemediationSuccess}
- isDisabled={isDisabled}
- buttonProps={{ isLoading }}
- patchNoAdvisoryText={patchNoAdvisoryText}
- hasSelected={hasSelected}
- >
- {intl.formatMessage(messages.labelsRemediate)}
-
- );
+ return (
+ }
+ dataProvider={remediationProvider}
+ onRemediationCreated={handleRemediationSuccess}
+ isDisabled={isDisabled}
+ buttonProps={{ isLoading }}
+ patchNoAdvisoryText={patchNoAdvisoryText}
+ hasSelected={hasSelected}
+ >
+ {intl.formatMessage(messages.labelsRemediate)}
+
+ );
};
AsyncRemediationButton.propTypes = {
- remediationProvider: propTypes.func,
- isDisabled: propTypes.bool,
- isLoading: propTypes.bool,
- patchNoAdvisoryText: propTypes.string,
- hasSelected: propTypes.bool
+ remediationProvider: propTypes.func,
+ isDisabled: propTypes.bool,
+ isLoading: propTypes.bool,
+ patchNoAdvisoryText: propTypes.string,
+ hasSelected: propTypes.bool,
};
export default AsyncRemediationButton;
diff --git a/src/SmartComponents/Remediation/RemediationWizard.js b/src/SmartComponents/Remediation/RemediationWizard.js
index eca83d402..c2eadb7d8 100644
--- a/src/SmartComponents/Remediation/RemediationWizard.js
+++ b/src/SmartComponents/Remediation/RemediationWizard.js
@@ -2,20 +2,18 @@ import React from 'react';
import propTypes from 'prop-types';
import AsyncComponent from '@redhat-cloud-services/frontend-components/AsyncComponent';
-const RemediationWizard = ({ data, setRemediationOpen }) => {
- return (
- }
- data={data}
- />
- );
-};
+const RemediationWizard = ({ data, setRemediationOpen }) => (
+ }
+ data={data}
+ />
+);
RemediationWizard.propTypes = {
- data: propTypes.object,
- setRemediationOpen: propTypes.func
+ data: propTypes.object,
+ setRemediationOpen: propTypes.func,
};
export default RemediationWizard;
diff --git a/src/SmartComponents/SystemAdvisories/SystemAdvisories.js b/src/SmartComponents/SystemAdvisories/SystemAdvisories.js
index ee672ea7f..34ebc89a2 100644
--- a/src/SmartComponents/SystemAdvisories/SystemAdvisories.js
+++ b/src/SmartComponents/SystemAdvisories/SystemAdvisories.js
@@ -11,170 +11,172 @@ import { Unavailable } from '@redhat-cloud-services/frontend-components/Unavaila
import TableView from '../../PresentationalComponents/TableView/TableView';
import { systemAdvisoriesColumns } from '../../PresentationalComponents/TableView/TableViewAssets';
import {
- changeSystemAdvisoryListParams,
- clearSystemAdvisoriesStore,
- expandSystemAdvisoryRow,
- fetchApplicableSystemAdvisories,
- selectSystemAdvisoryRow
+ changeSystemAdvisoryListParams,
+ clearSystemAdvisoriesStore,
+ expandSystemAdvisoryRow,
+ fetchApplicableSystemAdvisories,
+ selectSystemAdvisoryRow,
} from '../../store/Actions/Actions';
import { exportSystemAdvisoriesCSV, exportSystemAdvisoriesJSON } from '../../Utilities/api';
import { remediationIdentifiers } from '../../Utilities/constants';
import { createSystemAdvisoriesRows } from '../../Utilities/DataMappers';
import {
- arrayFromObj, createSortBy, decodeQueryparams,
- getRowIdByIndexExpandable, remediationProvider, encodeURLParams
+ arrayFromObj,
+ createSortBy,
+ decodeQueryparams,
+ getRowIdByIndexExpandable,
+ remediationProvider,
+ encodeURLParams,
} from '../../Utilities/Helpers';
import {
- usePerPageSelect, useSetPage, useSortColumn, useOnExport,
- useOnSelect, ID_API_ENDPOINTS
+ usePerPageSelect,
+ useSetPage,
+ useSortColumn,
+ useOnExport,
+ useOnSelect,
+ ID_API_ENDPOINTS,
} from '../../Utilities/hooks';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
import severityFilter from '../../PresentationalComponents/Filters/SeverityFilter';
const SystemAdvisories = ({ handleNoSystemData, inventoryId, shouldRefresh }) => {
- const dispatch = useDispatch();
- const [firstMount, setFirstMount] = useState(true);
- const advisories = useSelector(
- ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.rows
- );
+ const dispatch = useDispatch();
+ const [firstMount, setFirstMount] = useState(true);
+ const advisories = useSelector(({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.rows);
- const expandedRows = useSelector(
- ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.expandedRows
- );
- const queryParams = useSelector(
- ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.queryParams
- );
- const selectedRows = useSelector(
- ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.selectedRows
- );
- const metadata = useSelector(
- ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.metadata
- );
- const status = useSelector(
- ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.status
- );
- const rows = useMemo(
- () =>
- createSystemAdvisoriesRows(advisories, expandedRows, selectedRows, metadata),
- [advisories, expandedRows, selectedRows]
- );
+ const expandedRows = useSelector(
+ ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.expandedRows,
+ );
+ const queryParams = useSelector(
+ ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.queryParams,
+ );
+ const selectedRows = useSelector(
+ ({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.selectedRows,
+ );
+ const metadata = useSelector(({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.metadata);
+ const status = useSelector(({ SystemAdvisoryListStore }) => SystemAdvisoryListStore.status);
+ const rows = useMemo(
+ () => createSystemAdvisoriesRows(advisories, expandedRows, selectedRows, metadata),
+ [advisories, expandedRows, selectedRows],
+ );
- const [searchParams, setSearchParams] = useSearchParams();
+ const [searchParams, setSearchParams] = useSearchParams();
- useEffect(() => {
- return () => dispatch(clearSystemAdvisoriesStore());
- }, []);
+ useEffect(() => () => dispatch(clearSystemAdvisoriesStore()), []);
- useEffect(() => {
- if (firstMount) {
- apply(decodeQueryparams('?' + searchParams.toString()));
- setFirstMount(false);
- } else {
- setSearchParams(encodeURLParams(queryParams), { replace: true });
- dispatch(
- fetchApplicableSystemAdvisories({ id: inventoryId, ...queryParams })
- );
- }
- }, [firstMount, queryParams]);
+ useEffect(() => {
+ if (firstMount) {
+ apply(decodeQueryparams('?' + searchParams.toString()));
+ setFirstMount(false);
+ } else {
+ setSearchParams(encodeURLParams(queryParams), { replace: true });
+ dispatch(fetchApplicableSystemAdvisories({ id: inventoryId, ...queryParams }));
+ }
+ }, [firstMount, queryParams]);
- useEffect(() => {
- if (shouldRefresh) {
- dispatch(fetchApplicableSystemAdvisories({ id: inventoryId, ...queryParams }));
- }
- }, [shouldRefresh]);
+ useEffect(() => {
+ if (shouldRefresh) {
+ dispatch(fetchApplicableSystemAdvisories({ id: inventoryId, ...queryParams }));
+ }
+ }, [shouldRefresh]);
- const onCollapse = useCallback((_, rowId, value) =>
- dispatch(
- expandSystemAdvisoryRow({
- rowId: getRowIdByIndexExpandable(advisories, rowId),
- value
- })
- ), [JSON.stringify(advisories)]
- );
+ const onCollapse = useCallback(
+ (_, rowId, value) =>
+ dispatch(
+ expandSystemAdvisoryRow({
+ rowId: getRowIdByIndexExpandable(advisories, rowId),
+ value,
+ }),
+ ),
+ [JSON.stringify(advisories)],
+ );
- const constructFilename = (advisory) => advisory?.id || advisory;
- const onSelect = useOnSelect(
- rows,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.systemAdvisories(inventoryId),
- queryParams,
- selectionDispatcher: selectSystemAdvisoryRow,
- constructFilename,
- totalItems: metadata?.total_items
- }
- );
+ const constructFilename = (advisory) => advisory?.id || advisory;
+ const onSelect = useOnSelect(rows, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.systemAdvisories(inventoryId),
+ queryParams,
+ selectionDispatcher: selectSystemAdvisoryRow,
+ constructFilename,
+ totalItems: metadata?.total_items,
+ });
- const onSort = useSortColumn(systemAdvisoriesColumns, apply, 2);
- const sortBy = React.useMemo(
- () => createSortBy(systemAdvisoriesColumns, metadata.sort, 2),
- [metadata.sort]
- );
- const onSetPage = useSetPage(metadata.limit, apply);
- const onPerPageSelect = usePerPageSelect(apply);
+ const onSort = useSortColumn(systemAdvisoriesColumns, apply, 2);
+ const sortBy = React.useMemo(
+ () => createSortBy(systemAdvisoriesColumns, metadata.sort, 2),
+ [metadata.sort],
+ );
+ const onSetPage = useSetPage(metadata.limit, apply);
+ const onPerPageSelect = usePerPageSelect(apply);
- function apply(params) {
- dispatch(changeSystemAdvisoryListParams({ id: inventoryId, ...params }));
- }
+ function apply(params) {
+ dispatch(changeSystemAdvisoryListParams({ id: inventoryId, ...params }));
+ }
- const errorState = status.code === 404 ? handleNoSystemData() : ;
+ const errorState = status.code === 404 ? handleNoSystemData() : ;
- const onExport = useOnExport(inventoryId, queryParams, {
- csv: exportSystemAdvisoriesCSV,
- json: exportSystemAdvisoriesJSON
- }, dispatch);
+ const onExport = useOnExport(
+ inventoryId,
+ queryParams,
+ {
+ csv: exportSystemAdvisoriesCSV,
+ json: exportSystemAdvisoriesJSON,
+ },
+ dispatch,
+ );
- return (
-
-
- remediationProvider(
- arrayFromObj(selectedRows),
- inventoryId,
- remediationIdentifiers.advisory
- )
- }
- selectedRows={selectedRows}
- systemId={inventoryId}
- apply={apply}
- store={{ rows, metadata, status, queryParams }}
- remediationButtonOUIA={'toolbar-remediation-button'}
- tableOUIA={'system-advisories-table'}
- paginationOUIA={'system-advisories-pagination'}
- filterConfig={{
- items: [
- searchFilter(apply, queryParams.search,
- intl.formatMessage(messages.labelsFiltersSearchAdvisoriesTitle),
- intl.formatMessage(messages.labelsFiltersSearchAdvisoriesPlaceholder)
- ),
- typeFilter(apply, queryParams.filter),
- severityFilter(apply, queryParams?.filter),
- publishDateFilter(apply, queryParams.filter),
- rebootFilter(apply, queryParams.filter),
- advisoryStatusFilter(apply, queryParams.filter)
- ]
- }}
- errorState={errorState}
- searchChipLabel={intl.formatMessage(messages.labelsFiltersSearchAdvisoriesTitle)}
- hasColumnManagement
- />
-
- );
+ return (
+
+
+ remediationProvider(
+ arrayFromObj(selectedRows),
+ inventoryId,
+ remediationIdentifiers.advisory,
+ )
+ }
+ selectedRows={selectedRows}
+ systemId={inventoryId}
+ apply={apply}
+ store={{ rows, metadata, status, queryParams }}
+ remediationButtonOUIA='toolbar-remediation-button'
+ tableOUIA='system-advisories-table'
+ paginationOUIA='system-advisories-pagination'
+ filterConfig={{
+ items: [
+ searchFilter(
+ apply,
+ queryParams.search,
+ intl.formatMessage(messages.labelsFiltersSearchAdvisoriesTitle),
+ intl.formatMessage(messages.labelsFiltersSearchAdvisoriesPlaceholder),
+ ),
+ typeFilter(apply, queryParams.filter),
+ severityFilter(apply, queryParams?.filter),
+ publishDateFilter(apply, queryParams.filter),
+ rebootFilter(apply, queryParams.filter),
+ advisoryStatusFilter(apply, queryParams.filter),
+ ],
+ }}
+ errorState={errorState}
+ searchChipLabel={intl.formatMessage(messages.labelsFiltersSearchAdvisoriesTitle)}
+ hasColumnManagement
+ />
+
+ );
};
SystemAdvisories.propTypes = {
- handleNoSystemData: propTypes.func,
- inventoryId: propTypes.string.isRequired,
- shouldRefresh: propTypes.bool
+ handleNoSystemData: propTypes.func,
+ inventoryId: propTypes.string.isRequired,
+ shouldRefresh: propTypes.bool,
};
export default SystemAdvisories;
diff --git a/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js b/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js
index be17668b4..694983a6e 100644
--- a/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js
+++ b/src/SmartComponents/SystemAdvisories/SystemAdvisories.test.js
@@ -9,114 +9,112 @@ import { render, waitFor, screen } from '@testing-library/react';
initMocks();
jest.mock('../../Utilities/Helpers', () => ({
- ...jest.requireActual('../../Utilities/Helpers'),
- remediationProvider: jest.fn()
+ ...jest.requireActual('../../Utilities/Helpers'),
+ remediationProvider: jest.fn(),
}));
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- fetchIDs: jest.fn(() => Promise.resolve({ ids: [] }).catch((err) => console.log(err)))
+ ...jest.requireActual('../../Utilities/api'),
+ fetchIDs: jest.fn(() => Promise.resolve({ ids: [] }).catch((err) => console.log(err))),
}));
jest.mock('../Remediation/AsyncRemediationButton', () => ({
- __esModule: true,
- default: jest.fn((props) => (
-
- Remediation
-
- ))
+ __esModule: true,
+ default: jest.fn((props) => (
+
+ Remediation
+
+ )),
}));
const mockState = {
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 101
- },
- expandedRows: {},
- selectedRows: {},
- queryParams: {},
- error: {},
- status: {},
- rows: systemAdvisoryRows
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 101,
+ },
+ expandedRows: {},
+ selectedRows: {},
+ queryParams: {},
+ error: {},
+ status: {},
+ rows: systemAdvisoryRows,
};
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore({ SystemAdvisoryListStore: state });
+ const mockStore = configureStore([]);
+ return mockStore({ SystemAdvisoryListStore: state });
};
-describe('Selection', () => {
- beforeEach(() => {
- const store = initStore(mockState);
- render(
-
- );
- });
-
- testBulkSelection(
- fetchIDs,
- '/ids/systems/test/advisories',
- 'selectSystemAdvisoryRow',
- [
- {
- id: 'RHSA-2020:2774',
- selected: 'RHSA-2020:2774'
- }
- ]
+describe('Selection', () => {
+ beforeEach(() => {
+ const store = initStore(mockState);
+ render(
+
+
+ ,
);
+ });
+
+ testBulkSelection(fetchIDs, '/ids/systems/test/advisories', 'selectSystemAdvisoryRow', [
+ {
+ id: 'RHSA-2020:2774',
+ selected: 'RHSA-2020:2774',
+ },
+ ]);
});
describe('SystemAdvisories.js', () => {
- it('should render remediation button', async () => {
- render(
-
-
-
- );
+ it('should render remediation button', async () => {
+ render(
+
+
+ ,
+ );
- expect(screen.getByText('Remediation')).toBeVisible();
- });
+ expect(screen.getByText('Remediation')).toBeVisible();
+ });
- it('Should display SystemUpToDate when status is resolved, but there are no applicable advisories', async () => {
- const emptyState = {
- ...mockState,
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 0,
- filter: {}
- },
- rows: []
- };
+ it('Should display SystemUpToDate when status is resolved, but there are no applicable advisories', async () => {
+ const emptyState = {
+ ...mockState,
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 0,
+ filter: {},
+ },
+ rows: [],
+ };
- render(
-
- );
+ render(
+
+
+ ,
+ );
- await waitFor(() =>
- expect(screen.getByText('No applicable advisories')).toBeInTheDocument()
- );
- });
+ await waitFor(() => expect(screen.getByText('No applicable advisories')).toBeInTheDocument());
+ });
- it('Should display EmptyAdvisoryList when status is resolved, but there are no items', async () => {
- const emptyState = {
- ...mockState,
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 0,
- search: 'test',
- filter: {}
- },
- rows: []
- };
+ it('Should display EmptyAdvisoryList when status is resolved, but there are no items', async () => {
+ const emptyState = {
+ ...mockState,
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 0,
+ search: 'test',
+ filter: {},
+ },
+ rows: [],
+ };
- render(
-
- );
+ render(
+
+
+ ,
+ );
- await waitFor(() =>
- expect(screen.getByText('No matching advisories found')).toBeInTheDocument()
- );
- });
+ await waitFor(() =>
+ expect(screen.getByText('No matching advisories found')).toBeInTheDocument(),
+ );
+ });
});
-
diff --git a/src/SmartComponents/SystemDetail/InventoryDetail.js b/src/SmartComponents/SystemDetail/InventoryDetail.js
index 20f97e4a3..fefca7aa1 100644
--- a/src/SmartComponents/SystemDetail/InventoryDetail.js
+++ b/src/SmartComponents/SystemDetail/InventoryDetail.js
@@ -7,10 +7,13 @@ import { defaultReducers } from '../../store';
import { SystemDetailStore } from '../../store/Reducers/SystemDetailStore';
import { intl } from '../../Utilities/IntlProvider';
import messages from '../../Messages';
-import { InventoryDetailHead, DetailWrapper } from '@redhat-cloud-services/frontend-components/Inventory';
-import { Alert, Grid, GridItem, Content } from '@patternfly/react-core';
+import {
+ InventoryDetailHead,
+ DetailWrapper,
+} from '@redhat-cloud-services/frontend-components/Inventory';
+import { Alert, Grid, GridItem, Content } from '@patternfly/react-core';
import { fetchSystemDetailsAction } from '../../store/Actions/Actions';
-import { clearNotifications } from '@redhat-cloud-services/frontend-components-notifications/redux';;
+import { clearNotifications } from '@redhat-cloud-services/frontend-components-notifications/redux';
import PatchSetWrapper from '../../PresentationalComponents/PatchSetWrapper/PatchSetWrapper';
import { usePatchSetState } from '../../Utilities/hooks';
import { useParams } from 'react-router-dom';
@@ -19,132 +22,137 @@ import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome'
import { InsightsLink } from '@redhat-cloud-services/frontend-components/InsightsLink';
const InventoryDetail = () => {
- const { inventoryId } = useParams();
- const store = useStore();
- const dispatch = useDispatch();
+ const { inventoryId } = useParams();
+ const store = useStore();
+ const dispatch = useDispatch();
- const { hasThirdPartyRepo, satelliteManaged,
- templateName, templateUUID } = useSelector(
- ({ SystemDetailStore }) => SystemDetailStore
- );
+ const { hasThirdPartyRepo, satelliteManaged, templateName, templateUUID } = useSelector(
+ ({ SystemDetailStore }) => SystemDetailStore,
+ );
- const { display_name: displayName } = useSelector(
- ({ entityDetails }) => entityDetails?.entity ?? {}
- );
+ const { display_name: displayName } = useSelector(
+ ({ entityDetails }) => entityDetails?.entity ?? {},
+ );
- const { patchSetState, setPatchSetState } = usePatchSetState();
+ const { patchSetState, setPatchSetState } = usePatchSetState();
- useEffect(() => {
- dispatch(fetchSystemDetailsAction(inventoryId));
+ useEffect(() => {
+ dispatch(fetchSystemDetailsAction(inventoryId));
- return () => {
- dispatch(clearNotifications());
- };
- }, []);
+ return () => {
+ dispatch(clearNotifications());
+ };
+ }, []);
- useEffect(() => {
- if (patchSetState.shouldRefresh) {
- dispatch(fetchSystemDetailsAction(inventoryId));
- }
- }, [patchSetState.shouldRefresh]);
+ useEffect(() => {
+ if (patchSetState.shouldRefresh) {
+ dispatch(fetchSystemDetailsAction(inventoryId));
+ }
+ }, [patchSetState.shouldRefresh]);
- const chrome = useChrome();
- useEffect(() => {
- displayName && chrome.updateDocumentTitle(`${displayName} - Systems - Patch | RHEL`, true);
- }, [chrome, displayName]);
+ const chrome = useChrome();
+ useEffect(() => {
+ displayName && chrome.updateDocumentTitle(`${displayName} - Systems - Patch | RHEL`, true);
+ }, [chrome, displayName]);
- return (
- {
- store.replaceReducer(combineReducers({
- ...defaultReducers,
- ...mergeWithDetail(SystemDetailStore)
- }));
- }}
- inventoryId={inventoryId}
+ return (
+ {
+ store.replaceReducer(
+ combineReducers({
+ ...defaultReducers,
+ ...mergeWithDetail(SystemDetailStore),
+ }),
+ );
+ }}
+ inventoryId={inventoryId}
+ >
+
+
+
-
-
-
-
- {templateName &&
-
-
- {intl.formatMessage(messages.labelsColumnsTemplate)}:
-
- {templateName}
-
-
-
- }
-
- {satelliteManaged
- ?
-
-
-
- Read more
-
-
-
- : hasThirdPartyRepo &&
- }
-
-
-
-
-
-
-
- );
+ option.'
+ >
+
+ Read more
+
+
+
+ ) : (
+ hasThirdPartyRepo && (
+
+ )
+ )}
+
+
+
+
+
+
+
+
+ );
};
export default InventoryDetail;
diff --git a/src/SmartComponents/SystemDetail/InventoryDetail.test.js b/src/SmartComponents/SystemDetail/InventoryDetail.test.js
index 411f9cf2d..2501b3ae3 100644
--- a/src/SmartComponents/SystemDetail/InventoryDetail.test.js
+++ b/src/SmartComponents/SystemDetail/InventoryDetail.test.js
@@ -1,12 +1,11 @@
import InventoryDetail from './InventoryDetail';
import { act } from 'react-dom/test-utils';
import { render } from '@testing-library/react';
-import { Provider } from 'react-redux';
+import { Provider, useSelector } from 'react-redux';
import { entityDetail } from '../../Utilities/RawDataForTesting';
import configureStore from 'redux-mock-store';
import { initMocks, mountWithIntl } from '../../Utilities/unitTestingUtilities.js';
import { BrowserRouter as Router } from 'react-router-dom';
-import { useSelector } from 'react-redux';
import { InventoryDetailHead } from '@redhat-cloud-services/frontend-components/Inventory';
import UnassignSystemsModal from '../Modals/UnassignSystemsModal';
import { useFeatureFlag } from '../../Utilities/hooks';
@@ -14,130 +13,178 @@ import { useFeatureFlag } from '../../Utilities/hooks';
initMocks();
jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useParams: () => ({
- inventoryId: 'test-system-id'
- }),
- useRouteMatch: () => ({ url: '/systems/test-system-id' })
+ ...jest.requireActual('react-router-dom'),
+ useParams: () => ({
+ inventoryId: 'test-system-id',
+ }),
+ useRouteMatch: () => ({ url: '/systems/test-system-id' }),
}));
jest.mock('@redhat-cloud-services/frontend-components/Inventory', () => ({
- InventoryDetailHead: jest.fn(() => ),
- DetailWrapper: jest.fn(({ children }) => )
+ InventoryDetailHead: jest.fn(() => (
+
+ )),
+ DetailWrapper: jest.fn(({ children }) => (
+
+ )),
}));
jest.mock('./SystemDetail', () => () => This is system detail
);
const mockState = { ...entityDetail, SystemDetailStore: {} };
const initStore = (state) => {
- const customMiddleWare = () => next => action => {
- useSelector.mockImplementation(callback => {
- return callback({ entityDetails: state, SystemDetailStore: state });
- });
- next(action);
- };
-
- const mockStore = configureStore([customMiddleWare]);
- return mockStore({ entityDetails: state, SystemDetailStore: state });
+ const customMiddleWare = () => (next) => (action) => {
+ useSelector.mockImplementation((callback) =>
+ callback({ entityDetails: state, SystemDetailStore: state }),
+ );
+ next(action);
+ };
+
+ const mockStore = configureStore([customMiddleWare]);
+ return mockStore({ entityDetails: state, SystemDetailStore: state });
};
let wrapper;
let store = initStore(mockState);
beforeEach(() => {
- console.error = () => {};
-
- store.clearActions();
- useSelector.mockImplementation(callback => {
- return callback({ entityDetails: mockState, SystemDetailStore: {} });
- });
- wrapper = mountWithIntl(
-
- );
+ console.error = () => {};
+
+ store.clearActions();
+ useSelector.mockImplementation((callback) =>
+ callback({ entityDetails: mockState, SystemDetailStore: {} }),
+ );
+ wrapper = mountWithIntl(
+
+
+
+
+ ,
+ );
});
afterEach(() => {
- useSelector.mockClear();
+ useSelector.mockClear();
});
describe('InventoryPage.js', () => {
- it('Should match the snapshots', () => {
- const { asFragment } = render(
-
-
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
-
- it('Should display "Remove from a template" action in disabled state', () => {
- const { actions } = wrapper.find(InventoryDetailHead).props();
-
- expect(actions).toEqual(
- [
- { key: 'assign-to-template', onClick: expect.any(Function), title: 'Assign to a template' },
- { isDisabled: true, key: 'remove-from-template', onClick: expect.any(Function), title: 'Remove from a template' }
- ]);
- });
-
- it('Should display "Remove from a template" action in enabled state', () => {
- useSelector.mockImplementation(callback => {
- return callback({
- entityDetails: { ...mockState, patchSetName: 'test-name' },
- SystemDetailStore: { patchSetName: 'template-name' }
- });
- });
- const tempWrapper = mount(
-
- );
- const { actions } = tempWrapper.find(InventoryDetailHead).props();
-
- expect(actions).toEqual([
- { key: 'assign-to-template', onClick: expect.any(Function), title: 'Assign to a template' },
- { isDisabled: false, key: 'remove-from-template', onClick: expect.any(Function), title: 'Remove from a template' }
- ]);
+ it('Should match the snapshots', () => {
+ const { asFragment } = render(
+
+
+
+
+ ,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
+
+ it('Should display "Remove from a template" action in disabled state', () => {
+ const { actions } = wrapper.find(InventoryDetailHead).props();
+
+ expect(actions).toEqual([
+ { key: 'assign-to-template', onClick: expect.any(Function), title: 'Assign to a template' },
+ {
+ isDisabled: true,
+ key: 'remove-from-template',
+ onClick: expect.any(Function),
+ title: 'Remove from a template',
+ },
+ ]);
+ });
+
+ it('Should display "Remove from a template" action in enabled state', () => {
+ useSelector.mockImplementation((callback) =>
+ callback({
+ entityDetails: { ...mockState, patchSetName: 'test-name' },
+ SystemDetailStore: { patchSetName: 'template-name' },
+ }),
+ );
+ const tempWrapper = mount(
+
+
+
+
+ ,
+ );
+ const { actions } = tempWrapper.find(InventoryDetailHead).props();
+
+ expect(actions).toEqual([
+ { key: 'assign-to-template', onClick: expect.any(Function), title: 'Assign to a template' },
+ {
+ isDisabled: false,
+ key: 'remove-from-template',
+ onClick: expect.any(Function),
+ title: 'Remove from a template',
+ },
+ ]);
+ });
+
+ it('Should open UnassignSystemsModal when "Remove from a template" action is called', () => {
+ const testID = 'test-system-id';
+ useSelector.mockImplementation((callback) =>
+ callback({
+ entityDetails: { ...mockState, patchSetName: 'test-name' },
+ SystemDetailStore: {},
+ }),
+ );
+ const tempWrapper = mountWithIntl(
+
+
+
+
+ ,
+ );
+ const { actions } = tempWrapper.find(InventoryDetailHead).props();
+ actions.find((action) => action.key === 'remove-from-template')?.onClick();
+
+ const unassignSystemsModalState = tempWrapper
+ .update()
+ .find(UnassignSystemsModal)
+ .props().unassignSystemsModalState;
+ expect(unassignSystemsModalState).toEqual({
+ systemsIDs: [testID],
+ isUnassignSystemsModalOpen: true,
+ shouldRefresh: false,
});
-
- it('Should open UnassignSystemsModal when "Remove from a template" action is called', () => {
- const testID = 'test-system-id';
- useSelector.mockImplementation(callback => {
- return callback({ entityDetails: { ...mockState, patchSetName: 'test-name' }, SystemDetailStore: {} });
- });
- const tempWrapper = mountWithIntl(
-
- );
- const { actions } = tempWrapper.find(InventoryDetailHead).props();
- actions.find(action => action.key === 'remove-from-template')?.onClick();
-
- const unassignSystemsModalState = tempWrapper.update().find(UnassignSystemsModal).props().unassignSystemsModalState;
- expect(unassignSystemsModalState).toEqual({
- systemsIDs: [testID], isUnassignSystemsModalOpen: true, shouldRefresh: false
- });
+ });
+
+ it('Should refresh the page after successful system removal from a template', async () => {
+ const { actions } = wrapper.find(InventoryDetailHead).props();
+ actions.find((action) => action.key === 'remove-from-template')?.onClick();
+
+ const setUnassignSystemsModalOpen = wrapper
+ .update()
+ .find(UnassignSystemsModal)
+ .props().setUnassignSystemsModalOpen;
+ await act(async () => {
+ setUnassignSystemsModalOpen({
+ isUnassignSystemsModalOpen: false,
+ systemsIDs: [],
+ shouldRefresh: true,
+ });
});
- it('Should refresh the page after successful system removal from a template', async () => {
- const { actions } = wrapper.find(InventoryDetailHead).props();
- actions.find(action => action.key === 'remove-from-template')?.onClick();
-
- const setUnassignSystemsModalOpen = wrapper.update().find(UnassignSystemsModal).props().setUnassignSystemsModalOpen;
- await act(async () => {
- setUnassignSystemsModalOpen({
- isUnassignSystemsModalOpen: false,
- systemsIDs: [],
- shouldRefresh: true
- });
- });
-
- expect(store.getActions().filter(action => action.type === 'FETCH_SYSTEM_DETAIL').length).toEqual(2);
- });
-
- it('Should hide all dropdown actions when patch template flag is disabled', () => {
- useFeatureFlag.mockReturnValueOnce(false);
- const tempWrapper = mountWithIntl(
-
- );
-
- const { actions } = tempWrapper.find(InventoryDetailHead).props();
- expect(actions.length).toEqual(undefined);
- });
+ expect(
+ store.getActions().filter((action) => action.type === 'FETCH_SYSTEM_DETAIL').length,
+ ).toEqual(2);
+ });
+
+ it('Should hide all dropdown actions when patch template flag is disabled', () => {
+ useFeatureFlag.mockReturnValueOnce(false);
+ const tempWrapper = mountWithIntl(
+
+
+
+
+ ,
+ );
+
+ const { actions } = tempWrapper.find(InventoryDetailHead).props();
+ expect(actions.length).toEqual(undefined);
+ });
});
diff --git a/src/SmartComponents/SystemDetail/SystemDetail.js b/src/SmartComponents/SystemDetail/SystemDetail.js
index e7297929e..15c517246 100644
--- a/src/SmartComponents/SystemDetail/SystemDetail.js
+++ b/src/SmartComponents/SystemDetail/SystemDetail.js
@@ -10,55 +10,57 @@ import { NotConnected } from '@redhat-cloud-services/frontend-components/NotConn
import propTypes from 'prop-types';
const SystemDetail = ({ isInventoryApp, inventoryId, shouldRefresh }) => {
- const { state } = useLocation();
+ const { state } = useLocation();
- const [activeTabKey, setActiveTabKey] = useState(
- (state?.tab === 'packages') ? 1 : 0
- );
- const [areTabsHidden, setTabsHidden] = useState(false);
+ const [activeTabKey, setActiveTabKey] = useState(state?.tab === 'packages' ? 1 : 0);
+ const [areTabsHidden, setTabsHidden] = useState(false);
- const onTabSelect = (event, id) => {
- setActiveTabKey(id);
- };
+ const onTabSelect = (event, id) => {
+ setActiveTabKey(id);
+ };
- const handleNoSystemData = () => {
- isInventoryApp && setTabsHidden(prevTabsHidden => !prevTabsHidden);
- return isInventoryApp && null || ;
- };
+ const handleNoSystemData = () => {
+ isInventoryApp && setTabsHidden((prevTabsHidden) => !prevTabsHidden);
+ return isInventoryApp ? null : ;
+ };
- return (!areTabsHidden && (
-
- {intl.formatMessage(messages.titlesAdvisories)}}
- data-ouia-component-type={`system-advisories-tab`}
- data-ouia-component-id={`system-advisories-tab`}
- id={`system-advisories-tab`}
- >
-
-
- {intl.formatMessage(messages.titlesPackages)}}
- data-ouia-component-type={`system-packages-tab`}
- data-ouia-component-id={`system-packages-tab`}
- id={`system-packages-tab`}
- >
-
-
-
- ) || );
+ return (
+ (!areTabsHidden && (
+
+ {intl.formatMessage(messages.titlesAdvisories)}}
+ data-ouia-component-type='system-advisories-tab'
+ data-ouia-component-id='system-advisories-tab'
+ id='system-advisories-tab'
+ >
+
+
+ {intl.formatMessage(messages.titlesPackages)}}
+ data-ouia-component-type='system-packages-tab'
+ data-ouia-component-id='system-packages-tab'
+ id='system-packages-tab'
+ >
+
+
+
+ )) ||
+ );
};
SystemDetail.propTypes = {
- isInventoryApp: propTypes.bool,
- inventoryId: propTypes.string.isRequired,
- shouldRefresh: propTypes.bool
+ isInventoryApp: propTypes.bool,
+ inventoryId: propTypes.string.isRequired,
+ shouldRefresh: propTypes.bool,
};
export default SystemDetail;
diff --git a/src/SmartComponents/SystemDetail/SystemDetail.scss b/src/SmartComponents/SystemDetail/SystemDetail.scss
index ba048c531..a3ed25d08 100644
--- a/src/SmartComponents/SystemDetail/SystemDetail.scss
+++ b/src/SmartComponents/SystemDetail/SystemDetail.scss
@@ -1,6 +1,6 @@
.patchTabSelect {
- background-color: white;
- .pf-v6-c-tabs__item-text {
- padding: 8px 0px 8px 0px;
- }
-}
\ No newline at end of file
+ background-color: white;
+ .pf-v6-c-tabs__item-text {
+ padding: 8px 0px 8px 0px;
+ }
+}
diff --git a/src/SmartComponents/SystemDetail/SystemDetail.test.js b/src/SmartComponents/SystemDetail/SystemDetail.test.js
index 6c51e882d..b5cdd1e4f 100644
--- a/src/SmartComponents/SystemDetail/SystemDetail.test.js
+++ b/src/SmartComponents/SystemDetail/SystemDetail.test.js
@@ -1,71 +1,75 @@
import SystemDetail from './SystemDetail';
-import { useLocation } from 'react-router-dom';
+import { useLocation, BrowserRouter as Router } from 'react-router-dom';
import { Provider, useSelector } from 'react-redux';
import configureStore from 'redux-mock-store';
-import { BrowserRouter as Router } from 'react-router-dom';
import { render } from '@testing-library/react';
import { systemAdvisoryRows, systemPackages } from '../../Utilities/RawDataForTesting';
import { storeListDefaults } from '../../Utilities/constants';
const mockState = {
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 10
- },
- expandedRows: {},
- selectedRows: { 'RHSA-2020:2774': true },
- queryParams: {},
- error: {},
- status: {},
- rows: systemAdvisoryRows
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 10,
+ },
+ expandedRows: {},
+ selectedRows: { 'RHSA-2020:2774': true },
+ queryParams: {},
+ error: {},
+ status: {},
+ rows: systemAdvisoryRows,
};
jest.mock('react-redux', () => ({
- ...jest.requireActual('react-redux'),
- useSelector: jest.fn(),
- useDispatch: jest.fn(() => () => {})
+ ...jest.requireActual('react-redux'),
+ useSelector: jest.fn(),
+ useDispatch: jest.fn(() => () => {}),
}));
const initStore = (state) => {
- const customMiddleWare = () => next => action => {
- useSelector.mockImplementation(callback => {
- return callback({ SystemAdvisoryListStore: state });
- });
- next(action);
- };
+ const customMiddleWare = () => (next) => (action) => {
+ useSelector.mockImplementation((callback) => callback({ SystemAdvisoryListStore: state }));
+ next(action);
+ };
- const mockStore = configureStore([customMiddleWare]);
- return mockStore({ SystemAdvisoryListStore: state });
+ const mockStore = configureStore([customMiddleWare]);
+ return mockStore({ SystemAdvisoryListStore: state });
};
jest.mock('react-router-dom', () => ({
- ...jest.requireActual('react-router-dom'),
- useLocation: jest.fn(() => ({ state: 'advisories' }))
+ ...jest.requireActual('react-router-dom'),
+ useLocation: jest.fn(() => ({ state: 'advisories' })),
}));
let store = initStore(mockState);
describe('SystemDetail.js', () => {
- it('Should match the snapshots', () => {
- useSelector.mockImplementation(callback => {
- return callback({ SystemAdvisoryListStore: mockState,
- SystemPackageListStore: { ...storeListDefaults, rows: systemPackages } });
- });
+ it('Should match the snapshots', () => {
+ useSelector.mockImplementation((callback) =>
+ callback({
+ SystemAdvisoryListStore: mockState,
+ SystemPackageListStore: { ...storeListDefaults, rows: systemPackages },
+ }),
+ );
- const { asFragment } = render(
-
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ const { asFragment } = render(
+
+
+
+
+ ,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
- it('Should match the snapshot when Package tab is active by default', () => {
- useLocation.mockImplementation(() => ({ state: { tab: 'packages' } }));
- const { asFragment } = render(
-
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
+ it('Should match the snapshot when Package tab is active by default', () => {
+ useLocation.mockImplementation(() => ({ state: { tab: 'packages' } }));
+ const { asFragment } = render(
+
+
+
+
+ ,
+ );
+ expect(asFragment()).toMatchSnapshot();
+ });
});
-
diff --git a/src/SmartComponents/SystemPackages/SystemPackages.js b/src/SmartComponents/SystemPackages/SystemPackages.js
index 688b53e15..46dce062e 100644
--- a/src/SmartComponents/SystemPackages/SystemPackages.js
+++ b/src/SmartComponents/SystemPackages/SystemPackages.js
@@ -9,147 +9,147 @@ import { SystemUpToDate } from '../../PresentationalComponents/Snippets/SystemUp
import TableView from '../../PresentationalComponents/TableView/TableView';
import { systemPackagesColumns } from '../../PresentationalComponents/TableView/TableViewAssets';
import {
- changeSystemPackagesParams, clearSystemPackagesStore,
- fetchApplicableSystemPackages, selectSystemPackagesRow
+ changeSystemPackagesParams,
+ clearSystemPackagesStore,
+ fetchApplicableSystemPackages,
+ selectSystemPackagesRow,
} from '../../store/Actions/Actions';
import { exportSystemPackagesCSV, exportSystemPackagesJSON } from '../../Utilities/api';
import { remediationIdentifiers, systemPackagesDefaultFilters } from '../../Utilities/constants';
import { createSystemPackagesRows } from '../../Utilities/DataMappers';
import { arrayFromObj, createSortBy, remediationProvider } from '../../Utilities/Helpers';
-import { usePerPageSelect, useSetPage, useSortColumn, useOnExport,
- useOnSelect, ID_API_ENDPOINTS } from '../../Utilities/hooks';
+import {
+ usePerPageSelect,
+ useSetPage,
+ useSortColumn,
+ useOnExport,
+ useOnSelect,
+ ID_API_ENDPOINTS,
+} from '../../Utilities/hooks';
import { intl } from '../../Utilities/IntlProvider';
const SystemPackages = ({ handleNoSystemData, inventoryId, shouldRefresh }) => {
- const dispatch = useDispatch();
- const packages = useSelector(
- ({ SystemPackageListStore }) => SystemPackageListStore.rows
- );
- const queryParams = useSelector(
- ({ SystemPackageListStore }) => SystemPackageListStore.queryParams
- );
- const selectedRows = useSelector(
- ({ SystemPackageListStore }) => SystemPackageListStore.selectedRows
- );
- const metadata = useSelector(
- ({ SystemPackageListStore }) => SystemPackageListStore.metadata
- );
- const status = useSelector(
- ({ SystemPackageListStore }) => SystemPackageListStore.status
- );
- const error = useSelector(
- ({ SystemPackageListStore }) => SystemPackageListStore.error
- );
- const rows = useMemo(
- () =>
- createSystemPackagesRows(packages, selectedRows),
- [packages, selectedRows]
- );
+ const dispatch = useDispatch();
+ const packages = useSelector(({ SystemPackageListStore }) => SystemPackageListStore.rows);
+ const queryParams = useSelector(
+ ({ SystemPackageListStore }) => SystemPackageListStore.queryParams,
+ );
+ const selectedRows = useSelector(
+ ({ SystemPackageListStore }) => SystemPackageListStore.selectedRows,
+ );
+ const metadata = useSelector(({ SystemPackageListStore }) => SystemPackageListStore.metadata);
+ const status = useSelector(({ SystemPackageListStore }) => SystemPackageListStore.status);
+ const error = useSelector(({ SystemPackageListStore }) => SystemPackageListStore.error);
+ const rows = useMemo(
+ () => createSystemPackagesRows(packages, selectedRows),
+ [packages, selectedRows],
+ );
- useEffect(() => {
- return () => dispatch(clearSystemPackagesStore());
- }, []);
+ useEffect(() => () => dispatch(clearSystemPackagesStore()), []);
- useEffect(()=> {
- dispatch(fetchApplicableSystemPackages({ id: inventoryId, ...queryParams }));
- }, [queryParams]);
+ useEffect(() => {
+ dispatch(fetchApplicableSystemPackages({ id: inventoryId, ...queryParams }));
+ }, [queryParams]);
- useEffect(() => {
- if (shouldRefresh) {
- dispatch(fetchApplicableSystemPackages({ id: inventoryId, ...queryParams }));
- }
- }, [shouldRefresh]);
+ useEffect(() => {
+ if (shouldRefresh) {
+ dispatch(fetchApplicableSystemPackages({ id: inventoryId, ...queryParams }));
+ }
+ }, [shouldRefresh]);
- const constructFilename = (pkg) => {
- const pkgUpdates = pkg.updates || [];
- const latestUpdate = pkgUpdates[pkgUpdates.length - 1];
- return latestUpdate && `${pkg.name}-${latestUpdate.evra}`;
- };
+ const constructFilename = (pkg) => {
+ const pkgUpdates = pkg.updates || [];
+ const latestUpdate = pkgUpdates[pkgUpdates.length - 1];
+ return latestUpdate && `${pkg.name}-${latestUpdate.evra}`;
+ };
- const transformKey = (row) => {
- return `${row.name}-${row.evra}`;
- };
+ const transformKey = (row) => `${row.name}-${row.evra}`;
- const onSelect = useOnSelect(
- packages,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.systemPackages(inventoryId),
- queryParams,
- selectionDispatcher: selectSystemPackagesRow,
- constructFilename,
- transformKey,
- totalItems: metadata?.total_items
- }
- );
+ const onSelect = useOnSelect(packages, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.systemPackages(inventoryId),
+ queryParams,
+ selectionDispatcher: selectSystemPackagesRow,
+ constructFilename,
+ transformKey,
+ totalItems: metadata?.total_items,
+ });
- function apply(params) {
- dispatch(changeSystemPackagesParams({ id: inventoryId, ...params }));
- }
+ function apply(params) {
+ dispatch(changeSystemPackagesParams({ id: inventoryId, ...params }));
+ }
- const onSort = useSortColumn(systemPackagesColumns, apply, 1);
- const sortBy = useMemo(
- () => createSortBy(systemPackagesColumns, metadata.sort, 1),
- [metadata.sort]
- );
- const onSetPage = useSetPage(metadata.limit, apply);
- const onPerPageSelect = usePerPageSelect(apply);
+ const onSort = useSortColumn(systemPackagesColumns, apply, 1);
+ const sortBy = useMemo(
+ () => createSortBy(systemPackagesColumns, metadata.sort, 1),
+ [metadata.sort],
+ );
+ const onSetPage = useSetPage(metadata.limit, apply);
+ const onPerPageSelect = usePerPageSelect(apply);
- const errorState = status.hasError && (error.status === 404 ? handleNoSystemData() : );
- const emptyState = (!status.isLoading && !status.hasError && metadata.total_items === 0
- && Object.keys(queryParams).length === 0) && ;
- const onExport = useOnExport(inventoryId, queryParams, {
- csv: exportSystemPackagesCSV,
- json: exportSystemPackagesJSON
- }, dispatch);
+ const errorState =
+ status.hasError && (error.status === 404 ? handleNoSystemData() : );
+ const emptyState = !status.isLoading &&
+ !status.hasError &&
+ metadata.total_items === 0 &&
+ Object.keys(queryParams).length === 0 && ;
+ const onExport = useOnExport(
+ inventoryId,
+ queryParams,
+ {
+ csv: exportSystemPackagesCSV,
+ json: exportSystemPackagesJSON,
+ },
+ dispatch,
+ );
- return (
-
-
- remediationProvider(
- arrayFromObj(selectedRows),
- inventoryId,
- remediationIdentifiers.package
- )
- }
- apply={apply}
- filterConfig={{
- items: [
- searchFilter(apply, queryParams.search,
- intl.formatMessage(messages.labelsFiltersPackagesSearchTitle),
- intl.formatMessage(messages.labelsFiltersPackagesSearchPlaceHolder)
- ),
- statusFilter(apply, queryParams.filter)
- ]
- }}
- defaultFilters = {systemPackagesDefaultFilters}
- remediationButtonOUIA={'toolbar-remediation-button'}
- tableOUIA={'system-packages-table'}
- paginationOUIA={'system-packages-pagination'}
- errorState={errorState}
- emptyState={emptyState}
- searchChipLabel={intl.formatMessage(messages.labelsFiltersPackagesSearchTitle)}
- hasColumnManagement
- />
-
- );
+ return (
+
+
+ remediationProvider(
+ arrayFromObj(selectedRows),
+ inventoryId,
+ remediationIdentifiers.package,
+ )
+ }
+ apply={apply}
+ filterConfig={{
+ items: [
+ searchFilter(
+ apply,
+ queryParams.search,
+ intl.formatMessage(messages.labelsFiltersPackagesSearchTitle),
+ intl.formatMessage(messages.labelsFiltersPackagesSearchPlaceHolder),
+ ),
+ statusFilter(apply, queryParams.filter),
+ ],
+ }}
+ defaultFilters={systemPackagesDefaultFilters}
+ remediationButtonOUIA='toolbar-remediation-button'
+ tableOUIA='system-packages-table'
+ paginationOUIA='system-packages-pagination'
+ errorState={errorState}
+ emptyState={emptyState}
+ searchChipLabel={intl.formatMessage(messages.labelsFiltersPackagesSearchTitle)}
+ hasColumnManagement
+ />
+
+ );
};
SystemPackages.propTypes = {
- handleNoSystemData: propTypes.func,
- inventoryId: propTypes.string.isRequired,
- shouldRefresh: propTypes.bool
+ handleNoSystemData: propTypes.func,
+ inventoryId: propTypes.string.isRequired,
+ shouldRefresh: propTypes.bool,
};
export default SystemPackages;
-
diff --git a/src/SmartComponents/SystemPackages/SystemPackages.test.js b/src/SmartComponents/SystemPackages/SystemPackages.test.js
index 1941ea4e0..6d872d5a1 100644
--- a/src/SmartComponents/SystemPackages/SystemPackages.test.js
+++ b/src/SmartComponents/SystemPackages/SystemPackages.test.js
@@ -13,147 +13,153 @@ import userEvent from '@testing-library/user-event';
initMocks();
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- fetchIDs: jest.fn(() => Promise.resolve({
- data: [{
- attributes: {
- advisory_type: 2,
- description: 'The tzdata penhancements.',
- public_date: '2020-10-19T15:02:38Z',
- synopsis: 'tzdata enhancement update'
- },
- id: 'RHBA-2020:4282',
- type: 'advisory'
- }]
- }).catch((err) => console.log(err)))
+ ...jest.requireActual('../../Utilities/api'),
+ fetchIDs: jest.fn(() =>
+ Promise.resolve({
+ data: [
+ {
+ attributes: {
+ advisory_type: 2,
+ description: 'The tzdata penhancements.',
+ public_date: '2020-10-19T15:02:38Z',
+ synopsis: 'tzdata enhancement update',
+ },
+ id: 'RHBA-2020:4282',
+ type: 'advisory',
+ },
+ ],
+ }).catch((err) => console.log(err)),
+ ),
}));
jest.mock('../../Utilities/Helpers', () => ({
- ...jest.requireActual('../../Utilities/Helpers'),
- encodeApiParams: jest.fn(),
- remediationProvider: jest.fn()
+ ...jest.requireActual('../../Utilities/Helpers'),
+ encodeApiParams: jest.fn(),
+ remediationProvider: jest.fn(),
}));
jest.mock('../Remediation/AsyncRemediationButton', () => ({
- __esModule: true,
- default: jest.fn(({ remediationProvider, ...props }) => {
- remediationProvider();
- return (
-
- Remediation
-
- );
- }
- )
+ __esModule: true,
+ default: jest.fn(({ remediationProvider, ...props }) => {
+ remediationProvider();
+ return (
+
+ Remediation
+
+ );
+ }),
}));
const mockState = {
- ...storeListDefaults,
- rows: systemPackages,
- status: { code: 200, isLoading: false, hasError: false },
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 101
- }
+ ...storeListDefaults,
+ rows: systemPackages,
+ status: { code: 200, isLoading: false, hasError: false },
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 101,
+ },
};
const mountComponent = (state, componentProps) => {
- const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore({ SystemPackageListStore: state });
- };
-
- render(
-
- );
+ const initStore = (state) => {
+ const mockStore = configureStore([]);
+ return mockStore({ SystemPackageListStore: state });
+ };
+
+ render(
+
+
+ ,
+ );
};
const user = userEvent.setup();
describe('Selection', () => {
- beforeEach(async () =>{
- mountComponent(mockState);
- await waitFor(() => screen.getByLabelText('Patch table view'));
- });
- testBulkSelection(
- fetchIDs,
- '/systems/entity/packages',
- 'selectSystemPackagesRow',
- [{
- id: 'test-name-test-evra',
- selected: 'test-name-test-evra'
- }]
- );
+ beforeEach(async () => {
+ mountComponent(mockState);
+ await waitFor(() => screen.getByLabelText('Patch table view'));
+ });
+ testBulkSelection(fetchIDs, '/systems/entity/packages', 'selectSystemPackagesRow', [
+ {
+ id: 'test-name-test-evra',
+ selected: 'test-name-test-evra',
+ },
+ ]);
});
describe('SystemPackages', () => {
- it('Should provide correct remediation data', async () => {
- const selectedState = {
- ...mockState,
- selectedRows: { 'test-id-0': 'test-id-0' }
- };
-
- mountComponent(selectedState);
- await waitFor(() => screen.getByLabelText('Patch table view'));
-
- await user.click(screen.getByText('Remediation'));
- await waitFor(() => {
- expect(remediationProvider).toHaveBeenCalledWith(['test-id-0'], 'entity', remediationIdentifiers.package);
- });
+ it('Should provide correct remediation data', async () => {
+ const selectedState = {
+ ...mockState,
+ selectedRows: { 'test-id-0': 'test-id-0' },
+ };
+
+ mountComponent(selectedState);
+ await waitFor(() => screen.getByLabelText('Patch table view'));
+
+ await user.click(screen.getByText('Remediation'));
+ await waitFor(() => {
+ expect(remediationProvider).toHaveBeenCalledWith(
+ ['test-id-0'],
+ 'entity',
+ remediationIdentifiers.package,
+ );
});
+ });
- it('Should render no access component', async () => {
- const rejectedState = {
- ...mockState,
- status: { code: 403, isLoading: false, hasError: true },
- error: { detail: 'test' }
- };
+ it('Should render no access component', async () => {
+ const rejectedState = {
+ ...mockState,
+ status: { code: 403, isLoading: false, hasError: true },
+ error: { detail: 'test' },
+ };
- mountComponent(rejectedState);
+ mountComponent(rejectedState);
- expect(screen.getByText('You do not have permissions to view or manage Patch')).toBeVisible();
- });
+ expect(screen.getByText('You do not have permissions to view or manage Patch')).toBeVisible();
+ });
- it('Should display SystemUpToDate when status is resolved, but there is no items', async () => {
- const emptyState = {
- ...mockState,
- metadata: {
- ...mockState.metadata,
- total_items: 0,
- has_systems: false
- },
- queryParams: {}
- };
-
- mountComponent(emptyState);
- expect(screen.getByText('No applicable advisories')).toBeVisible();
- });
+ it('Should display SystemUpToDate when status is resolved, but there is no items', async () => {
+ const emptyState = {
+ ...mockState,
+ metadata: {
+ ...mockState.metadata,
+ total_items: 0,
+ has_systems: false,
+ },
+ queryParams: {},
+ };
- it('Should display Unavailable component when there is a generic error', async () => {
- const unavailableState = {
- ...mockState,
- status: { code: 500, isLoading: false, hasError: true }
- };
+ mountComponent(emptyState);
+ expect(screen.getByText('No applicable advisories')).toBeVisible();
+ });
- mountComponent(unavailableState);
- expect(screen.getByText('This page is temporarily unavailable')).toBeVisible();
- });
+ it('Should display Unavailable component when there is a generic error', async () => {
+ const unavailableState = {
+ ...mockState,
+ status: { code: 500, isLoading: false, hasError: true },
+ };
- it('Should display NotConnected', async () => {
- const notFoundState = {
- ...mockState,
- status: { code: 404, isLoading: false, hasError: true },
- error: {
- status: 404,
- title: 'testTitle',
- detail: 'testDescription'
- }
- };
+ mountComponent(unavailableState);
+ expect(screen.getByText('This page is temporarily unavailable')).toBeVisible();
+ });
+
+ it('Should display NotConnected', async () => {
+ const notFoundState = {
+ ...mockState,
+ status: { code: 404, isLoading: false, hasError: true },
+ error: {
+ status: 404,
+ title: 'testTitle',
+ detail: 'testDescription',
+ },
+ };
- const handleNoSystemData = jest.fn(() => () => Mocked component
);
+ const handleNoSystemData = jest.fn(() => () => Mocked component
);
- mountComponent(notFoundState, { handleNoSystemData });
+ mountComponent(notFoundState, { handleNoSystemData });
- expect(handleNoSystemData).toHaveBeenCalled();
- });
+ expect(handleNoSystemData).toHaveBeenCalled();
+ });
});
diff --git a/src/SmartComponents/Systems/SystemListAssets.test.js b/src/SmartComponents/Systems/SystemListAssets.test.js
index 34c53ed93..dcc656832 100644
--- a/src/SmartComponents/Systems/SystemListAssets.test.js
+++ b/src/SmartComponents/Systems/SystemListAssets.test.js
@@ -1,79 +1,86 @@
import {
- SYSTEMS_LIST_COLUMNS, PACKAGE_SYSTEMS_COLUMNS, systemsRowActions, useActivateRemediationModal
+ SYSTEMS_LIST_COLUMNS,
+ PACKAGE_SYSTEMS_COLUMNS,
+ systemsRowActions,
+ useActivateRemediationModal,
} from './SystemsListAssets';
-import { createAdvisoriesIcons, createUpgradableColumn, remediationProvider } from '../../Utilities/Helpers';
+import {
+ createAdvisoriesIcons,
+ createUpgradableColumn,
+ remediationProvider,
+} from '../../Utilities/Helpers';
import { fetchApplicableSystemAdvisoriesApi } from '../../Utilities/api';
import { remediationIdentifiers } from '../../Utilities/constants';
import { renderHook, waitFor } from '@testing-library/react';
jest.mock('../../Utilities/Helpers', () => ({
- ...jest.requireActual('../../Utilities/Helpers'),
- createAdvisoriesIcons: jest.fn(),
- createUpgradableColumn: jest.fn(),
- remediationProvider: jest.fn()
+ ...jest.requireActual('../../Utilities/Helpers'),
+ createAdvisoriesIcons: jest.fn(),
+ createUpgradableColumn: jest.fn(),
+ remediationProvider: jest.fn(),
}));
jest.mock('../../Utilities/api', () => ({
- ...jest.requireActual('../../Utilities/api'),
- fetchApplicableSystemAdvisoriesApi: jest.fn()
+ ...jest.requireActual('../../Utilities/api'),
+ fetchApplicableSystemAdvisoriesApi: jest.fn(),
}));
describe('SystemListAssets.js', () => {
+ it('Should call systemsListColumns on Applicable advisories renderFunc with correct params', () => {
+ SYSTEMS_LIST_COLUMNS.find((c) => c.key === 'applicable_advisories').renderFunc('testValue');
+ expect(createAdvisoriesIcons).toHaveBeenCalledWith('testValue', 'installable');
+ });
- it('Should call systemsListColumns on Applicable advisories renderFunc with correct params', () => {
- SYSTEMS_LIST_COLUMNS.find(c => c.key === 'applicable_advisories').renderFunc('testValue');
- expect(createAdvisoriesIcons).toHaveBeenCalledWith('testValue', 'installable');
- });
-
- it('Should call createUpgradableColumn on Status renderFunc with correct params', () => {
- PACKAGE_SYSTEMS_COLUMNS.find(c => c.key === 'update_status').renderFunc('testValue');
- expect(createUpgradableColumn).toHaveBeenCalledWith('testValue');
- });
+ it('Should call createUpgradableColumn on Status renderFunc with correct params', () => {
+ PACKAGE_SYSTEMS_COLUMNS.find((c) => c.key === 'update_status').renderFunc('testValue');
+ expect(createUpgradableColumn).toHaveBeenCalledWith('testValue');
+ });
- describe('test systemsRowActions: ', () => {
- const getMockedData = (id) => Promise.resolve({ data: [{ id }], meta: { total_items: 51 } });
- fetchApplicableSystemAdvisoriesApi.mockReturnValueOnce(getMockedData('testDataID-1'))
- .mockReturnValueOnce(getMockedData('testDataID-2'))
- .mockReturnValue(getMockedData('testDataID-3'));
+ describe('test systemsRowActions: ', () => {
+ const getMockedData = (id) => Promise.resolve({ data: [{ id }], meta: { total_items: 51 } });
+ fetchApplicableSystemAdvisoriesApi
+ .mockReturnValueOnce(getMockedData('testDataID-1'))
+ .mockReturnValueOnce(getMockedData('testDataID-2'))
+ .mockReturnValue(getMockedData('testDataID-3'));
- const mockShowRemediationModal = jest.fn();
- const mockSetRemediationCmp = jest.fn();
- const { result } = renderHook(() =>
- useActivateRemediationModal(
- mockSetRemediationCmp,
- mockShowRemediationModal
- )
- );
- const actions = systemsRowActions(result.current);
- actions[0].onClick(null, null, { id: 'testId' });
+ const mockShowRemediationModal = jest.fn();
+ const mockSetRemediationCmp = jest.fn();
+ const { result } = renderHook(() =>
+ useActivateRemediationModal(mockSetRemediationCmp, mockShowRemediationModal),
+ );
+ const actions = systemsRowActions(result.current);
+ actions[0].onClick(null, null, { id: 'testId' });
- it('Should enable remediation modal', async () => {
- await waitFor(() => {
- expect(mockShowRemediationModal).toHaveBeenCalledWith(true);
- });
- });
- it('Should fetch only Installable advisories from fetchApplicableSystemAdvisoriesApi', () => {
- expect(fetchApplicableSystemAdvisoriesApi).toHaveBeenCalledWith(
- expect.objectContaining({
- id: 'testId',
- 'filter[status]': 'in:Installable'
- })
- );
- expect(fetchApplicableSystemAdvisoriesApi).toHaveBeenCalledTimes(3);
- });
- it('Should call remediationProvider with fetched advisories data', () => {
- expect(remediationProvider).toHaveBeenCalledWith(
- ['testDataID-2', 'testDataID-3'],
- 'testId',
- remediationIdentifiers.advisory
- );
- });
- it('Should disable "Apply all applicable advisories" action when there is no applicable advisories ', () => {
- const testRow = { applicable_advisories: [0, 0, 0, 0] };
- const actions = systemsRowActions(null, null, null, testRow);
- expect(actions).toEqual(
- [{ isDisabled: true, onClick: expect.any(Function), title: 'Apply all applicable advisories' }]
- );
- });
+ it('Should enable remediation modal', async () => {
+ await waitFor(() => {
+ expect(mockShowRemediationModal).toHaveBeenCalledWith(true);
+ });
});
+ it('Should fetch only Installable advisories from fetchApplicableSystemAdvisoriesApi', () => {
+ expect(fetchApplicableSystemAdvisoriesApi).toHaveBeenCalledWith(
+ expect.objectContaining({
+ id: 'testId',
+ 'filter[status]': 'in:Installable',
+ }),
+ );
+ expect(fetchApplicableSystemAdvisoriesApi).toHaveBeenCalledTimes(3);
+ });
+ it('Should call remediationProvider with fetched advisories data', () => {
+ expect(remediationProvider).toHaveBeenCalledWith(
+ ['testDataID-2', 'testDataID-3'],
+ 'testId',
+ remediationIdentifiers.advisory,
+ );
+ });
+ it('Should disable "Apply all applicable advisories" action when there is no applicable advisories ', () => {
+ const testRow = { applicable_advisories: [0, 0, 0, 0] };
+ const actions = systemsRowActions(null, null, null, testRow);
+ expect(actions).toEqual([
+ {
+ isDisabled: true,
+ onClick: expect.any(Function),
+ title: 'Apply all applicable advisories',
+ },
+ ]);
+ });
+ });
});
-
diff --git a/src/SmartComponents/Systems/SystemTable.test.js b/src/SmartComponents/Systems/SystemTable.test.js
index c0cab3eb4..117d3c2da 100644
--- a/src/SmartComponents/Systems/SystemTable.test.js
+++ b/src/SmartComponents/Systems/SystemTable.test.js
@@ -8,251 +8,252 @@ import { InventoryTable } from '@redhat-cloud-services/frontend-components/Inven
initMocks();
const mockState = {
- entities: {
- rows: systemRows,
- metadata: {
- limit: 25,
- offset: 0,
- has_systems: true
- },
- selectedRows: { 'test-system-id-1': true },
- total: systemRows.length
+ entities: {
+ rows: systemRows,
+ metadata: {
+ limit: 25,
+ offset: 0,
+ has_systems: true,
},
- SystemsStore: {
- queryParams: {}
- }
+ selectedRows: { 'test-system-id-1': true },
+ total: systemRows.length,
+ },
+ SystemsStore: {
+ queryParams: {},
+ },
};
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore(state);
+ const mockStore = configureStore([]);
+ return mockStore(state);
};
const renderComponent = async (mockedStore) => {
- render(
-
- );
+ render(
+
+
+ ,
+ );
- await waitFor(() => {
- expect(
- screen.getByTestId('inventory-mock-component')
- ).toBeInTheDocument();
- });
+ await waitFor(() => {
+ expect(screen.getByTestId('inventory-mock-component')).toBeInTheDocument();
+ });
};
describe('SystemsTable', () => {
- it('Should render inventory table', async () => {
- await renderComponent(mockState);
- expect(screen.getByTestId('inventory-mock-component')).toBeVisible();
- });
-
- it('Should provide customFilters prop', async () => {
- const filteredState = {
- ...mockState,
- SystemsStore: {
- queryParams: {
- filter: { packages_updatable: 'eq:0' },
- selectedTags: ['tags=test-tag'],
- systemProfile: { ansible: { controller_version: 'not_nil' } }
- }
- }
- };
+ it('Should render inventory table', async () => {
+ await renderComponent(mockState);
+ expect(screen.getByTestId('inventory-mock-component')).toBeVisible();
+ });
- await renderComponent(filteredState);
- await waitFor(() =>
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- customFilters: {
- patchParams: {
- filter: { packages_updatable: 'eq:0' },
- search: undefined,
- selectedTags: ['tags=test-tag'],
- systemProfile: { ansible: { controller_version: 'not_nil' } }
- }
- }
- }),
- {}
- )
- );
- });
+ it('Should provide customFilters prop', async () => {
+ const filteredState = {
+ ...mockState,
+ SystemsStore: {
+ queryParams: {
+ filter: { packages_updatable: 'eq:0' },
+ selectedTags: ['tags=test-tag'],
+ systemProfile: { ansible: { controller_version: 'not_nil' } },
+ },
+ },
+ };
- it('should use group, os and tag filter from Inventory', async () => {
- await renderComponent(mockState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- hideFilters: {
- all: true,
- tags: false,
- hostGroupFilter: false,
- operatingSystem: false
- }
- }),
- {}
- );
- });
+ await renderComponent(filteredState);
+ await waitFor(() =>
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ customFilters: {
+ patchParams: {
+ filter: { packages_updatable: 'eq:0' },
+ search: undefined,
+ selectedTags: ['tags=test-tag'],
+ systemProfile: { ansible: { controller_version: 'not_nil' } },
+ },
+ },
+ }),
+ {},
+ ),
+ );
+ });
- it('should disable pagination and export when there are no rows', async () => {
- const emptyStateState = {
- ...mockState,
- entities: {
- ...mockState.entities,
- total: 0
- }
- };
+ it('should use group, os and tag filter from Inventory', async () => {
+ await renderComponent(mockState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ hideFilters: {
+ all: true,
+ tags: false,
+ hostGroupFilter: false,
+ operatingSystem: false,
+ },
+ }),
+ {},
+ );
+ });
- await renderComponent(emptyStateState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- paginationProps: {
- isDisabled: true
- }
- }),
- {}
- );
+ it('should disable pagination and export when there are no rows', async () => {
+ const emptyStateState = {
+ ...mockState,
+ entities: {
+ ...mockState.entities,
+ total: 0,
+ },
+ };
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- exportConfig: {
- isDisabled: true,
- onSelect: expect.any(Function)
- }
- }),
- {}
- );
- });
+ await renderComponent(emptyStateState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ paginationProps: {
+ isDisabled: true,
+ },
+ }),
+ {},
+ );
- it('should provide filterConfig', async () => {
- await renderComponent(mockState);
- await waitFor(() => expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- filterConfig: {
- items: [
- {
- filterValues: {
- 'aria-label': 'search-field',
- onChange: expect.any(Function),
- placeholder: 'Filter by name',
- value: undefined
- },
- label: 'System',
- type: 'text'
- },
- {
- filterValues: {
- items: [
- {
- label: 'Stale',
- value: 'true'
- },
- {
- label: 'Fresh',
- value: 'false'
- }
- ],
- onChange: expect.any(Function),
- placeholder: 'Filter by status',
- value: undefined
- },
- label: 'Status',
- type: 'checkbox'
- },
- {
- filterValues: {
- items: [
- {
- label: 'Systems up to date',
- value: 'eq:0'
- },
- {
- label: 'Systems with patches available',
- value: 'gt:0'
- }
- ],
- onChange: expect.any(Function),
- placeholder: 'Filter by patch status',
- value: undefined
- },
- label: 'Patch status',
- type: 'singleSelect'
- }
- ]
- }
- }),
- {}
- ));
- });
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ exportConfig: {
+ isDisabled: true,
+ onSelect: expect.any(Function),
+ },
+ }),
+ {},
+ );
+ });
- it('should provide actions config', async () => {
- await renderComponent(mockState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- actionsConfig: {
- actions: [
- expect.anything(), // remediation button
- expect.anything() // column mgmt button
+ it('should provide filterConfig', async () => {
+ await renderComponent(mockState);
+ await waitFor(() =>
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ filterConfig: {
+ items: [
+ {
+ filterValues: {
+ 'aria-label': 'search-field',
+ onChange: expect.any(Function),
+ placeholder: 'Filter by name',
+ value: undefined,
+ },
+ label: 'System',
+ type: 'text',
+ },
+ {
+ filterValues: {
+ items: [
+ {
+ label: 'Stale',
+ value: 'true',
+ },
+ {
+ label: 'Fresh',
+ value: 'false',
+ },
+ ],
+ onChange: expect.any(Function),
+ placeholder: 'Filter by status',
+ value: undefined,
+ },
+ label: 'Status',
+ type: 'checkbox',
+ },
+ {
+ filterValues: {
+ items: [
+ {
+ label: 'Systems up to date',
+ value: 'eq:0',
+ },
+ {
+ label: 'Systems with patches available',
+ value: 'gt:0',
+ },
+ ],
+ onChange: expect.any(Function),
+ placeholder: 'Filter by patch status',
+ value: undefined,
+ },
+ label: 'Patch status',
+ type: 'singleSelect',
+ },
+ ],
+ },
+ }),
+ {},
+ ),
+ );
+ });
- ]
- }
- }),
- {}
- );
- });
+ it('should provide actions config', async () => {
+ await renderComponent(mockState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ actionsConfig: {
+ actions: [
+ expect.anything(), // remediation button
+ expect.anything(), // column mgmt button
+ ],
+ },
+ }),
+ {},
+ );
+ });
- it('should provide activeFilters config', async () => {
- await renderComponent(mockState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- activeFiltersConfig: {
- deleteTitle: 'Reset filters',
- filters: [
- {
- category: 'Patch status',
- chips: [
- {
- id: 'eq:0',
- name: 'Systems up to date',
- value: 'eq:0'
- }
- ],
- id: 'packages_updatable'
- }
- ],
- onDelete: expect.any(Function)
- }
- }),
- {}
- );
- });
+ it('should provide activeFilters config', async () => {
+ await renderComponent(mockState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ activeFiltersConfig: {
+ deleteTitle: 'Reset filters',
+ filters: [
+ {
+ category: 'Patch status',
+ chips: [
+ {
+ id: 'eq:0',
+ name: 'Systems up to date',
+ value: 'eq:0',
+ },
+ ],
+ id: 'packages_updatable',
+ },
+ ],
+ onDelete: expect.any(Function),
+ },
+ }),
+ {},
+ );
+ });
- it('should provide bulkSelect config', async () => {
- await renderComponent(mockState);
- expect(InventoryTable).toHaveBeenCalledWith(
- expect.objectContaining({
- bulkSelect: {
- checked: null,
- isDisabled: false,
- count: 1,
- items: [
- {
- onClick: expect.any(Function),
- title: 'Select none (0)'
- },
- {
- onClick: expect.any(Function),
- title: 'Select page (2)'
- },
- {
- onClick: expect.any(Function),
- title: 'Select all (2)'
- }
- ],
- onSelect: expect.any(Function),
- toggleProps: {
- 'aria-label': 'Select',
- 'data-ouia-component-type': 'bulk-select-toggle-button'
- }
- }
- }),
- {}
- );
- });
+ it('should provide bulkSelect config', async () => {
+ await renderComponent(mockState);
+ expect(InventoryTable).toHaveBeenCalledWith(
+ expect.objectContaining({
+ bulkSelect: {
+ checked: null,
+ isDisabled: false,
+ count: 1,
+ items: [
+ {
+ onClick: expect.any(Function),
+ title: 'Select none (0)',
+ },
+ {
+ onClick: expect.any(Function),
+ title: 'Select page (2)',
+ },
+ {
+ onClick: expect.any(Function),
+ title: 'Select all (2)',
+ },
+ ],
+ onSelect: expect.any(Function),
+ toggleProps: {
+ 'aria-label': 'Select',
+ 'data-ouia-component-type': 'bulk-select-toggle-button',
+ },
+ },
+ }),
+ {},
+ );
+ });
});
diff --git a/src/SmartComponents/Systems/SystemsListAssets.js b/src/SmartComponents/Systems/SystemsListAssets.js
index 253ca158f..8f64a9743 100644
--- a/src/SmartComponents/Systems/SystemsListAssets.js
+++ b/src/SmartComponents/Systems/SystemsListAssets.js
@@ -2,8 +2,11 @@ import React, { useCallback } from 'react';
import { fetchApplicableSystemAdvisoriesApi } from '../../Utilities/api';
import { remediationIdentifiers } from '../../Utilities/constants';
import {
- createAdvisoriesIcons, createUpgradableColumn,
- remediationProvider, createOSColumn, createPackagesColumn
+ createAdvisoriesIcons,
+ createUpgradableColumn,
+ remediationProvider,
+ createOSColumn,
+ createPackagesColumn,
} from '../../Utilities/Helpers';
import './SystemsListAssets.scss';
import { sortable } from '@patternfly/react-table';
@@ -12,312 +15,322 @@ import { Content, Tooltip } from '@patternfly/react-core';
import { useFetchBatched } from '../../Utilities/hooks';
export const ManagedBySatelliteCell = () => (
-
-
-
- Managed by Satellite
-
-
-
+
+
+
+ Managed by Satellite
+
+
+
);
export const SYSTEMS_LIST_COLUMNS = [
- {
- key: 'display_name',
- title: 'Name',
- renderFunc: (displayName, id) => {displayName},
- isShown: true,
- isShownByDefault: true,
- isUntoggleable: true
+ {
+ key: 'display_name',
+ title: 'Name',
+ renderFunc: (displayName, id) => (
+ {displayName}
+ ),
+ isShown: true,
+ isShownByDefault: true,
+ isUntoggleable: true,
+ },
+ {
+ key: 'groups',
+ title: 'Workspace',
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'tags',
+ title: 'Tags',
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'operating_system',
+ title: 'OS',
+ renderFunc: (value) => createOSColumn(value),
+ props: {
+ width: 5,
},
- {
- key: 'groups',
- title: 'Workspace',
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'template_name',
+ title: 'Template',
+ renderFunc: (value, _, row) =>
+ row.satellite_managed ? (
+
+ ) : value ? (
+
+ {value}
+
+ ) : (
+ 'No template'
+ ),
+ props: {
+ width: 5,
},
- {
- key: 'tags',
- title: 'Tags',
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'applicable_advisories',
+ title: 'Installable advisories',
+ props: {
+ width: 15,
},
- {
- key: 'operating_system',
- title: 'OS',
- renderFunc: value => createOSColumn(value),
- props: {
- width: 5
- },
- isShown: true,
- isShownByDefault: true
- },
- {
- key: 'template_name',
- title: 'Template',
- renderFunc: (value, _, row) =>
- row.satellite_managed
- ?
- : value
- ? {value}
- : 'No template',
- props: {
- width: 5
- },
- isShown: true,
- isShownByDefault: true
- },
- {
- key: 'applicable_advisories',
- title: 'Installable advisories',
- props: {
- width: 15
- },
- renderFunc: value => createAdvisoriesIcons(value, 'installable'),
- isShown: true,
- isShownByDefault: true
- },
- {
- key: 'packages_installed',
- title: 'Installed packages',
- renderFunc: (packageCount, systemID) => createPackagesColumn(packageCount, systemID),
- props: {
- width: 10
- },
- isShown: true,
- isShownByDefault: true
+ renderFunc: (value) => createAdvisoriesIcons(value, 'installable'),
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'packages_installed',
+ title: 'Installed packages',
+ renderFunc: (packageCount, systemID) => createPackagesColumn(packageCount, systemID),
+ props: {
+ width: 10,
},
- {
- inventoryKey: 'updated',
- key: 'last_upload',
- sortKey: 'last_upload',
- isShown: true,
- isShownByDefault: true
- }
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ inventoryKey: 'updated',
+ key: 'last_upload',
+ sortKey: 'last_upload',
+ isShown: true,
+ isShownByDefault: true,
+ },
];
export const ADVISORY_SYSTEMS_COLUMNS = [
- {
- key: 'display_name',
- title: 'Name',
- renderFunc: (displayName, id) => {displayName},
- isShown: true,
- isShownByDefault: true,
- isUntoggleable: true
+ {
+ key: 'display_name',
+ title: 'Name',
+ renderFunc: (displayName, id) => (
+ {displayName}
+ ),
+ isShown: true,
+ isShownByDefault: true,
+ isUntoggleable: true,
+ },
+ {
+ key: 'groups',
+ title: 'Workspace',
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'tags',
+ title: 'Tags',
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'os',
+ title: 'OS',
+ renderFunc: (value) => createOSColumn(value),
+ props: {
+ width: 5,
},
- {
- key: 'groups',
- title: 'Workspace',
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'template_name',
+ title: 'Template',
+ renderFunc: (value, _, row) =>
+ row.satellite_managed ? (
+
+ ) : value ? (
+
+ {value}
+
+ ) : (
+ 'No template'
+ ),
+ props: {
+ width: 5,
},
- {
- key: 'tags',
- title: 'Tags',
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'status',
+ title: 'Status',
+ props: {
+ width: 5,
+ isStatic: true,
},
- {
- key: 'os',
- title: 'OS',
- renderFunc: value => createOSColumn(value),
- props: {
- width: 5
- },
- isShown: true,
- isShownByDefault: true
- },
- {
- key: 'template_name',
- title: 'Template',
- renderFunc: (value, _, row) =>
- row.satellite_managed
- ?
- : value
- ? {value}
- : 'No template',
- props: {
- width: 5
- },
- isShown: true,
- isShownByDefault: true
- },
- {
- key: 'status',
- title: 'Status',
- props: {
- width: 5,
- isStatic: true
- },
- transforms: [sortable],
- isShown: true,
- isShownByDefault: true
- },
- {
- inventoryKey: 'updated',
- key: 'last_upload',
- sortKey: 'last_upload',
- isShown: true,
- isShownByDefault: true
- }
+ transforms: [sortable],
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ inventoryKey: 'updated',
+ key: 'last_upload',
+ sortKey: 'last_upload',
+ isShown: true,
+ isShownByDefault: true,
+ },
];
export const PACKAGE_SYSTEMS_COLUMNS = [
- {
- key: 'display_name',
- title: 'Name',
- isShown: true,
- isShownByDefault: true,
- isUntoggleable: true
- },
- {
- key: 'tags',
- title: 'Tags',
- isShown: true,
- isShownByDefault: true
+ {
+ key: 'display_name',
+ title: 'Name',
+ isShown: true,
+ isShownByDefault: true,
+ isUntoggleable: true,
+ },
+ {
+ key: 'tags',
+ title: 'Tags',
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'os',
+ title: 'OS',
+ renderFunc: (value) => createOSColumn(value),
+ props: {
+ width: 5,
},
- {
- key: 'os',
- title: 'OS',
- renderFunc: value => createOSColumn(value),
- props: {
- width: 5
- },
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'template_name',
+ title: 'Template',
+ renderFunc: (value, _, row) =>
+ row.satellite_managed ? (
+
+ ) : value ? (
+
+ {value}
+
+ ) : (
+ 'No template'
+ ),
+ props: {
+ width: 5,
},
- {
- key: 'template_name',
- title: 'Template',
- renderFunc: (value, _, row) =>
- row.satellite_managed
- ?
- : value
- ? {value}
- : 'No template',
- props: {
- width: 5
- },
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'installed_evra',
+ title: 'Installed version',
+ props: {
+ width: 15,
},
- {
- key: 'installed_evra',
- title: 'Installed version',
- props: {
- width: 15
- },
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'available_evra',
+ title: 'Latest version',
+ props: {
+ width: 15,
},
- {
- key: 'available_evra',
- title: 'Latest version',
- props: {
- width: 15
- },
- isShown: true,
- isShownByDefault: true
+ isShown: true,
+ isShownByDefault: true,
+ },
+ {
+ key: 'update_status',
+ title: 'Status',
+ props: {
+ width: 20,
},
- {
- key: 'update_status',
- title: 'Status',
- props: {
- width: 20
- },
- renderFunc: value => createUpgradableColumn(value),
- isShown: true,
- isShownByDefault: true
- }
+ renderFunc: (value) => createUpgradableColumn(value),
+ isShown: true,
+ isShownByDefault: true,
+ },
];
const isRemediationDisabled = (row) => {
- const { status } = row?.attributes || {};
- const { applicable_advisories: applicableAdvisories } = row || {};
+ const { status } = row?.attributes || {};
+ const { applicable_advisories: applicableAdvisories } = row || {};
- return (applicableAdvisories && applicableAdvisories.every(typeSum => typeSum === 0)) || (status === 'Applicable');
+ return (
+ (applicableAdvisories && applicableAdvisories.every((typeSum) => typeSum === 0)) ||
+ status === 'Applicable'
+ );
};
const isPatchSetRemovalDisabled = (row) => {
- const { baseline_name: baselineName } = row || {};
- return !baselineName || (typeof baselineName === 'string' && baselineName === '');
+ const { baseline_name: baselineName } = row || {};
+ return !baselineName || (typeof baselineName === 'string' && baselineName === '');
};
export const useActivateRemediationModal = (setRemediationIssues, setRemediationOpen) => {
- const { fetchBatched } = useFetchBatched();
-
- return useCallback(async (rowData) => {
- const filter = {
- id: rowData.id,
- 'filter[status]': 'in:Installable'
- };
+ const { fetchBatched } = useFetchBatched();
- const totalCount = await fetchApplicableSystemAdvisoriesApi({ ...filter, limit: 1 }).then(
- (response) => response?.meta?.total_items || 0
- );
+ return useCallback(async (rowData) => {
+ const filter = {
+ id: rowData.id,
+ 'filter[status]': 'in:Installable',
+ };
- fetchBatched(
- (filterWithPagination) => fetchApplicableSystemAdvisoriesApi(filterWithPagination),
- filter,
- totalCount
- ).then(response => {
- const advisories = response.flatMap(({ data }) => data);
- const remediationIssues = remediationProvider(
- advisories.map(item => item.id),
- rowData.id,
- remediationIdentifiers.advisory
- );
+ const totalCount = await fetchApplicableSystemAdvisoriesApi({ ...filter, limit: 1 }).then(
+ (response) => response?.meta?.total_items || 0,
+ );
- setRemediationIssues(remediationIssues);
+ fetchBatched(
+ (filterWithPagination) => fetchApplicableSystemAdvisoriesApi(filterWithPagination),
+ filter,
+ totalCount,
+ )
+ .then((response) => {
+ const advisories = response.flatMap(({ data }) => data);
+ const remediationIssues = remediationProvider(
+ advisories.map((item) => item.id),
+ rowData.id,
+ remediationIdentifiers.advisory,
+ );
- setRemediationOpen(true);
- })
- .catch(() => {
- setRemediationOpen(false);
- });
- }, []);
+ setRemediationIssues(remediationIssues);
+ setRemediationOpen(true);
+ })
+ .catch(() => {
+ setRemediationOpen(false);
+ });
+ }, []);
};
export const systemsRowActions = (
- activateRemediationModal,
- showTemplateAssignSystemsModal,
- openUnassignSystemsModal,
- row,
- hasTemplateAccess
-) => {
- return [
+ activateRemediationModal,
+ showTemplateAssignSystemsModal,
+ openUnassignSystemsModal,
+ row,
+ hasTemplateAccess,
+) => [
+ {
+ title: 'Apply all applicable advisories',
+ isDisabled: isRemediationDisabled(row),
+ onClick: (event, rowId, rowData) => {
+ activateRemediationModal(rowData);
+ },
+ },
+ ...(showTemplateAssignSystemsModal
+ ? [
{
- title: 'Apply all applicable advisories',
- isDisabled: isRemediationDisabled(row),
- onClick: (event, rowId, rowData) => {
- activateRemediationModal(rowData);
- }
- },
- ...(showTemplateAssignSystemsModal ? [{
- title: 'Assign to a template',
- isDisabled: !hasTemplateAccess || row.satellite_managed,
- onClick: (event, rowId, rowData) => {
- showTemplateAssignSystemsModal({ [rowData.id]: true });
- }
+ title: 'Assign to a template',
+ isDisabled: !hasTemplateAccess || row.satellite_managed,
+ onClick: (event, rowId, rowData) => {
+ showTemplateAssignSystemsModal({ [rowData.id]: true });
+ },
},
{
- title: 'Remove from a template',
- isDisabled: !hasTemplateAccess || isPatchSetRemovalDisabled(row) || row.satellite_managed,
- onClick: (event, rowId, rowData) => {
- openUnassignSystemsModal([rowData.id]);
- }
- }
- ] : [])
- ];
-};
-
+ title: 'Remove from a template',
+ isDisabled: !hasTemplateAccess || isPatchSetRemovalDisabled(row) || row.satellite_managed,
+ onClick: (event, rowId, rowData) => {
+ openUnassignSystemsModal([rowData.id]);
+ },
+ },
+ ]
+ : []),
+];
diff --git a/src/SmartComponents/Systems/SystemsListAssets.scss b/src/SmartComponents/Systems/SystemsListAssets.scss
index 7788b2b09..a53b84571 100644
--- a/src/SmartComponents/Systems/SystemsListAssets.scss
+++ b/src/SmartComponents/Systems/SystemsListAssets.scss
@@ -1,6 +1,6 @@
.col-width-30 {
- width: 30%;
+ width: 30%;
}
.col-width-40 {
- width: 40%;
+ width: 40%;
}
diff --git a/src/SmartComponents/Systems/SystemsMainContent.js b/src/SmartComponents/Systems/SystemsMainContent.js
index dac67ac89..e4d72ecbf 100644
--- a/src/SmartComponents/Systems/SystemsMainContent.js
+++ b/src/SmartComponents/Systems/SystemsMainContent.js
@@ -13,77 +13,68 @@ import SystemsTable from './SystemsTable';
import { useSearchParams } from 'react-router-dom';
const SystemsMainContent = () => {
- const [searchParams, setSearchParams] = useSearchParams();
- const dispatch = useDispatch();
- const [isRemediationOpen, setRemediationOpen] = useState(false);
- const decodedParams = decodeQueryparams('?' + searchParams.toString());
- const [remediationIssues, setRemediationIssues] = useState([]);
+ const [searchParams, setSearchParams] = useSearchParams();
+ const dispatch = useDispatch();
+ const [isRemediationOpen, setRemediationOpen] = useState(false);
+ const decodedParams = decodeQueryparams('?' + searchParams.toString());
+ const [remediationIssues, setRemediationIssues] = useState([]);
- const selectedRows = useSelector(
- ({ entities }) => entities?.selectedRows || []
- );
- const { hasError, code } = useSelector(
- ({ entities }) => entities?.status || {}
- );
- const metadata = useSelector(
- ({ SystemsStore }) => SystemsStore?.metadata || {}
- );
+ const selectedRows = useSelector(({ entities }) => entities?.selectedRows || []);
+ const { hasError, code } = useSelector(({ entities }) => entities?.status || {});
+ const metadata = useSelector(({ SystemsStore }) => SystemsStore?.metadata || {});
- const queryParams = useSelector(
- ({ SystemsStore }) => SystemsStore?.queryParams || {}
- );
+ const queryParams = useSelector(({ SystemsStore }) => SystemsStore?.queryParams || {});
- const apply = (queryParams) => {
- dispatch(changeSystemsParams(queryParams));
- };
+ const apply = (queryParams) => {
+ dispatch(changeSystemsParams(queryParams));
+ };
- useEffect(() => {
- apply(decodedParams);
- return () => dispatch(clearInventoryReducer());
- }, []);
+ useEffect(() => {
+ apply(decodedParams);
+ return () => dispatch(clearInventoryReducer());
+ }, []);
- const {
- patchSetState, setPatchSetState, openUnassignSystemsModal, openAssignSystemsModal
- } = usePatchSetState(selectedRows);
+ const { patchSetState, setPatchSetState, openUnassignSystemsModal, openAssignSystemsModal } =
+ usePatchSetState(selectedRows);
- const activateRemediationModal = useActivateRemediationModal(
- setRemediationIssues,
- setRemediationOpen
- );
+ const activateRemediationModal = useActivateRemediationModal(
+ setRemediationIssues,
+ setRemediationOpen,
+ );
- if (hasError || metadata?.has_systems === false) {
- return ;
- }
+ if (hasError || metadata?.has_systems === false) {
+ return ;
+ }
- return (
-
-
-
- {isRemediationOpen &&
-
- || null
- }
-
-
-
-
- );
+ return (
+
+
+
+ {(isRemediationOpen && (
+
+ )) ||
+ null}
+
+
+
+
+ );
};
export default SystemsMainContent;
diff --git a/src/SmartComponents/Systems/SystemsMainContent.test.js b/src/SmartComponents/Systems/SystemsMainContent.test.js
index 46103b722..9abc18405 100644
--- a/src/SmartComponents/Systems/SystemsMainContent.test.js
+++ b/src/SmartComponents/Systems/SystemsMainContent.test.js
@@ -9,146 +9,151 @@ import userEvent from '@testing-library/user-event';
initMocks();
jest.mock('./SystemsTable', () => ({
- __esModule: true,
- default: jest.fn(({ openAssignSystemsModal, openUnassignSystemsModal, activateRemediationModal, ...props }) => {
- return (
-
-
- openUnassignSystemsModal(['test-system-id-1'])}/>
-
- Systems table
-
- );
- })
+ __esModule: true,
+ default: jest.fn(
+ ({ openAssignSystemsModal, openUnassignSystemsModal, activateRemediationModal, ...props }) => (
+
+
+ openUnassignSystemsModal(['test-system-id-1'])}
+ />
+
+ Systems table
+
+ ),
+ ),
}));
-jest.mock(
- '../../PresentationalComponents/Filters/OsVersionFilter'
-);
+jest.mock('../../PresentationalComponents/Filters/OsVersionFilter');
jest.mock('../Remediation/RemediationWizard', () => ({
- __esModule: true,
- default: jest.fn((props) => (
-
- Remediation wizard
-
- ))
+ __esModule: true,
+ default: jest.fn((props) => (
+
+ Remediation wizard
+
+ )),
}));
jest.mock('../../Utilities/api', () => ({
- fetchSystems: jest.fn(() => Promise.resolve({
- meta: {
- subtotals: { patched: 10, unpatched: 5, stale: 20 }
- }
- })),
- fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test-system-id-1' }] })),
- fetchApplicableSystemAdvisoriesApi: jest.fn(() => Promise.resolve({
- data: [{
- attributes: {
- advisory_type: 2,
- description: 'The tzdata penhancements.',
- public_date: '2020-10-19T15:02:38Z',
- synopsis: 'tzdata enhancement update'
- },
- id: 'RHBA-2020:4282',
- type: 'advisory'
- }]
- }))
+ fetchSystems: jest.fn(() =>
+ Promise.resolve({
+ meta: {
+ subtotals: { patched: 10, unpatched: 5, stale: 20 },
+ },
+ }),
+ ),
+ fetchIDs: jest.fn(() => Promise.resolve({ data: [{ id: 'test-system-id-1' }] })),
+ fetchApplicableSystemAdvisoriesApi: jest.fn(() =>
+ Promise.resolve({
+ data: [
+ {
+ attributes: {
+ advisory_type: 2,
+ description: 'The tzdata penhancements.',
+ public_date: '2020-10-19T15:02:38Z',
+ synopsis: 'tzdata enhancement update',
+ },
+ id: 'RHBA-2020:4282',
+ type: 'advisory',
+ },
+ ],
+ }),
+ ),
}));
const mockState = {
- entities: {
- metadata: {
- has_systems: true
- },
- selectedRows: [{ 'test-system-id-1': true }],
- status: { hasError: false, code: 200 }
+ entities: {
+ metadata: {
+ has_systems: true,
},
- GlobalFilterStore: { selectedTags: [], selectedGlobalTags: [] },
- SystemsStore: {
- queryParams: {}
- }
+ selectedRows: [{ 'test-system-id-1': true }],
+ status: { hasError: false, code: 200 },
+ },
+ GlobalFilterStore: { selectedTags: [], selectedGlobalTags: [] },
+ SystemsStore: {
+ queryParams: {},
+ },
};
const initStore = (state) => {
- const mockStore = configureStore([]);
- return mockStore(state);
+ const mockStore = configureStore([]);
+ return mockStore(state);
};
const renderComponent = async (mockedStore) => {
- render(
-
- );
+ render(
+
+
+ ,
+ );
};
const user = userEvent.setup();
describe('SystemsTable', () => {
- it('Should display systems table when there are no errors', async () => {
- renderComponent(mockState);
- expect(screen.getByTestId('systems-table-mock')).toBeVisible();
- });
-
- it('Should display systems status report cards', async () => {
- renderComponent(mockState);
- await waitFor(() =>{
- expect(screen.getByText('Stale systems')).toBeVisible();
- expect(screen.getByText('20')).toBeVisible();
-
- expect(screen.getByText('Systems with patches available')).toBeVisible();
- expect(screen.getByText('5')).toBeVisible();
-
- expect(screen.getByText('Systems up to date')).toBeVisible();
- expect(screen.getByText('10')).toBeVisible();
- });
- });
-
- it('Should display not found component when status is rejected', () => {
- const noAccessState = {
- ...mockState,
- entities: {
- metadata: {
- has_systems: true
- },
- status: { hasError: true, code: 403 }
- }
- };
- renderComponent(noAccessState);
- expect(
- screen.getByText('You do not have permissions to view or manage Patch')
- ).toBeTruthy();
- });
-
- it('Should display NoRegisteredSystems component if there are no systems registered', () => {
- const noSystemState = {
- ...mockState,
- SystemsStore: {
- metadata: {
- has_systems: false
- }
- }
- };
-
- renderComponent(noSystemState);
- expect(
- screen.getByText(`Do more with your Red Hat Enterprise Linux environment`)
- ).toBeTruthy();
- });
-
- it('Should display assign systems modal', async () => {
- renderComponent(mockState);
- await user.click(screen.getByTestId('open-assign-modal'));
- await waitFor(() => expect(screen.getByTestId('assign-systems-modal')).toBeVisible());
- });
-
- it('Should display unassign systems modal', async () => {
- renderComponent(mockState);
- await user.click(screen.getByTestId('open-unasssign-modal'));
- await waitFor(() => expect(screen.getByTestId('unassign-systems-modal')).toBeVisible());
+ it('Should display systems table when there are no errors', async () => {
+ renderComponent(mockState);
+ expect(screen.getByTestId('systems-table-mock')).toBeVisible();
+ });
+
+ it('Should display systems status report cards', async () => {
+ renderComponent(mockState);
+ await waitFor(() => {
+ expect(screen.getByText('Stale systems')).toBeVisible();
+ expect(screen.getByText('20')).toBeVisible();
+
+ expect(screen.getByText('Systems with patches available')).toBeVisible();
+ expect(screen.getByText('5')).toBeVisible();
+
+ expect(screen.getByText('Systems up to date')).toBeVisible();
+ expect(screen.getByText('10')).toBeVisible();
});
+ });
- it('Should display remediation wizard', async () => {
- renderComponent(mockState);
- await user.click(screen.getByTestId('active-remediation-modal'));
- expect(screen.getByTestId('remediation-wizard-mock')).toBeVisible();
- });
+ it('Should display not found component when status is rejected', () => {
+ const noAccessState = {
+ ...mockState,
+ entities: {
+ metadata: {
+ has_systems: true,
+ },
+ status: { hasError: true, code: 403 },
+ },
+ };
+ renderComponent(noAccessState);
+ expect(screen.getByText('You do not have permissions to view or manage Patch')).toBeTruthy();
+ });
+
+ it('Should display NoRegisteredSystems component if there are no systems registered', () => {
+ const noSystemState = {
+ ...mockState,
+ SystemsStore: {
+ metadata: {
+ has_systems: false,
+ },
+ },
+ };
+
+ renderComponent(noSystemState);
+ expect(screen.getByText(`Do more with your Red Hat Enterprise Linux environment`)).toBeTruthy();
+ });
+
+ it('Should display assign systems modal', async () => {
+ renderComponent(mockState);
+ await user.click(screen.getByTestId('open-assign-modal'));
+ await waitFor(() => expect(screen.getByTestId('assign-systems-modal')).toBeVisible());
+ });
+
+ it('Should display unassign systems modal', async () => {
+ renderComponent(mockState);
+ await user.click(screen.getByTestId('open-unasssign-modal'));
+ await waitFor(() => expect(screen.getByTestId('unassign-systems-modal')).toBeVisible());
+ });
+
+ it('Should display remediation wizard', async () => {
+ renderComponent(mockState);
+ await user.click(screen.getByTestId('active-remediation-modal'));
+ expect(screen.getByTestId('remediation-wizard-mock')).toBeVisible();
+ });
});
diff --git a/src/SmartComponents/Systems/SystemsPage.js b/src/SmartComponents/Systems/SystemsPage.js
index cc1cde7b4..2cbbf07a1 100644
--- a/src/SmartComponents/Systems/SystemsPage.js
+++ b/src/SmartComponents/Systems/SystemsPage.js
@@ -7,17 +7,17 @@ import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome'
import SystemsMainContent from './SystemsMainContent';
const SystemsPage = () => {
- const chrome = useChrome();
- useEffect(()=>{
- chrome.updateDocumentTitle(`Systems - Patch | RHEL`, true);
- }, [chrome, intl]);
+ const chrome = useChrome();
+ useEffect(() => {
+ chrome.updateDocumentTitle(`Systems - Patch | RHEL`, true);
+ }, [chrome, intl]);
- return (
-
-
-
-
- );
+ return (
+
+
+
+
+ );
};
export default SystemsPage;
diff --git a/src/SmartComponents/Systems/SystemsTable.js b/src/SmartComponents/Systems/SystemsTable.js
index f4aa91bb2..e86ee328e 100644
--- a/src/SmartComponents/Systems/SystemsTable.js
+++ b/src/SmartComponents/Systems/SystemsTable.js
@@ -4,244 +4,249 @@ import { InventoryTable } from '@redhat-cloud-services/frontend-components/Inven
import { shallowEqual, useDispatch, useSelector, useStore } from 'react-redux';
import { defaultReducers } from '../../store';
import { changeSystemsMetadata, changeTags, systemSelectAction } from '../../store/Actions/Actions';
-import { inventoryEntitiesReducer, modifyInventory } from '../../store/Reducers/InventoryEntitiesReducer';
import {
- exportSystemsCSV, exportSystemsJSON, fetchSystems
-} from '../../Utilities/api';
+ inventoryEntitiesReducer,
+ modifyInventory,
+} from '../../store/Reducers/InventoryEntitiesReducer';
+import { exportSystemsCSV, exportSystemsJSON, fetchSystems } from '../../Utilities/api';
import { systemsListDefaultFilters, NO_ADVISORIES_TEXT } from '../../Utilities/constants';
import { arrayFromObj, persistantParams } from '../../Utilities/Helpers';
import {
- useBulkSelectConfig,
- useGetEntities,
- useOnExport,
- useRemoveFilter,
- useRemediationDataProvider,
- useOnSelect,
- ID_API_ENDPOINTS,
- useColumnManagement
+ useBulkSelectConfig,
+ useGetEntities,
+ useOnExport,
+ useRemoveFilter,
+ useRemediationDataProvider,
+ useOnSelect,
+ ID_API_ENDPOINTS,
+ useColumnManagement,
} from '../../Utilities/hooks';
import { SYSTEMS_LIST_COLUMNS, systemsRowActions } from './SystemsListAssets';
import AsyncRemediationButton from '../Remediation/AsyncRemediationButton';
-import { buildFilterConfig, buildActiveFiltersConfig, mergeInventoryColumns } from '../../Utilities/SystemsHelpers';
+import {
+ buildFilterConfig,
+ buildActiveFiltersConfig,
+ mergeInventoryColumns,
+} from '../../Utilities/SystemsHelpers';
import { combineReducers } from 'redux';
import { usePermissionsWithContext } from '@redhat-cloud-services/frontend-components-utilities/RBACHook';
import propTypes from 'prop-types';
const SystemsTable = ({
+ apply,
+ patchSetState,
+ openUnassignSystemsModal,
+ setSearchParams,
+ activateRemediationModal,
+ decodedParams,
+}) => {
+ const store = useStore();
+ const inventory = useRef(null);
+
+ const dispatch = useDispatch();
+ const [isRemediationLoading, setRemediationLoading] = useState(false);
+ const systems = useSelector(({ entities }) => entities?.rows || [], shallowEqual);
+ const totalItems = useSelector(({ entities }) => entities?.total || 0);
+
+ const selectedRows = useSelector(({ entities }) => entities?.selectedRows || []);
+ const areAllSelected = useSelector(({ SystemsStore }) => SystemsStore?.areAllSelected);
+ const queryParams = useSelector(({ SystemsStore }) => SystemsStore?.queryParams || {});
+
+ const { hasAccess: hasTemplateAccess } = usePermissionsWithContext([
+ 'patch:*:*',
+ 'patch:template:write',
+ ]);
+
+ const [appliedColumns, setAppliedColumns] = React.useState(SYSTEMS_LIST_COLUMNS);
+ const [ColumnManagementModal, setColumnManagementModalOpen] = useColumnManagement(
+ appliedColumns,
+ (newColumns) => setAppliedColumns(newColumns),
+ );
+
+ const {
+ systemProfile,
+ selectedTags,
+ filter: queryParamsFilter,
+ search,
+ page,
+ perPage,
+ sort,
+ } = queryParams;
+ const { os: operatingSystemFilter, ...filter } = queryParamsFilter || {};
+ const osFilter = operatingSystemFilter && [
+ {
+ osFilter: operatingSystemFilter.reduce((osFilter, os) => {
+ const [osName, osVersion] = os.split(' ');
+ const [major] = osVersion.split('.');
+
+ return {
+ ...osFilter,
+ [`${osName}-${major}`]: {
+ ...(osFilter[`${osName}-${major}`] || {}),
+ [`${osName}-${major}-${osVersion}`]: true,
+ },
+ };
+ }, {}),
+ },
+ ];
+
+ const applyMetadata = (metadata) => {
+ dispatch(changeSystemsMetadata(metadata));
+ };
+
+ const applyGlobalFilter = (tags) => {
+ dispatch(changeTags(tags));
+ };
+
+ const [deleteFilters] = useRemoveFilter({ search, ...filter }, apply, systemsListDefaultFilters);
+ const filterConfig = buildFilterConfig(search, filter, apply);
+
+ const activeFiltersConfig = buildActiveFiltersConfig(filter, search, deleteFilters);
+
+ const onSelect = useOnSelect(systems, selectedRows, {
+ endpoint: ID_API_ENDPOINTS.systems,
+ queryParams,
+ selectionDispatcher: systemSelectAction,
+ totalItems,
+ });
+
+ useEffect(() => {
+ if (patchSetState.shouldRefresh) {
+ onSelect('none');
+ // timestamp is used to force inventory to refresh
+ // if it wasn't there inventory might ignore request to refresh because parameters are the same
+ inventory?.current?.onRefreshData({ timestamp: Date.now() });
+ }
+ }, [patchSetState.shouldRefresh]);
+
+ const onExport = useOnExport(
+ 'systems',
+ queryParams,
+ {
+ csv: exportSystemsCSV,
+ json: exportSystemsJSON,
+ },
+ dispatch,
+ );
+
+ const getEntities = useGetEntities(
+ fetchSystems,
apply,
- patchSetState,
- openUnassignSystemsModal,
+ {},
setSearchParams,
- activateRemediationModal,
- decodedParams
-}) => {
- const store = useStore();
- const inventory = useRef(null);
-
- const dispatch = useDispatch();
- const [isRemediationLoading, setRemediationLoading] = useState(false);
- const systems = useSelector(({ entities }) => entities?.rows || [], shallowEqual);
- const totalItems = useSelector(
- ({ entities }) => entities?.total || 0
- );
-
- const selectedRows = useSelector(
- ({ entities }) => entities?.selectedRows || []
- );
- const areAllSelected = useSelector(
- ({ SystemsStore }) => SystemsStore?.areAllSelected
- );
- const queryParams = useSelector(
- ({ SystemsStore }) => SystemsStore?.queryParams || {}
- );
-
- const { hasAccess: hasTemplateAccess } = usePermissionsWithContext([
- 'patch:*:*',
- 'patch:template:write'
- ]);
-
- const [appliedColumns, setAppliedColumns] = React.useState(SYSTEMS_LIST_COLUMNS);
- const [ColumnManagementModal, setColumnManagementModalOpen] =
- useColumnManagement(appliedColumns, newColumns => setAppliedColumns(newColumns));
-
- const { systemProfile, selectedTags,
- filter: queryParamsFilter, search, page, perPage, sort
- } = queryParams;
- const { os: operatingSystemFilter, ...filter } = queryParamsFilter || {};
- const osFilter = operatingSystemFilter && [{
- osFilter: operatingSystemFilter.reduce((osFilter, os) => {
- const [osName, osVersion] = os.split(' ');
- const [major] = osVersion.split('.');
-
- return {
- ...osFilter,
- [`${osName}-${major}`]: {
- ...osFilter[`${osName}-${major}`] || {},
- [`${osName}-${major}-${osVersion}`]: true
- }
- };
- }, {})
- }];
-
- const applyMetadata = (metadata) => {
- dispatch(changeSystemsMetadata(metadata));
- };
-
- const applyGlobalFilter = (tags) => {
- dispatch(changeTags(tags));
- };
-
- const [deleteFilters] = useRemoveFilter(
- { search, ...filter },
- apply,
- systemsListDefaultFilters
- );
- const filterConfig = buildFilterConfig(search, filter, apply);
-
- const activeFiltersConfig = buildActiveFiltersConfig(filter, search, deleteFilters);
-
- const onSelect = useOnSelect(
- systems,
- selectedRows,
- {
- endpoint: ID_API_ENDPOINTS.systems,
- queryParams,
- selectionDispatcher: systemSelectAction,
- totalItems
- }
- );
-
- useEffect(() => {
- if (patchSetState.shouldRefresh) {
- onSelect('none');
- // timestamp is used to force inventory to refresh
- // if it wasn't there inventory might ignore request to refresh because parameters are the same
- inventory?.current?.onRefreshData({ timestamp: Date.now() });
+ applyMetadata,
+ applyGlobalFilter,
+ );
+
+ const remediationDataProvider = useRemediationDataProvider(
+ selectedRows,
+ setRemediationLoading,
+ 'systems',
+ areAllSelected,
+ );
+
+ const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
+
+ const bulkSelectConfig = useBulkSelectConfig(
+ selectedCount,
+ onSelect,
+ { total_items: totalItems },
+ systems,
+ );
+
+ return (
+
+ {ColumnManagementModal}
+
+
+ mergeInventoryColumns(
+ appliedColumns.filter((column) => column.isShown),
+ inventoryColumns,
+ )
}
- }, [patchSetState.shouldRefresh]);
-
- const onExport = useOnExport(
- 'systems',
- queryParams,
- {
- csv: exportSystemsCSV,
- json: exportSystemsJSON
- }, dispatch
- );
-
- const getEntities = useGetEntities(
- fetchSystems,
- apply,
- {},
- setSearchParams,
- applyMetadata,
- applyGlobalFilter
- );
-
- const remediationDataProvider = useRemediationDataProvider(
- selectedRows,
- setRemediationLoading,
- 'systems',
- areAllSelected
- );
-
- const selectedCount = selectedRows && arrayFromObj(selectedRows).length;
-
- const bulkSelectConfig = useBulkSelectConfig(
- selectedCount,
- onSelect,
- { total_items: totalItems },
- systems
- );
-
- return (
-
- {ColumnManagementModal}
-
-
- mergeInventoryColumns(appliedColumns.filter(column => column.isShown), inventoryColumns)
- }
- showTags
- customFilters={{
- ...operatingSystemFilter ? {
- filters: [...(osFilter || [])]
- } : {},
- patchParams: {
- search,
- filter,
- systemProfile,
- selectedTags
- }
- }}
- paginationProps={{
- isDisabled: totalItems === 0
- }}
- onLoad={({ mergeWithEntities }) => {
- store.replaceReducer(combineReducers({
- ...defaultReducers,
- ...mergeWithEntities(
- inventoryEntitiesReducer(SYSTEMS_LIST_COLUMNS, modifyInventory),
- persistantParams({ page, perPage, sort, search }, decodedParams)
- )
- }));
- }}
- getEntities={getEntities}
- tableProps={{
- actionResolver: (row) =>
- systemsRowActions(
- activateRemediationModal,
- false,
- openUnassignSystemsModal,
- row,
- hasTemplateAccess
- ),
- canSelectAll: false,
- variant: TableVariant.compact,
- className: 'patchCompactInventory',
- isStickyHeader: true
- }}
- bulkSelect={bulkSelectConfig}
- exportConfig={{
- isDisabled: totalItems === 0,
- onSelect: onExport
- }}
- actionsConfig={{
- actions: [
- 0}
- />,
- {
- label: 'Manage columns',
- onClick: () => setColumnManagementModalOpen(true)
- }
- ]
- }}
- filterConfig={filterConfig}
- activeFiltersConfig={activeFiltersConfig}
- />
-
- );
+ showTags
+ customFilters={{
+ ...(operatingSystemFilter
+ ? {
+ filters: [...(osFilter || [])],
+ }
+ : {}),
+ patchParams: {
+ search,
+ filter,
+ systemProfile,
+ selectedTags,
+ },
+ }}
+ paginationProps={{
+ isDisabled: totalItems === 0,
+ }}
+ onLoad={({ mergeWithEntities }) => {
+ store.replaceReducer(
+ combineReducers({
+ ...defaultReducers,
+ ...mergeWithEntities(
+ inventoryEntitiesReducer(SYSTEMS_LIST_COLUMNS, modifyInventory),
+ persistantParams({ page, perPage, sort, search }, decodedParams),
+ ),
+ }),
+ );
+ }}
+ getEntities={getEntities}
+ tableProps={{
+ actionResolver: (row) =>
+ systemsRowActions(
+ activateRemediationModal,
+ false,
+ openUnassignSystemsModal,
+ row,
+ hasTemplateAccess,
+ ),
+ canSelectAll: false,
+ variant: TableVariant.compact,
+ className: 'patchCompactInventory',
+ isStickyHeader: true,
+ }}
+ bulkSelect={bulkSelectConfig}
+ exportConfig={{
+ isDisabled: totalItems === 0,
+ onSelect: onExport,
+ }}
+ actionsConfig={{
+ actions: [
+ 0}
+ />,
+ {
+ label: 'Manage columns',
+ onClick: () => setColumnManagementModalOpen(true),
+ },
+ ],
+ }}
+ filterConfig={filterConfig}
+ activeFiltersConfig={activeFiltersConfig}
+ />
+
+ );
};
SystemsTable.propTypes = {
- apply: propTypes.func.isRequired,
- patchSetState: propTypes.object.isRequired,
- openUnassignSystemsModal: propTypes.func.isRequired,
- setSearchParams: propTypes.func.isRequired,
- activateRemediationModal: propTypes.func.isRequired,
- decodedParams: propTypes.func.isRequired
+ apply: propTypes.func.isRequired,
+ patchSetState: propTypes.object.isRequired,
+ openUnassignSystemsModal: propTypes.func.isRequired,
+ setSearchParams: propTypes.func.isRequired,
+ activateRemediationModal: propTypes.func.isRequired,
+ decodedParams: propTypes.func.isRequired,
};
export default SystemsTable;
diff --git a/src/Utilities/DataMappers.js b/src/Utilities/DataMappers.js
index 9d75f568f..3210a1d61 100644
--- a/src/Utilities/DataMappers.js
+++ b/src/Utilities/DataMappers.js
@@ -5,11 +5,11 @@ import messages from '../Messages';
import AdvisoryType from '../PresentationalComponents/AdvisoryType/AdvisoryType';
import { DescriptionWithLink } from '../PresentationalComponents/Snippets/DescriptionWithLink';
import {
- EmptyAdvisoryList,
- EmptyCvesList,
- EmptyPackagesList,
- EmptyPatchSetList,
- EmptySystemsList
+ EmptyAdvisoryList,
+ EmptyCvesList,
+ EmptyPackagesList,
+ EmptyPatchSetList,
+ EmptySystemsList,
} from '../PresentationalComponents/Snippets/EmptyStates';
import { SystemUpToDate } from '../PresentationalComponents/Snippets/SystemUpToDate';
import { advisorySeverities, entityTypes } from './constants';
@@ -20,486 +20,440 @@ import { ManagedBySatelliteCell } from '../SmartComponents/Systems/SystemsListAs
import AdvisorySeverity from '../PresentationalComponents/AdvisorySeverity/AdvisorySeverity';
export const createAdvisoriesRows = (rows, expandedRows, selectedRows) => {
- if (rows.length !== 0) {
- return flatMap(rows, (row, index) => {
- // Bugfixes and enhancements lack the severity property, so we default to "None"
- const severityObject = row.attributes?.severity ? advisorySeverities[row.attributes.severity] : advisorySeverities[0];
- return [
- {
- id: row.id,
- isOpen: expandedRows[row.id] === true,
- selected: selectedRows[row.id] !== undefined,
- cells: [
- {
- title: handlePatchLink(
- entityTypes.advisories,
- row.id
- )
- },
- {
- title: handleLongSynopsis(row.attributes.synopsis)
- },
- {
- title: (
-
- )
- },
- {
- title: ()
- },
- {
- title: handlePatchLink(
- entityTypes.advisories,
- row.id,
- row.attributes.applicable_systems
- )
- },
- {
- title:
- (row.attributes.reboot_required &&
- intl.formatMessage(
- messages.labelsRebootRequired
- )) ||
- intl.formatMessage(
- messages.labelsRebootNotRequired
- )
- },
- {
- title: row.attributes.public_date
- ? processDate(row.attributes.public_date)
- : 'Not Available'
- }
- ]
- },
- {
- cells: [
- {
- title:
- }
- ],
- parent: index * 2,
- isExpandedRow: true
- }
- ];
- });
- } else {
- return [
+ if (rows.length !== 0) {
+ return flatMap(rows, (row, index) => {
+ // Bugfixes and enhancements lack the severity property, so we default to "None"
+ const severityObject = row.attributes?.severity
+ ? advisorySeverities[row.attributes.severity]
+ : advisorySeverities[0];
+ return [
+ {
+ id: row.id,
+ isOpen: expandedRows[row.id] === true,
+ selected: selectedRows[row.id] !== undefined,
+ cells: [
{
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 5 },
- title:
- }
- ]
- }
- ];
- }
+ title: handlePatchLink(entityTypes.advisories, row.id),
+ },
+ {
+ title: handleLongSynopsis(row.attributes.synopsis),
+ },
+ {
+ title: ,
+ },
+ {
+ title: ,
+ },
+ {
+ title: handlePatchLink(
+ entityTypes.advisories,
+ row.id,
+ row.attributes.applicable_systems,
+ ),
+ },
+ {
+ title:
+ (row.attributes.reboot_required &&
+ intl.formatMessage(messages.labelsRebootRequired)) ||
+ intl.formatMessage(messages.labelsRebootNotRequired),
+ },
+ {
+ title: row.attributes.public_date
+ ? processDate(row.attributes.public_date)
+ : 'Not Available',
+ },
+ ],
+ },
+ {
+ cells: [
+ {
+ title: ,
+ },
+ ],
+ parent: index * 2,
+ isExpandedRow: true,
+ },
+ ];
+ });
+ } else {
+ return [
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 5 },
+ title: ,
+ },
+ ],
+ },
+ ];
+ }
};
-export const createSystemAdvisoriesRows = (
- rows,
- expandedRows,
- selectedRows,
- metadata
-) => {
- if (rows.length !== 0) {
- return flatMap(rows, (row, index) => {
- const severityObject = row.attributes?.severity ? advisorySeverities[row.attributes.severity] : advisorySeverities[0];
- return [
- {
- id: row.id,
- isOpen: expandedRows[row.id] === true,
- selected: selectedRows[row.id] !== undefined,
- disableSelection: row.attributes.status !== 'Installable',
- cells: [
- {
- title: handlePatchLink(
- entityTypes.advisories,
- row.id
- )
- },
- {
- title: handleLongSynopsis(row.attributes.synopsis)
- },
- {
- title: row.attributes.status
- },
- {
- title: (
-
- )
- },
- {
- title: ()
- },
- {
- title:
- (row.attributes.reboot_required &&
- intl.formatMessage(
- messages.labelsRebootRequired
- )) ||
- intl.formatMessage(
- messages.labelsRebootNotRequired
- )
- },
- { title: processDate(row.attributes.public_date) }
- ]
- },
- {
- cells: [
- {
- title:
- }
- ],
- parent: index * 2,
- isExpandedRow: true
- }
- ];
- });
- } else {
- return [
+export const createSystemAdvisoriesRows = (rows, expandedRows, selectedRows, metadata) => {
+ if (rows.length !== 0) {
+ return flatMap(rows, (row, index) => {
+ const severityObject = row.attributes?.severity
+ ? advisorySeverities[row.attributes.severity]
+ : advisorySeverities[0];
+ return [
+ {
+ id: row.id,
+ isOpen: expandedRows[row.id] === true,
+ selected: selectedRows[row.id] !== undefined,
+ disableSelection: row.attributes.status !== 'Installable',
+ cells: [
+ {
+ title: handlePatchLink(entityTypes.advisories, row.id),
+ },
+ {
+ title: handleLongSynopsis(row.attributes.synopsis),
+ },
+ {
+ title: row.attributes.status,
+ },
{
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 6 },
- title: (!metadata.search &&
- metadata.filter &&
- Object.keys(metadata.filter).length === 0 && (
-
- )) ||
- }
- ]
- }
- ];
- }
+ title: ,
+ },
+ {
+ title: ,
+ },
+ {
+ title:
+ (row.attributes.reboot_required &&
+ intl.formatMessage(messages.labelsRebootRequired)) ||
+ intl.formatMessage(messages.labelsRebootNotRequired),
+ },
+ { title: processDate(row.attributes.public_date) },
+ ],
+ },
+ {
+ cells: [
+ {
+ title: ,
+ },
+ ],
+ parent: index * 2,
+ isExpandedRow: true,
+ },
+ ];
+ });
+ } else {
+ return [
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 6 },
+ title: (!metadata.search &&
+ metadata.filter &&
+ Object.keys(metadata.filter).length === 0 && ) || (
+
+ ),
+ },
+ ],
+ },
+ ];
+ }
};
export const createSystemsRows = (rows, selectedRows = {}) => {
- const data = rows.map(({ id, ...rest }) => {
- const {
- packages_installed: installedPckg,
- rhba_count: rhba,
- rhsa_count: rhsa,
- rhea_count: rhea,
- other_count: other,
- os,
- rhsm,
- tags,
- last_upload: lastUpload
- } = rest;
- return {
- id,
- ...rest,
- key: Math.random().toString() + id,
- packages_installed: installedPckg,
- applicable_advisories: [
- rhea || 0,
- rhba || 0,
- rhsa || 0,
- other || 0
- ],
- operating_system: {
- osName: os || 'N/A',
- rhsm
- },
- selected: selectedRows[id] !== undefined,
- tags,
- updated: lastUpload
- };
- });
- return data || [];
+ const data = rows.map(({ id, ...rest }) => {
+ const {
+ packages_installed: installedPckg,
+ rhba_count: rhba,
+ rhsa_count: rhsa,
+ rhea_count: rhea,
+ other_count: other,
+ os,
+ rhsm,
+ tags,
+ last_upload: lastUpload,
+ } = rest;
+ return {
+ id,
+ ...rest,
+ key: Math.random().toString() + id,
+ packages_installed: installedPckg,
+ applicable_advisories: [rhea || 0, rhba || 0, rhsa || 0, other || 0],
+ operating_system: {
+ osName: os || 'N/A',
+ rhsm,
+ },
+ selected: selectedRows[id] !== undefined,
+ tags,
+ updated: lastUpload,
+ };
+ });
+ return data || [];
};
export const createPackageSystemsRows = (rows, selectedRows = {}) => {
- const data =
- rows &&
- rows.map((row) => {
- return {
- id: row.id,
- key: Math.random().toString() + row.id,
- display_name: row.display_name,
- installed_evra: row.installed_evra,
- available_evra: row.updatable
- ? row.available_evra
- : row.installed_evra,
- disableSelection: !row.updatable,
- updatable: row.updatable,
- update_status: row.update_status,
- selected: selectedRows[row.id] !== undefined,
- tags: row.tags,
- os: {
- osName: row.os?.osName || row.os || 'N/A',
- rhsm: row.rhsm
- },
- baseline_name: row.baseline_name, //ToBeDeprecated
- template_name: row.template_name,
- template_uuid: row.template_uuid,
- baseline_id: row.baseline_id,
- satellite_managed: row.satellite_managed
- };
- });
- return data || [];
+ const data =
+ rows &&
+ rows.map((row) => ({
+ id: row.id,
+ key: Math.random().toString() + row.id,
+ display_name: row.display_name,
+ installed_evra: row.installed_evra,
+ available_evra: row.updatable ? row.available_evra : row.installed_evra,
+ disableSelection: !row.updatable,
+ updatable: row.updatable,
+ update_status: row.update_status,
+ selected: selectedRows[row.id] !== undefined,
+ tags: row.tags,
+ os: {
+ osName: row.os?.osName || row.os || 'N/A',
+ rhsm: row.rhsm,
+ },
+ baseline_name: row.baseline_name, // ToBeDeprecated
+ template_name: row.template_name,
+ template_uuid: row.template_uuid,
+ baseline_id: row.baseline_id,
+ satellite_managed: row.satellite_managed,
+ }));
+ return data || [];
};
export const createAdvisorySystemsRows = (rows, selectedRows = {}) => {
- const data = rows.map(({ id, ...rest }) => {
- const {
- packages_installed: installedPckg,
- os,
- rhsm,
- tags,
- last_upload: lastUpload,
- status
- } = rest;
- return {
- id,
- ...rest,
- key: Math.random().toString() + id,
- packages_installed: installedPckg,
- os: {
- osName: os.osName || os || 'N/A',
- rhsm
- },
- selected: selectedRows[id] !== undefined,
- tags,
- updated: lastUpload,
- disableSelection: status !== 'Installable'
- };
- });
- return data || [];
+ const data = rows.map(({ id, ...rest }) => {
+ const {
+ packages_installed: installedPckg,
+ os,
+ rhsm,
+ tags,
+ last_upload: lastUpload,
+ status,
+ } = rest;
+ return {
+ id,
+ ...rest,
+ key: Math.random().toString() + id,
+ packages_installed: installedPckg,
+ os: {
+ osName: os.osName || os || 'N/A',
+ rhsm,
+ },
+ selected: selectedRows[id] !== undefined,
+ tags,
+ updated: lastUpload,
+ disableSelection: status !== 'Installable',
+ };
+ });
+ return data || [];
};
export const createSystemPackagesRows = (rows, selectedRows = {}) => {
- if (rows && rows.length !== 0) {
- return rows.map((pkg) => {
- const pkgNEVRA = `${pkg.name}-${pkg.evra}`;
- const pkgUpdates = pkg.updates || [];
- const latestApplicable = pkgUpdates[pkgUpdates.length - 1];
- const latestInstallable = pkgUpdates
- .filter((version) => version.status === 'Installable')
- .pop();
+ if (rows && rows.length !== 0) {
+ return rows.map((pkg) => {
+ const pkgNEVRA = `${pkg.name}-${pkg.evra}`;
+ const pkgUpdates = pkg.updates || [];
+ const latestApplicable = pkgUpdates[pkgUpdates.length - 1];
+ const latestInstallable = pkgUpdates
+ .filter((version) => version.status === 'Installable')
+ .pop();
- return {
- id: pkgNEVRA,
- key: pkgNEVRA,
- selected: selectedRows[pkgNEVRA] !== undefined,
- disableSelection: !pkg.updatable,
- cells: [
- { title: handlePatchLink(entityTypes.packages, pkg.name) },
- { title: pkg.evra },
- { title: latestInstallable?.evra ?? pkg.evra },
- { title: latestApplicable?.evra ?? pkg.evra },
- { title: createUpgradableColumn(pkg.update_status) },
- { title: pkg.summary }
- ]
- };
- });
- } else {
- return [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 7 },
- title:
- }
- ]
- }
- ];
- }
+ return {
+ id: pkgNEVRA,
+ key: pkgNEVRA,
+ selected: selectedRows[pkgNEVRA] !== undefined,
+ disableSelection: !pkg.updatable,
+ cells: [
+ { title: handlePatchLink(entityTypes.packages, pkg.name) },
+ { title: pkg.evra },
+ { title: latestInstallable?.evra ?? pkg.evra },
+ { title: latestApplicable?.evra ?? pkg.evra },
+ { title: createUpgradableColumn(pkg.update_status) },
+ { title: pkg.summary },
+ ],
+ };
+ });
+ } else {
+ return [
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 7 },
+ title: ,
+ },
+ ],
+ },
+ ];
+ }
};
export const createPackagesRows = (rows) => {
- if (rows && rows.length !== 0) {
- return rows.map((pkg) => {
- return {
- id: pkg.name,
- key: pkg.name,
- cells: [
- { title: handlePatchLink(entityTypes.packages, pkg.name) },
- { title: pkg.systems_installed },
- { title: pkg.systems_applicable },
- { title: pkg.systems_installable },
- { title: pkg.summary }
- ]
- };
- });
- } else {
- return [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 7 },
- title:
- }
- ]
- }
- ];
- }
+ if (rows && rows.length !== 0) {
+ return rows.map((pkg) => ({
+ id: pkg.name,
+ key: pkg.name,
+ cells: [
+ { title: handlePatchLink(entityTypes.packages, pkg.name) },
+ { title: pkg.systems_installed },
+ { title: pkg.systems_applicable },
+ { title: pkg.systems_installable },
+ { title: pkg.summary },
+ ],
+ }));
+ } else {
+ return [
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 7 },
+ title: ,
+ },
+ ],
+ },
+ ];
+ }
};
export const createCvesRows = (rows) => {
- if (rows.length !== 0) {
- return rows.map((cve) => {
- const { attributes, id } = cve;
- const severityObject = advisorySeverities.filter(
- (severity) => severity.label === attributes.impact
- )[0];
+ if (rows.length !== 0) {
+ return rows.map((cve) => {
+ const { attributes, id } = cve;
+ const severityObject = advisorySeverities.filter(
+ (severity) => severity.label === attributes.impact,
+ )[0];
- return {
- id,
- key: id,
- cells: [
- {
- title: (
-
- {attributes.synopsis}
-
- )
- },
- {
- title: ,
- value: severityObject.label
- },
- { title: parseFloat(attributes.cvss_score).toFixed(1) }
- ]
- };
- });
- } else {
- return [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 4 },
- title:
- }
- ]
- }
- ];
- }
+ return {
+ id,
+ key: id,
+ cells: [
+ {
+ title: (
+
+ {attributes.synopsis}
+
+ ),
+ },
+ {
+ title: ,
+ value: severityObject.label,
+ },
+ { title: parseFloat(attributes.cvss_score).toFixed(1) },
+ ],
+ };
+ });
+ } else {
+ return [
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 4 },
+ title: ,
+ },
+ ],
+ },
+ ];
+ }
};
export const createSystemsRowsReview = (rows, selectedRows) => {
- if (rows.length !== 0) {
- return rows.map((system) => {
- const { attributes, id } = system;
+ if (rows.length !== 0) {
+ return rows.map((system) => {
+ const { attributes, id } = system;
- return {
- id,
- key: id,
- selected: selectedRows[system.id] !== undefined,
- cells: [
- {
- title: attributes.display_name
- },
- {
- title: attributes.os || 'N/A'
- },
- {
- title: attributes.satellite_managed ? (
-
- ) : (
- attributes.baseline_name || 'No template'
- )
- },
- {
- title: processDate(attributes.last_upload)
- }
- ]
- };
- });
- } else {
- return [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 4 },
- title:
- }
- ]
- }
- ];
- }
+ return {
+ id,
+ key: id,
+ selected: selectedRows[system.id] !== undefined,
+ cells: [
+ {
+ title: attributes.display_name,
+ },
+ {
+ title: attributes.os || 'N/A',
+ },
+ {
+ title: attributes.satellite_managed ? (
+
+ ) : (
+ attributes.baseline_name || 'No template'
+ ),
+ },
+ {
+ title: processDate(attributes.last_upload),
+ },
+ ],
+ };
+ });
+ } else {
+ return [
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 4 },
+ title: ,
+ },
+ ],
+ },
+ ];
+ }
};
export const createPatchSetRows = (rows, selectedRows = {}, filters) => {
- const data =
- rows &&
- rows.map((row) => {
- return {
- id: row.id,
- displayName: row.name,
- key: row.id,
- selected: selectedRows[row.id] !== undefined,
- cells: [
- {
- title: (
-
- {row.name}
-
- )
- },
- {
- title:
- row.systems ||
- intl.formatMessage(
- messages.labelsTemplateNoSystems
- )
- },
- { title: processDate(row.last_edited) },
- { title: processDate(row.published) },
- { title: row.creator }
- ]
- };
- });
+ const data =
+ rows &&
+ rows.map((row) => ({
+ id: row.id,
+ displayName: row.name,
+ key: row.id,
+ selected: selectedRows[row.id] !== undefined,
+ cells: [
+ {
+ title: {row.name},
+ },
+ {
+ title: row.systems || intl.formatMessage(messages.labelsTemplateNoSystems),
+ },
+ { title: processDate(row.last_edited) },
+ { title: processDate(row.published) },
+ { title: row.creator },
+ ],
+ }));
- return data?.length > 0
- ? data
- : filters.search || Object.keys(filters.filter).length
- ? [
- {
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 6 },
- title:
- }
- ]
- }
- ]
- : [];
+ return data?.length > 0
+ ? data
+ : filters.search || Object.keys(filters.filter).length
+ ? [
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 6 },
+ title: ,
+ },
+ ],
+ },
+ ]
+ : [];
};
export const createPatchSetDetailRows = (rows) => {
- const data =
- rows &&
- rows.map((row) => {
- row = { ...row, ...row.attributes };
+ const data =
+ rows &&
+ rows.map((row) => {
+ row = { ...row, ...row.attributes };
- return {
- ...row,
- id: row.inventory_id,
- display_name: row.display_name,
- key: row.inventory_id,
- os: {
- osName: row.os || 'N/A',
- rhsm: row.rhsm
- },
- last_upload: row.last_upload,
- tags: row.tags
- };
- });
+ return {
+ ...row,
+ id: row.inventory_id,
+ display_name: row.display_name,
+ key: row.inventory_id,
+ os: {
+ osName: row.os || 'N/A',
+ rhsm: row.rhsm,
+ },
+ last_upload: row.last_upload,
+ tags: row.tags,
+ };
+ });
- return data;
+ return data;
};
diff --git a/src/Utilities/DataMappers.test.js b/src/Utilities/DataMappers.test.js
index cf0118f4b..2bc2e7fb1 100644
--- a/src/Utilities/DataMappers.test.js
+++ b/src/Utilities/DataMappers.test.js
@@ -1,10 +1,10 @@
import { processDate } from '@redhat-cloud-services/frontend-components-utilities/helpers';
import { EmptyAdvisoryList } from '../PresentationalComponents/Snippets/EmptyStates';
import {
- createAdvisoriesRows,
- createSystemAdvisoriesRows,
- createSystemPackagesRows,
- createSystemsRows
+ createAdvisoriesRows,
+ createSystemAdvisoriesRows,
+ createSystemPackagesRows,
+ createSystemsRows,
} from './DataMappers';
import { handlePatchLink } from './Helpers';
import { advisoryRows, systemAdvisoryRows, systemPackages, systemRows } from './RawDataForTesting';
@@ -13,154 +13,175 @@ import messages from '../Messages';
import { intl } from '../Utilities/IntlProvider';
describe('DataMappers', () => {
- it('Should create advisories rows', () => {
- const [firstRow, secondRow] = createAdvisoriesRows(advisoryRows, [], []);
- expect(firstRow.id).toEqual(advisoryRows[0].id);
- expect(firstRow.isOpen).toEqual(false);
- expect(firstRow.selected).toEqual(false);
- expect(firstRow.cells[0].title).toEqual(handlePatchLink('advisories', advisoryRows[0].id));
- expect(firstRow.cells[5].title).toEqual(intl.formatMessage(messages.labelsRebootRequired));
- expect(firstRow.cells[6].title).toEqual(processDate(advisoryRows[0].attributes.public_date));
- expect(firstRow.cells[2].title.props.type).toEqual(advisoryRows[0].attributes.advisory_type_name);
- expect(firstRow.cells[3].title.props.severity.value).toEqual(advisoryRows[0].attributes.severity);
- expect(firstRow.cells[4].title).toEqual(
- handlePatchLink('advisories', advisoryRows[0].id, advisoryRows[0].attributes.applicable_systems)
- );
- expect(firstRow.cells[1]).toBeTruthy();
- const portalAdvisoryLink = secondRow.cells[0].title;
- expect(portalAdvisoryLink.props.row).toEqual(advisoryRows[0]);
- });
+ it('Should create advisories rows', () => {
+ const [firstRow, secondRow] = createAdvisoriesRows(advisoryRows, [], []);
+ expect(firstRow.id).toEqual(advisoryRows[0].id);
+ expect(firstRow.isOpen).toEqual(false);
+ expect(firstRow.selected).toEqual(false);
+ expect(firstRow.cells[0].title).toEqual(handlePatchLink('advisories', advisoryRows[0].id));
+ expect(firstRow.cells[5].title).toEqual(intl.formatMessage(messages.labelsRebootRequired));
+ expect(firstRow.cells[6].title).toEqual(processDate(advisoryRows[0].attributes.public_date));
+ expect(firstRow.cells[2].title.props.type).toEqual(
+ advisoryRows[0].attributes.advisory_type_name,
+ );
+ expect(firstRow.cells[3].title.props.severity.value).toEqual(
+ advisoryRows[0].attributes.severity,
+ );
+ expect(firstRow.cells[4].title).toEqual(
+ handlePatchLink(
+ 'advisories',
+ advisoryRows[0].id,
+ advisoryRows[0].attributes.applicable_systems,
+ ),
+ );
+ expect(firstRow.cells[1]).toBeTruthy();
+ const portalAdvisoryLink = secondRow.cells[0].title;
+ expect(portalAdvisoryLink.props.row).toEqual(advisoryRows[0]);
+ });
- it('Should createAdvisoriesRows handle empty row data', () => {
- const result = createAdvisoriesRows([], [], []);
- expect(result[0].heightAuto).toBeTruthy();
- expect(result[0].cells[0].props).toEqual({ colSpan: 5 });
- expect(result[0].cells[0].title.type).toEqual(EmptyAdvisoryList);
- });
+ it('Should createAdvisoriesRows handle empty row data', () => {
+ const result = createAdvisoriesRows([], [], []);
+ expect(result[0].heightAuto).toBeTruthy();
+ expect(result[0].cells[0].props).toEqual({ colSpan: 5 });
+ expect(result[0].cells[0].title.type).toEqual(EmptyAdvisoryList);
+ });
- it('Should create System Advisories Rows', () => {
- const [firstRow, secondRow] = createSystemAdvisoriesRows(systemAdvisoryRows, [], []);
+ it('Should create System Advisories Rows', () => {
+ const [firstRow, secondRow] = createSystemAdvisoriesRows(systemAdvisoryRows, [], []);
- expect(firstRow.id).toEqual(systemAdvisoryRows[0].id);
- expect(firstRow.isOpen).toEqual(false);
- expect(firstRow.selected).toEqual(false);
- expect(firstRow.cells[6].title).toEqual(processDate(systemAdvisoryRows[0].attributes.public_date));
- expect(firstRow.cells[5].title).toEqual('Required');
- expect(firstRow.cells[3].title.props.type).toEqual(systemAdvisoryRows[0].attributes.advisory_type_name);
- expect(firstRow.cells[4].title.props.severity.value).toEqual(advisoryRows[0].attributes.severity);
- expect(firstRow.cells[1]).toBeTruthy();
- expect(firstRow.cells[0].title).toEqual(handlePatchLink('advisories', systemAdvisoryRows[0].id));
- const portalAdvisoryLink = secondRow.cells[0].title;
- expect(portalAdvisoryLink.props.row).toEqual(systemAdvisoryRows[0]);
- });
+ expect(firstRow.id).toEqual(systemAdvisoryRows[0].id);
+ expect(firstRow.isOpen).toEqual(false);
+ expect(firstRow.selected).toEqual(false);
+ expect(firstRow.cells[6].title).toEqual(
+ processDate(systemAdvisoryRows[0].attributes.public_date),
+ );
+ expect(firstRow.cells[5].title).toEqual('Required');
+ expect(firstRow.cells[3].title.props.type).toEqual(
+ systemAdvisoryRows[0].attributes.advisory_type_name,
+ );
+ expect(firstRow.cells[4].title.props.severity.value).toEqual(
+ advisoryRows[0].attributes.severity,
+ );
+ expect(firstRow.cells[1]).toBeTruthy();
+ expect(firstRow.cells[0].title).toEqual(
+ handlePatchLink('advisories', systemAdvisoryRows[0].id),
+ );
+ const portalAdvisoryLink = secondRow.cells[0].title;
+ expect(portalAdvisoryLink.props.row).toEqual(systemAdvisoryRows[0]);
+ });
- it('Should createSystemAdvisoriesRows handle empty row data and show SystemUpToDate', () => {
- const result = createSystemAdvisoriesRows([], [], [], { filter: {} });
- expect(result[0].heightAuto).toBeTruthy();
- expect(result[0].cells[0].props).toEqual({ colSpan: 6 });
- expect(result[0].cells[0].title.type).toEqual(SystemUpToDate);
- });
+ it('Should createSystemAdvisoriesRows handle empty row data and show SystemUpToDate', () => {
+ const result = createSystemAdvisoriesRows([], [], [], { filter: {} });
+ expect(result[0].heightAuto).toBeTruthy();
+ expect(result[0].cells[0].props).toEqual({ colSpan: 6 });
+ expect(result[0].cells[0].title.type).toEqual(SystemUpToDate);
+ });
- it('Should createSystemAdvisoriesRows handle empty row data and show EmptyAdvisoryList', () => {
- const result = createSystemAdvisoriesRows([], [], [], { filter: { search: 'test' } });
- expect(result[0].heightAuto).toBeTruthy();
- expect(result[0].cells[0].props).toEqual({ colSpan: 6 });
- expect(result[0].cells[0].title.type).toEqual(EmptyAdvisoryList);
- });
+ it('Should createSystemAdvisoriesRows handle empty row data and show EmptyAdvisoryList', () => {
+ const result = createSystemAdvisoriesRows([], [], [], { filter: { search: 'test' } });
+ expect(result[0].heightAuto).toBeTruthy();
+ expect(result[0].cells[0].props).toEqual({ colSpan: 6 });
+ expect(result[0].cells[0].title.type).toEqual(EmptyAdvisoryList);
+ });
- it('Should create system rows', () => {
- const result = createSystemsRows(systemRows, []);
- expect(result[0].id).toEqual(systemRows[0].id);
- expect(result[0].key).toEqual(expect.stringContaining(systemRows[0].id));
- expect(result[0].applicable_advisories).toEqual([
- systemRows[0].rhea_count,
- systemRows[0].rhba_count,
- systemRows[0].rhsa_count,
- systemRows[0].other_count
- ]);
- expect(result[0].selected).toEqual(false);
- });
+ it('Should create system rows', () => {
+ const result = createSystemsRows(systemRows, []);
+ expect(result[0].id).toEqual(systemRows[0].id);
+ expect(result[0].key).toEqual(expect.stringContaining(systemRows[0].id));
+ expect(result[0].applicable_advisories).toEqual([
+ systemRows[0].rhea_count,
+ systemRows[0].rhba_count,
+ systemRows[0].rhsa_count,
+ systemRows[0].other_count,
+ ]);
+ expect(result[0].selected).toEqual(false);
+ });
- it('Should createSystemRows handle empty data', () => {
- const result = createSystemsRows([], []);
- expect(result).toEqual([]);
- });
+ it('Should createSystemRows handle empty data', () => {
+ const result = createSystemsRows([], []);
+ expect(result).toEqual([]);
+ });
- it('Should createSystemRows handle undfined rhea_count, rhba_count, rhsa_count', () => {
- const testData = [{
- attributes: {
- display_name: 'automation_host',
- last_evaluation: '2020-08-12T13:57:54.028883Z',
- last_upload: '2020-08-12T09:26:33.891907Z',
- packages_installed: 0,
- packages_updatable: 0,
- stale: false
- },
- id: '8ddb54f5-aeeb-49b1-8448-c29049d686c1',
- type: 'system'
- }];
+ it('Should createSystemRows handle undfined rhea_count, rhba_count, rhsa_count', () => {
+ const testData = [
+ {
+ attributes: {
+ display_name: 'automation_host',
+ last_evaluation: '2020-08-12T13:57:54.028883Z',
+ last_upload: '2020-08-12T09:26:33.891907Z',
+ packages_installed: 0,
+ packages_updatable: 0,
+ stale: false,
+ },
+ id: '8ddb54f5-aeeb-49b1-8448-c29049d686c1',
+ type: 'system',
+ },
+ ];
- const result = createSystemsRows(testData);
- expect(result[0].applicable_advisories).toEqual([
- 0,
- 0,
- 0,
- 0
- ]);
- });
+ const result = createSystemsRows(testData);
+ expect(result[0].applicable_advisories).toEqual([0, 0, 0, 0]);
+ });
- it('Should create package list', () => {
- const packages = createSystemPackagesRows(systemPackages);
- expect(packages).toEqual([{
- id: 'test-name-test-evra',
- key: 'test-name-test-evra',
- selected: false,
- disableSelection: true,
- cells: [
- { title: expect.anything() }, // FIXME!
- { title: 'test-evra' },
- { title: 'test-evra' },
- { title: expect.anything() },
- { title: expect.anything() },
- { title: 'Access control list utilities' }
- ]
- }]);
+ it('Should create package list', () => {
+ const packages = createSystemPackagesRows(systemPackages);
+ expect(packages).toEqual([
+ {
+ id: 'test-name-test-evra',
+ key: 'test-name-test-evra',
+ selected: false,
+ disableSelection: true,
+ cells: [
+ { title: expect.anything() }, // FIXME!
+ { title: 'test-evra' },
+ { title: 'test-evra' },
+ { title: expect.anything() },
+ { title: expect.anything() },
+ { title: 'Access control list utilities' },
+ ],
+ },
+ ]);
- expect(packages[0]).toMatchSnapshot();
+ expect(packages[0]).toMatchSnapshot();
- const packagesWithCompleteData = createSystemPackagesRows([{
- ...systemPackages[0],
- updates: [{ evra: 'testEvra', status: 'Installable' }],
- updatable: true,
- update_status: 'Installable'
- }]);
+ const packagesWithCompleteData = createSystemPackagesRows([
+ {
+ ...systemPackages[0],
+ updates: [{ evra: 'testEvra', status: 'Installable' }],
+ updatable: true,
+ update_status: 'Installable',
+ },
+ ]);
- expect(packagesWithCompleteData).toEqual([{
- id: 'test-name-test-evra',
- key: 'test-name-test-evra',
- selected: false,
- disableSelection: false,
- cells: [
- { title: expect.anything() }, // FIXME!
- { title: 'test-evra' },
- { title: 'testEvra' },
- { title: expect.anything() },
- { title: expect.anything() },
- { title: 'Access control list utilities' }
- ]
- }]);
- });
+ expect(packagesWithCompleteData).toEqual([
+ {
+ id: 'test-name-test-evra',
+ key: 'test-name-test-evra',
+ selected: false,
+ disableSelection: false,
+ cells: [
+ { title: expect.anything() }, // FIXME!
+ { title: 'test-evra' },
+ { title: 'testEvra' },
+ { title: expect.anything() },
+ { title: expect.anything() },
+ { title: 'Access control list utilities' },
+ ],
+ },
+ ]);
+ });
- it('Should create empty package list', () => {
- const packages = createSystemPackagesRows([]);
- expect(packages).toEqual([{
- heightAuto: true,
- cells: [
- {
- props: { colSpan: 7 },
- title: expect.anything()
- }
- ]
- }]);
- });
+ it('Should create empty package list', () => {
+ const packages = createSystemPackagesRows([]);
+ expect(packages).toEqual([
+ {
+ heightAuto: true,
+ cells: [
+ {
+ props: { colSpan: 7 },
+ title: expect.anything(),
+ },
+ ],
+ },
+ ]);
+ });
});
diff --git a/src/Utilities/Helpers.js b/src/Utilities/Helpers.js
index 66aa9f391..af91c3d44 100644
--- a/src/Utilities/Helpers.js
+++ b/src/Utilities/Helpers.js
@@ -1,11 +1,10 @@
-/* eslint-disable camelcase */
import { Flex, FlexItem, Tooltip } from '@patternfly/react-core';
import {
- BugIcon,
- EnhancementIcon,
- FlagIcon,
- InfoCircleIcon,
- SecurityIcon
+ BugIcon,
+ EnhancementIcon,
+ FlagIcon,
+ InfoCircleIcon,
+ SecurityIcon,
} from '@patternfly/react-icons';
import { SortByDirection } from '@patternfly/react-table';
import flatten from 'lodash/flatten';
@@ -17,824 +16,684 @@ import LinesEllipsis from 'react-lines-ellipsis';
import messages from '../Messages';
import AdvisoriesIcon from '../PresentationalComponents/Snippets/AdvisoriesIcon';
import {
- advisorySeverities,
- defaultCompoundSortValues,
- filterCategories,
- multiValueFilters
+ advisorySeverities,
+ defaultCompoundSortValues,
+ filterCategories,
+ multiValueFilters,
} from './constants';
import { intl } from './IntlProvider';
import { generateFilter } from '@redhat-cloud-services/frontend-components-utilities/helpers';
import { InsightsLink } from '@redhat-cloud-services/frontend-components/InsightsLink';
export const removeUndefinedObjectItems = (originalObject) => {
- const newObject = JSON.parse(JSON.stringify(originalObject));
- Object.keys(newObject).forEach(
- (key) => newObject[key] === undefined && delete newObject[key]
- );
- return newObject;
+ const newObject = JSON.parse(JSON.stringify(originalObject));
+ Object.keys(newObject).forEach((key) => newObject[key] === undefined && delete newObject[key]);
+ return newObject;
};
-export const convertLimitOffset = (limit, offset) => {
- return [offset / limit + 1, limit];
-};
+export const convertLimitOffset = (limit, offset) => [offset / limit + 1, limit];
export const transformPairs = (input, remediationIdentifier) => {
- let issues = [];
-
- const advisoriesNames = Object.keys(input?.data || {});
- for (let i = 0; i < advisoriesNames.length; i++) {
- if (input.data[advisoriesNames[i]][0] !== '') {
- issues.push({
- id: `${remediationIdentifier}:${advisoriesNames[i]}`,
- description: advisoriesNames[i],
- systems: input.data[advisoriesNames[i]]
- });
- }
+ let issues = [];
+
+ const advisoriesNames = Object.keys(input?.data || {});
+ for (let i = 0; i < advisoriesNames.length; i++) {
+ if (input.data[advisoriesNames[i]][0] !== '') {
+ issues.push({
+ id: `${remediationIdentifier}:${advisoriesNames[i]}`,
+ description: advisoriesNames[i],
+ systems: input.data[advisoriesNames[i]],
+ });
}
+ }
- return { issues };
+ return { issues };
};
export const createSortBy = (
- header,
- values,
- offset,
- compoundSortValues = defaultCompoundSortValues
+ header,
+ values,
+ offset,
+ compoundSortValues = defaultCompoundSortValues,
) => {
- if (values) {
- let [column] = values;
- let multiple = values.join();
- let direction =
- column[0] === '-' ? SortByDirection.desc : SortByDirection.asc;
- Object.keys(compoundSortValues).forEach((col) => {
- Object.keys(compoundSortValues[col]).forEach((dir) => {
- if (compoundSortValues[col][dir] === multiple) {
- column = col;
- direction = dir;
- }
- });
- });
-
- column = column.replace(/^(-|\+)/, '');
- const index = findIndex(header, (item) => item.key === column);
- let sort = {
- index: index + offset,
- direction
- };
- return sort;
- }
+ if (values) {
+ let [column] = values;
+ let multiple = values.join();
+ let direction = column[0] === '-' ? SortByDirection.desc : SortByDirection.asc;
+ Object.keys(compoundSortValues).forEach((col) => {
+ Object.keys(compoundSortValues[col]).forEach((dir) => {
+ if (compoundSortValues[col][dir] === multiple) {
+ column = col;
+ direction = dir;
+ }
+ });
+ });
- return {};
+ column = column.replace(/^(-|\+)/, '');
+ const index = findIndex(header, (item) => item.key === column);
+ let sort = {
+ index: index + offset,
+ direction,
+ };
+ return sort;
+ }
+
+ return {};
};
export const addOrRemoveItemFromSet = (targetObj, inputArr) => {
- const inputObj = inputArr.reduce(
- (obj, item) => ((obj[item.rowId] = item.value || undefined), obj),
- {}
- );
- const result = { ...targetObj, ...inputObj };
- return result;
+ const inputObj = inputArr.reduce(
+ (obj, item) => ((obj[item.rowId] = item.value || undefined), obj),
+ {},
+ );
+ const result = { ...targetObj, ...inputObj };
+ return result;
};
export const getNewSelectedItems = (selectedItems, currentItems) => {
- let payload = []
- .concat(selectedItems)
- .map((item) => ({ rowId: item.id, value: item.selected }));
- const mergedSelection = addOrRemoveItemFromSet(currentItems, payload);
+ let payload = [].concat(selectedItems).map((item) => ({ rowId: item.id, value: item.selected }));
+ const mergedSelection = addOrRemoveItemFromSet(currentItems, payload);
- return pickBy(mergedSelection, (v) => !!v);
+ return pickBy(mergedSelection, (v) => !!v);
};
// for expandable rows only
-export const getRowIdByIndexExpandable = (arrayOfObjects, index) => {
- return arrayOfObjects[index / 2].id;
-};
+export const getRowIdByIndexExpandable = (arrayOfObjects, index) => arrayOfObjects[index / 2].id;
-export const getOffsetFromPageLimit = (page, limit) => {
- return page * limit - limit;
-};
+export const getOffsetFromPageLimit = (page, limit) => page * limit - limit;
-export const getLimitFromPageSize = (limit) => {
- return limit;
-};
+export const getLimitFromPageSize = (limit) => limit;
export function truncate(str, max, end) {
- return str.length > max ? (
-
- {str.substring(0, max - 1)}
- ... {end}
-
- ) : (
- str
- );
+ return str.length > max ? (
+
+ {str.substring(0, max - 1)}
+ ... {end}
+
+ ) : (
+ str
+ );
}
const findBullets = (description) => {
- let substringIndex = description.search(/:/);
- // + 2 accounts for the 2 new lines to separate the sentence from the start of the bullets
- return substringIndex > 0
- ? description.slice(0, substringIndex + 2) +
+ let substringIndex = description.search(/:/);
+ // + 2 accounts for the 2 new lines to separate the sentence from the start of the bullets
+ return substringIndex > 0
+ ? description.slice(0, substringIndex + 2) +
preserveNewlines(description.substring(substringIndex + 2))
- : description;
+ : description;
};
export const truncateDescription = (description, wordLength, setWordLength) =>
- truncate(
- findBullets(description),
- wordLength,
- setWordLength(description.length)}>
- {intl.formatMessage(messages.linksReadMore)}
-
- );
-
-export function createAdvisoriesIcons(
- [rhea, rhba, rhsa, other],
- type = 'applicable'
-) {
- return (
-
- {[rhea, rhba, rhsa].every((item) => item === 0) &&
- `No ${type} advisories`}
- {rhsa !== 0 && (
-
-
-
- )}
- {rhba !== 0 && (
-
-
-
- )}
- {rhea !== 0 && (
-
-
-
- )}
- {other !== 0 && (
-
-
-
- )}
-
- );
+ truncate(
+ findBullets(description),
+ wordLength,
+ setWordLength(description.length)}>
+ {intl.formatMessage(messages.linksReadMore)}
+ ,
+ );
+
+export function createAdvisoriesIcons([rhea, rhba, rhsa, other], type = 'applicable') {
+ return (
+
+ {[rhea, rhba, rhsa].every((item) => item === 0) && `No ${type} advisories`}
+ {rhsa !== 0 && (
+
+
+
+ )}
+ {rhba !== 0 && (
+
+
+
+ )}
+ {rhea !== 0 && (
+
+
+
+ )}
+ {other !== 0 && (
+
+
+
+ )}
+
+ );
}
export function createUpgradableColumn(updatableStatus) {
- switch (updatableStatus) {
- case 'None':
- return intl.formatMessage(messages.labelsColumnsUpToApplicable);
- case 'Applicable':
- return intl.formatMessage(messages.labelsColumnsUpToInstallable);
- case 'Installable':
- return intl.formatMessage(messages.labelsColumnsUpgradable);
- }
+ switch (updatableStatus) {
+ case 'None':
+ return intl.formatMessage(messages.labelsColumnsUpToApplicable);
+ case 'Applicable':
+ return intl.formatMessage(messages.labelsColumnsUpToInstallable);
+ case 'Installable':
+ return intl.formatMessage(messages.labelsColumnsUpgradable);
+ }
}
export function getSeverityByValue(value) {
- // Convert `undefined` to `null`, as utility functions rely on `null` to signify no severity
- const severityValue = value === undefined ? null : value;
+ // Convert `undefined` to `null`, as utility functions rely on `null` to signify no severity
+ const severityValue = value === undefined ? null : value;
- return (
- advisorySeverities.find((item) => item.value === severityValue) ||
- advisorySeverities[0]
- );
+ return advisorySeverities.find((item) => item.value === severityValue) || advisorySeverities[0];
}
export const createPackagesColumn = (packageCount, systemID) => (
-
- {packageCount}
-
+
+ {packageCount}
+
);
export function handlePatchLink(type, name, body) {
- if (location.href.indexOf('inventory') === -1) {
- return (
-
- {body === undefined ? name : body}
-
- );
- } else {
- return (
-
- {body || name}
-
- );
- }
+ if (location.href.indexOf('inventory') === -1) {
+ return {body === undefined ? name : body};
+ } else {
+ return {body || name};
+ }
}
-export const arrayFromObj = (items) =>
- Object.values(items).filter((value) => value);
+export const arrayFromObj = (items) => Object.values(items).filter((value) => value);
export const remediationProvider = (issues, systems, remediationIdentifier) => {
- issues = [].concat(issues);
- systems = [].concat(systems);
- return issues.length && systems.length
- ? {
- issues: issues.map((item) => ({
- id: `${remediationIdentifier}:${item}`,
- description: item
- })),
- systems
- }
- : false;
-};
-
-export const remediationProviderWithPairs = (
- issuePairs,
- transformFunc,
- remediationIdentifier
-) => {
- return issuePairs
- ? transformFunc(issuePairs, remediationIdentifier)
- : false;
-};
+ issues = [].concat(issues);
+ systems = [].concat(systems);
+ return issues.length && systems.length
+ ? {
+ issues: issues.map((item) => ({
+ id: `${remediationIdentifier}:${item}`,
+ description: item,
+ })),
+ systems,
+ }
+ : false;
+};
+
+export const remediationProviderWithPairs = (issuePairs, transformFunc, remediationIdentifier) =>
+ issuePairs ? transformFunc(issuePairs, remediationIdentifier) : false;
export const getFilterValue = (category, key) => {
- const filterCategory = filterCategories[category];
- if (filterCategory) {
- const filterOption =
- /* some filters don't have constant values */
- (filterCategory?.values || []).find((item) => item.value === key);
- return filterOption || { apiValue: key };
- } else {
- return { apiValue: key };
- }
+ const filterCategory = filterCategories[category];
+ if (filterCategory) {
+ const filterOption =
+ /* some filters don't have constant values */
+ (filterCategory?.values || []).find((item) => item.value === key);
+ return filterOption || { apiValue: key };
+ } else {
+ return { apiValue: key };
+ }
};
export const encodeParams = (parameters, shouldTranslateKeys) => {
- const calculateWorkloads = ({ sap_sids, ...restOfProfile }) => {
- let result = '';
- Object.entries(
- generateFilter({ system_profile: restOfProfile })
- ).forEach((entry) => {
- const [key, value] = entry;
- result = `${result}&${key}=${value}`;
- });
-
- const SIDsFilter = sap_sids
- ?.map((sid) => `filter[system_profile][sap_sids][in]=${sid}`)
- .join('&');
-
- return result.concat(
- sap_sids ? `&${SIDsFilter}#SIDs=${sap_sids.join(',')}` : ''
- );
- };
-
- const flattenFilters = (filter) => {
- let result = {};
- filter &&
- Object.entries(filter).forEach((item) => {
- let [key, value] = item;
- value =
- (shouldTranslateKeys &&
- getFilterValue(key, value).apiValue) ||
- value;
- const operator =
- [].concat(value).length > 1 ||
- multiValueFilters.includes(key)
- ? 'in:'
- : '';
- result = {
- ...result,
- [`filter[${key}]`]: `${operator}${String(value)}`
- };
- });
- return result;
- };
-
- let { filter, systemProfile = {}, group_name, ...allParams } = parameters;
-
- allParams = {
- ...allParams,
- ...flattenFilters({ ...filter, ...(group_name ? { group_name } : {}) })
- };
- let params = [];
- Object.keys(allParams).forEach((key) => {
- const argKey = encodeURIComponent(key);
- const argValue = encodeURIComponent(allParams[key]);
-
- if (
- !['', undefined, null].some((value) =>
- [argValue, key].includes(value)
- )
- ) {
- if (!['selectedTags', 'systemProfile'].includes(key)) {
- params.push(argKey.concat('=').concat(argValue));
- } else if (key === 'selectedTags') {
- params.push.apply(params, allParams[key]);
- }
- }
+ const calculateWorkloads = ({ sap_sids, ...restOfProfile }) => {
+ let result = '';
+ Object.entries(generateFilter({ system_profile: restOfProfile })).forEach((entry) => {
+ const [key, value] = entry;
+ result = `${result}&${key}=${value}`;
});
- const workloadsFilter =
- (Object.keys(systemProfile).length > 0 &&
- calculateWorkloads(systemProfile)) ||
- '';
+ const SIDsFilter = sap_sids
+ ?.map((sid) => `filter[system_profile][sap_sids][in]=${sid}`)
+ .join('&');
+
+ return result.concat(sap_sids ? `&${SIDsFilter}#SIDs=${sap_sids.join(',')}` : '');
+ };
+
+ const flattenFilters = (filter) => {
+ let result = {};
+ filter &&
+ Object.entries(filter).forEach((item) => {
+ let [key, value] = item;
+ value = (shouldTranslateKeys && getFilterValue(key, value).apiValue) || value;
+ const operator =
+ [].concat(value).length > 1 || multiValueFilters.includes(key) ? 'in:' : '';
+ result = {
+ ...result,
+ [`filter[${key}]`]: `${operator}${String(value)}`,
+ };
+ });
+ return result;
+ };
+
+ let { filter, systemProfile = {}, group_name, ...allParams } = parameters;
+
+ allParams = {
+ ...allParams,
+ ...flattenFilters({ ...filter, ...(group_name ? { group_name } : {}) }),
+ };
+ let params = [];
+ Object.keys(allParams).forEach((key) => {
+ const argKey = encodeURIComponent(key);
+ const argValue = encodeURIComponent(allParams[key]);
+
+ if (!['', undefined, null].some((value) => [argValue, key].includes(value))) {
+ if (!['selectedTags', 'systemProfile'].includes(key)) {
+ params.push(argKey.concat('=').concat(argValue));
+ } else if (key === 'selectedTags') {
+ params.push.apply(params, allParams[key]);
+ }
+ }
+ });
- return '?'.concat(params.join('&')).concat(workloadsFilter);
-};
+ const workloadsFilter =
+ (Object.keys(systemProfile).length > 0 && calculateWorkloads(systemProfile)) || '';
-export const encodeApiParams = (parameters) => {
- return encodeParams(parameters, true);
+ return '?'.concat(params.join('&')).concat(workloadsFilter);
};
+export const encodeApiParams = (parameters) => encodeParams(parameters, true);
+
export const encodeURLParams = (parameters) => {
- delete parameters.id;
- let urlParams = { ...parameters };
- delete urlParams.selectedTags;
- return encodeParams(removeUndefinedObjectItems(urlParams), false);
+ delete parameters.id;
+ let urlParams = { ...parameters };
+ delete urlParams.selectedTags;
+ return encodeParams(removeUndefinedObjectItems(urlParams), false);
};
export const decomposeFilterValue = (filterValue, parser) => {
- if (parser) {
- return parser(filterValue);
- } else if (
- typeof filterValue === 'string' &&
- filterValue.startsWith('in:')
- ) {
- const values = filterValue.slice(3);
- return values.split(',');
- } else {
- return filterValue;
- }
+ if (parser) {
+ return parser(filterValue);
+ } else if (typeof filterValue === 'string' && filterValue.startsWith('in:')) {
+ const values = filterValue.slice(3);
+ return values.split(',');
+ } else {
+ return filterValue;
+ }
};
const getApiValueFromFilterString = (value) => {
- if (Array.isArray(value)) {
- return value.map(getApiValueFromFilterString);
- }
+ if (Array.isArray(value)) {
+ return value.map(getApiValueFromFilterString);
+ }
- return value === 'null' ? null : value;
+ return value === 'null' ? null : value;
};
export const decodeQueryparams = (queryString, parsers = {}) => {
- const parsed = qs.parse(queryString);
- const res = {};
- Object.keys(parsed).forEach((key) => {
- if (!key.startsWith('filter[system_profile]')) {
- const convertedToInt = parseInt(parsed[key], 10);
- const typeHandledParam = isNaN(convertedToInt)
- ? parsed[key]
- : convertedToInt;
- const bracketIndex = key.search(/\[.*\]/);
- if (bracketIndex > 0) {
- const objParent = key.slice(0, bracketIndex);
- const objKey = key.slice(bracketIndex + 1, -1);
- const parser = parsers[objKey];
- const decomposedValue = decomposeFilterValue(
- typeHandledParam,
- parser
- );
- const normalizedValue =
- objParent === 'filter'
- ? getApiValueFromFilterString(decomposedValue)
- : decomposedValue;
- res[objParent] = {
- ...res[objParent],
- [objKey]: normalizedValue
- };
- } else {
- res[key] = typeHandledParam;
- }
- }
- });
- return res;
-};
+ const parsed = qs.parse(queryString);
+ const res = {};
+ Object.keys(parsed).forEach((key) => {
+ if (!key.startsWith('filter[system_profile]')) {
+ const convertedToInt = parseInt(parsed[key], 10);
+ const typeHandledParam = isNaN(convertedToInt) ? parsed[key] : convertedToInt;
+ const bracketIndex = key.search(/\[.*\]/);
+ if (bracketIndex > 0) {
+ const objParent = key.slice(0, bracketIndex);
+ const objKey = key.slice(bracketIndex + 1, -1);
+ const parser = parsers[objKey];
+ const decomposedValue = decomposeFilterValue(typeHandledParam, parser);
+ const normalizedValue =
+ objParent === 'filter' ? getApiValueFromFilterString(decomposedValue) : decomposedValue;
+ res[objParent] = {
+ ...res[objParent],
+ [objKey]: normalizedValue,
+ };
+ } else {
+ res[key] = typeHandledParam;
+ }
+ }
+ });
+ return res;
+};
+
+const getFilterStringFromApi = (value) => (value === null ? 'null' : String(value));
+
+export const buildFilterChips = (filters, search, searchChipLabel = 'Search', parsers = {}) => {
+ let filterConfig = [];
+ const buildChips = (filters, category) => {
+ if (parsers[category]) {
+ return parsers[category](filters[category]);
+ } else if (multiValueFilters.includes(category)) {
+ const filterValues =
+ (filters[category] &&
+ ((typeof filters[category] === 'string' && filters[category].split(',')) ||
+ filters[category])) ||
+ [];
+ // Leave the raw value intact (including `null`) so chips render and removal logic works
+ return filterValues.map((value) => ({
+ name: value,
+ id: category,
+ value,
+ }));
+ } else {
+ const { values } = filterCategories[category];
-const getFilterStringFromApi = (value) =>
- value === null ? 'null' : String(value);
+ // Previously we dropped truthy-but-falsy values like `null`, which hid the severity chip
+ if (filters[category] === undefined || filters[category] === '') {
+ return [];
+ }
-export const buildFilterChips = (
- filters,
- search,
- searchChipLabel = 'Search',
- parsers = {}
-) => {
- let filterConfig = [];
- const buildChips = (filters, category) => {
- if (parsers[category]) {
- return parsers[category](filters[category]);
- } else if (multiValueFilters.includes(category)) {
- const filterValues =
- (filters[category] &&
- ((typeof filters[category] === 'string' &&
- filters[category].split(',')) ||
- filters[category])) ||
- [];
- // Leave the raw value intact (including `null`) so chips render and removal logic works
- return filterValues.map((value) => ({
- name: value,
- id: category,
- value
- }));
- } else {
- const { values } = filterCategories[category];
-
- // Previously we dropped truthy-but-falsy values like `null`, which hid the severity chip
- if (filters[category] === undefined || filters[category] === '') {
- return [];
- }
-
- return [].concat(filters[category]).map((filterValue) => {
- const match = values.find(
- (item) =>
- getFilterStringFromApi(item.value) ===
- getFilterStringFromApi(filterValue)
- );
- return {
- name: match.label,
- value: filterValue,
- id: match.value
- };
- });
- }
- };
-
- const processFilters = () => {
- let categories = Object.keys(filters).filter(
- (item) =>
- filters[item] !== '' && [].concat(filters[item]).length !== 0
- );
- filterConfig = filterConfig.concat(
- categories.map((category) => {
- const label =
- (category === 'installed_evra' && 'Package version') ||
- filterCategories[category].label;
- return {
- category: label,
- id: category,
- chips: buildChips(filters, category)
- };
- })
+ return [].concat(filters[category]).map((filterValue) => {
+ const match = values.find(
+ (item) => getFilterStringFromApi(item.value) === getFilterStringFromApi(filterValue),
);
- };
+ return {
+ name: match.label,
+ value: filterValue,
+ id: match.value,
+ };
+ });
+ }
+ };
- const processSearch = () => {
- filterConfig = filterConfig.concat([
- {
- category: searchChipLabel,
- id: 'search',
- chips: [
- {
- name: search,
- value: search
- }
- ]
- }
- ]);
- };
+ const processFilters = () => {
+ let categories = Object.keys(filters).filter(
+ (item) => filters[item] !== '' && [].concat(filters[item]).length !== 0,
+ );
+ filterConfig = filterConfig.concat(
+ categories.map((category) => {
+ const label =
+ (category === 'installed_evra' && 'Package version') || filterCategories[category].label;
+ return {
+ category: label,
+ id: category,
+ chips: buildChips(filters, category),
+ };
+ }),
+ );
+ };
- filters && processFilters();
- search && processSearch();
+ const processSearch = () => {
+ filterConfig = filterConfig.concat([
+ {
+ category: searchChipLabel,
+ id: 'search',
+ chips: [
+ {
+ name: search,
+ value: search,
+ },
+ ],
+ },
+ ]);
+ };
- return filterConfig;
+ filters && processFilters();
+ search && processSearch();
+
+ return filterConfig;
};
export const buildOsFilter = (osFilter = {}) => {
- const osVersions = Object.entries(osFilter).reduce(
- (acc, [, osGroupValues]) => {
- return [
- ...acc,
- ...Object.entries(osGroupValues)
- .filter(([, value]) => value === true)
- .map(([key]) => {
- const keyParts = key.split('-');
- return (
- keyParts.slice(0, keyParts.length - 2) +
- ' ' +
- keyParts[keyParts.length - 1]
- );
- })
- ];
- },
- []
- );
+ const osVersions = Object.entries(osFilter).reduce(
+ (acc, [, osGroupValues]) => [
+ ...acc,
+ ...Object.entries(osGroupValues)
+ .filter(([, value]) => value === true)
+ .map(([key]) => {
+ const keyParts = key.split('-');
+ return keyParts.slice(0, keyParts.length - 2) + ' ' + keyParts[keyParts.length - 1];
+ }),
+ ],
+ [],
+ );
- return osVersions.length > 0
- ? {
- os: osVersions.join(',')
- }
- : {};
+ return osVersions.length > 0
+ ? {
+ os: osVersions.join(','),
+ }
+ : {};
};
export const buildApiFilters = (patchFilters, inventoryFilters) => ({
- ...patchFilters,
- ...(Array.isArray(inventoryFilters.hostGroupFilter) &&
- inventoryFilters.hostGroupFilter.length > 0
- ? { group_name: inventoryFilters.hostGroupFilter }
- : {}),
- ...buildOsFilter(inventoryFilters?.osFilter)
+ ...patchFilters,
+ ...(Array.isArray(inventoryFilters.hostGroupFilter) && inventoryFilters.hostGroupFilter.length > 0
+ ? { group_name: inventoryFilters.hostGroupFilter }
+ : {}),
+ ...buildOsFilter(inventoryFilters?.osFilter),
});
export const changeListParams = (oldParams, newParams) => {
- const newState = { ...oldParams, ...newParams };
- const offsetResetParams = ['filter', 'search', 'limit', 'selectedTags'];
- if (offsetResetParams.some((item) => newParams.hasOwnProperty(item))) {
- newState.offset = 0;
- }
+ const newState = { ...oldParams, ...newParams };
+ const offsetResetParams = ['filter', 'search', 'limit', 'selectedTags'];
+ if (offsetResetParams.some((item) => newParams.hasOwnProperty(item))) {
+ newState.offset = 0;
+ }
+
+ if (newParams.hasOwnProperty('filter')) {
+ newState.filter = { ...oldParams.filter, ...newParams.filter };
+
+ // we need explicitly remove 'undefined' filters for safety
+ Object.keys(newState.filter).forEach(
+ (key) =>
+ (newState.filter[key] === undefined || newState.filter[key] === '') &&
+ delete newState.filter[key],
+ );
+ }
- if (newParams.hasOwnProperty('filter')) {
- newState.filter = { ...oldParams.filter, ...newParams.filter };
+ if (newState.hasOwnProperty('tags')) {
+ newState && delete newState.tags;
+ }
- //we need explicitly remove 'undefined' filters for safety
- Object.keys(newState.filter).forEach(
- (key) =>
- (newState.filter[key] === undefined ||
- newState.filter[key] === '') &&
- delete newState.filter[key]
- );
- }
-
- if (newState.hasOwnProperty('tags')) {
- newState && delete newState.tags;
- }
-
- return newState;
+ return newState;
};
export function subtractDate(days) {
- const date = new Date();
- date.setDate(date.getDate() - days);
- return date.toISOString();
+ const date = new Date();
+ date.setDate(date.getDate() - days);
+ return date.toISOString();
}
export function preserveNewlines(input) {
- return (
- input && input.replace(new RegExp('\\n\\n(?=.*[\\n\\n])', 'g'), '\n')
- );
+ return input && input.replace(new RegExp('\\n\\n(?=.*[\\n\\n])', 'g'), '\n');
}
export function sortCves(cves, index, direction) {
- const sortedCves = cves.sort(({ cells: aCells }, { cells: bCells }) => {
- const aCell = aCells[index].value || aCells[index].title;
- const bCell = bCells[index].value || bCells[index].title;
+ const sortedCves = cves.sort(({ cells: aCells }, { cells: bCells }) => {
+ const aCell = aCells[index].value || aCells[index].title;
+ const bCell = bCells[index].value || bCells[index].title;
- const stringA = aCell.toString().toUpperCase();
- const stringB = bCell.toString().toUpperCase();
+ const stringA = aCell.toString().toUpperCase();
+ const stringB = bCell.toString().toUpperCase();
- return stringA.localeCompare(stringB);
- });
+ return stringA.localeCompare(stringB);
+ });
- return {
- sortBy: { index, direction },
- sortedCves:
- direction === SortByDirection.asc
- ? sortedCves
- : sortedCves.reverse()
- };
+ return {
+ sortBy: { index, direction },
+ sortedCves: direction === SortByDirection.asc ? sortedCves : sortedCves.reverse(),
+ };
}
export const createOSColumn = ({ osName, rhsm }) =>
- !rhsm ? (
- osName
- ) : (
-
-
- {osName}
-
-
-
-
-
- );
+ !rhsm ? (
+ osName
+ ) : (
+
+
+ {osName}
+
+
+
+
+
+ );
export const removeUndefinedObjectKeys = (selectedRows) =>
- Object.keys(selectedRows).filter((row) => selectedRows[row]);
+ Object.keys(selectedRows).filter((row) => selectedRows[row]);
export const prepareEntitiesParams = (parameters) => {
- const offset =
- parameters.offset ||
- getOffsetFromPageLimit(parameters.page || 1, parameters.perPage || 20);
- const limit =
- parameters.limit || getLimitFromPageSize(parameters.perPage || 20);
+ const offset =
+ parameters.offset || getOffsetFromPageLimit(parameters.page || 1, parameters.perPage || 20);
+ const limit = parameters.limit || getLimitFromPageSize(parameters.perPage || 20);
- const apiParams = { ...parameters, offset, limit };
+ const apiParams = { ...parameters, offset, limit };
- //we need explicitly remove 'undefined' parameters for safety
- return removeUndefinedObjectItems(apiParams);
+ // we need explicitly remove 'undefined' parameters for safety
+ return removeUndefinedObjectItems(apiParams);
};
export const filterRemediatableSystems = (result) => ({
- data: result?.data.filter((system) => {
- const {
- packages_installed: installedPckg,
- packages_updatable: updatablePckg,
- rhba_count: rhba,
- rhsa_count: rhsa,
- rhea_count: rhea
- } = system.attributes || {};
-
- const isDisabled =
- updatablePckg === 0 ||
- [installedPckg, rhba, rhsa, rhea].every((count) => count === 0);
-
- return !isDisabled;
- })
+ data: result?.data.filter((system) => {
+ const {
+ packages_installed: installedPckg,
+ packages_updatable: updatablePckg,
+ rhba_count: rhba,
+ rhsa_count: rhsa,
+ rhea_count: rhea,
+ } = system.attributes || {};
+
+ const isDisabled =
+ updatablePckg === 0 || [installedPckg, rhba, rhsa, rhea].every((count) => count === 0);
+
+ return !isDisabled;
+ }),
});
export const filterRemediatablePackageSystems = (result) => ({
- data: result.data.filter((system) => system.updatable)
+ data: result.data.filter((system) => system.updatable),
});
export const persistantParams = (patchParams, decodedParams) => {
- const persistantParams = { ...patchParams, ...decodedParams };
-
- if (
- typeof persistantParams.sort === 'string' &&
- persistantParams.sort.match(/-?groups/)
- ) {
- // "group_name" is the sort key used by Inventory (requires translation between Patch and Inventory)
- persistantParams.sort = persistantParams.sort.replace(
- 'groups',
- 'group_name'
- );
- }
-
- return {
- page: Number(persistantParams.page || 1),
- perPage: Number(persistantParams.perPage || 20),
- ...(persistantParams.sort && {
- sortBy: {
- key: persistantParams.sort.replace(/^-/, ''),
- direction: persistantParams.sort.match(/^-/) ? 'desc' : 'asc'
- }
- })
- };
-};
-
-export const handleLongSynopsis = (synopsis) => {
- return (
-
- );
-};
+ const persistantParams = { ...patchParams, ...decodedParams };
+
+ if (typeof persistantParams.sort === 'string' && persistantParams.sort.match(/-?groups/)) {
+ // "group_name" is the sort key used by Inventory (requires translation between Patch and Inventory)
+ persistantParams.sort = persistantParams.sort.replace('groups', 'group_name');
+ }
+
+ return {
+ page: Number(persistantParams.page || 1),
+ perPage: Number(persistantParams.perPage || 20),
+ ...(persistantParams.sort && {
+ sortBy: {
+ key: persistantParams.sort.replace(/^-/, ''),
+ direction: persistantParams.sort.match(/^-/) ? 'desc' : 'asc',
+ },
+ }),
+ };
+};
+
+export const handleLongSynopsis = (synopsis) => (
+
+);
-export const isRHAdvisory = (name) => {
- return /^(RHEA|RHBA|RHSA)/.test(name);
-};
+export const isRHAdvisory = (name) => /^(RHEA|RHBA|RHSA)/.test(name);
-export const buildTagString = (tag) => {
- return `${tag.category}/${tag.values?.tagKey}=${tag.value?.tagValue}`;
-};
+export const buildTagString = (tag) =>
+ `${tag.category}/${tag.values?.tagKey}=${tag.value?.tagValue}`;
export const mapGlobalFilters = (tags, SIDs, workloads = {}) => {
- let tagsInUrlFormat = [];
- tags &&
+ let tagsInUrlFormat = [];
+ tags &&
tags.forEach((tag, index) => {
- let tagGruop = tag;
- if (typeof tag === 'object') {
- tagGruop = tag?.values.map(
- (value) =>
- `tags=${encodeURIComponent(
- `${tag.category}/${value.tagKey}=${value.value}`
- )}`
- );
- tagsInUrlFormat[index] =
- (Array.isArray(tagGruop) && flatten(tagGruop)) || tagGruop;
- } else {
- tagsInUrlFormat[index] = `tags=${encodeURIComponent(tagGruop)}`;
- }
+ let tagGruop = tag;
+ if (typeof tag === 'object') {
+ tagGruop = tag?.values.map(
+ (value) => `tags=${encodeURIComponent(`${tag.category}/${value.tagKey}=${value.value}`)}`,
+ );
+ tagsInUrlFormat[index] = (Array.isArray(tagGruop) && flatten(tagGruop)) || tagGruop;
+ } else {
+ tagsInUrlFormat[index] = `tags=${encodeURIComponent(tagGruop)}`;
+ }
});
- const globalFilterConfig = { selectedTags: [], systemProfile: {} };
+ const globalFilterConfig = { selectedTags: [], systemProfile: {} };
- globalFilterConfig.systemProfile = {
- ...(workloads?.SAP?.isSelected && { sap_system: true }),
- ...(workloads?.['Ansible Automation Platform']?.isSelected && {
- ansible: { controller_version: 'not_nil' }
- }),
- ...(workloads?.['Microsoft SQL']?.isSelected && {
- mssql: { version: 'not_nil' }
- }),
- ...(SIDs?.length > 0 && { sap_sids: SIDs })
- };
+ globalFilterConfig.systemProfile = {
+ ...(workloads?.SAP?.isSelected && { sap_system: true }),
+ ...(workloads?.['Ansible Automation Platform']?.isSelected && {
+ ansible: { controller_version: 'not_nil' },
+ }),
+ ...(workloads?.['Microsoft SQL']?.isSelected && {
+ mssql: { version: 'not_nil' },
+ }),
+ ...(SIDs?.length > 0 && { sap_sids: SIDs }),
+ };
- tagsInUrlFormat && (globalFilterConfig.selectedTags = tagsInUrlFormat);
+ tagsInUrlFormat && (globalFilterConfig.selectedTags = tagsInUrlFormat);
- return globalFilterConfig;
+ return globalFilterConfig;
};
export const convertIsoToDate = (isoDate) => {
- if (!isoDate) {
- return '';
- }
+ if (!isoDate) {
+ return '';
+ }
- const dateObject = new Date(isoDate);
- return (
- `${dateObject.getFullYear()}-${(dateObject.getMonth() + 1)
- .toString()
- .padStart(2, '0')}` +
- `-${dateObject.getDate().toString().padStart(2, '0')}`
- );
+ const dateObject = new Date(isoDate);
+ return (
+ `${dateObject.getFullYear()}-${(dateObject.getMonth() + 1).toString().padStart(2, '0')}` +
+ `-${dateObject.getDate().toString().padStart(2, '0')}`
+ );
};
// 2023-03-05 -> 05 Mar 2023
// 2023-03-22T20:00:00-04:00 (ISO format) -> 23 Mar 2023
export const templateDateFormat = (dateString) => {
- if (!dateString) {
- return 'N/A';
- }
-
- // handle ISO format - convert timezone to GMT and slice off the time
- if (dateString.includes('T')) {
- const gmtTime = new Date(dateString).toISOString();
- [dateString] = gmtTime.split('T');
- }
-
- const MONTHS = [
- 'Jan',
- 'Feb',
- 'Mar',
- 'Apr',
- 'May',
- 'June',
- 'July',
- 'Aug',
- 'Sept',
- 'Oct',
- 'Nov',
- 'Dec'
- ];
- const [year, month, day] = dateString.split('-');
-
- return `${day} ${MONTHS[parseInt(month) - 1]} ${year}`;
+ if (!dateString) {
+ return 'N/A';
+ }
+
+ // handle ISO format - convert timezone to GMT and slice off the time
+ if (dateString.includes('T')) {
+ const gmtTime = new Date(dateString).toISOString();
+ [dateString] = gmtTime.split('T');
+ }
+
+ const MONTHS = [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'June',
+ 'July',
+ 'Aug',
+ 'Sept',
+ 'Oct',
+ 'Nov',
+ 'Dec',
+ ];
+ const [year, month, day] = dateString.split('-');
+
+ return `${day} ${MONTHS[parseInt(month) - 1]} ${year}`;
};
export const filterSelectedActiveSystemIDs = (selectedSystemsObject) => {
- const formValueSystemIDs = [];
- if (typeof selectedSystemsObject === 'object') {
- Object.keys(selectedSystemsObject).forEach((key) => {
- if (selectedSystemsObject[key]) {
- formValueSystemIDs.push(key);
- }
- });
- }
+ const formValueSystemIDs = [];
+ if (typeof selectedSystemsObject === 'object') {
+ Object.keys(selectedSystemsObject).forEach((key) => {
+ if (selectedSystemsObject[key]) {
+ formValueSystemIDs.push(key);
+ }
+ });
+ }
- return formValueSystemIDs;
+ return formValueSystemIDs;
};
export const buildSelectedSystemsObj = (systemsIDs, formValueSystems) => {
- const mergedSystems = [
- ...systemsIDs,
- ...filterSelectedActiveSystemIDs(formValueSystems)
- ];
+ const mergedSystems = [...systemsIDs, ...filterSelectedActiveSystemIDs(formValueSystems)];
- const assignedSystemsObject = mergedSystems?.reduce((object, system) => {
- object[system] = true;
- return object;
- }, {});
+ const assignedSystemsObject = mergedSystems?.reduce((object, system) => {
+ object[system] = true;
+ return object;
+ }, {});
- return assignedSystemsObject;
+ return assignedSystemsObject;
};
export const objUndefinedToFalse = (object) =>
- Object.keys(object).reduce((modifiedObject, key) => {
- modifiedObject[key] = object[key] === undefined ? false : object[key];
- return modifiedObject;
- }, {});
+ Object.keys(object).reduce((modifiedObject, key) => {
+ modifiedObject[key] = object[key] === undefined ? false : object[key];
+ return modifiedObject;
+ }, {});
export const objOnlyWithTrue = (object) =>
- Object.keys(
- Object.fromEntries(Object.entries(object).filter(([, v]) => v === true))
- );
+ Object.keys(Object.fromEntries(Object.entries(object).filter(([, v]) => v === true)));
-export const isObject = (variable) => {
- return typeof variable === 'object' && variable !== null ? true : false;
-};
+export const isObject = (variable) =>
+ typeof variable === 'object' && variable !== null ? true : false;
-export const findFilterData = (optionName, options) => {
- return options.find((item) => item.label === optionName);
-};
+export const findFilterData = (optionName, options) =>
+ options.find((item) => item.label === optionName);
diff --git a/src/Utilities/Helpers.test.js b/src/Utilities/Helpers.test.js
index 469dd8d0e..099fa78fb 100644
--- a/src/Utilities/Helpers.test.js
+++ b/src/Utilities/Helpers.test.js
@@ -1,507 +1,530 @@
/* eslint-disable */
-import {SortByDirection} from '@patternfly/react-table';
-import {publicDateOptions, remediationIdentifiers} from '../Utilities/constants';
+import { SortByDirection } from '@patternfly/react-table';
+import { publicDateOptions, remediationIdentifiers } from '../Utilities/constants';
import {
- addOrRemoveItemFromSet,
- arrayFromObj,
- buildApiFilters,
- buildFilterChips,
- changeListParams,
- convertLimitOffset,
- createAdvisoriesIcons,
- createSortBy,
- decodeQueryparams,
- encodeApiParams,
- encodeParams,
- encodeURLParams,
- getFilterValue,
- getLimitFromPageSize,
- getNewSelectedItems,
- getOffsetFromPageLimit,
- getRowIdByIndexExpandable,
- getSeverityByValue,
- handlePatchLink,
- mapGlobalFilters,
- persistantParams,
- remediationProvider,
- templateDateFormat,
- transformPairs
+ addOrRemoveItemFromSet,
+ arrayFromObj,
+ buildApiFilters,
+ buildFilterChips,
+ changeListParams,
+ convertLimitOffset,
+ createAdvisoriesIcons,
+ createSortBy,
+ decodeQueryparams,
+ encodeApiParams,
+ encodeParams,
+ encodeURLParams,
+ getFilterValue,
+ getLimitFromPageSize,
+ getNewSelectedItems,
+ getOffsetFromPageLimit,
+ getRowIdByIndexExpandable,
+ getSeverityByValue,
+ handlePatchLink,
+ mapGlobalFilters,
+ persistantParams,
+ remediationProvider,
+ templateDateFormat,
+ transformPairs,
} from './Helpers';
-import {render} from '@testing-library/react';
+import { render } from '@testing-library/react';
-const TestHook = ({callback}) => {
- callback();
- return null;
+const TestHook = ({ callback }) => {
+ callback();
+ return null;
};
-export const testHook = callback => {
- mount();
+export const testHook = (callback) => {
+ mount();
};
describe('Helpers tests', () => {
- let header = [
- {
- key: 'a'
- },
- {
- key: 'b'
- },
- {
- key: 'c'
- },
- {
- key: 'd'
- }
- ];
- it.each`
- header | value | offset | result
- ${header} | ${['-a']} | ${0} | ${{index: 0, direction: SortByDirection.desc}}
- ${header} | ${['c']} | ${1} | ${{index: 3, direction: SortByDirection.asc}}
- ${undefined} | ${undefined} | ${undefined} | ${{}}
- `('createSortBy: Should create correct sort for $value and offset $offset', ({header, value, offset, result}) => {
- let ret = createSortBy(header, value, offset);
- expect(ret).toEqual(result);
- });
-
- it.each`
+ let header = [
+ {
+ key: 'a',
+ },
+ {
+ key: 'b',
+ },
+ {
+ key: 'c',
+ },
+ {
+ key: 'd',
+ },
+ ];
+ it.each`
+ header | value | offset | result
+ ${header} | ${['-a']} | ${0} | ${{ index: 0, direction: SortByDirection.desc }}
+ ${header} | ${['c']} | ${1} | ${{ index: 3, direction: SortByDirection.asc }}
+ ${undefined} | ${undefined} | ${undefined} | ${{}}
+ `(
+ 'createSortBy: Should create correct sort for $value and offset $offset',
+ ({ header, value, offset, result }) => {
+ let ret = createSortBy(header, value, offset);
+ expect(ret).toEqual(result);
+ },
+ );
+
+ it.each`
rhea | rhba | rhsa
${1} | ${2} | ${3}
${0} | ${0} | ${0}
${0} | ${5} | ${3}
${1} | ${0} | ${3}
${1} | ${2} | ${0}
- `('createAdvisoriesIcons: Should match advisory icons snapshot for [$rhea, $rhba, $rhsa]', ({rhea, rhba, rhsa}) => {
- const {container} = render(createAdvisoriesIcons([rhea, rhba, rhsa]))
- expect(container).toMatchSnapshot();
- });
-
- it.each`
+ `(
+ 'createAdvisoriesIcons: Should match advisory icons snapshot for [$rhea, $rhba, $rhsa]',
+ ({ rhea, rhba, rhsa }) => {
+ const { container } = render(createAdvisoriesIcons([rhea, rhba, rhsa]));
+ expect(container).toMatchSnapshot();
+ },
+ );
+
+ it.each`
severity | result
- ${123} | ${"None"}
- ${0} | ${"None"}
- ${1} | ${"Low"}
- ${2} | ${"Moderate"}
- ${3} | ${"Important"}
- ${4} | ${"Critical"}
- `('getSeverityByValue: Should match $severity to value $result', ({severity, result}) => {
- expect(getSeverityByValue(severity).label).toEqual(result);
- });
-
- it('addOrRemoveItemFromSet: Should create correct object ', () => {
- let inputArr = [
- {
- rowId: 0,
- value: 'a'
- },
- {
- rowId: 1,
- value: 'b'
- },
- {
- rowId: 2,
- value: 'c'
- },
- {
- rowId: 3,
- value: 'd'
- },
- {
- rowId: 5,
- value: undefined
- }
- ];
- let targetObj = {'4': 'e'};
- let expected = {'0': 'a', '1': 'b', '2': 'c', '3': 'd', '4': 'e'};
- let ret = addOrRemoveItemFromSet(targetObj, inputArr);
-
- expect(ret).toEqual(expected);
- });
-
- it('convertLimitOffset: Should get correct limit and offset', () => {
- let ret = convertLimitOffset(50, 1100);
- let expected = [23, 50];
-
- expect(ret).toEqual(expected);
- });
-
- it('getRowIdByIndexExpandable: Should return correct id', () => {
- let inputArr = [
- {
- id: 0,
- value: 'a'
- },
- {
- id: 1,
- value: 'b'
- },
- {
- id: 2,
- value: 'c'
- },
- {
- id: 3,
- value: 'd'
- }
- ];
- let ret = getRowIdByIndexExpandable(inputArr, 2);
- let expected = 1;
-
- expect(ret).toEqual(expected);
- });
-
- it('handlePatchLink: Get advisory link from inventory', () => {
- delete global.window.location;
- global.window.location = {
- href: 'https://cloud.redhat.com/insights/inventory'
- };
- const host = document.baseURI;
- let advisoryName = 'ABCD';
- const expected = `${host}insights/patch/advisories/${advisoryName}`;
- let result = handlePatchLink('advisories', advisoryName);
- let {
- props: {href, children}
- } = result;
- expect(href).toEqual(expected);
- expect(children).toEqual(advisoryName);
- });
-
- it('handlePatchLink: Get advisory link from inventory with custom text', () => {
- delete global.window.location;
- global.window.location = {
- href: 'https://cloud.redhat.com/insights/inventory'
- };
- const host = document.baseURI;
- let advisoryName = 'ABCD';
- const expected = `${host}insights/patch/advisories/${advisoryName}`;
- let result = handlePatchLink('advisories', advisoryName, 'custom text');
- let {
- props: {href, children}
- } = result;
- expect(href).toEqual(expected);
- expect(children).toEqual('custom text');
- });
-
- it('handlePatchLink: Get advisory link from patch', () => {
- delete global.window.location;
- global.window.location = {
- href: 'https://cloud.redhat.com/rhel/patch'
- };
- let advisoryName = 'ABCD';
- const expected = `/advisories/${advisoryName}`;
- let result = handlePatchLink('advisories', advisoryName);
- let {
- props: {to, children}
- } = result;
- expect(to).toEqual(expected);
- expect(children).toEqual(advisoryName);
- });
-
- it('handlePatchLink: Get advisory link from patch', () => {
- delete global.window.location;
- global.window.location = {
- href: 'https://cloud.redhat.com/rhel/patch'
- };
- let advisoryName = 'ABCD';
- const expected = `/advisories/${advisoryName}`;
- let result = handlePatchLink('advisories', advisoryName, 'custom text');
- let {
- props: {to, children}
- } = result;
- expect(to).toEqual(expected);
- expect(children).toEqual('custom text');
- });
-
- it('getLimitFromPageSize: Should get correct Limit', () => {
- let limit = Math.random();
- let result = getLimitFromPageSize(limit);
- expect(result).toEqual(limit);
- });
-
- it('getOffsetFromPageLimit: Should get correct offset', () => {
- let page = Math.random() * 10;
- let limit = Math.random() * 10;
- let result = getOffsetFromPageLimit(page, limit);
- expect(result).toEqual(page * limit - limit);
- });
-
- it('arrayFromObj: Should create correct array', () => {
- let items = {a: "value1", b: false, c: "value2"}
- let expected = ["value1", "value2"]
- let result = arrayFromObj(items);
- expect(result).toEqual(expected);
- });
-
- it.each`
- issues | systems | identifier | result
- ${["issue-1"]} | ${["system-1"]} | ${remediationIdentifiers.advisory} | ${{
- issues: [{
- id: "patch-advisory:issue-1",
- description: "issue-1"
- }], systems: ["system-1"]
- }}
- ${"issue-1"} | ${"system-1"} | ${remediationIdentifiers.package} | ${{
- issues: [{
- id: "patch-package:issue-1",
- description: "issue-1"
- }], systems: ["system-1"]
- }}
- ${[]} | ${["system-1"]} | ${remediationIdentifiers.package} | ${false}
- `('remediationProvider: Should create correct remediation object for $issues $systems', ({
- issues,
- systems,
- identifier,
- result
- }) => {
- expect(remediationProvider(issues, systems, identifier)).toEqual(result);
- });
+ ${123} | ${'None'}
+ ${0} | ${'None'}
+ ${1} | ${'Low'}
+ ${2} | ${'Moderate'}
+ ${3} | ${'Important'}
+ ${4} | ${'Critical'}
+ `('getSeverityByValue: Should match $severity to value $result', ({ severity, result }) => {
+ expect(getSeverityByValue(severity).label).toEqual(result);
+ });
+
+ it('addOrRemoveItemFromSet: Should create correct object ', () => {
+ let inputArr = [
+ {
+ rowId: 0,
+ value: 'a',
+ },
+ {
+ rowId: 1,
+ value: 'b',
+ },
+ {
+ rowId: 2,
+ value: 'c',
+ },
+ {
+ rowId: 3,
+ value: 'd',
+ },
+ {
+ rowId: 5,
+ value: undefined,
+ },
+ ];
+ let targetObj = { 4: 'e' };
+ let expected = { 0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e' };
+ let ret = addOrRemoveItemFromSet(targetObj, inputArr);
+
+ expect(ret).toEqual(expected);
+ });
+
+ it('convertLimitOffset: Should get correct limit and offset', () => {
+ let ret = convertLimitOffset(50, 1100);
+ let expected = [23, 50];
+
+ expect(ret).toEqual(expected);
+ });
+
+ it('getRowIdByIndexExpandable: Should return correct id', () => {
+ let inputArr = [
+ {
+ id: 0,
+ value: 'a',
+ },
+ {
+ id: 1,
+ value: 'b',
+ },
+ {
+ id: 2,
+ value: 'c',
+ },
+ {
+ id: 3,
+ value: 'd',
+ },
+ ];
+ let ret = getRowIdByIndexExpandable(inputArr, 2);
+ let expected = 1;
- it.each`
- category | key | result
- ${"public_date"} | ${"last7"} | ${publicDateOptions[0]}
- ${"public_date"} | ${"random value"} | ${{apiValue: "random value"}}
- ${undefined} | ${"last7"} | ${{"apiValue": "last7"}}
- `('getFilterValue: Should create object for $category', ({category, key, result}) => {
- expect(getFilterValue(category, key)).toEqual(result);
- });
+ expect(ret).toEqual(expected);
+ });
- it.each`
- parameters | shouldTranslate | result
- ${{search: "trolo"}} | ${true} | ${"?search=trolo"}
- ${{search: ""}} | ${true} | ${"?"}
- ${{filter: {advisory_type: 2}}} | ${false} | ${"?filter%5Badvisory_type%5D=2"}
- ${{filter: {advisory_type: [1, 2]}}} | ${true} | ${"?filter%5Badvisory_type%5D=in%3A1%2C2"}
+ it('handlePatchLink: Get advisory link from inventory', () => {
+ delete global.window.location;
+ global.window.location = {
+ href: 'https://cloud.redhat.com/insights/inventory',
+ };
+ const host = document.baseURI;
+ let advisoryName = 'ABCD';
+ const expected = `${host}insights/patch/advisories/${advisoryName}`;
+ let result = handlePatchLink('advisories', advisoryName);
+ let {
+ props: { href, children },
+ } = result;
+ expect(href).toEqual(expected);
+ expect(children).toEqual(advisoryName);
+ });
+
+ it('handlePatchLink: Get advisory link from inventory with custom text', () => {
+ delete global.window.location;
+ global.window.location = {
+ href: 'https://cloud.redhat.com/insights/inventory',
+ };
+ const host = document.baseURI;
+ let advisoryName = 'ABCD';
+ const expected = `${host}insights/patch/advisories/${advisoryName}`;
+ let result = handlePatchLink('advisories', advisoryName, 'custom text');
+ let {
+ props: { href, children },
+ } = result;
+ expect(href).toEqual(expected);
+ expect(children).toEqual('custom text');
+ });
+
+ it('handlePatchLink: Get advisory link from patch', () => {
+ delete global.window.location;
+ global.window.location = {
+ href: 'https://cloud.redhat.com/rhel/patch',
+ };
+ let advisoryName = 'ABCD';
+ const expected = `/advisories/${advisoryName}`;
+ let result = handlePatchLink('advisories', advisoryName);
+ let {
+ props: { to, children },
+ } = result;
+ expect(to).toEqual(expected);
+ expect(children).toEqual(advisoryName);
+ });
+
+ it('handlePatchLink: Get advisory link from patch', () => {
+ delete global.window.location;
+ global.window.location = {
+ href: 'https://cloud.redhat.com/rhel/patch',
+ };
+ let advisoryName = 'ABCD';
+ const expected = `/advisories/${advisoryName}`;
+ let result = handlePatchLink('advisories', advisoryName, 'custom text');
+ let {
+ props: { to, children },
+ } = result;
+ expect(to).toEqual(expected);
+ expect(children).toEqual('custom text');
+ });
+
+ it('getLimitFromPageSize: Should get correct Limit', () => {
+ let limit = Math.random();
+ let result = getLimitFromPageSize(limit);
+ expect(result).toEqual(limit);
+ });
+
+ it('getOffsetFromPageLimit: Should get correct offset', () => {
+ let page = Math.random() * 10;
+ let limit = Math.random() * 10;
+ let result = getOffsetFromPageLimit(page, limit);
+ expect(result).toEqual(page * limit - limit);
+ });
+
+ it('arrayFromObj: Should create correct array', () => {
+ let items = { a: 'value1', b: false, c: 'value2' };
+ let expected = ['value1', 'value2'];
+ let result = arrayFromObj(items);
+ expect(result).toEqual(expected);
+ });
+
+ it.each`
+ issues | systems | identifier | result
+ ${['issue-1']} | ${['system-1']} | ${remediationIdentifiers.advisory} | ${{
+ issues: [
+ {
+ id: 'patch-advisory:issue-1',
+ description: 'issue-1',
+ },
+ ],
+ systems: ['system-1'],
+}}
+ ${'issue-1'} | ${'system-1'} | ${remediationIdentifiers.package} | ${{
+ issues: [
+ {
+ id: 'patch-package:issue-1',
+ description: 'issue-1',
+ },
+ ],
+ systems: ['system-1'],
+}}
+ ${[]} | ${['system-1']} | ${remediationIdentifiers.package} | ${false}
+ `(
+ 'remediationProvider: Should create correct remediation object for $issues $systems',
+ ({ issues, systems, identifier, result }) => {
+ expect(remediationProvider(issues, systems, identifier)).toEqual(result);
+ },
+ );
+
+ it.each`
+ category | key | result
+ ${'public_date'} | ${'last7'} | ${publicDateOptions[0]}
+ ${'public_date'} | ${'random value'} | ${{ apiValue: 'random value' }}
+ ${undefined} | ${'last7'} | ${{ apiValue: 'last7' }}
+ `('getFilterValue: Should create object for $category', ({ category, key, result }) => {
+ expect(getFilterValue(category, key)).toEqual(result);
+ });
+
+ it.each`
+ parameters | shouldTranslate | result
+ ${{ search: 'trolo' }} | ${true} | ${'?search=trolo'}
+ ${{ search: '' }} | ${true} | ${'?'}
+ ${{ filter: { advisory_type: 2 } }} | ${false} | ${'?filter%5Badvisory_type%5D=2'}
+ ${{ filter: { advisory_type: [1, 2] } }} | ${true} | ${'?filter%5Badvisory_type%5D=in%3A1%2C2'}
${{
- filter: {advisory_type: [1, 2]},
- param: "text"
- }} | ${true} | ${"?param=text&filter%5Badvisory_type%5D=in%3A1%2C2"}
- `('encodeParams: Should encode parameters $parameters', ({parameters, shouldTranslate, result}) => {
- expect(encodeParams(parameters, shouldTranslate)).toEqual(result);
- });
-
- it.each`
- parameters | result
- ${"search=trolo"} | ${{search: "trolo"}}
- ${"filter%5Badvisory_type%5D=2"} | ${{filter: {advisory_type: 2}}}
- ${"param=text&filter%5Badvisory_type%5D=in%3A1%2C2"} | ${{filter: {advisory_type: ["1", "2"]}, param: "text"}}
- `('decodeQueryparams: Should decodeQueryParams $parameters', ({parameters, result}) => {
- expect(decodeQueryparams(parameters)).toEqual(result);
- });
-
- it.each`
- filters | search | result
- ${{advisory_type_name: 'bugfix'}} | ${undefined} | ${[{
- "category": "Advisory type",
- "chips": [{"id": 'bugfix', "name": "Bugfix", "value": 'bugfix'}],
- "id": "advisory_type_name"
- }]}
- ${undefined} | ${"firefox"} | ${[{
- "category": "Search",
- "chips": [{"name": "firefox", "value": "firefox"}],
- "id": "search"
- }]}
- `('buildFilterChips: Should build correct filter chip, $filters, $search ', ({filters, search, result}) => {
- expect(buildFilterChips(filters, search)).toEqual(result);
- });
-
- it.each`
- oldParams | newParams | result
- ${{param: "Hey!"}} | ${{param: "Yo!"}} | ${{param: "Yo!"}}
- ${{offset: 15}} | ${{limit: 100}} | ${{"limit": 100, "offset": 0}}
- ${{filter: {advisory_type: 2}}} | ${{filter: {public_date: "last7"}}} | ${{
- filter: {
- advisory_type: 2,
- public_date: "last7"
- }, offset: 0
- }}
- `('changeListParams: Should return correct parameters', ({oldParams, newParams, result}) => {
- expect(changeListParams(oldParams, newParams)).toEqual(result);
- });
-
- it.each`
- parameters | result
- ${{filter: {advisory_type: 2}}} | ${"?filter%5Badvisory_type%5D=2"}
- ${{filter: {advisory_type: 1}, id: 15}} | ${"?filter%5Badvisory_type%5D=1"}
- `('encodeURLParams: Should return correct string for $parameters', ({parameters, result}) => {
- expect(encodeURLParams(parameters)).toEqual(result);
- });
-
- it.each`
- parameters | result
- ${{filter: {advisory_type: 2}}} | ${"?filter%5Badvisory_type%5D=2"}
- ${{filter: {advisory_type: 1}, id: 15}} | ${"?id=15&filter%5Badvisory_type%5D=1"}
- `('encodeApiParams: Should return correct string for $parameters', ({parameters, result}) => {
- expect(encodeApiParams(parameters)).toEqual(result);
- });
-
- it.each`
- selectedItems | currentItems | result
- ${{id: "a", selected: true}} | ${{c: true, d: false}} | ${{"a": true, "c": true}}
- ${{id: "a", selected: true}} | ${{c: undefined, d: true}} | ${{"a": true, "d": true}}
- ${{id: "a", selected: true}} | ${{c: '', d: true}} | ${{"a": true, "d": true}}
- `('getNewSelectedItems: Should return new set of selected items', ({selectedItems, currentItems, result}) => {
- expect(getNewSelectedItems(selectedItems, currentItems)).toEqual(result);
- });
-
- it('Should return "false" when there is no issues available', () => {
- const resultWhenParams = transformPairs({data: {}});
- expect(resultWhenParams).toEqual({"issues": []});
-
- const resultWhenNoParams = transformPairs();
- expect(resultWhenNoParams).toEqual({"issues": []});
- });
- it('Should return transformed issues', () => {
- const resultWhenParams = transformPairs({
- data: {
- testAdvisory1: ['test-system-1'],
- testAdvisory2: ['test-system-2']
- }
- }, 'test-identifier');
- expect(resultWhenParams).toEqual({
- issues: [
- {description: 'testAdvisory1', id: 'test-identifier:testAdvisory1', systems: ['test-system-1']},
- {description: 'testAdvisory2', id: 'test-identifier:testAdvisory2', systems: ['test-system-2']}
- ]
- });
+ filter: { advisory_type: [1, 2] },
+ param: 'text',
+}} | ${true} | ${'?param=text&filter%5Badvisory_type%5D=in%3A1%2C2'}
+ `(
+ 'encodeParams: Should encode parameters $parameters',
+ ({ parameters, shouldTranslate, result }) => {
+ expect(encodeParams(parameters, shouldTranslate)).toEqual(result);
+ },
+ );
+
+ it.each`
+ parameters | result
+ ${'search=trolo'} | ${{ search: 'trolo' }}
+ ${'filter%5Badvisory_type%5D=2'} | ${{ filter: { advisory_type: 2 } }}
+ ${'param=text&filter%5Badvisory_type%5D=in%3A1%2C2'} | ${{ filter: { advisory_type: ['1', '2'] }, param: 'text' }}
+ `('decodeQueryparams: Should decodeQueryParams $parameters', ({ parameters, result }) => {
+ expect(decodeQueryparams(parameters)).toEqual(result);
+ });
+
+ it.each`
+ filters | search | result
+ ${{ advisory_type_name: 'bugfix' }} | ${undefined} | ${[
+ {
+ category: 'Advisory type',
+ chips: [{ id: 'bugfix', name: 'Bugfix', value: 'bugfix' }],
+ id: 'advisory_type_name',
+ },
+]}
+ ${undefined} | ${'firefox'} | ${[
+ {
+ category: 'Search',
+ chips: [{ name: 'firefox', value: 'firefox' }],
+ id: 'search',
+ },
+]}
+ `(
+ 'buildFilterChips: Should build correct filter chip, $filters, $search ',
+ ({ filters, search, result }) => {
+ expect(buildFilterChips(filters, search)).toEqual(result);
+ },
+ );
+
+ it.each`
+ oldParams | newParams | result
+ ${{ param: 'Hey!' }} | ${{ param: 'Yo!' }} | ${{ param: 'Yo!' }}
+ ${{ offset: 15 }} | ${{ limit: 100 }} | ${{ limit: 100, offset: 0 }}
+ ${{ filter: { advisory_type: 2 } }} | ${{ filter: { public_date: 'last7' } }} | ${{
+ filter: {
+ advisory_type: 2,
+ public_date: 'last7',
+ },
+ offset: 0,
+}}
+ `('changeListParams: Should return correct parameters', ({ oldParams, newParams, result }) => {
+ expect(changeListParams(oldParams, newParams)).toEqual(result);
+ });
+
+ it.each`
+ parameters | result
+ ${{ filter: { advisory_type: 2 } }} | ${'?filter%5Badvisory_type%5D=2'}
+ ${{ filter: { advisory_type: 1 }, id: 15 }} | ${'?filter%5Badvisory_type%5D=1'}
+ `('encodeURLParams: Should return correct string for $parameters', ({ parameters, result }) => {
+ expect(encodeURLParams(parameters)).toEqual(result);
+ });
+
+ it.each`
+ parameters | result
+ ${{ filter: { advisory_type: 2 } }} | ${'?filter%5Badvisory_type%5D=2'}
+ ${{ filter: { advisory_type: 1 }, id: 15 }} | ${'?id=15&filter%5Badvisory_type%5D=1'}
+ `('encodeApiParams: Should return correct string for $parameters', ({ parameters, result }) => {
+ expect(encodeApiParams(parameters)).toEqual(result);
+ });
+
+ it.each`
+ selectedItems | currentItems | result
+ ${{ id: 'a', selected: true }} | ${{ c: true, d: false }} | ${{ a: true, c: true }}
+ ${{ id: 'a', selected: true }} | ${{ c: undefined, d: true }} | ${{ a: true, d: true }}
+ ${{ id: 'a', selected: true }} | ${{ c: '', d: true }} | ${{ a: true, d: true }}
+ `(
+ 'getNewSelectedItems: Should return new set of selected items',
+ ({ selectedItems, currentItems, result }) => {
+ expect(getNewSelectedItems(selectedItems, currentItems)).toEqual(result);
+ },
+ );
+
+ it('Should return "false" when there is no issues available', () => {
+ const resultWhenParams = transformPairs({ data: {} });
+ expect(resultWhenParams).toEqual({ issues: [] });
+
+ const resultWhenNoParams = transformPairs();
+ expect(resultWhenNoParams).toEqual({ issues: [] });
+ });
+ it('Should return transformed issues', () => {
+ const resultWhenParams = transformPairs(
+ {
+ data: {
+ testAdvisory1: ['test-system-1'],
+ testAdvisory2: ['test-system-2'],
+ },
+ },
+ 'test-identifier',
+ );
+ expect(resultWhenParams).toEqual({
+ issues: [
+ {
+ description: 'testAdvisory1',
+ id: 'test-identifier:testAdvisory1',
+ systems: ['test-system-1'],
+ },
+ {
+ description: 'testAdvisory2',
+ id: 'test-identifier:testAdvisory2',
+ systems: ['test-system-2'],
+ },
+ ],
});
+ });
- test("templateDateFormat function should correctly parse dates", () => {
- expect(templateDateFormat("2023-03-05")).toEqual("05 Mar 2023");
- expect(templateDateFormat("2023-03-22T20:00:00-04:00")).toEqual("23 Mar 2023");
- expect(templateDateFormat("2023-03-22T20:00:00-00:00")).toEqual("22 Mar 2023");
- expect(templateDateFormat("2023-03-22T20:00:00+04:00")).toEqual("22 Mar 2023");
- expect(templateDateFormat("2023-03-22T20:00:00Z")).toEqual("22 Mar 2023");
- });
+ test('templateDateFormat function should correctly parse dates', () => {
+ expect(templateDateFormat('2023-03-05')).toEqual('05 Mar 2023');
+ expect(templateDateFormat('2023-03-22T20:00:00-04:00')).toEqual('23 Mar 2023');
+ expect(templateDateFormat('2023-03-22T20:00:00-00:00')).toEqual('22 Mar 2023');
+ expect(templateDateFormat('2023-03-22T20:00:00+04:00')).toEqual('22 Mar 2023');
+ expect(templateDateFormat('2023-03-22T20:00:00Z')).toEqual('22 Mar 2023');
+ });
});
describe('Test global filters', () => {
-
- it.each`
- tags | SIDs | workloads | result
- ${[]} | ${[]} | ${{'Ansible Automation Platform': {isSelected: true}}} | ${{
- selectedTags: [],
- systemProfile: {ansible: {controller_version: 'not_nil'}}
- }}
- ${[]} | ${[]} | ${{'Microsoft SQL': {isSelected: true}}} | ${{
- selectedTags: [],
- systemProfile: {mssql: {version: 'not_nil'}}
- }}
- ${[]} | ${[]} | ${{SAP: {isSelected: true}}} | ${{
- selectedTags: [],
- systemProfile: {sap_system: true}
- }}
- ${[]} | ${['abc']} | ${{SAP: {isSelected: true}}} | ${{
- selectedTags: [],
- systemProfile: {sap_sids: ['abc'], sap_system: true}
- }}
- ${[]} | ${['abc', 'bca']} | ${{
- SAP: {isSelected: true},
- 'Microsoft SQL': {isSelected: true}
- }} | ${{
- selectedTags: [],
- systemProfile: {sap_sids: ['abc', 'bca'], sap_system: true, mssql: {version: 'not_nil'}}
- }}
- ${['null/key.BnZPeP=tag.MNGmxQ']} | ${['abc', 'bca']} | ${{SAP: {isSelected: true}}} | ${{
- selectedTags: ["tags=null%2Fkey.BnZPeP%3Dtag.MNGmxQ"],
- systemProfile: {sap_sids: ['abc', 'bca'], sap_system: true}
- }}
- `('mapGlobalFilters: Should build correct global filters, $tags, $SIDs, $workloads ', ({
- tags,
- SIDs,
- workloads,
- result
- }) => {
- expect(mapGlobalFilters(tags, SIDs, workloads,)).toEqual(result);
- });
-})
+ it.each`
+ tags | SIDs | workloads | result
+ ${[]} | ${[]} | ${{ 'Ansible Automation Platform': { isSelected: true } }} | ${{
+ selectedTags: [],
+ systemProfile: { ansible: { controller_version: 'not_nil' } },
+}}
+ ${[]} | ${[]} | ${{ 'Microsoft SQL': { isSelected: true } }} | ${{
+ selectedTags: [],
+ systemProfile: { mssql: { version: 'not_nil' } },
+}}
+ ${[]} | ${[]} | ${{ SAP: { isSelected: true } }} | ${{
+ selectedTags: [],
+ systemProfile: { sap_system: true },
+}}
+ ${[]} | ${['abc']} | ${{ SAP: { isSelected: true } }} | ${{
+ selectedTags: [],
+ systemProfile: { sap_sids: ['abc'], sap_system: true },
+}}
+ ${[]} | ${['abc', 'bca']} | ${{
+ SAP: { isSelected: true },
+ 'Microsoft SQL': { isSelected: true },
+}} | ${{
+ selectedTags: [],
+ systemProfile: { sap_sids: ['abc', 'bca'], sap_system: true, mssql: { version: 'not_nil' } },
+}}
+ ${['null/key.BnZPeP=tag.MNGmxQ']} | ${['abc', 'bca']} | ${{ SAP: { isSelected: true } }} | ${{
+ selectedTags: ['tags=null%2Fkey.BnZPeP%3Dtag.MNGmxQ'],
+ systemProfile: { sap_sids: ['abc', 'bca'], sap_system: true },
+}}
+ `(
+ 'mapGlobalFilters: Should build correct global filters, $tags, $SIDs, $workloads ',
+ ({ tags, SIDs, workloads, result }) => {
+ expect(mapGlobalFilters(tags, SIDs, workloads)).toEqual(result);
+ },
+ );
+});
/* eslint-enable */
describe('persistantParams', () => {
- it('should translate descoded desc group sort parameter correctly', () => {
- expect(persistantParams({}, { sort: '-groups' })).toEqual({
- page: 1,
- perPage: 20,
- sortBy: {
- key: 'group_name',
- direction: 'desc'
- }
- });
- });
-
- it('should translate descoded asc group sort parameter correctly', () => {
- expect(persistantParams({}, { sort: 'groups' })).toEqual({
- page: 1,
- perPage: 20,
- sortBy: {
- key: 'group_name',
- direction: 'asc'
- }
- });
- });
-
- it('should translate other descoded desc sort parameter correctly', () => {
- expect(persistantParams({}, { sort: '-abc' })).toEqual({
- page: 1,
- perPage: 20,
- sortBy: {
- key: 'abc',
- direction: 'desc'
- }
- });
- });
-
- it('should translate other descoded asc sort parameter correctly', () => {
- expect(persistantParams({}, { sort: 'abc' })).toEqual({
- page: 1,
- perPage: 20,
- sortBy: {
- key: 'abc',
- direction: 'asc'
- }
- });
- });
+ it('should translate descoded desc group sort parameter correctly', () => {
+ expect(persistantParams({}, { sort: '-groups' })).toEqual({
+ page: 1,
+ perPage: 20,
+ sortBy: {
+ key: 'group_name',
+ direction: 'desc',
+ },
+ });
+ });
+
+ it('should translate descoded asc group sort parameter correctly', () => {
+ expect(persistantParams({}, { sort: 'groups' })).toEqual({
+ page: 1,
+ perPage: 20,
+ sortBy: {
+ key: 'group_name',
+ direction: 'asc',
+ },
+ });
+ });
+
+ it('should translate other descoded desc sort parameter correctly', () => {
+ expect(persistantParams({}, { sort: '-abc' })).toEqual({
+ page: 1,
+ perPage: 20,
+ sortBy: {
+ key: 'abc',
+ direction: 'desc',
+ },
+ });
+ });
+
+ it('should translate other descoded asc sort parameter correctly', () => {
+ expect(persistantParams({}, { sort: 'abc' })).toEqual({
+ page: 1,
+ perPage: 20,
+ sortBy: {
+ key: 'abc',
+ direction: 'asc',
+ },
+ });
+ });
});
describe('buildApiFilters', () => {
- const patchFilters = {
- patchFilter: 'value'
- };
-
- it('combines patch and inventory filters into API params', () => {
- const inventoryFilters = {
- inventoryFilter: 'inventoryValue'
- };
- expect(buildApiFilters(
- patchFilters,
- inventoryFilters
- )).toEqual({
- ...patchFilters
- });
- });
+ const patchFilters = {
+ patchFilter: 'value',
+ };
- it('adds a group_name filter when the inventory is filtered by a hostGroup', () => {
- const hostGroupFilter = ['groupFilterValue'];
- const inventoryFilters = {
- hostGroupFilter
- };
- expect(buildApiFilters(
- patchFilters,
- inventoryFilters
- ).group_name).toEqual(hostGroupFilter);
+ it('combines patch and inventory filters into API params', () => {
+ const inventoryFilters = {
+ inventoryFilter: 'inventoryValue',
+ };
+ expect(buildApiFilters(patchFilters, inventoryFilters)).toEqual({
+ ...patchFilters,
});
+ });
- it('adds a os filter when the inventory is filtered by OS', () => {
- const osFilter = {
- 'RHEL-8': {
- 'RHEL-8-8.8': true,
- 'RHEL-8-8.9': true
- }
- };
- const inventoryFilters = {
- osFilter
- };
- expect(buildApiFilters(
- patchFilters,
- inventoryFilters
- ).os).toEqual('RHEL 8.8,RHEL 8.9');
- });
+ it('adds a group_name filter when the inventory is filtered by a hostGroup', () => {
+ const hostGroupFilter = ['groupFilterValue'];
+ const inventoryFilters = {
+ hostGroupFilter,
+ };
+ expect(buildApiFilters(patchFilters, inventoryFilters).group_name).toEqual(hostGroupFilter);
+ });
+
+ it('adds a os filter when the inventory is filtered by OS', () => {
+ const osFilter = {
+ 'RHEL-8': {
+ 'RHEL-8-8.8': true,
+ 'RHEL-8-8.9': true,
+ },
+ };
+ const inventoryFilters = {
+ osFilter,
+ };
+ expect(buildApiFilters(patchFilters, inventoryFilters).os).toEqual('RHEL 8.8,RHEL 8.9');
+ });
});
diff --git a/src/Utilities/IntlProvider.js b/src/Utilities/IntlProvider.js
index 6509d8c53..edac0b760 100644
--- a/src/Utilities/IntlProvider.js
+++ b/src/Utilities/IntlProvider.js
@@ -3,10 +3,12 @@ import { createIntl, createIntlCache } from 'react-intl';
const cache = createIntlCache();
const locale = navigator.language.slice(0, 2);
-export const intl = createIntl({
- // eslint-disable-next-line no-console
+export const intl = createIntl(
+ {
onError: console.log,
- locale
-}, cache);
+ locale,
+ },
+ cache,
+);
export const intlSettings = { locale };
diff --git a/src/Utilities/NavigateToSystem.js b/src/Utilities/NavigateToSystem.js
index 7ad0983e7..cefa26eb0 100644
--- a/src/Utilities/NavigateToSystem.js
+++ b/src/Utilities/NavigateToSystem.js
@@ -2,9 +2,7 @@ import React from 'react';
import { Navigate, useParams } from 'react-router-dom';
export const NavigateToSystem = () => {
- const { inventoryId } = useParams();
+ const { inventoryId } = useParams();
- return (
-
- );
+ return ;
};
diff --git a/src/Utilities/RawDataForTesting.js b/src/Utilities/RawDataForTesting.js
index 0faf478b3..4a31d070a 100644
--- a/src/Utilities/RawDataForTesting.js
+++ b/src/Utilities/RawDataForTesting.js
@@ -1,36 +1,41 @@
// raw data for testing purposes only
-export const advisoryRows = [{
+export const advisoryRows = [
+ {
attributes: {
- advisory_type: 1,
- advisory_type_name: 'enhancement',
- applicable_systems: 1,
- description: 'The microcode_ctl ',
- public_date: '2020-06-24T17:22:25Z',
- reboot_required: true,
- synopsis: 'microcode_ctl',
- severity: 3
+ advisory_type: 1,
+ advisory_type_name: 'enhancement',
+ applicable_systems: 1,
+ description: 'The microcode_ctl ',
+ public_date: '2020-06-24T17:22:25Z',
+ reboot_required: true,
+ synopsis: 'microcode_ctl',
+ severity: 3,
},
id: 'RHEA-2020:2743',
- type: 'advisory'
-}];
+ type: 'advisory',
+ },
+];
-export const systemAdvisoryRows = [{
+export const systemAdvisoryRows = [
+ {
attributes: {
- advisory_type: 3,
- advisory_type_name: 'security',
- description: 'Kernel-based Virtual.',
- public_date: '2020-06-30T13:38:53Z',
- severity: 3,
- synopsis: 'Important',
- reboot_required: true,
- status: 'Installable'
+ advisory_type: 3,
+ advisory_type_name: 'security',
+ description: 'Kernel-based Virtual.',
+ public_date: '2020-06-30T13:38:53Z',
+ severity: 3,
+ synopsis: 'Important',
+ reboot_required: true,
+ status: 'Installable',
},
id: 'RHSA-2020:2774',
- type: 'advisory'
-}];
+ type: 'advisory',
+ },
+];
-export const systemRows = [{
+export const systemRows = [
+ {
id: 'test-system-id-1',
created: '2021-06-05T09:03:09.154453Z',
culled_timestamp: '2021-06-20T14:03:09.096101Z',
@@ -51,9 +56,9 @@ export const systemRows = [{
stale: false,
stale_timestamp: '2021-06-06T14:03:09.096101Z',
stale_warning_timestamp: '2021-06-13T14:03:09.096101Z',
- third_party: true
-},
-{
+ third_party: true,
+ },
+ {
id: 'test-system-id-2',
created: '2021-06-05T09:03:09.154453Z',
culled_timestamp: '2021-06-20T14:03:09.096101Z',
@@ -74,43 +79,45 @@ export const systemRows = [{
stale: false,
stale_timestamp: '2021-06-06T14:03:09.096101Z',
stale_warning_timestamp: '2021-06-13T14:03:09.096101Z',
- third_party: true
-}];
+ third_party: true,
+ },
+];
export const advisoryHeader = {
- attributes: {
- advisory_type: 3,
- advisory_type_name: 'security',
- description: 'Kernel-based Virtual.',
- public_date: '2020-06-30T13:38:53Z',
- modified_date: '2020-06-30T13:38:53Z',
- severity: 3,
- synopsis: 'Important'
- },
- id: 'RHSA-2020:2774',
- type: 'advisory'
+ attributes: {
+ advisory_type: 3,
+ advisory_type_name: 'security',
+ description: 'Kernel-based Virtual.',
+ public_date: '2020-06-30T13:38:53Z',
+ modified_date: '2020-06-30T13:38:53Z',
+ severity: 3,
+ synopsis: 'Important',
+ },
+ id: 'RHSA-2020:2774',
+ type: 'advisory',
};
export const advisoryDetailRows = {
- data: {
- attributes: {
- cves: ['CVE-2020-11080'],
- description: 'libnghttp2.',
- fixes: null,
- modified_date: '2020-06-25T16:31:29Z',
- packages: { libnghttp2: '1.33.0-3.el8_2.1.x86_64' },
- public_date: '2020-06-25T16:31:29Z',
- references: [],
- severity: 3,
- solution: 'For details',
- synopsis: 'Important: ',
- topic: 'An update .'
- }
+ data: {
+ attributes: {
+ cves: ['CVE-2020-11080'],
+ description: 'libnghttp2.',
+ fixes: null,
+ modified_date: '2020-06-25T16:31:29Z',
+ packages: { libnghttp2: '1.33.0-3.el8_2.1.x86_64' },
+ public_date: '2020-06-25T16:31:29Z',
+ references: [],
+ severity: 3,
+ solution: 'For details',
+ synopsis: 'Important: ',
+ topic: 'An update .',
},
- id: 'RHSA-2020:2755',
- type: 'advisory'
+ },
+ id: 'RHSA-2020:2755',
+ type: 'advisory',
};
-export const systemPackages = [{
+export const systemPackages = [
+ {
description: 'This package contains testing data',
evra: 'test-evra',
name: 'test-name',
@@ -118,324 +125,291 @@ export const systemPackages = [{
id: 'test-id-0',
updatable: false,
update_status: 'None',
- updates: [{ evra: 'test-evra' }]
-}];
+ updates: [{ evra: 'test-evra' }],
+ },
+];
export const entityDetail = {
- loaded: true,
- activeApps: [],
- entity: {
- account: '60',
- insights_id: 'test-insights-id'
- }
+ loaded: true,
+ activeApps: [],
+ entity: {
+ account: '60',
+ insights_id: 'test-insights-id',
+ },
};
-export const cveRows = [{
+export const cveRows = [
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29921'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29921',
},
id: 'CVE-2021-29921',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29922'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29922',
},
id: 'CVE-2021-29922',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29923'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29923',
},
id: 'CVE-2021-29923',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29924'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29924',
},
id: 'CVE-2021-29924',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29925'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29925',
},
id: 'CVE-2021-29925',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29926'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29926',
},
id: 'CVE-2021-29926',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29927'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29927',
},
id: 'CVE-2021-29927',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29928'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29928',
},
id: 'CVE-2021-29928',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29929'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29929',
},
id: 'CVE-2021-29929',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29930'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29930',
},
id: 'CVE-2021-29930',
- type: 'cve'
-},
-{
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29931'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29931',
},
id: 'CVE-2021-29931',
- type: 'cve'
-}, {
+ type: 'cve',
+ },
+ {
attributes: {
- cvss_score: '7.300',
- impact: 'Moderate',
- synopsis: 'CVE-2021-29932'
+ cvss_score: '7.300',
+ impact: 'Moderate',
+ synopsis: 'CVE-2021-29932',
},
id: 'CVE-2021-29932',
- type: 'cve'
-}];
+ type: 'cve',
+ },
+];
export const readyCveRows = [
- {
- id: 'CVE-2021-29921',
- key: 'CVE-2021-29921',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29922',
- key: 'CVE-2021-29922',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29923',
- key: 'CVE-2021-29923',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29924',
- key: 'CVE-2021-29924',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29925',
- key: 'CVE-2021-29925',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29926',
- key: 'CVE-2021-29926',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29927',
- key: 'CVE-2021-29927',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29928',
- key: 'CVE-2021-29928',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29929',
- key: 'CVE-2021-29929',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29930',
- key: 'CVE-2021-29930',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29931',
- key: 'CVE-2021-29931',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- },
- {
- id: 'CVE-2021-29932',
- key: 'CVE-2021-29932',
- cells: [{ title: '[Object] ' },
- { title: '[Object]', value: 'Moderate' },
- { title: '7.3' }
- ]
- }
+ {
+ id: 'CVE-2021-29921',
+ key: 'CVE-2021-29921',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29922',
+ key: 'CVE-2021-29922',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29923',
+ key: 'CVE-2021-29923',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29924',
+ key: 'CVE-2021-29924',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29925',
+ key: 'CVE-2021-29925',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29926',
+ key: 'CVE-2021-29926',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29927',
+ key: 'CVE-2021-29927',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29928',
+ key: 'CVE-2021-29928',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29929',
+ key: 'CVE-2021-29929',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29930',
+ key: 'CVE-2021-29930',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29931',
+ key: 'CVE-2021-29931',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
+ {
+ id: 'CVE-2021-29932',
+ key: 'CVE-2021-29932',
+ cells: [{ title: '[Object] ' }, { title: '[Object]', value: 'Moderate' }, { title: '7.3' }],
+ },
];
export const packageDetailData = {
- data: {
- attributes: {
- description: 'testDescription'
- }
- }
+ data: {
+ attributes: {
+ description: 'testDescription',
+ },
+ },
};
export const systemsStoreState = {
- selectedRows: {},
- queryParams: { page: 1, perPage: 20, search: 'testSearch', offset: 0 },
- loaded: true,
- columns: [{ key: 'testCol' }],
- rows: [
- {
- id: 'test-system-id-1',
- created: '2021-06-05T09:03:09.154453Z',
- culled_timestamp: '2021-06-20T14:03:09.096101Z',
- display_name: 'test-system-1',
- insights_id: 'f87cff90-d61a-4f9e-92d4-cdb18f0dd5df',
- last_evaluation: '2021-06-05T09:03:10.698831Z',
- last_upload: '2021-06-07T12:34:18.186723Z',
- os_major: '',
- os_minor: '',
- os_name: '',
- packages_installed: 573,
- packages_updatable: 0,
- rhba_count: 0,
- rhea_count: 0,
- rhsa_count: 0,
- other_count: 0,
- rhsm: '',
- stale: false,
- stale_timestamp: '2021-06-06T14:03:09.096101Z',
- stale_warning_timestamp: '2021-06-13T14:03:09.096101Z',
- third_party: true
- },
- {
- id: 'test-system-id-2',
- created: '2021-06-05T09:03:09.154453Z',
- culled_timestamp: '2021-06-20T14:03:09.096101Z',
- display_name: 'test-system-2',
- insights_id: 'f87cff90-d61a-4f9e-92d4-cdb18f0dd5df',
- last_evaluation: '2021-06-05T09:03:10.698831Z',
- last_upload: '2021-06-07T12:34:18.186723Z',
- os_major: '',
- os_minor: '',
- os_name: '',
- packages_installed: 573,
- packages_updatable: 0,
- rhba_count: 0,
- rhea_count: 0,
- rhsa_count: 0,
- other_count: 0,
- rhsm: '',
- stale: false,
- stale_timestamp: '2021-06-06T14:03:09.096101Z',
- stale_warning_timestamp: '2021-06-13T14:03:09.096101Z',
- third_party: true
- }
- ]
+ selectedRows: {},
+ queryParams: { page: 1, perPage: 20, search: 'testSearch', offset: 0 },
+ loaded: true,
+ columns: [{ key: 'testCol' }],
+ rows: [
+ {
+ id: 'test-system-id-1',
+ created: '2021-06-05T09:03:09.154453Z',
+ culled_timestamp: '2021-06-20T14:03:09.096101Z',
+ display_name: 'test-system-1',
+ insights_id: 'f87cff90-d61a-4f9e-92d4-cdb18f0dd5df',
+ last_evaluation: '2021-06-05T09:03:10.698831Z',
+ last_upload: '2021-06-07T12:34:18.186723Z',
+ os_major: '',
+ os_minor: '',
+ os_name: '',
+ packages_installed: 573,
+ packages_updatable: 0,
+ rhba_count: 0,
+ rhea_count: 0,
+ rhsa_count: 0,
+ other_count: 0,
+ rhsm: '',
+ stale: false,
+ stale_timestamp: '2021-06-06T14:03:09.096101Z',
+ stale_warning_timestamp: '2021-06-13T14:03:09.096101Z',
+ third_party: true,
+ },
+ {
+ id: 'test-system-id-2',
+ created: '2021-06-05T09:03:09.154453Z',
+ culled_timestamp: '2021-06-20T14:03:09.096101Z',
+ display_name: 'test-system-2',
+ insights_id: 'f87cff90-d61a-4f9e-92d4-cdb18f0dd5df',
+ last_evaluation: '2021-06-05T09:03:10.698831Z',
+ last_upload: '2021-06-07T12:34:18.186723Z',
+ os_major: '',
+ os_minor: '',
+ os_name: '',
+ packages_installed: 573,
+ packages_updatable: 0,
+ rhba_count: 0,
+ rhea_count: 0,
+ rhsa_count: 0,
+ other_count: 0,
+ rhsm: '',
+ stale: false,
+ stale_timestamp: '2021-06-06T14:03:09.096101Z',
+ stale_warning_timestamp: '2021-06-13T14:03:09.096101Z',
+ third_party: true,
+ },
+ ],
};
export const packageVersions = {
- data: [
- { evra: '0.0.25-1.el7.noarch' },
- { evra: '0.0.25-4.el8.noarch' }
- ],
- links: {
- first: '/packages/abattis-cantarell-fonts/versions?offset=0\u0026limit=20\u0026sort=evra',
- last: '/packages/abattis-cantarell-fonts/versions?offset=0\u0026limit=20\u0026sort=evra',
- next: null, previous: null },
- meta: { limit: 20, offset: 0, sort: ['evra'], filter: {}, total_items: 2 }
+ data: [{ evra: '0.0.25-1.el7.noarch' }, { evra: '0.0.25-4.el8.noarch' }],
+ links: {
+ first: '/packages/abattis-cantarell-fonts/versions?offset=0\u0026limit=20\u0026sort=evra',
+ last: '/packages/abattis-cantarell-fonts/versions?offset=0\u0026limit=20\u0026sort=evra',
+ next: null,
+ previous: null,
+ },
+ meta: { limit: 20, offset: 0, sort: ['evra'], filter: {}, total_items: 2 },
};
export const patchSets = [
- {
- name: 'test-set-1',
- systems: 1,
- id: 1
- },
- {
- name: 'test-set-2',
- systems: 0,
- id: 2
- },
- {
- name: 'test-set-3',
- systems: 0,
- id: 3
- },
- {
- name: 'test-set-4',
- systems: 0,
- id: 4
- },
- {
- name: 'test-set-5',
- systems: 0,
- id: 5
- }
+ {
+ name: 'test-set-1',
+ systems: 1,
+ id: 1,
+ },
+ {
+ name: 'test-set-2',
+ systems: 0,
+ id: 2,
+ },
+ {
+ name: 'test-set-3',
+ systems: 0,
+ id: 3,
+ },
+ {
+ name: 'test-set-4',
+ systems: 0,
+ id: 4,
+ },
+ {
+ name: 'test-set-5',
+ systems: 0,
+ id: 5,
+ },
];
diff --git a/src/Utilities/RemediationPairs.js b/src/Utilities/RemediationPairs.js
index 958325759..b6f72c65e 100644
--- a/src/Utilities/RemediationPairs.js
+++ b/src/Utilities/RemediationPairs.js
@@ -2,132 +2,114 @@ import chunk from 'lodash/chunk';
const REQUEST_CHUNK_SIZE = 100;
const BATCH_REQUEST_SIZE = 10;
-const REQUEST_INTERVAL = 15000; //15 seconds. AKAMAI allowed life for 5 API calls
-
-const fetchDataCallback = (endpoint, authToken) => (input) => {
- return fetch(`/api/patch/v3/views${endpoint}`, {
- method: 'POST',
- credentials: 'include',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- Authorization: 'Bearer ' + authToken
- },
- body: JSON.stringify(input)
- }).then(result =>
- result.status === 200
- ? result.json()
- : Promise.reject(result.statusText)
- );
-};
-
-export const transformPairs = (input) => {
- return {
- issues: Object.keys(input?.data || {}).map(advisory => {
- return {
- id: `patch-advisory:${advisory}`,
- description: advisory,
- systems: input.data[advisory]
- };
- }
- )
- };
-};
+const REQUEST_INTERVAL = 15000; // 15 seconds. AKAMAI allowed life for 5 API calls
+
+const fetchDataCallback = (endpoint, authToken) => (input) =>
+ fetch(`/api/patch/v3/views${endpoint}`, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ Authorization: 'Bearer ' + authToken,
+ },
+ body: JSON.stringify(input),
+ }).then((result) => (result.status === 200 ? result.json() : Promise.reject(result.statusText)));
+
+export const transformPairs = (input) => ({
+ issues: Object.keys(input?.data || {}).map((advisory) => ({
+ id: `patch-advisory:${advisory}`,
+ description: advisory,
+ systems: input.data[advisory],
+ })),
+});
const transformSystemsPairs = (input) => {
- const pairs = [];
- Object.entries(input.data).map(
- ([systemID, advisories]) => {
- advisories.map(advisory => {
- const pairID = `patch-advisory:${advisory}`;
- const index = pairs.findIndex(pair => pair.id === pairID);
- if (index >= 0) {
- pairs[index].systems.push(systemID);
- } else {
- pairs.push(
- {
- id: pairID,
- description: advisory,
- systems: [systemID]
- }
- );
- }
- });
+ const pairs = [];
+ Object.entries(input.data).map(([systemID, advisories]) => {
+ advisories.map((advisory) => {
+ const pairID = `patch-advisory:${advisory}`;
+ const index = pairs.findIndex((pair) => pair.id === pairID);
+ if (index >= 0) {
+ pairs[index].systems.push(systemID);
+ } else {
+ pairs.push({
+ id: pairID,
+ description: advisory,
+ systems: [systemID],
});
+ }
+ });
+ });
- return { issues: pairs };
+ return { issues: pairs };
};
-const batchRequest = async (
- payload,
- { responseTransformer, dataFetcher, payloadModifier }
-) => {
-
- const payloadChunks = chunk(payload, REQUEST_CHUNK_SIZE);
-
- const paginatedRequest = async (batchIndex, groupChunks) => {
- const requests = [];
- for (let i = 0; i < groupChunks.length; i++) {
- requests.push(
- await dataFetcher({
- ...payloadModifier(payload),
- limit: REQUEST_CHUNK_SIZE,
- offset: ((batchIndex * BATCH_REQUEST_SIZE) + i) * REQUEST_CHUNK_SIZE
- }
- ).then(result => responseTransformer(result))
- );
- }
-
- return requests;
- };
-
- const batchRequests = [];
- for (let i = 0; i < Math.ceil(payloadChunks.length / BATCH_REQUEST_SIZE); i++) {
- batchRequests.push(
- new Promise((resolve, reject) => {
- setTimeout(async () => {
- try {
- const groupChunks = payloadChunks.splice(0, 5);
- resolve(await paginatedRequest(i, groupChunks));
- }
- catch {
- reject('Loading issues failed');
- }
- }, i === 0 ? 0 : REQUEST_INTERVAL);
- })
- );
+const batchRequest = async (payload, { responseTransformer, dataFetcher, payloadModifier }) => {
+ const payloadChunks = chunk(payload, REQUEST_CHUNK_SIZE);
+
+ const paginatedRequest = async (batchIndex, groupChunks) => {
+ const requests = [];
+ for (let i = 0; i < groupChunks.length; i++) {
+ requests.push(
+ await dataFetcher({
+ ...payloadModifier(payload),
+ limit: REQUEST_CHUNK_SIZE,
+ offset: (batchIndex * BATCH_REQUEST_SIZE + i) * REQUEST_CHUNK_SIZE,
+ }).then((result) => responseTransformer(result)),
+ );
}
- return await Promise.all(batchRequests).then(([apiResults] = [[]]) =>
- ({
- status: 'resolved',
- result: apiResults.reduce(
- (prev, current) => ({ issues: prev.issues.concat(current?.issues || []) }),
- { issues: [] })
- })
- ).catch(error => ({
- status: 'rejected',
- error
+ return requests;
+ };
+
+ const batchRequests = [];
+ for (let i = 0; i < Math.ceil(payloadChunks.length / BATCH_REQUEST_SIZE); i++) {
+ batchRequests.push(
+ new Promise((resolve, reject) => {
+ setTimeout(
+ async () => {
+ try {
+ const groupChunks = payloadChunks.splice(0, 5);
+ resolve(await paginatedRequest(i, groupChunks));
+ } catch {
+ reject('Loading issues failed');
+ }
+ },
+ i === 0 ? 0 : REQUEST_INTERVAL,
+ );
+ }),
+ );
+ }
+
+ return await Promise.all(batchRequests)
+ .then(([apiResults] = [[]]) => ({
+ status: 'resolved',
+ result: apiResults.reduce(
+ (prev, current) => ({ issues: prev.issues.concat(current?.issues || []) }),
+ { issues: [] },
+ ),
+ }))
+ .catch((error) => ({
+ status: 'rejected',
+ error,
}));
};
onmessage = async ({ data = {} } = {}) => {
- const { remediationType, areAllSelected, payload = [], authToken } = data;
- const shouldMapSystems = remediationType === 'systems' && !areAllSelected;
+ const { remediationType, areAllSelected, payload = [], authToken } = data;
+ const shouldMapSystems = remediationType === 'systems' && !areAllSelected;
- const endpoint = shouldMapSystems ? '/systems/advisories' : '/advisories/systems';
- const responseTransformer = shouldMapSystems ? transformSystemsPairs : transformPairs;
+ const endpoint = shouldMapSystems ? '/systems/advisories' : '/advisories/systems';
+ const responseTransformer = shouldMapSystems ? transformSystemsPairs : transformPairs;
- const payloadModifier = (payload) => (!areAllSelected ? { [remediationType]: payload } : {});
+ const payloadModifier = (payload) => (!areAllSelected ? { [remediationType]: payload } : {});
- const result = await batchRequest(
- payload,
- {
- dataFetcher: fetchDataCallback(endpoint, authToken),
- payloadModifier,
- responseTransformer
- }
- );
+ const result = await batchRequest(payload, {
+ dataFetcher: fetchDataCallback(endpoint, authToken),
+ payloadModifier,
+ responseTransformer,
+ });
- postMessage(result);
+ postMessage(result);
};
diff --git a/src/Utilities/SystemHelpers.test.js b/src/Utilities/SystemHelpers.test.js
index 1a9d8caf1..404c90ea9 100644
--- a/src/Utilities/SystemHelpers.test.js
+++ b/src/Utilities/SystemHelpers.test.js
@@ -1,126 +1,117 @@
import { createSystemsSortBy, mergeInventoryColumns } from './SystemsHelpers';
describe('createSystemsSortBy,', () => {
- it('should translate main parameters', () => {
- expect(createSystemsSortBy('abc', 'ASC', undefined)).toEqual('abc');
- expect(createSystemsSortBy('abc', 'DESC', undefined)).toEqual('-abc');
- });
+ it('should translate main parameters', () => {
+ expect(createSystemsSortBy('abc', 'ASC', undefined)).toEqual('abc');
+ expect(createSystemsSortBy('abc', 'DESC', undefined)).toEqual('-abc');
+ });
- it('should translate group name parameter', () => {
- expect(createSystemsSortBy('group_name', 'ASC', undefined)).toEqual(
- 'groups'
- );
- expect(createSystemsSortBy('group_name', 'DESC', undefined)).toEqual(
- '-groups'
- );
- });
+ it('should translate group name parameter', () => {
+ expect(createSystemsSortBy('group_name', 'ASC', undefined)).toEqual('groups');
+ expect(createSystemsSortBy('group_name', 'DESC', undefined)).toEqual('-groups');
+ });
- it('should translate updated parameter', () => {
- expect(createSystemsSortBy('updated', 'ASC', false)).toEqual(
- 'last_upload'
- );
- expect(createSystemsSortBy('updated', 'DESC', false)).toEqual(
- '-last_upload'
- );
- });
+ it('should translate updated parameter', () => {
+ expect(createSystemsSortBy('updated', 'ASC', false)).toEqual('last_upload');
+ expect(createSystemsSortBy('updated', 'DESC', false)).toEqual('-last_upload');
+ });
- it('should translate updated parameter while having last upload', () => {
- expect(createSystemsSortBy('updated', 'ASC', true)).toEqual(
- 'os'
- );
- expect(createSystemsSortBy('updated', 'DESC', true)).toEqual(
- '-os'
- );
- });
+ it('should translate updated parameter while having last upload', () => {
+ expect(createSystemsSortBy('updated', 'ASC', true)).toEqual('os');
+ expect(createSystemsSortBy('updated', 'DESC', true)).toEqual('-os');
+ });
});
describe('mergeInventoryColumns', () => {
- it('should merge basic columns correctly', () => {
- const patchColumns = [
- {
- key: 'display_name'
- },
- {
- key: 'package_count',
- title: 'Package count'
- }
- ];
+ it('should merge basic columns correctly', () => {
+ const patchColumns = [
+ {
+ key: 'display_name',
+ },
+ {
+ key: 'package_count',
+ title: 'Package count',
+ },
+ ];
- const inventoryColumns = [
- {
- key: 'display_name',
- title: 'Display name'
- }
- ];
+ const inventoryColumns = [
+ {
+ key: 'display_name',
+ title: 'Display name',
+ },
+ ];
- expect(mergeInventoryColumns(patchColumns, inventoryColumns))
- .toMatchObject([{
- key: 'display_name',
- title: 'Display name'
- },
- {
- key: 'package_count',
- title: 'Package count'
- }]);
- });
+ expect(mergeInventoryColumns(patchColumns, inventoryColumns)).toMatchObject([
+ {
+ key: 'display_name',
+ title: 'Display name',
+ },
+ {
+ key: 'package_count',
+ title: 'Package count',
+ },
+ ]);
+ });
- it('should merge modified columns correctly', () => {
- const patchColumns = [
- {
- key: 'display_name',
- title: 'Name'
- },
- {
- key: 'package_count',
- title: 'Package count'
- }
- ];
+ it('should merge modified columns correctly', () => {
+ const patchColumns = [
+ {
+ key: 'display_name',
+ title: 'Name',
+ },
+ {
+ key: 'package_count',
+ title: 'Package count',
+ },
+ ];
- const inventoryColumns = [
- {
- key: 'display_name',
- title: 'Display name'
- }
- ];
+ const inventoryColumns = [
+ {
+ key: 'display_name',
+ title: 'Display name',
+ },
+ ];
- expect(mergeInventoryColumns(patchColumns, inventoryColumns))
- .toMatchObject([{
- key: 'display_name',
- title: 'Name'
- },
- {
- key: 'package_count',
- title: 'Package count'
- }]);
- });
+ expect(mergeInventoryColumns(patchColumns, inventoryColumns)).toMatchObject([
+ {
+ key: 'display_name',
+ title: 'Name',
+ },
+ {
+ key: 'package_count',
+ title: 'Package count',
+ },
+ ]);
+ });
- it('should merge renamed columns correctly', () => {
- const patchColumns = [
- {
- inventoryKey: 'display_name',
- key: 'name'
- },
- {
- key: 'package_count',
- title: 'Package count'
- }
- ];
+ it('should merge renamed columns correctly', () => {
+ const patchColumns = [
+ {
+ inventoryKey: 'display_name',
+ key: 'name',
+ },
+ {
+ key: 'package_count',
+ title: 'Package count',
+ },
+ ];
- const inventoryColumns = [
- {
- key: 'display_name',
- title: 'Display name'
- }
- ];
+ const inventoryColumns = [
+ {
+ key: 'display_name',
+ title: 'Display name',
+ },
+ ];
- expect(mergeInventoryColumns(patchColumns, inventoryColumns))
- .toMatchObject([{
- key: 'name',
- title: 'Display name'
- },
- {
- key: 'package_count',
- title: 'Package count'
- }]);
- });
+ expect(mergeInventoryColumns(patchColumns, inventoryColumns)).toMatchObject([
+ {
+ key: 'name',
+ title: 'Display name',
+ },
+ {
+ key: 'package_count',
+ title: 'Package count',
+ },
+ ]);
+ });
});
diff --git a/src/Utilities/SystemsHelpers.js b/src/Utilities/SystemsHelpers.js
index 379599e11..8bb355dcf 100644
--- a/src/Utilities/SystemsHelpers.js
+++ b/src/Utilities/SystemsHelpers.js
@@ -9,102 +9,116 @@ import { defaultCompoundSortValues } from './constants';
import { patchSetDetailColumns } from '../SmartComponents/PatchSetDetail/PatchSetDetailAssets';
import { InsightsLink } from '@redhat-cloud-services/frontend-components/InsightsLink';
-export const buildFilterConfig = (search, filter, apply) => {
- return {
- items: [
- searchFilter(
- apply,
- search,
- intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
- intl.formatMessage(
- messages.labelsFiltersSystemsSearchPlaceholder
- )
- ),
- staleFilter(apply, filter),
- systemsUpdatableFilter(apply, filter)
- ]
- };
-};
+export const buildFilterConfig = (search, filter, apply) => ({
+ items: [
+ searchFilter(
+ apply,
+ search,
+ intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
+ intl.formatMessage(messages.labelsFiltersSystemsSearchPlaceholder),
+ ),
+ staleFilter(apply, filter),
+ systemsUpdatableFilter(apply, filter),
+ ],
+});
export const buildTemplateFilterConfig = (search, apply) => ({
- items: [
- searchFilter(
- apply,
- search,
- intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
- intl.formatMessage(
- messages.labelsFiltersSystemsSearchPlaceholder
- )
- )
- ]
+ items: [
+ searchFilter(
+ apply,
+ search,
+ intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
+ intl.formatMessage(messages.labelsFiltersSystemsSearchPlaceholder),
+ ),
+ ],
});
export const buildActiveFiltersConfig = (filter, search, deleteFilters) => {
- if (filter?.group_name?.length === 0) {
- delete filter.group_name;
- }
+ if (filter?.group_name?.length === 0) {
+ delete filter.group_name;
+ }
- return {
- filters: buildFilterChips(filter, search, intl.formatMessage(messages.labelsFiltersSystemsSearchTitle)),
- onDelete: deleteFilters,
- deleteTitle: intl.formatMessage(messages.labelsFiltersReset)
- };};
+ return {
+ filters: buildFilterChips(
+ filter,
+ search,
+ intl.formatMessage(messages.labelsFiltersSystemsSearchTitle),
+ ),
+ onDelete: deleteFilters,
+ deleteTitle: intl.formatMessage(messages.labelsFiltersReset),
+ };
+};
export const mergeInventoryColumns = (patchmanColumns, inventoryColumns) =>
- patchmanColumns.map(column => ({
- ...inventoryColumns.find(inventoryColumn => inventoryColumn.key === (column.inventoryKey ?? column.key)),
- ...column
- }));
+ patchmanColumns.map((column) => ({
+ ...inventoryColumns.find(
+ (inventoryColumn) => inventoryColumn.key === (column.inventoryKey ?? column.key),
+ ),
+ ...column,
+ }));
export const templateSystemsColumnsMerger = (defaultColumns) => {
- let lastSeen = defaultColumns.filter(({ key }) => key === 'updated');
- lastSeen = [{ ...lastSeen[0], key: 'last_upload', sortKey: 'last_upload', renderFunc: value => templateDateFormat(value) }];
+ let lastSeen = defaultColumns.filter(({ key }) => key === 'updated');
+ lastSeen = [
+ {
+ ...lastSeen[0],
+ key: 'last_upload',
+ sortKey: 'last_upload',
+ renderFunc: (value) => templateDateFormat(value),
+ },
+ ];
- let name = defaultColumns.filter(({ key }) => key === 'display_name');
- let tag = defaultColumns.filter(({ key }) => key === 'tags');
+ let name = defaultColumns.filter(({ key }) => key === 'display_name');
+ let tag = defaultColumns.filter(({ key }) => key === 'tags');
- name = [{
- ...name[0],
- renderFunc: (displayName, id) => {displayName}
- }];
+ name = [
+ {
+ ...name[0],
+ renderFunc: (displayName, id) => (
+ {displayName}
+ ),
+ },
+ ];
- return [...name, ...tag, ...patchSetDetailColumns, lastSeen[0]];
+ return [...name, ...tag, ...patchSetDetailColumns, lastSeen[0]];
};
export const createSystemsSortBy = (orderBy, orderDirection, hasLastUpload) => {
- if (orderBy === 'updated') {
- if (!hasLastUpload) {
- orderBy = 'last_upload';
- } else {
- orderBy = 'os';
- }
- } else if (orderBy === 'group_name') {
- orderBy = 'groups'; // patch API service uses 'groups' instead of 'group_name' sort parameter
+ if (orderBy === 'updated') {
+ if (!hasLastUpload) {
+ orderBy = 'last_upload';
+ } else {
+ orderBy = 'os';
}
+ } else if (orderBy === 'group_name') {
+ orderBy = 'groups'; // patch API service uses 'groups' instead of 'group_name' sort parameter
+ }
- let sort = `${orderDirection === 'ASC' ? '' : '-'}${orderBy}`;
+ let sort = `${orderDirection === 'ASC' ? '' : '-'}${orderBy}`;
- //if orderBy is for a compound column reset sort value to relative compound sort value
- Object.keys(defaultCompoundSortValues).forEach(col => {
- if (col === orderBy) {
- sort = defaultCompoundSortValues[col][orderDirection.toLowerCase()];
- }
- });
+ // if orderBy is for a compound column reset sort value to relative compound sort value
+ Object.keys(defaultCompoundSortValues).forEach((col) => {
+ if (col === orderBy) {
+ sort = defaultCompoundSortValues[col][orderDirection.toLowerCase()];
+ }
+ });
- return sort;
+ return sort;
};
-export const osParamParser = (paramValue) => {
- return paramValue.replace('in:', '').split(',').reduce((osFilter, os) => {
- const [osName, osVersion] = os.split(' ');
- const [major] = osVersion.split('.');
+export const osParamParser = (paramValue) =>
+ paramValue
+ .replace('in:', '')
+ .split(',')
+ .reduce((osFilter, os) => {
+ const [osName, osVersion] = os.split(' ');
+ const [major] = osVersion.split('.');
- return {
- ...osFilter,
- [`${osName}-${major}`]: {
- ...osFilter[`${osName}-${major}`] || {},
- [`${osName}-${major}-${osVersion}`]: true
- }
- };
+ return {
+ ...osFilter,
+ [`${osName}-${major}`]: {
+ ...(osFilter[`${osName}-${major}`] || {}),
+ [`${osName}-${major}-${osVersion}`]: true,
+ },
+ };
}, {});
-};
diff --git a/src/Utilities/TestingUtilities.js b/src/Utilities/TestingUtilities.js
index 4e2e9fcb2..91c9dd75f 100644
--- a/src/Utilities/TestingUtilities.js
+++ b/src/Utilities/TestingUtilities.js
@@ -9,108 +9,97 @@ import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom';
import * as Actions from '../store/Actions/Actions';
-export const ComponentWithContext = ({
- renderOptions = {},
- children
-}) => {
- const mockStore = configureStore();
-
- return (
-
-
-
- {
- renderOptions?.componentPath ? (
-
-
- {children}
-
-
- ) : children
- }
-
-
-
- );
+export const ComponentWithContext = ({ renderOptions = {}, children }) => {
+ const mockStore = configureStore();
+
+ return (
+
+
+
+ {renderOptions?.componentPath ? (
+
+ {children}
+
+ ) : (
+ children
+ )}
+
+
+
+ );
};
ComponentWithContext.propTypes = {
- children: PropTypes.element,
- renderOptions: PropTypes.object
+ children: PropTypes.element,
+ renderOptions: PropTypes.object,
};
export const testExport = (exportCveCallback, exportJsonCallback, exportType) => {
- const user = userEvent.setup();
- describe('test exports', () => {
- global.Headers = jest.fn();
- global.fetch = jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err)));
- it('Should download csv file current', async () => {
- await user.click(screen.getByLabelText('Export'));
- await waitFor(() => {
- expect(screen.getByText('Export to CSV')).toBeVisible();
- });
+ const user = userEvent.setup();
+ describe('test exports', () => {
+ global.Headers = jest.fn();
+ global.fetch = jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ );
+ it('Should download csv file current', async () => {
+ await user.click(screen.getByLabelText('Export'));
+ await waitFor(() => {
+ expect(screen.getByText('Export to CSV')).toBeVisible();
+ });
- await user.click(screen.getByText('Export to CSV'));
+ await user.click(screen.getByText('Export to CSV'));
- await waitFor(() => {
- expect(exportCveCallback).toHaveBeenCalledWith({ page: 1, page_size: 20 }, exportType);
- });
- });
+ await waitFor(() => {
+ expect(exportCveCallback).toHaveBeenCalledWith({ page: 1, page_size: 20 }, exportType);
+ });
+ });
- it('Should download csv file current', async () => {
- await user.click(screen.getByLabelText('Export'));
- await waitFor(() => {
- expect(screen.getByText('Export to CSV')).toBeVisible();
- });
+ it('Should download csv file current', async () => {
+ await user.click(screen.getByLabelText('Export'));
+ await waitFor(() => {
+ expect(screen.getByText('Export to CSV')).toBeVisible();
+ });
- await user.click(screen.getByText('Export to JSON'));
+ await user.click(screen.getByText('Export to JSON'));
- await waitFor(() => {
- expect(exportJsonCallback).toHaveBeenCalledWith({ page: 1, page_size: 20 }, exportType);
- });
- });
+ await waitFor(() => {
+ expect(exportJsonCallback).toHaveBeenCalledWith({ page: 1, page_size: 20 }, exportType);
+ });
});
+ });
};
export const testBulkSelection = (fetchAllCallback, fetchAllUrl, spyOnAction, selectedItem) => {
- const user = userEvent.setup();
- const spy = jest.spyOn(Actions, spyOnAction);
-
- it('should fetch all the data using limit=-1', async () => {
- await user.click(screen.getByLabelText('Select'));
- await user.click(screen.getByText('Select all (101)'));
- await waitFor(
- () => {
- expect(fetchAllCallback).toHaveBeenCalledTimes(2);
- expect(fetchAllCallback).toHaveBeenCalledWith(
- fetchAllUrl,
- expect.objectContaining({ limit: 100, offset: 0 })
- );
- expect(fetchAllCallback).toHaveBeenCalledWith(
- fetchAllUrl,
- expect.objectContaining({ limit: 100, offset: 100 })
- );
- }
- );
-
+ const user = userEvent.setup();
+ const spy = jest.spyOn(Actions, spyOnAction);
+
+ it('should fetch all the data using limit=-1', async () => {
+ await user.click(screen.getByLabelText('Select'));
+ await user.click(screen.getByText('Select all (101)'));
+ await waitFor(() => {
+ expect(fetchAllCallback).toHaveBeenCalledTimes(2);
+ expect(fetchAllCallback).toHaveBeenCalledWith(
+ fetchAllUrl,
+ expect.objectContaining({ limit: 100, offset: 0 }),
+ );
+ expect(fetchAllCallback).toHaveBeenCalledWith(
+ fetchAllUrl,
+ expect.objectContaining({ limit: 100, offset: 100 }),
+ );
});
+ });
- it('should unselect rows', async () => {
- await user.click(screen.getByLabelText('Select'));
- await user.click(screen.getByText('Select none (0)'));
-
- await waitFor(() =>
- expect(spy).toHaveBeenCalledWith([])
- );
- });
+ it('should unselect rows', async () => {
+ await user.click(screen.getByLabelText('Select'));
+ await user.click(screen.getByText('Select none (0)'));
- it('should select rows', async () => {
- await user.click(screen.getByLabelText('Select'));
- await user.click(screen.getByText('Select page (1)'));
+ await waitFor(() => expect(spy).toHaveBeenCalledWith([]));
+ });
- await waitFor(() =>
- expect(spy).toHaveBeenCalledWith(selectedItem)
- );
- });
+ it('should select rows', async () => {
+ await user.click(screen.getByLabelText('Select'));
+ await user.click(screen.getByText('Select page (1)'));
+ await waitFor(() => expect(spy).toHaveBeenCalledWith(selectedItem));
+ });
};
diff --git a/src/Utilities/api.js b/src/Utilities/api.js
index 68615712a..f7c549b72 100644
--- a/src/Utilities/api.js
+++ b/src/Utilities/api.js
@@ -6,227 +6,221 @@ import { encodeApiParams, prepareEntitiesParams } from './Helpers';
const INVENTORY_API_BASE = '/api/inventory/v1';
export function createApiCall(
- endpoint,
- version,
- method,
- parameters = undefined,
- data = undefined,
- requestConfig = undefined
+ endpoint,
+ version,
+ method,
+ parameters = undefined,
+ data = undefined,
+ requestConfig = undefined,
) {
- if (parameters && method === 'get') {
- endpoint = endpoint.concat(encodeApiParams(parameters));
- }
-
- let result = axiosInstance({
- method,
- url: '/api/patch/' + version + endpoint,
- withCredentials: true,
- data,
- ...requestConfig
- });
-
- return result;
+ if (parameters && method === 'get') {
+ endpoint = endpoint.concat(encodeApiParams(parameters));
+ }
+
+ let result = axiosInstance({
+ method,
+ url: '/api/patch/' + version + endpoint,
+ withCredentials: true,
+ data,
+ ...requestConfig,
+ });
+
+ return result;
}
-// eslint-disable-next-line new-cap
const hostInventoryApi = APIFactory(
- INVENTORY_API_BASE,
- {
- apiSystemProfileGetOperatingSystem
- },
- {
- axios: axiosInstance
- }
+ INVENTORY_API_BASE,
+ {
+ apiSystemProfileGetOperatingSystem,
+ },
+ {
+ axios: axiosInstance,
+ },
);
-export const fetchApplicableAdvisoriesApi = params => {
- return createApiCall('/advisories', 'v3', 'get', params);
-};
+export const fetchApplicableAdvisoriesApi = (params) =>
+ createApiCall('/advisories', 'v3', 'get', params);
-export const fetchApplicableSystemAdvisoriesApi = params => {
- let { id, ...allParams } = params;
- return createApiCall(`/systems/${id}/advisories`, 'v3', 'get', allParams);
+export const fetchApplicableSystemAdvisoriesApi = (params) => {
+ let { id, ...allParams } = params;
+ return createApiCall(`/systems/${id}/advisories`, 'v3', 'get', allParams);
};
-export const fetchSystems = params => {
- return createApiCall('/systems', 'v3', 'get', prepareEntitiesParams(params));
-};
+export const fetchSystems = (params) =>
+ createApiCall('/systems', 'v3', 'get', prepareEntitiesParams(params));
-export const fetchSystemDetails = id => {
- return createApiCall(`/systems/${id}`, 'v3', 'get');
-};
+export const fetchSystemDetails = (id) => createApiCall(`/systems/${id}`, 'v3', 'get');
-export const fetchAdvisoryDetailsApi = params => {
- return createApiCall(`/advisories/${params.advisoryName}`, 'v3', 'get');
-};
+export const fetchAdvisoryDetailsApi = (params) =>
+ createApiCall(`/advisories/${params.advisoryName}`, 'v3', 'get');
-export const fetchPackageDetailsApi = params => {
- return createApiCall(`/packages/${params.packageName}`, 'v3', 'get');
-};
+export const fetchPackageDetailsApi = (params) =>
+ createApiCall(`/packages/${params.packageName}`, 'v3', 'get');
-export const fetchApplicablePackagesApi = params => {
- let { id, ...allParams } = params;
- return createApiCall(`/systems/${id}/packages`, 'v3', 'get', allParams);
+export const fetchApplicablePackagesApi = (params) => {
+ let { id, ...allParams } = params;
+ return createApiCall(`/systems/${id}/packages`, 'v3', 'get', allParams);
};
-export const fetchAdvisorySystems = params => {
- const { id, ...args } = params;
- return createApiCall(`/advisories/${id}/systems`, 'v3', 'get', prepareEntitiesParams(args));
+export const fetchAdvisorySystems = (params) => {
+ const { id, ...args } = params;
+ return createApiCall(`/advisories/${id}/systems`, 'v3', 'get', prepareEntitiesParams(args));
};
-export const fetchPackageSystems = params => {
- const { package_name: packageName, ...args } = params;
- return createApiCall(`/packages/${packageName}/systems`, 'v3', 'get', prepareEntitiesParams(args));
+export const fetchPackageSystems = (params) => {
+ const { package_name: packageName, ...args } = params;
+ return createApiCall(
+ `/packages/${packageName}/systems`,
+ 'v3',
+ 'get',
+ prepareEntitiesParams(args),
+ );
};
-export const fetchPackageVersions = params => {
- const { package_name: packageName, ...args } = params;
- return createApiCall(`/packages/${packageName}/versions`, 'v3', 'get', args);
+export const fetchPackageVersions = (params) => {
+ const { package_name: packageName, ...args } = params;
+ return createApiCall(`/packages/${packageName}/versions`, 'v3', 'get', args);
};
-export const fetchPackagesList = params => {
- const { systems_applicable: systemsUpdatable } = params.filter;
+export const fetchPackagesList = (params) => {
+ const { systems_applicable: systemsUpdatable } = params.filter;
- // we have to reset systems_applicable filter to include all filters when we want to show all the data
- if (Array.isArray(systemsUpdatable) && systemsUpdatable.length === 2) {
- const paramsWithoutSystemsUpdatable = JSON.parse(JSON.stringify(params));
- delete paramsWithoutSystemsUpdatable.filter.systems_applicable;
+ // we have to reset systems_applicable filter to include all filters when we want to show all the data
+ if (Array.isArray(systemsUpdatable) && systemsUpdatable.length === 2) {
+ const paramsWithoutSystemsUpdatable = JSON.parse(JSON.stringify(params));
+ delete paramsWithoutSystemsUpdatable.filter.systems_applicable;
- return createApiCall('/packages', 'v3', 'get', paramsWithoutSystemsUpdatable);
- }
+ return createApiCall('/packages', 'v3', 'get', paramsWithoutSystemsUpdatable);
+ }
- return createApiCall('/packages', 'v3', 'get', params);
+ return createApiCall('/packages', 'v3', 'get', params);
};
export const fetchCvesInfo = async ({ cveIds }) => {
+ const result = await fetch(
+ `/api/vulnerability/v1/vulnerabilities/cves?limit=${cveIds && cveIds.length}`,
+ {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ Accept: 'application/vnd.api+json',
+ 'Content-Type': 'application/vnd.api+json',
+ },
+ body: JSON.stringify({ cve_list: cveIds }),
+ },
+ )
+ .then((res) => res.json())
+ .then((data) => data)
+ .catch((err) => err);
- const result = await fetch(`/api/vulnerability/v1/vulnerabilities/cves?limit=${cveIds && cveIds.length}`, {
- method: 'POST',
- credentials: 'include',
- headers: {
- Accept: 'application/vnd.api+json',
- 'Content-Type': 'application/vnd.api+json'
- },
- body: JSON.stringify({ cve_list: cveIds })
- }).then(res => res.json()).then(data => data).catch(err => err);
-
- return result;
+ return result;
};
const fetchFile = (params, endpoint, type) => {
- endpoint = endpoint.concat(encodeApiParams(params));
- return fetch('/api/patch/v3' + endpoint, {
- method: 'get',
- credentials: 'include',
- headers: { accept: type }
- }).then(res => res.text()).catch(err => err);
+ endpoint = endpoint.concat(encodeApiParams(params));
+ return fetch('/api/patch/v3' + endpoint, {
+ method: 'get',
+ credentials: 'include',
+ headers: { accept: type },
+ })
+ .then((res) => res.text())
+ .catch((err) => err);
};
-export const exportAdvisoriesCSV = params => {
- let endpoint = '/export/advisories';
- return fetchFile(params, endpoint, 'text/csv');
+export const exportAdvisoriesCSV = (params) => {
+ let endpoint = '/export/advisories';
+ return fetchFile(params, endpoint, 'text/csv');
};
-export const exportAdvisoriesJSON = params => {
- let endpoint = '/export/advisories';
- return fetchFile(params, endpoint, 'application/json');
+export const exportAdvisoriesJSON = (params) => {
+ let endpoint = '/export/advisories';
+ return fetchFile(params, endpoint, 'application/json');
};
-export const exportSystemsCSV = params => {
- let endpoint = '/export/systems';
- return fetchFile(params, endpoint, 'text/csv');
+export const exportSystemsCSV = (params) => {
+ let endpoint = '/export/systems';
+ return fetchFile(params, endpoint, 'text/csv');
};
-export const exportSystemsJSON = params => {
- let endpoint = '/export/systems';
- return fetchFile(params, endpoint, 'application/json');
+export const exportSystemsJSON = (params) => {
+ let endpoint = '/export/systems';
+ return fetchFile(params, endpoint, 'application/json');
};
-export const exportPackagesCSV = params => {
- let endpoint = '/export/packages';
- return fetchFile(params, endpoint, 'text/csv');
+export const exportPackagesCSV = (params) => {
+ let endpoint = '/export/packages';
+ return fetchFile(params, endpoint, 'text/csv');
};
-export const exportPackagesJSON = params => {
- let endpoint = '/export/packages';
- return fetchFile(params, endpoint, 'application/json');
+export const exportPackagesJSON = (params) => {
+ let endpoint = '/export/packages';
+ return fetchFile(params, endpoint, 'application/json');
};
export const exportAdvisorySystemsCSV = (params, advisoryId) => {
- let endpoint = `/export/advisories/${advisoryId}/systems`;
- return fetchFile(params, endpoint, 'text/csv');
+ let endpoint = `/export/advisories/${advisoryId}/systems`;
+ return fetchFile(params, endpoint, 'text/csv');
};
export const exportAdvisorySystemsJSON = (params, advisoryId) => {
- let endpoint = `/export/advisories/${advisoryId}/systems`;
- return fetchFile(params, endpoint, 'application/json');
+ let endpoint = `/export/advisories/${advisoryId}/systems`;
+ return fetchFile(params, endpoint, 'application/json');
};
export const exportSystemAdvisoriesCSV = (params, systemName) => {
- let endpoint = `/export/systems/${systemName}/advisories`;
- return fetchFile(params, endpoint, 'text/csv');
+ let endpoint = `/export/systems/${systemName}/advisories`;
+ return fetchFile(params, endpoint, 'text/csv');
};
export const exportSystemAdvisoriesJSON = (params, systemName) => {
- let endpoint = `/export/systems/${systemName}/advisories`;
- return fetchFile(params, endpoint, 'application/json');
+ let endpoint = `/export/systems/${systemName}/advisories`;
+ return fetchFile(params, endpoint, 'application/json');
};
export const exportSystemPackagesCSV = (params, systemName) => {
- let endpoint = `/export/systems/${systemName}/packages`;
- return fetchFile(params, endpoint, 'text/csv');
+ let endpoint = `/export/systems/${systemName}/packages`;
+ return fetchFile(params, endpoint, 'text/csv');
};
export const exportSystemPackagesJSON = (params, systemName) => {
- let endpoint = `/export/systems/${systemName}/packages`;
- return fetchFile(params, endpoint, 'application/json');
+ let endpoint = `/export/systems/${systemName}/packages`;
+ return fetchFile(params, endpoint, 'application/json');
};
export const exportPackageSystemsCSV = (params, packageName) => {
- let endpoint = `/export/packages/${packageName}/systems`;
- return fetchFile(params, endpoint, 'text/csv');
+ let endpoint = `/export/packages/${packageName}/systems`;
+ return fetchFile(params, endpoint, 'text/csv');
};
export const exportPackageSystemsJSON = (params, packageName) => {
- let endpoint = `/export/packages/${packageName}/systems`;
- return fetchFile(params, endpoint, 'application/json');
+ let endpoint = `/export/packages/${packageName}/systems`;
+ return fetchFile(params, endpoint, 'application/json');
};
-export const assignSystemToPatchSet = (payload) => {
- return createApiCall(`/baselines`, 'v3', 'put', null, payload);
-};
+export const assignSystemToPatchSet = (payload) =>
+ createApiCall(`/baselines`, 'v3', 'put', null, payload);
-export const fetchPatchSets = params => {
- return createApiCall(`/baselines`, 'v3', 'get', params);
-};
+export const fetchPatchSets = (params) => createApiCall(`/baselines`, 'v3', 'get', params);
-export const updatePatchSets = (payload, id) => {
- return createApiCall(`/baselines/${id}`, 'v3', 'put', null, payload);
-};
+export const updatePatchSets = (payload, id) =>
+ createApiCall(`/baselines/${id}`, 'v3', 'put', null, payload);
-export const deletePatchSet = patchSetID => {
- return createApiCall(`/baselines/${patchSetID}`, 'v3', 'delete');
-};
+export const deletePatchSet = (patchSetID) =>
+ createApiCall(`/baselines/${patchSetID}`, 'v3', 'delete');
-export const fetchPatchSet = id => {
- return createApiCall(`/baselines/${id}`, 'v3', 'get');
-};
+export const fetchPatchSet = (id) => createApiCall(`/baselines/${id}`, 'v3', 'get');
export const fetchPatchSetSystems = (params) => {
- const id = params.id;
- delete params.id;
+ const id = params.id;
+ delete params.id;
- return createApiCall(`/baselines/${id}/systems`, 'v3', 'get', prepareEntitiesParams(params));
+ return createApiCall(`/baselines/${id}/systems`, 'v3', 'get', prepareEntitiesParams(params));
};
-export const unassignSystemFromPatchSet = (payload) => {
- return createApiCall('/baselines/systems/remove', 'v3', 'post', null, payload);
-};
+export const unassignSystemFromPatchSet = (payload) =>
+ createApiCall('/baselines/systems/remove', 'v3', 'post', null, payload);
-export const getOperatingSystems = () => {
- return hostInventoryApi.apiSystemProfileGetOperatingSystem();
-};
+export const getOperatingSystems = () => hostInventoryApi.apiSystemProfileGetOperatingSystem();
-export const fetchIDs = (endpoint, queryParams) => {
- return createApiCall(endpoint, 'v3', 'get', queryParams);
-};
+export const fetchIDs = (endpoint, queryParams) =>
+ createApiCall(endpoint, 'v3', 'get', queryParams);
diff --git a/src/Utilities/api.test.js b/src/Utilities/api.test.js
index 0eca4e633..586ce6cf9 100644
--- a/src/Utilities/api.test.js
+++ b/src/Utilities/api.test.js
@@ -1,96 +1,112 @@
import {
- createApiCall,
- exportAdvisoriesCSV,
- exportAdvisoriesJSON,
- exportSystemsCSV,
- exportSystemsJSON
+ createApiCall,
+ exportAdvisoriesCSV,
+ exportAdvisoriesJSON,
+ exportSystemsCSV,
+ exportSystemsJSON,
} from './api';
import { initMocks } from '../Utilities/unitTestingUtilities';
initMocks();
describe('api', () => {
- describe('test createApiCall function: ', () => {
- it('Should "get" method in createApiCall return error from backend', () => {
- global.fetch = jest.fn(() => Promise.resolve({
- ok: false,
- status: 400,
- statusText: 'testStatusText',
- headers: { get: () => [] }
- })
- );
- const response = createApiCall('testEndpoint', 'v2', 'get', { testParam: 1 }, { data: 'testData' });
- response.catch((err) => {
- expect(err).toEqual({
- title: 'There was an error getting data',
- detail: 'testStatusTextsssss',
- status: 400
- });
- });
- });
-
- it('Should "get" method in createApiCall return network error', () => {
- global.fetch = jest.fn(() => Promise.resolve({
- ok: false,
- status: 400,
- statusText: 'testStatusText',
- headers: { get: () => ['json'] }
- })
- );
- const response = createApiCall('testEndpoint', 'v2', 'get', { testParam: 1 }, { data: 'testData' });
- response.catch((res) => expect(res).toEqual({
- title: 'There was an error getting data',
- detail: 'testStatusTextsssss',
- status: 400
- }));
+ describe('test createApiCall function: ', () => {
+ it('Should "get" method in createApiCall return error from backend', () => {
+ global.fetch = jest.fn(() =>
+ Promise.resolve({
+ ok: false,
+ status: 400,
+ statusText: 'testStatusText',
+ headers: { get: () => [] },
+ }),
+ );
+ const response = createApiCall(
+ 'testEndpoint',
+ 'v2',
+ 'get',
+ { testParam: 1 },
+ { data: 'testData' },
+ );
+ response.catch((err) => {
+ expect(err).toEqual({
+ title: 'There was an error getting data',
+ detail: 'testStatusTextsssss',
+ status: 400,
});
+ });
});
- describe('test export api call functions', () => {
-
- global.Headers = jest.fn();
- global.fetch = jest.fn(() => Promise.resolve({ success: true }).catch((err) => console.log(err)));
+ it('Should "get" method in createApiCall return network error', () => {
+ global.fetch = jest.fn(() =>
+ Promise.resolve({
+ ok: false,
+ status: 400,
+ statusText: 'testStatusText',
+ headers: { get: () => ['json'] },
+ }),
+ );
+ const response = createApiCall(
+ 'testEndpoint',
+ 'v2',
+ 'get',
+ { testParam: 1 },
+ { data: 'testData' },
+ );
+ response.catch((res) =>
+ expect(res).toEqual({
+ title: 'There was an error getting data',
+ detail: 'testStatusTextsssss',
+ status: 400,
+ }),
+ );
+ });
+ });
- it('Should export advisory cvs', () => {
- const result = exportAdvisoriesCSV('testParams');
- expect(result).toBeTruthy();
- expect(global.fetch).toHaveBeenCalledWith(
- '/api/patch/v3/export/advisories?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
- { credentials: 'include', headers: { accept: 'text/csv' }, method: 'get' }
- );
+ describe('test export api call functions', () => {
+ global.Headers = jest.fn();
+ global.fetch = jest.fn(() =>
+ Promise.resolve({ success: true }).catch((err) => console.log(err)),
+ );
- global.fetch.mockClear();
- });
+ it('Should export advisory cvs', () => {
+ const result = exportAdvisoriesCSV('testParams');
+ expect(result).toBeTruthy();
+ expect(global.fetch).toHaveBeenCalledWith(
+ '/api/patch/v3/export/advisories?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
+ { credentials: 'include', headers: { accept: 'text/csv' }, method: 'get' },
+ );
- it('Should export advisory json', () => {
- const result = exportAdvisoriesJSON('testParams');
- expect(result).toBeTruthy();
- expect(global.fetch).toHaveBeenCalledWith(
- '/api/patch/v3/export/advisories?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
- { credentials: 'include', headers: { accept: 'application/json' }, method: 'get' }
- );
- global.fetch.mockClear();
- });
+ global.fetch.mockClear();
+ });
- it('Should export system cves', () => {
- const result = exportSystemsCSV('testParams');
- expect(result).toBeTruthy();
- expect(global.fetch).toHaveBeenCalledWith(
- '/api/patch/v3/export/systems?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
- { credentials: 'include', headers: { accept: 'text/csv' }, method: 'get' }
- );
- global.fetch.mockClear();
- });
+ it('Should export advisory json', () => {
+ const result = exportAdvisoriesJSON('testParams');
+ expect(result).toBeTruthy();
+ expect(global.fetch).toHaveBeenCalledWith(
+ '/api/patch/v3/export/advisories?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
+ { credentials: 'include', headers: { accept: 'application/json' }, method: 'get' },
+ );
+ global.fetch.mockClear();
+ });
- it('Should export system json', () => {
- const result = exportSystemsJSON('testParams');
- expect(result).toBeTruthy();
- expect(global.fetch).toHaveBeenCalledWith(
- '/api/patch/v3/export/systems?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
- { credentials: 'include', headers: { accept: 'application/json' }, method: 'get' }
- );
- global.fetch.mockClear();
- });
+ it('Should export system cves', () => {
+ const result = exportSystemsCSV('testParams');
+ expect(result).toBeTruthy();
+ expect(global.fetch).toHaveBeenCalledWith(
+ '/api/patch/v3/export/systems?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
+ { credentials: 'include', headers: { accept: 'text/csv' }, method: 'get' },
+ );
+ global.fetch.mockClear();
});
+ it('Should export system json', () => {
+ const result = exportSystemsJSON('testParams');
+ expect(result).toBeTruthy();
+ expect(global.fetch).toHaveBeenCalledWith(
+ '/api/patch/v3/export/systems?0=t&1=e&2=s&3=t&4=P&5=a&6=r&7=a&8=m&9=s',
+ { credentials: 'include', headers: { accept: 'application/json' }, method: 'get' },
+ );
+ global.fetch.mockClear();
+ });
+ });
});
diff --git a/src/Utilities/axiosInterceptors.js b/src/Utilities/axiosInterceptors.js
index 91db21cd6..0573e2901 100644
--- a/src/Utilities/axiosInterceptors.js
+++ b/src/Utilities/axiosInterceptors.js
@@ -1,53 +1,50 @@
-import {
- authInterceptor
-} from '@redhat-cloud-services/frontend-components-utilities/interceptors';
+import { authInterceptor } from '@redhat-cloud-services/frontend-components-utilities/interceptors';
import axios from 'axios';
import { ReadOnlyNotification } from './constants';
const axiosInstance = axios.create();
export function errorInterceptor(err) {
+ if (!axios.isCancel(err)) {
+ const { response } = { ...err };
- if (!axios.isCancel(err)) {
- const { response } = { ...err };
+ if (response && err.isAxiosError) {
+ const { status, statusText, data } = response;
- if (response && err.isAxiosError) {
- const { status, statusText, data } = response;
-
- if (!status) {
- return err;
- } else {
- const genericError = {
- title: 'There was an error getting data'
- };
-
- const result = { ...genericError, detail: data.error || statusText, status };
+ if (!status) {
+ return err;
+ } else {
+ const genericError = {
+ title: 'There was an error getting data',
+ };
- throw result;
- }
- }
+ const result = { ...genericError, detail: data.error || statusText, status };
- return err;
+ throw result;
+ }
}
return err;
+ }
+
+ return err;
}
export function readOnlyInterceptor(error) {
- if (error.response && error.response.status === 503) {
- const data = ReadOnlyNotification;
- throw data;
- }
+ if (error.response && error.response.status === 503) {
+ const data = ReadOnlyNotification;
+ throw data;
+ }
- throw error;
+ throw error;
}
export function responseDataInterceptor(response) {
- if (response.data && typeof response.data === 'object') {
- return { ...response.data, status: response.status };
- }
+ if (response.data && typeof response.data === 'object') {
+ return { ...response.data, status: response.status };
+ }
- return response;
+ return response;
}
axiosInstance.interceptors.request.use(authInterceptor);
diff --git a/src/Utilities/constants.js b/src/Utilities/constants.js
index 2cbd50abd..f990d86a8 100644
--- a/src/Utilities/constants.js
+++ b/src/Utilities/constants.js
@@ -7,308 +7,309 @@ export const STATUS_LOADING = 'loading';
export const STATUS_RESOLVED = 'resolved';
export const defaultCompoundSortValues = {
- operating_system: {
- asc: 'osname,osmajor,osminor',
- desc: '-osname,-osmajor,-osminor'
- },
- applicable_advisories: {
- asc: 'rhsa_count,rhba_count,rhea_count',
- desc: '-rhsa_count,-rhba_count,-rhea_count'
- }
+ operating_system: {
+ asc: 'osname,osmajor,osminor',
+ desc: '-osname,-osmajor,-osminor',
+ },
+ applicable_advisories: {
+ asc: 'rhsa_count,rhba_count,rhea_count',
+ desc: '-rhsa_count,-rhba_count,-rhea_count',
+ },
};
export const templateCompoundSortValues = {
- applicable_advisories: {
- asc: 'applicable_rhsa_count,applicable_rhba_count,applicable_rhea_count',
- desc: '-applicable_rhsa_count,-applicable_rhba_count,-applicable_rhea_count'
- },
- installable_advisories: {
- asc: 'installable_rhsa_count,installable_rhba_count,installable_rhea_count',
- desc: '-installable_rhsa_count,-installable_rhba_count,-installable_rhea_count'
- }
+ applicable_advisories: {
+ asc: 'applicable_rhsa_count,applicable_rhba_count,applicable_rhea_count',
+ desc: '-applicable_rhsa_count,-applicable_rhba_count,-applicable_rhea_count',
+ },
+ installable_advisories: {
+ asc: 'installable_rhsa_count,installable_rhba_count,installable_rhea_count',
+ desc: '-installable_rhsa_count,-installable_rhba_count,-installable_rhea_count',
+ },
};
export const storeListDefaults = {
- rows: [],
- status: { isLoading: true },
- metadata: {
- limit: 25,
- offset: 0,
- total_items: 0
- },
- expandedRows: {},
- selectedRows: {},
- queryParams: {
- page: 1,
- page_size: 20
- },
- error: {}
+ rows: [],
+ status: { isLoading: true },
+ metadata: {
+ limit: 25,
+ offset: 0,
+ total_items: 0,
+ },
+ expandedRows: {},
+ selectedRows: {},
+ queryParams: {
+ page: 1,
+ page_size: 20,
+ },
+ error: {},
};
export const systemPackagesDefaultFilters = {
- filter: { update_status: ['Installable'] }
+ filter: { update_status: ['Installable'] },
};
export const packagesListDefaultFilters = {
- filter: { systems_applicable: ['gt:0'] }
+ filter: { systems_applicable: ['gt:0'] },
};
export const systemsListDefaultFilters = {
- filter: { stale: [true, false] }
+ filter: { stale: [true, false] },
};
export const publicDateOptions = [
- {
- apiValue: `gt:${subtractDate(7)}`,
- label: 'Last 7 days',
- value: 'last7'
- },
- {
- apiValue: `gt:${subtractDate(30)}`,
- label: 'Last 30 days',
- value: 'last30'
- },
- {
- apiValue: `gt:${subtractDate(90)}`,
- label: 'Last 90 days',
- value: 'last90'
- },
- {
- apiValue: `gt:${subtractDate(365)}`,
- label: 'Last year',
- value: 'lastYear'
- },
- {
- apiValue: `lt:${subtractDate(365)}`,
- label: 'More than 1 year ago',
- value: 'moreThanYear'
- }
+ {
+ apiValue: `gt:${subtractDate(7)}`,
+ label: 'Last 7 days',
+ value: 'last7',
+ },
+ {
+ apiValue: `gt:${subtractDate(30)}`,
+ label: 'Last 30 days',
+ value: 'last30',
+ },
+ {
+ apiValue: `gt:${subtractDate(90)}`,
+ label: 'Last 90 days',
+ value: 'last90',
+ },
+ {
+ apiValue: `gt:${subtractDate(365)}`,
+ label: 'Last year',
+ value: 'lastYear',
+ },
+ {
+ apiValue: `lt:${subtractDate(365)}`,
+ label: 'More than 1 year ago',
+ value: 'moreThanYear',
+ },
];
export const advisorySeverities = [
- {
- value: null,
- label: 'None',
- color: 'var(--pf-t--global--icon--color--severity--minor--default)'
- },
- {
- value: 1,
- label: 'Low',
- color: 'var(--pf-t--global--icon--color--severity--minor--default)',
- text:
- 'This rating is given to all other issues that have a security impact. These are the types of vulnerabilities' +
- ' that are believed to require unlikely circumstances to be able to be exploited, or where a successful exploit' +
- ' would give minimal consequences.'
- },
- {
- value: 2,
- label: 'Moderate',
- color: 'var(--pf-t--global--icon--color--severity--moderate--default)',
- text:
- 'This rating is given to flaws that may be more difficult to exploit but could still lead to some' +
- ' compromise of the confidentiality, integrity, or availability of resources, under certain circumstances.' +
- ' These are the types of vulnerabilities that could have had a Critical impact or Important impact' +
- ' but are less easily exploited based on a technical evaluation of the flaw, or affect unlikely' +
- ' configurations.'
- },
- {
- value: 3,
- label: 'Important',
- color: 'var(--pf-t--global--icon--color--severity--important--default)',
- text:
- 'This rating is given to flaws that can easily compromise the confidentiality, integrity, or availability' +
- ' of resources. These are the types of vulnerabilities that allow local users to gain privileges, allow' +
- ' unauthenticated remote users to view resources that should otherwise be protected by authentication,' +
- ' allow authenticated remote users to execute arbitrary code, or allow remote users to cause a denial' +
- ' of service.'
- },
- {
- value: 4,
- label: 'Critical',
- color: 'var(--pf-t--global--icon--color--severity--critical--default)',
- text:
- 'This rating is given to flaws that could be easily exploited by a remote unauthenticated attacker' +
- ' and lead to system compromise (arbitrary code execution) without requiring user interaction.' +
- ' These are the types of vulnerabilities that can be exploited by worms. Flaws that require an authenticated' +
- ' remote user, a local user, or an unlikely configuration are not classed as Critical impact.'
- }
+ {
+ value: null,
+ label: 'None',
+ color: 'var(--pf-t--global--icon--color--severity--minor--default)',
+ },
+ {
+ value: 1,
+ label: 'Low',
+ color: 'var(--pf-t--global--icon--color--severity--minor--default)',
+ text:
+ 'This rating is given to all other issues that have a security impact. These are the types of vulnerabilities' +
+ ' that are believed to require unlikely circumstances to be able to be exploited, or where a successful exploit' +
+ ' would give minimal consequences.',
+ },
+ {
+ value: 2,
+ label: 'Moderate',
+ color: 'var(--pf-t--global--icon--color--severity--moderate--default)',
+ text:
+ 'This rating is given to flaws that may be more difficult to exploit but could still lead to some' +
+ ' compromise of the confidentiality, integrity, or availability of resources, under certain circumstances.' +
+ ' These are the types of vulnerabilities that could have had a Critical impact or Important impact' +
+ ' but are less easily exploited based on a technical evaluation of the flaw, or affect unlikely' +
+ ' configurations.',
+ },
+ {
+ value: 3,
+ label: 'Important',
+ color: 'var(--pf-t--global--icon--color--severity--important--default)',
+ text:
+ 'This rating is given to flaws that can easily compromise the confidentiality, integrity, or availability' +
+ ' of resources. These are the types of vulnerabilities that allow local users to gain privileges, allow' +
+ ' unauthenticated remote users to view resources that should otherwise be protected by authentication,' +
+ ' allow authenticated remote users to execute arbitrary code, or allow remote users to cause a denial' +
+ ' of service.',
+ },
+ {
+ value: 4,
+ label: 'Critical',
+ color: 'var(--pf-t--global--icon--color--severity--critical--default)',
+ text:
+ 'This rating is given to flaws that could be easily exploited by a remote unauthenticated attacker' +
+ ' and lead to system compromise (arbitrary code execution) without requiring user interaction.' +
+ ' These are the types of vulnerabilities that can be exploited by worms. Flaws that require an authenticated' +
+ ' remote user, a local user, or an unlikely configuration are not classed as Critical impact.',
+ },
];
export const advisoryTypes = [
- {
- value: 'security',
- label: 'Security',
- icon:
- },
- {
- value: 'bugfix',
- label: 'Bugfix',
- icon:
- },
- {
- value: 'enhancement',
- label: 'Enhancement',
- icon:
- },
- {
- value: 'other',
- label: 'Other',
- icon:
- }
+ {
+ value: 'security',
+ label: 'Security',
+ icon: ,
+ },
+ {
+ value: 'bugfix',
+ label: 'Bugfix',
+ icon: ,
+ },
+ {
+ value: 'enhancement',
+ label: 'Enhancement',
+ icon: ,
+ },
+ {
+ value: 'other',
+ label: 'Other',
+ icon: ,
+ },
];
export const updatableTypes = [
- {
- value: 'None',
- label: 'Up to date'
- },
- {
- value: 'Installable',
- label: 'Installable'
- },
- {
- value: 'Applicable',
- label: 'Applicable'
- }
+ {
+ value: 'None',
+ label: 'Up to date',
+ },
+ {
+ value: 'Installable',
+ label: 'Installable',
+ },
+ {
+ value: 'Applicable',
+ label: 'Applicable',
+ },
];
export const advisoryStatuses = [
- {
- value: 'Installable',
- label: 'Installable'
- },
- {
- value: 'Applicable',
- label: 'Applicable'
- }
+ {
+ value: 'Installable',
+ label: 'Installable',
+ },
+ {
+ value: 'Applicable',
+ label: 'Applicable',
+ },
];
export const packagesListUpdatableTypes = [
- {
- value: 'eq:0',
- label: 'Systems up to date'
- },
- {
- value: 'gt:0',
- label: 'Systems with patches available'
- }
+ {
+ value: 'eq:0',
+ label: 'Systems up to date',
+ },
+ {
+ value: 'gt:0',
+ label: 'Systems with patches available',
+ },
];
export const staleSystems = [
- {
- value: true,
- label: 'Stale'
- },
- {
- value: false,
- label: 'Fresh'
- }
+ {
+ value: true,
+ label: 'Stale',
+ },
+ {
+ value: false,
+ label: 'Fresh',
+ },
];
export const rebootRequired = [
- {
- value: true,
- label: 'Required'
- },
- {
- value: false,
- label: 'Not required'
- }
+ {
+ value: true,
+ label: 'Required',
+ },
+ {
+ value: false,
+ label: 'Not required',
+ },
];
export const filterCategories = {
- advisory_type_name: {
- label: 'Advisory type',
- values: advisoryTypes
- },
- severity: {
- label: 'Severity',
- values: advisorySeverities
- },
- public_date: {
- label: 'Public date',
- values: publicDateOptions
- },
- update_status: {
- label: 'Status',
- values: updatableTypes
- },
- systems_applicable: {
- label: 'Status',
- values: packagesListUpdatableTypes
- },
- packages_updatable: {
- label: 'Patch status',
- values: packagesListUpdatableTypes
- },
- stale: {
- label: 'Status',
- values: staleSystems
- },
- reboot_required: {
- label: 'Reboot',
- values: rebootRequired
- },
- os: {
- label: 'Operating system'
- },
- creator: {
- label: 'Creator'
- },
- status: {
- label: 'Status',
- values: advisoryStatuses
- },
- group_name: {
- label: 'Group'
- }
+ advisory_type_name: {
+ label: 'Advisory type',
+ values: advisoryTypes,
+ },
+ severity: {
+ label: 'Severity',
+ values: advisorySeverities,
+ },
+ public_date: {
+ label: 'Public date',
+ values: publicDateOptions,
+ },
+ update_status: {
+ label: 'Status',
+ values: updatableTypes,
+ },
+ systems_applicable: {
+ label: 'Status',
+ values: packagesListUpdatableTypes,
+ },
+ packages_updatable: {
+ label: 'Patch status',
+ values: packagesListUpdatableTypes,
+ },
+ stale: {
+ label: 'Status',
+ values: staleSystems,
+ },
+ reboot_required: {
+ label: 'Reboot',
+ values: rebootRequired,
+ },
+ os: {
+ label: 'Operating system',
+ },
+ creator: {
+ label: 'Creator',
+ },
+ status: {
+ label: 'Status',
+ values: advisoryStatuses,
+ },
+ group_name: {
+ label: 'Group',
+ },
};
export const entityTypes = {
- advisories: 'advisories',
- packages: 'packages'
+ advisories: 'advisories',
+ packages: 'packages',
};
export const ReadOnlyNotification = {
- title: 'title',
- detail: 'message'
+ title: 'title',
+ detail: 'message',
};
export const remediationIdentifiers = {
- package: 'patch-package',
- advisory: 'patch-advisory'
+ package: 'patch-package',
+ advisory: 'patch-advisory',
};
export const exportNotifications = (format) => ({
- pending: {
- title: `Preparing export of ${format?.toUpperCase()} format. Once complete, your download will start automatically.`,
- variant: 'info'
- },
- success: {
- title: `The exported ${format?.toUpperCase()} file is being downloaded`,
- variant: 'success'
- },
- error: {
- title: 'Couldn’t download export. Reinitiate this export to try again.',
- variant: 'danger'
- }
+ pending: {
+ title: `Preparing export of ${format?.toUpperCase()} format. Once complete, your download will start automatically.`,
+ variant: 'info',
+ },
+ success: {
+ title: `The exported ${format?.toUpperCase()} file is being downloaded`,
+ variant: 'success',
+ },
+ error: {
+ title: 'Couldn’t download export. Reinitiate this export to try again.',
+ variant: 'danger',
+ },
});
export const patchSetDeleteNotifications = (templateName) => ({
- success: {
- title: `Deleted “${templateName}”.`,
- variant: 'success'
- },
- error: {
- title: `Failed to delete “${templateName}”.`,
- variant: 'danger'
- }
+ success: {
+ title: `Deleted “${templateName}”.`,
+ variant: 'success',
+ },
+ error: {
+ title: `Failed to delete “${templateName}”.`,
+ variant: 'danger',
+ },
});
export const multiValueFilters = ['installed_evra', 'os', 'creator', 'status', 'group_name'];
export const featureFlags = {
- patch_set: 'patch.patch_set'
+ patch_set: 'patch.patch_set',
};
-export const NO_ADVISORIES_TEXT = 'There is no installable content that can be remediated with Ansible for selected systems.';
+export const NO_ADVISORIES_TEXT =
+ 'There is no installable content that can be remediated with Ansible for selected systems.';
diff --git a/src/Utilities/dateValidator.js b/src/Utilities/dateValidator.js
index b1cacb27f..a18cdabc7 100644
--- a/src/Utilities/dateValidator.js
+++ b/src/Utilities/dateValidator.js
@@ -6,27 +6,27 @@ validates date of a type YYYY-MM-DD with starting limit 1990-01-01.
regex is used to comply the Patternfly date format.
*/
const dateValidator = (dateStr) => {
- const regex = /^(\d{4})-(0[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$/;
+ const regex = /^(\d{4})-(0[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$/;
- if (dateStr && typeof dateStr === 'string' && dateStr.match(regex) === null) {
- return intl.formatMessage(messages.labelsErrorInvalidDate);
- }
+ if (dateStr && typeof dateStr === 'string' && dateStr.match(regex) === null) {
+ return intl.formatMessage(messages.labelsErrorInvalidDate);
+ }
- const date = new Date(dateStr);
- const timestamp = date.getTime();
+ const date = new Date(dateStr);
+ const timestamp = date.getTime();
- //Month had to be set to equal 0 to get the first month of the year.
- const minDate = new Date(1990, 0, 1);
+ // Month had to be set to equal 0 to get the first month of the year.
+ const minDate = new Date(1990, 0, 1);
- if (typeof timestamp !== 'number' || Number.isNaN(timestamp)) {
- return intl.formatMessage(messages.labelsErrorInvalidDate);
- }
+ if (typeof timestamp !== 'number' || Number.isNaN(timestamp)) {
+ return intl.formatMessage(messages.labelsErrorInvalidDate);
+ }
- if (date < minDate) {
- return intl.formatMessage(messages.labelsErrorDateLimit);
- }
+ if (date < minDate) {
+ return intl.formatMessage(messages.labelsErrorDateLimit);
+ }
- return;
+ return;
};
export default dateValidator;
diff --git a/src/Utilities/dateValidator.test.js b/src/Utilities/dateValidator.test.js
index 4958d0a9b..b34a88f2d 100644
--- a/src/Utilities/dateValidator.test.js
+++ b/src/Utilities/dateValidator.test.js
@@ -1,17 +1,17 @@
import dateValidator from './dateValidator';
-describe('dateValidator', () =>{
- it.each`
- date | result
- ${'1990-01-01'} | ${undefined}
- ${'2022-01-01'} | ${undefined}
- ${'2022-12-01'} | ${undefined}
- ${'1428-02-03'} | ${'Date is before the allowable range.'}
- ${'1989-12-31'} | ${'Date is before the allowable range.'}
- ${'2022-1-01'} | ${'The date should be valid of a type YYYY-MM-DD'}
- ${'random-text'}| ${'The date should be valid of a type YYYY-MM-DD'}
- `('dateValidator: Should match validate date', ({ date, result }) => {
- let validatedResult = dateValidator(date);
- expect(validatedResult).toEqual(result);
- });
+describe('dateValidator', () => {
+ it.each`
+ date | result
+ ${'1990-01-01'} | ${undefined}
+ ${'2022-01-01'} | ${undefined}
+ ${'2022-12-01'} | ${undefined}
+ ${'1428-02-03'} | ${'Date is before the allowable range.'}
+ ${'1989-12-31'} | ${'Date is before the allowable range.'}
+ ${'2022-1-01'} | ${'The date should be valid of a type YYYY-MM-DD'}
+ ${'random-text'} | ${'The date should be valid of a type YYYY-MM-DD'}
+ `('dateValidator: Should match validate date', ({ date, result }) => {
+ let validatedResult = dateValidator(date);
+ expect(validatedResult).toEqual(result);
+ });
});
diff --git a/src/Utilities/hooks/Hooks.js b/src/Utilities/hooks/Hooks.js
index e6c9084a8..93611ee19 100644
--- a/src/Utilities/hooks/Hooks.js
+++ b/src/Utilities/hooks/Hooks.js
@@ -6,330 +6,375 @@ import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome'
import isDeepEqualReact from 'fast-deep-equal/react';
import { Spinner } from '@patternfly/react-core';
import messages from '../../Messages';
-import { defaultCompoundSortValues, exportNotifications } from '../constants';
+import { defaultCompoundSortValues, exportNotifications, multiValueFilters } from '../constants';
import {
- convertLimitOffset,
- getLimitFromPageSize,
- buildApiFilters,
- getOffsetFromPageLimit,
- encodeURLParams,
- mapGlobalFilters,
- objUndefinedToFalse,
- objOnlyWithTrue
+ convertLimitOffset,
+ getLimitFromPageSize,
+ buildApiFilters,
+ getOffsetFromPageLimit,
+ encodeURLParams,
+ mapGlobalFilters,
+ objUndefinedToFalse,
+ objOnlyWithTrue,
} from '../Helpers';
import { intl } from '../IntlProvider';
-import { multiValueFilters } from '../constants';
import { assignSystemToPatchSet, updatePatchSets } from '../api';
import { createSystemsSortBy } from '../SystemsHelpers';
import { ColumnManagementModal } from '@patternfly/react-component-groups';
export const useSetPage = (limit, callback) => {
- const onSetPage = React.useCallback((_, page) =>
- callback({ offset: getOffsetFromPageLimit(page, limit) })
- );
- return onSetPage;
+ const onSetPage = React.useCallback((_, page) =>
+ callback({ offset: getOffsetFromPageLimit(page, limit) }),
+ );
+ return onSetPage;
};
export const useHandleRefresh = (metadata, callback) => {
- const handleRefresh = React.useCallback(({ page, per_page: perPage }) => {
- const offset = getOffsetFromPageLimit(page, perPage);
- const limit = getLimitFromPageSize(perPage);
- (metadata.offset !== offset || metadata.limit !== limit) &&
- callback({
- ...(metadata.offset !== offset && { offset }),
- ...(metadata.limit !== limit && { limit })
- });
- });
- return handleRefresh;
+ const handleRefresh = React.useCallback(({ page, per_page: perPage }) => {
+ const offset = getOffsetFromPageLimit(page, perPage);
+ const limit = getLimitFromPageSize(perPage);
+ (metadata.offset !== offset || metadata.limit !== limit) &&
+ callback({
+ ...(metadata.offset !== offset && { offset }),
+ ...(metadata.limit !== limit && { limit }),
+ });
+ });
+ return handleRefresh;
};
export const usePagePerPage = (limit, offset) => {
- const [page, perPage] = React.useMemo(
- () => convertLimitOffset(limit, offset),
- [limit, offset]
- );
- return [page, perPage];
+ const [page, perPage] = React.useMemo(() => convertLimitOffset(limit, offset), [limit, offset]);
+ return [page, perPage];
};
-export const usePerPageSelect = callback => {
- const onPerPageSelect = React.useCallback((_, perPage) =>
- callback({ limit: getLimitFromPageSize(perPage), offset: 0 })
- );
- return onPerPageSelect;
+export const usePerPageSelect = (callback) => {
+ const onPerPageSelect = React.useCallback((_, perPage) =>
+ callback({ limit: getLimitFromPageSize(perPage), offset: 0 }),
+ );
+ return onPerPageSelect;
};
-export const useSortColumn = (columns, callback, offset = 0, compoundSortValues = defaultCompoundSortValues) => {
- const onSort = React.useCallback((_, index, direction) => {
- let columnName = columns[index - offset].key;
- const compoundKey = compoundSortValues[columnName];
- if (compoundKey) {
- columnName = compoundKey[direction];
- }
- else if (direction === SortByDirection.desc) {
- columnName = '-' + columnName;
- }
+export const useSortColumn = (
+ columns,
+ callback,
+ offset = 0,
+ compoundSortValues = defaultCompoundSortValues,
+) => {
+ const onSort = React.useCallback((_, index, direction) => {
+ let columnName = columns[index - offset].key;
+ const compoundKey = compoundSortValues[columnName];
+ if (compoundKey) {
+ columnName = compoundKey[direction];
+ } else if (direction === SortByDirection.desc) {
+ columnName = '-' + columnName;
+ }
- callback({ sort: columnName });
- });
- return onSort;
+ callback({ sort: columnName });
+ });
+ return onSort;
};
export const useRemoveFilter = (filters, callback, defaultFilters = { filter: {} }) => {
- const removeFilter = React.useCallback((selected, resetFilters, shouldReset) => {
- let newParams = { filter: {} };
- selected.forEach(selectedItem => {
- let { id: categoryId, chips } = selectedItem;
-
- if (categoryId !== 'search' && !multiValueFilters.includes(categoryId)) {
- let activeFilter = filters[categoryId];
- const toRemove = chips.map(item => item.id?.toString());
- if (Array.isArray(activeFilter)) {
- newParams.filter[categoryId] = activeFilter.filter(
- item => !toRemove.includes(item.toString())
- );
- } else {
- newParams.filter[categoryId] = undefined;
- }
- } else if (multiValueFilters.includes(categoryId)) {
- const filterValues = filters[categoryId] &&
- (typeof(filters[categoryId]) === 'string' && filters[categoryId].split(',')
- || filters[categoryId]) || [];
-
- newParams.filter[categoryId] = (filterValues.length !== 1)
- && filterValues.filter(filterValue => !chips.find(chip => chip.value === filterValue)).join(',') || undefined;
- }
- else {
- newParams.search = '';
- }
-
- });
-
- if (shouldReset) {
- newParams = resetFilters(newParams);
+ const removeFilter = React.useCallback((selected, resetFilters, shouldReset) => {
+ let newParams = { filter: {} };
+ selected.forEach((selectedItem) => {
+ let { id: categoryId, chips } = selectedItem;
+
+ if (categoryId !== 'search' && !multiValueFilters.includes(categoryId)) {
+ let activeFilter = filters[categoryId];
+ const toRemove = chips.map((item) => item.id?.toString());
+ if (Array.isArray(activeFilter)) {
+ newParams.filter[categoryId] = activeFilter.filter(
+ (item) => !toRemove.includes(item.toString()),
+ );
+ } else {
+ newParams.filter[categoryId] = undefined;
}
-
- callback({ ...newParams });
+ } else if (multiValueFilters.includes(categoryId)) {
+ const filterValues =
+ (filters[categoryId] &&
+ ((typeof filters[categoryId] === 'string' && filters[categoryId].split(',')) ||
+ filters[categoryId])) ||
+ [];
+
+ newParams.filter[categoryId] =
+ (filterValues.length !== 1 &&
+ filterValues
+ .filter((filterValue) => !chips.find((chip) => chip.value === filterValue))
+ .join(',')) ||
+ undefined;
+ } else {
+ newParams.search = '';
+ }
});
- const deleteFilterGroup = (__, filters) => {
- removeFilter(filters);
- };
+ if (shouldReset) {
+ newParams = resetFilters(newParams);
+ }
- const deleteFilters = (__, selected, shouldReset) => {
- const resetFilters = (currentFilters) => {
- if (Object.keys(defaultFilters.filter).length > 0) {
- currentFilters.filter = { ...currentFilters.filter, ...defaultFilters.filter };
- }
+ callback({ ...newParams });
+ });
- return currentFilters;
- };
+ const deleteFilterGroup = (__, filters) => {
+ removeFilter(filters);
+ };
- removeFilter(selected, resetFilters, shouldReset);
+ const deleteFilters = (__, selected, shouldReset) => {
+ const resetFilters = (currentFilters) => {
+ if (Object.keys(defaultFilters.filter).length > 0) {
+ currentFilters.filter = { ...currentFilters.filter, ...defaultFilters.filter };
+ }
+
+ return currentFilters;
};
- return [deleteFilters, deleteFilterGroup];
+ removeFilter(selected, resetFilters, shouldReset);
+ };
+
+ return [deleteFilters, deleteFilterGroup];
};
export const useDeepCompareEffect = (effect, deps) => {
- const ref = React.useRef(undefined);
+ const ref = React.useRef(undefined);
- if (!ref.current || !isDeepEqualReact(deps, ref.current)) {
- ref.current = deps;
- }
+ if (!ref.current || !isDeepEqualReact(deps, ref.current)) {
+ ref.current = deps;
+ }
- React.useEffect(effect, ref.current);
+ React.useEffect(effect, ref.current);
};
-export const useBulkSelectConfig = (selectedCount, onSelect, metadata, rows, onCollapse, queryParams) => {
- const [isBulkLoading, setBulkLoading] = React.useState(false);
-
- return ({
- items: [{
- title: intl.formatMessage(messages.labelsBulkSelectNone),
- onClick: () => {
- onSelect('none');
- }
- }, {
- title: intl.formatMessage(messages.labelsBulkSelectPage,
- { count: onCollapse && rows.length / 2 || rows.length }
- ),
- onClick: () => {
- onSelect('page');
- }
+export const useBulkSelectConfig = (
+ selectedCount,
+ onSelect,
+ metadata,
+ rows,
+ onCollapse,
+ queryParams,
+) => {
+ const [isBulkLoading, setBulkLoading] = React.useState(false);
+
+ return {
+ items: [
+ {
+ title: intl.formatMessage(messages.labelsBulkSelectNone),
+ onClick: () => {
+ onSelect('none');
},
- {
- title: intl.formatMessage(messages.labelsBulkSelectAll, { count: metadata.total_items }),
- onClick: () => {
- setBulkLoading(true);
- onSelect('all', null, null, setBulkLoading);
- }
- }],
- onSelect: () => {
- let action = 'none';
- if (selectedCount === 0) {
- action = 'page';
- }
-
- onSelect(action);
+ },
+ {
+ title: intl.formatMessage(messages.labelsBulkSelectPage, {
+ count: (onCollapse && rows.length / 2) || rows.length,
+ }),
+ onClick: () => {
+ onSelect('page');
},
- toggleProps: {
- 'data-ouia-component-type': 'bulk-select-toggle-button',
- 'aria-label': 'Select',
- ...(isBulkLoading ? {
- children: [
-
-
- {` ${selectedCount} selected`}
-
- ]
- } : {})
+ },
+ {
+ title: intl.formatMessage(messages.labelsBulkSelectAll, { count: metadata.total_items }),
+ onClick: () => {
+ setBulkLoading(true);
+ onSelect('all', null, null, setBulkLoading);
},
-
- checked: selectedCount === 0 ? false : selectedCount === metadata.total_items ? true : null,
- isDisabled: isBulkLoading || (metadata.total_items === 0 && selectedCount === 0)
- || (queryParams?.filter?.status?.length === 1 && queryParams?.filter?.status?.[0] === 'Applicable'),
- count: selectedCount
- });
+ },
+ ],
+ onSelect: () => {
+ let action = 'none';
+ if (selectedCount === 0) {
+ action = 'page';
+ }
+
+ onSelect(action);
+ },
+ toggleProps: {
+ 'data-ouia-component-type': 'bulk-select-toggle-button',
+ 'aria-label': 'Select',
+ ...(isBulkLoading
+ ? {
+ children: [
+
+
+ {` ${selectedCount} selected`}
+ ,
+ ],
+ }
+ : {}),
+ },
+
+ checked: selectedCount === 0 ? false : selectedCount === metadata.total_items ? true : null,
+ isDisabled:
+ isBulkLoading ||
+ (metadata.total_items === 0 && selectedCount === 0) ||
+ (queryParams?.filter?.status?.length === 1 &&
+ queryParams?.filter?.status?.[0] === 'Applicable'),
+ count: selectedCount,
+ };
};
-export const useGetEntities = (fetchApi, apply, config, setSearchParams, applyMetadata, applyGlobalFilter) => {
- const { id, packageName } = config || {};
- const mounted = useRef(true);
-
- const getEntities = async (
- _items,
- { orderBy, orderDirection, page, per_page: perPage, patchParams, filters }
- ) => {
- const { selectedTags: activeTags = [] } = patchParams;
- const { selectedTags } = mapGlobalFilters(filters.tagFilters);
-
- const sort = createSystemsSortBy(orderBy, orderDirection, packageName);
- const filter = buildApiFilters(patchParams.filter, filters);
- const items = await fetchApi({
- page,
- perPage,
- ...patchParams,
- filter,
- selectedTags: [...activeTags, ...selectedTags],
- sort,
- ...id && { id } || {},
- ...packageName && { package_name: packageName } || {}
- });
+export const useGetEntities = (
+ fetchApi,
+ apply,
+ config,
+ setSearchParams,
+ applyMetadata,
+ applyGlobalFilter,
+) => {
+ const { id, packageName } = config || {};
+ const mounted = useRef(true);
+
+ const getEntities = async (
+ _items,
+ { orderBy, orderDirection, page, per_page: perPage, patchParams, filters },
+ ) => {
+ const { selectedTags: activeTags = [] } = patchParams;
+ const { selectedTags } = mapGlobalFilters(filters.tagFilters);
+
+ const sort = createSystemsSortBy(orderBy, orderDirection, packageName);
+ const filter = buildApiFilters(patchParams.filter, filters);
+ const items = await fetchApi({
+ page,
+ perPage,
+ ...patchParams,
+ filter,
+ selectedTags: [...activeTags, ...selectedTags],
+ sort,
+ ...((id && { id }) || {}),
+ ...((packageName && { package_name: packageName }) || {}),
+ });
- if (mounted.current) {
- apply({
- page,
- perPage,
- sort
- });
-
- applyMetadata && applyMetadata(items.meta);
- applyGlobalFilter && applyGlobalFilter(selectedTags);
-
- setSearchParams(encodeURLParams({
- page,
- perPage,
- sort,
- filter
- }), {
- replace: true
- });
- }
+ if (mounted.current) {
+ apply({
+ page,
+ perPage,
+ sort,
+ });
+
+ applyMetadata && applyMetadata(items.meta);
+ applyGlobalFilter && applyGlobalFilter(selectedTags);
+
+ setSearchParams(
+ encodeURLParams({
+ page,
+ perPage,
+ sort,
+ filter,
+ }),
+ {
+ replace: true,
+ },
+ );
+ }
- return {
- results: items.data.map(row => ({ ...row, ...row.attributes, id: row.id ?? row.inventory_id })),
- total: items.meta?.total_items
- };
+ return {
+ results: items.data.map((row) => ({
+ ...row,
+ ...row.attributes,
+ id: row.id ?? row.inventory_id,
+ })),
+ total: items.meta?.total_items,
};
+ };
- useEffect(() => {
- mounted.current = true;
+ useEffect(() => {
+ mounted.current = true;
- return () => {
- mounted.current = false;
- };
- }, []);
+ return () => {
+ mounted.current = false;
+ };
+ }, []);
- return getEntities;
+ return getEntities;
};
export const useOnExport = (prefix, queryParams, formatHandlers, dispatch) => {
- const onExport = React.useCallback((_, format) => {
- const date = new Date().toISOString().replace(/[T:]/g, '-').split('.')[0] + '-utc';
- const filename = `${prefix}-${date}`;
- dispatch(addNotification(exportNotifications(format).pending));
- formatHandlers[format](queryParams, prefix).then(data => {
- dispatch(addNotification(exportNotifications(format).success));
- downloadFile(data, filename, format);
- }).catch(() => dispatch(addNotification(exportNotifications().error)));
- });
- return onExport;
+ const onExport = React.useCallback((_, format) => {
+ const date = new Date().toISOString().replace(/[T:]/g, '-').split('.')[0] + '-utc';
+ const filename = `${prefix}-${date}`;
+ dispatch(addNotification(exportNotifications(format).pending));
+ formatHandlers[format](queryParams, prefix)
+ .then((data) => {
+ dispatch(addNotification(exportNotifications(format).success));
+ downloadFile(data, filename, format);
+ })
+ .catch(() => dispatch(addNotification(exportNotifications().error)));
+ });
+ return onExport;
};
export const usePatchSetApi = (wizardState, setWizardState, patchSetID) => {
- const handleApiResponse = (response) => response
- .then(() => {
+ const handleApiResponse = (response) =>
+ response
+ .then(() => {
setWizardState({ ...wizardState, submitted: true, failed: false, requestPending: false });
- })
- .catch((error) => {
- setWizardState({ ...wizardState, submitted: true, failed: true, requestPending: false, error });
- });
-
- const onSubmit = React.useCallback((formValues) => {
- const { name, description, toDate, id } = formValues.existing_patch_set || formValues;
- const { systems } = formValues;
-
- const gmtMidnightDate = new Date(toDate); // get last midnight GMT
- gmtMidnightDate.setDate(gmtMidnightDate.getDate() + 1); // get next midnight GMT
- const localTimezoneOffset = gmtMidnightDate.getTimezoneOffset() * 60000;
-
- // get next local midnight minus 1 second (23:59:59)
- const localMidnightDate = new Date(gmtMidnightDate.getTime() + localTimezoneOffset - 1000);
-
- const requestConfig = {
- name,
- description,
- inventory_ids: (patchSetID || id) ? objUndefinedToFalse(systems) : objOnlyWithTrue(systems),
- config: {
- to_time: localMidnightDate.toISOString()
- }
- };
+ })
+ .catch((error) => {
+ setWizardState({
+ ...wizardState,
+ submitted: true,
+ failed: true,
+ requestPending: false,
+ error,
+ });
+ });
+
+ const onSubmit = React.useCallback((formValues) => {
+ const { name, description, toDate, id } = formValues.existing_patch_set || formValues;
+ const { systems } = formValues;
+
+ const gmtMidnightDate = new Date(toDate); // get last midnight GMT
+ gmtMidnightDate.setDate(gmtMidnightDate.getDate() + 1); // get next midnight GMT
+ const localTimezoneOffset = gmtMidnightDate.getTimezoneOffset() * 60000;
+
+ // get next local midnight minus 1 second (23:59:59)
+ const localMidnightDate = new Date(gmtMidnightDate.getTime() + localTimezoneOffset - 1000);
+
+ const requestConfig = {
+ name,
+ description,
+ inventory_ids: patchSetID || id ? objUndefinedToFalse(systems) : objOnlyWithTrue(systems),
+ config: {
+ to_time: localMidnightDate.toISOString(),
+ },
+ };
- setWizardState({ ...wizardState, submitted: true, failed: false, requestPending: true });
+ setWizardState({ ...wizardState, submitted: true, failed: false, requestPending: true });
- const response = (patchSetID || id)
- ? updatePatchSets(requestConfig, patchSetID || id)
- : assignSystemToPatchSet(requestConfig);
+ const response =
+ patchSetID || id
+ ? updatePatchSets(requestConfig, patchSetID || id)
+ : assignSystemToPatchSet(requestConfig);
- handleApiResponse(response);
- });
- return onSubmit;
+ handleApiResponse(response);
+ });
+ return onSubmit;
};
-/***
+/** *
* Returns readly available user entitelments
* @returns {getEntitlements} function that returns entitlements
*/
export const useEntitlements = () => {
- const chrome = useChrome();
- const getEntitlements = useCallback(async () => {
- const user = await chrome.auth.getUser();
- return user.entitlements;
- });
+ const chrome = useChrome();
+ const getEntitlements = useCallback(async () => {
+ const user = await chrome.auth.getUser();
+ return user.entitlements;
+ });
- return getEntitlements;
+ return getEntitlements;
};
export const useColumnManagement = (columns, onApply) => {
- const [isModalOpen, setModalOpen] = useState(false);
-
- return [(
- onApply(newColumns)}
- isOpen={isModalOpen}
- setOpen={setModalOpen}
- onClose={() => setModalOpen(false)}
- key="column-mgmt-modal"
- />), setModalOpen];
+ const [isModalOpen, setModalOpen] = useState(false);
+
+ return [
+ onApply(newColumns)}
+ isOpen={isModalOpen}
+ setOpen={setModalOpen}
+ onClose={() => setModalOpen(false)}
+ key='column-mgmt-modal'
+ />,
+ setModalOpen,
+ ];
};
diff --git a/src/Utilities/hooks/Hooks.test.js b/src/Utilities/hooks/Hooks.test.js
index 00aec7285..41321ccdc 100644
--- a/src/Utilities/hooks/Hooks.test.js
+++ b/src/Utilities/hooks/Hooks.test.js
@@ -1,139 +1,150 @@
-/* eslint-disable */
import { SortByDirection } from '@patternfly/react-table';
-import { useEntitlements, useHandleRefresh, usePagePerPage,
- usePerPageSelect, useRemoveFilter, useSetPage, useSortColumn } from './Hooks';
+import {
+ useEntitlements,
+ useHandleRefresh,
+ usePagePerPage,
+ usePerPageSelect,
+ useRemoveFilter,
+ useSetPage,
+ useSortColumn,
+} from './Hooks';
import { packagesListDefaultFilters } from '../constants';
import { renderHook } from '@testing-library/react';
jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
- useChrome: jest.fn(() => ({
- auth: {
- getUser: () => new Promise(
- (resolve) => resolve({ entitlements: { 'test-entitelement': true } })
- )
- }
- }))
+ useChrome: jest.fn(() => ({
+ auth: {
+ getUser: () =>
+ new Promise((resolve) => resolve({ entitlements: { 'test-entitelement': true } })),
+ },
+ })),
}));
-
describe('Custom hooks tests', () => {
- it('useSetPage, should return correct offset for pagination', () => {
- let limit = 10;
- let page = 5;
- let finalResult = 40;
- let callback = jest.fn();
- const { result } = renderHook(() => useSetPage(limit, callback));
- result.current({}, page);
+ it('useSetPage, should return correct offset for pagination', () => {
+ let limit = 10;
+ let page = 5;
+ let finalResult = 40;
+ let callback = jest.fn();
+ const { result } = renderHook(() => useSetPage(limit, callback));
+ result.current({}, page);
- expect(callback).toHaveBeenCalledWith({ offset: finalResult });
- });
- it('usePerPageSelect, should return correct limit and offset', () => {
- let perPage = 15;
- let finalResult = { offset: 0, limit: perPage };
- let callback = jest.fn();
- const { result } = renderHook(() => usePerPageSelect(callback));
- result.current({}, perPage);
+ expect(callback).toHaveBeenCalledWith({ offset: finalResult });
+ });
+ it('usePerPageSelect, should return correct limit and offset', () => {
+ let perPage = 15;
+ let finalResult = { offset: 0, limit: perPage };
+ let callback = jest.fn();
+ const { result } = renderHook(() => usePerPageSelect(callback));
+ result.current({}, perPage);
- expect(callback).toHaveBeenCalledWith(finalResult);
- });
- it('useSortColumn, should return desc sort with offset ', () => {
- let columns = [
- {
- key: 'a'
- },
- {
- key: 'b'
- },
- {
- key: 'c'
- },
- {
- key: 'd'
- }
- ];
- let offset = 2;
- let index = 2;
- let direction = SortByDirection.desc;
- let finalResult = { sort: '-a' };
- let callback = jest.fn();
+ expect(callback).toHaveBeenCalledWith(finalResult);
+ });
+ it('useSortColumn, should return desc sort with offset ', () => {
+ let columns = [
+ {
+ key: 'a',
+ },
+ {
+ key: 'b',
+ },
+ {
+ key: 'c',
+ },
+ {
+ key: 'd',
+ },
+ ];
+ let offset = 2;
+ let index = 2;
+ let direction = SortByDirection.desc;
+ let finalResult = { sort: '-a' };
+ let callback = jest.fn();
- const { result } = renderHook(() => useSortColumn(columns, callback, offset));
- result.current({}, index, direction);
+ const { result } = renderHook(() => useSortColumn(columns, callback, offset));
+ result.current({}, index, direction);
- expect(callback).toHaveBeenCalledWith(finalResult);
- });
- it('useSortColumn, should return asc sort without offset', () => {
- let columns = [
- {
- key: 'a'
- },
- {
- key: 'b'
- },
- {
- key: 'c'
- },
- {
- key: 'd'
- }
- ];
- let index = 0;
- let direction = SortByDirection.asc;
- let finalResult = { sort: 'a' };
- let callback = jest.fn();
- const { result } = renderHook(() => useSortColumn(columns, callback));
- result.current({}, index, direction);
+ expect(callback).toHaveBeenCalledWith(finalResult);
+ });
+ it('useSortColumn, should return asc sort without offset', () => {
+ let columns = [
+ {
+ key: 'a',
+ },
+ {
+ key: 'b',
+ },
+ {
+ key: 'c',
+ },
+ {
+ key: 'd',
+ },
+ ];
+ let index = 0;
+ let direction = SortByDirection.asc;
+ let finalResult = { sort: 'a' };
+ let callback = jest.fn();
+ const { result } = renderHook(() => useSortColumn(columns, callback));
+ result.current({}, index, direction);
- expect(callback).toHaveBeenCalledWith(finalResult);
- });
- it('usePagePerPage, should return correct page and perPage', () => {
- let limit = 50;
- let offset = 1100;
- let expected = [23, 50];
- const { result } = renderHook(() => usePagePerPage(limit, offset));
- expect(result.current).toEqual(expected);
- });
+ expect(callback).toHaveBeenCalledWith(finalResult);
+ });
+ it('usePagePerPage, should return correct page and perPage', () => {
+ let limit = 50;
+ let offset = 1100;
+ let expected = [23, 50];
+ const { result } = renderHook(() => usePagePerPage(limit, offset));
+ expect(result.current).toEqual(expected);
+ });
- it.each`
- filter | apply | selected |finalResult
- ${{ advisory_type: 2 }} | ${jest.fn()} | ${[{ id: "advisory_type", chips: [{ id: 1 }] }]} | ${{ filter: { advisory_type: undefined }}}
- ${{advisory_type: [2,1]}} | ${jest.fn()} | ${[{ id: "advisory_type", chips: [{id: 1}] }]} | ${{filter: {advisory_type: [2]}}}
- ${{search: "asd"}} | ${jest.fn()} | ${[{ id: "search"}]} | ${{filter: {}, search: ''}}
- `('useRemoveFilter: should return correct filter for $filter',({filter, apply, finalResult, selected}) => {
- const { result } = renderHook(() => useRemoveFilter(filter, apply));
- result.current[0]({}, selected)
- expect(apply).toHaveBeenCalledWith(finalResult);
- });
+ it.each`
+ filter | apply | selected | finalResult
+ ${{ advisory_type: 2 }} | ${jest.fn()} | ${[{ id: 'advisory_type', chips: [{ id: 1 }] }]} | ${{ filter: { advisory_type: undefined } }}
+ ${{ advisory_type: [2, 1] }} | ${jest.fn()} | ${[{ id: 'advisory_type', chips: [{ id: 1 }] }]} | ${{ filter: { advisory_type: [2] } }}
+ ${{ search: 'asd' }} | ${jest.fn()} | ${[{ id: 'search' }]} | ${{ filter: {}, search: '' }}
+ `(
+ 'useRemoveFilter: should return correct filter for $filter',
+ ({ filter, apply, finalResult, selected }) => {
+ const { result } = renderHook(() => useRemoveFilter(filter, apply));
+ result.current[0]({}, selected);
+ expect(apply).toHaveBeenCalledWith(finalResult);
+ },
+ );
- it.each`
- filter | apply | selected |finalResult
- ${{ advisory_type: 2 }} | ${jest.fn()} | ${[{ id: "advisory_type", chips: [{ id: 1 }] }]} | ${{ filter: { advisory_type: undefined, systems_applicable: ["gt:0"] } }}
- ${{ search: "asd" }} | ${jest.fn()} | ${[{ id: "search" }]} | ${{ filter: { systems_applicable: ["gt:0"] }, search: '' }}
- `('useRemoveFilter: should reset to default filters for $filter while ', ({ filter, apply, finalResult, selected }) => {
- const { result } = renderHook(() => useRemoveFilter(filter, apply, packagesListDefaultFilters));
- result.current[0]({}, selected, true)
- expect(apply).toHaveBeenCalledWith(finalResult);
- });
+ it.each`
+ filter | apply | selected | finalResult
+ ${{ advisory_type: 2 }} | ${jest.fn()} | ${[{ id: 'advisory_type', chips: [{ id: 1 }] }]} | ${{ filter: { advisory_type: undefined, systems_applicable: ['gt:0'] } }}
+ ${{ search: 'asd' }} | ${jest.fn()} | ${[{ id: 'search' }]} | ${{ filter: { systems_applicable: ['gt:0'] }, search: '' }}
+ `(
+ 'useRemoveFilter: should reset to default filters for $filter while ',
+ ({ filter, apply, finalResult, selected }) => {
+ const { result } = renderHook(() =>
+ useRemoveFilter(filter, apply, packagesListDefaultFilters),
+ );
+ result.current[0]({}, selected, true);
+ expect(apply).toHaveBeenCalledWith(finalResult);
+ },
+ );
- it.each`
- metadata | apply | input | finalResult
- ${{limit: 10, offset: 0}} | ${jest.fn()} | ${{page: 2, per_page: 10}} | ${{offset:10}}
- ${{limit: 10, offset: 10}} | ${jest.fn()} | ${{page: 2, per_page: 20}} | ${{offset:20, limit: 20}}
- ${{limit: 10, offset: 10}} | ${jest.fn()} | ${{page: 2, per_page: 10}} | ${undefined}
- `('useHandleRefresh: should return correct filter',({metadata, apply, finalResult, input}) => {
- const { result } = renderHook(() =>useHandleRefresh(metadata, apply));
- result.current(input)
- if (finalResult) {
- expect(apply).toHaveBeenCalledWith(finalResult);
- }
- else {
- expect(apply).not.toHaveBeenCalled();
- }
- });
+ it.each`
+ metadata | apply | input | finalResult
+ ${{ limit: 10, offset: 0 }} | ${jest.fn()} | ${{ page: 2, per_page: 10 }} | ${{ offset: 10 }}
+ ${{ limit: 10, offset: 10 }} | ${jest.fn()} | ${{ page: 2, per_page: 20 }} | ${{ offset: 20, limit: 20 }}
+ ${{ limit: 10, offset: 10 }} | ${jest.fn()} | ${{ page: 2, per_page: 10 }} | ${undefined}
+ `('useHandleRefresh: should return correct filter', ({ metadata, apply, finalResult, input }) => {
+ const { result } = renderHook(() => useHandleRefresh(metadata, apply));
+ result.current(input);
+ if (finalResult) {
+ expect(apply).toHaveBeenCalledWith(finalResult);
+ } else {
+ expect(apply).not.toHaveBeenCalled();
+ }
+ });
- it('useEntitlements, should return correct entitlements', async () => {
- const { result } = renderHook(() => useEntitlements());
- const finalResult = await result.current();
- expect(finalResult).toEqual({ 'test-entitelement': true });
- });
+ it('useEntitlements, should return correct entitlements', async () => {
+ const { result } = renderHook(() => useEntitlements());
+ const finalResult = await result.current();
+ expect(finalResult).toEqual({ 'test-entitelement': true });
+ });
});
diff --git a/src/Utilities/hooks/useFeatureFlag.js b/src/Utilities/hooks/useFeatureFlag.js
index 012e7c7b9..7977b369d 100644
--- a/src/Utilities/hooks/useFeatureFlag.js
+++ b/src/Utilities/hooks/useFeatureFlag.js
@@ -1,7 +1,7 @@
import { useFlag, useFlagsStatus } from '@unleash/proxy-client-react';
export default (flag) => {
- const { flagsReady } = useFlagsStatus();
- const isFlagEnabled = useFlag(flag);
- return flagsReady ? isFlagEnabled : false;
+ const { flagsReady } = useFlagsStatus();
+ const isFlagEnabled = useFlag(flag);
+ return flagsReady ? isFlagEnabled : false;
};
diff --git a/src/Utilities/hooks/useFetchBatched.js b/src/Utilities/hooks/useFetchBatched.js
index d4ba16778..df15dfa4b 100644
--- a/src/Utilities/hooks/useFetchBatched.js
+++ b/src/Utilities/hooks/useFetchBatched.js
@@ -1,48 +1,43 @@
import usePromiseQueue from './usePromiseQueue';
export const useFetchBatched = () => {
- const { isResolving: isLoading, resolve } = usePromiseQueue();
-
- return {
- isLoading,
- fetchBatched: async (fetchFunction, filter, total, batchSize = 50) => {
- if (!total) {
- total = await fetchFunction({ ...filter, limit: 1 }).then(
- response => response?.meta?.total_items || 0
- );
- }
-
- const pages = Math.ceil(total / batchSize) || 1;
-
- const results = resolve(
- [...new Array(pages)].map(
- // eslint-disable-next-line camelcase
- (_, pageIdx) => () => {
- return fetchFunction({
- ...filter,
- offset: pageIdx * batchSize,
- limit: batchSize
- });
- }
- )
- );
-
- return results;
- },
- fetchBatchedInline: (fetchFunction, list, batchSize = 20) => {
- const pages = Math.ceil(list.length / batchSize) || 1;
-
- const results = resolve(
- [...new Array(pages)].map(
- (_, pageIdx) => () =>
- fetchFunction(
- list.slice(batchSize * pageIdx, batchSize * (pageIdx + 1))
- )
- )
- );
-
- return results;
- }
- };
+ const { isResolving: isLoading, resolve } = usePromiseQueue();
+
+ return {
+ isLoading,
+ fetchBatched: async (fetchFunction, filter, total, batchSize = 50) => {
+ if (!total) {
+ total = await fetchFunction({ ...filter, limit: 1 }).then(
+ (response) => response?.meta?.total_items || 0,
+ );
+ }
+
+ const pages = Math.ceil(total / batchSize) || 1;
+
+ const results = resolve(
+ [...new Array(pages)].map(
+ (_, pageIdx) => () =>
+ fetchFunction({
+ ...filter,
+ offset: pageIdx * batchSize,
+ limit: batchSize,
+ }),
+ ),
+ );
+
+ return results;
+ },
+ fetchBatchedInline: (fetchFunction, list, batchSize = 20) => {
+ const pages = Math.ceil(list.length / batchSize) || 1;
+
+ const results = resolve(
+ [...new Array(pages)].map(
+ (_, pageIdx) => () =>
+ fetchFunction(list.slice(batchSize * pageIdx, batchSize * (pageIdx + 1))),
+ ),
+ );
+
+ return results;
+ },
+ };
};
-
diff --git a/src/Utilities/hooks/useOnSelect.js b/src/Utilities/hooks/useOnSelect.js
index d2c1533af..cd5d781d5 100644
--- a/src/Utilities/hooks/useOnSelect.js
+++ b/src/Utilities/hooks/useOnSelect.js
@@ -7,176 +7,168 @@ import { useFetchBatched } from './useFetchBatched';
import isArray from 'lodash/isArray';
export const ID_API_ENDPOINTS = {
- advisories: '/ids/advisories',
- systems: '/ids/systems',
- templates: '/baselines',
- advisorySystems: (advisoryID) => `/ids/advisories/${advisoryID}/systems`,
- systemAdvisories: (systemID) => `/ids/systems/${systemID}/advisories`,
- packageSystems: (packageName) => `/packages/${packageName}/systems`,
- systemPackages: (systemID) => `/systems/${systemID}/packages`,
- templateSystems: (templateId) => `/ids/baselines/${templateId}/systems`
-};
-const isArrayWithData = (dataStructure) => {
- return isArray(dataStructure) && dataStructure.length;
+ advisories: '/ids/advisories',
+ systems: '/ids/systems',
+ templates: '/baselines',
+ advisorySystems: (advisoryID) => `/ids/advisories/${advisoryID}/systems`,
+ systemAdvisories: (systemID) => `/ids/systems/${systemID}/advisories`,
+ packageSystems: (packageName) => `/packages/${packageName}/systems`,
+ systemPackages: (systemID) => `/systems/${systemID}/packages`,
+ templateSystems: (templateId) => `/ids/baselines/${templateId}/systems`,
};
+const isArrayWithData = (dataStructure) => isArray(dataStructure) && dataStructure.length;
+
+const useFetchAllIDs = (endpoint, apiResponseTransformer, totalItems) => {
+ const { fetchBatched } = useFetchBatched();
+ return useCallback(
+ async (queryParams) => {
+ const response = await fetchBatched(
+ (filter) => fetchIDs(endpoint, filter),
+ queryParams,
+ totalItems,
+ 100,
+ );
+
+ const aggregatedResponse = response.reduce(
+ (accumulator = {}, currentValue) => {
+ Object.keys(accumulator).forEach((key) => {
+ if (isArrayWithData(currentValue[key])) {
+ accumulator[key] = accumulator[key].concat(currentValue[key]);
+ }
+ });
-const useFetchAllIDs = (
- endpoint,
- apiResponseTransformer,
- totalItems
-) => {
- const { fetchBatched } = useFetchBatched();
- return useCallback(async (queryParams) => {
- const response = await fetchBatched(
- (filter) => fetchIDs(endpoint, filter),
- queryParams,
- totalItems,
- 100
- );
-
- const aggregatedResponse = response.reduce((accumulator = {}, currentValue) => {
- Object.keys(accumulator).forEach(key => {
- if (isArrayWithData(currentValue[key])) {
- accumulator[key] = accumulator[key].concat(currentValue[key]);
- }
- });
-
- return accumulator;
- }, { data: [], ids: [] });
-
- return apiResponseTransformer ? apiResponseTransformer(aggregatedResponse) : aggregatedResponse;
+ return accumulator;
+ },
+ { data: [], ids: [] },
+ );
+
+ return apiResponseTransformer
+ ? apiResponseTransformer(aggregatedResponse)
+ : aggregatedResponse;
},
- [totalItems, endpoint, fetchBatched]);
+ [totalItems, endpoint, fetchBatched],
+ );
};
const useCreateSelectedRow = (transformKey, constructFilename) =>
- useCallback((rows, toSelect = []) => {
- const { ids, data } = rows;
- const shouldUseOnlyIDs = !isArrayWithData(data);
- const items = shouldUseOnlyIDs ? ids : data;
-
- items.forEach((item) => {
- const id = shouldUseOnlyIDs ? item : item.id;
-
- //expanded rows does not have ID and should be disabled for selection
- if (!(isObject(item) && item.isExpandedRow)) {
- toSelect.push(
- {
- id: transformKey ? transformKey(item) : id,
- selected: constructFilename ? constructFilename(item) : id
- }
- );
- }
+ useCallback((rows, toSelect = []) => {
+ const { ids, data } = rows;
+ const shouldUseOnlyIDs = !isArrayWithData(data);
+ const items = shouldUseOnlyIDs ? ids : data;
+
+ items.forEach((item) => {
+ const id = shouldUseOnlyIDs ? item : item.id;
+
+ // expanded rows does not have ID and should be disabled for selection
+ if (!(isObject(item) && item.isExpandedRow)) {
+ toSelect.push({
+ id: transformKey ? transformKey(item) : id,
+ selected: constructFilename ? constructFilename(item) : id,
});
-
- return toSelect;
+ }
});
-const createSelectors = (
- createSelectedRow,
- dispatchSelection,
- toggleAllSystemsSelected
-) => {
- const selectNone = (rows) => {
- const toSelect = [];
- Object.keys(rows).forEach(id => {
- toSelect.push(
- {
- id,
- selected: false
- }
- );
- });
+ return toSelect;
+ });
+
+const createSelectors = (createSelectedRow, dispatchSelection, toggleAllSystemsSelected) => {
+ const selectNone = (rows) => {
+ const toSelect = [];
+ Object.keys(rows).forEach((id) => {
+ toSelect.push({
+ id,
+ selected: false,
+ });
+ });
- dispatchSelection(toSelect);
- toggleAllSystemsSelected(false);
- };
-
- const selectPage = (pageRows) => {
- if (Array.isArray(pageRows)) {
- pageRows = pageRows.filter(row => !row.disableSelection);
- }
-
- dispatchSelection(createSelectedRow({ data: pageRows }));
- };
-
- const selectAll = (fetchIDs, queryParams) => {
- return fetchIDs(queryParams).then(response => {
- if (isArrayWithData(response.data)) {
- let rowsToSelect = response.data.filter(row => row.status !== 'Applicable');
- dispatchSelection(createSelectedRow({ data: rowsToSelect }));
- } else {
- dispatchSelection(createSelectedRow(response));
- toggleAllSystemsSelected(true);
- }
- });
- };
+ dispatchSelection(toSelect);
+ toggleAllSystemsSelected(false);
+ };
+
+ const selectPage = (pageRows) => {
+ if (Array.isArray(pageRows)) {
+ pageRows = pageRows.filter((row) => !row.disableSelection);
+ }
+
+ dispatchSelection(createSelectedRow({ data: pageRows }));
+ };
+
+ const selectAll = (fetchIDs, queryParams) =>
+ fetchIDs(queryParams).then((response) => {
+ if (isArrayWithData(response.data)) {
+ let rowsToSelect = response.data.filter((row) => row.status !== 'Applicable');
+ dispatchSelection(createSelectedRow({ data: rowsToSelect }));
+ } else {
+ dispatchSelection(createSelectedRow(response));
+ toggleAllSystemsSelected(true);
+ }
+ });
- return { selectNone, selectPage, selectAll };
+ return { selectNone, selectPage, selectAll };
};
export const useOnSelect = (rawData, selectedRows, config) => {
- const {
- endpoint,
- queryParams,
- selectionDispatcher,
- constructFilename,
- transformKey,
- apiResponseTransformer,
- //TODO: get rid of this custom selector
- customSelector,
- totalItems
- } = config;
-
- const dispatch = useDispatch();
- const fetchIDs = useFetchAllIDs(endpoint, apiResponseTransformer, totalItems);
- const createSelectedRow = useCreateSelectedRow(transformKey, constructFilename);
-
- const toggleAllSystemsSelected = (flagState) => {
- dispatch(toggleAllSelectedAction(flagState));
- };
-
- const dispatchSelection = (toSelect) => {
- if (customSelector) {
- customSelector(toSelect);
- } else {
- dispatch(selectionDispatcher(toSelect));
- }
- };
-
- const { selectNone, selectPage, selectAll } = createSelectors(
- createSelectedRow,
- dispatchSelection,
- toggleAllSystemsSelected
- );
-
- const onSelect = useCallback(
- async (event, selected, rowId, setBulkLoading = () => {}) => {
- switch (event) {
- case 'none': {
- selectNone(selectedRows);
- break;
- }
-
- case 'page': {
- selectPage(rawData);
- break;
- }
-
- case 'all': {
- selectAll(fetchIDs, queryParams)
- .then(() => setBulkLoading(false));
- break;
- }
-
- default: {
- dispatchSelection([{
- id: transformKey ? transformKey(rawData[rowId]) : rawData[rowId].id,
- selected: selected && (constructFilename ? constructFilename(rawData[rowId]) : true)
- }]);
- }
- }
- });
-
- return onSelect;
+ const {
+ endpoint,
+ queryParams,
+ selectionDispatcher,
+ constructFilename,
+ transformKey,
+ apiResponseTransformer,
+ // TODO: get rid of this custom selector
+ customSelector,
+ totalItems,
+ } = config;
+
+ const dispatch = useDispatch();
+ const fetchIDs = useFetchAllIDs(endpoint, apiResponseTransformer, totalItems);
+ const createSelectedRow = useCreateSelectedRow(transformKey, constructFilename);
+
+ const toggleAllSystemsSelected = (flagState) => {
+ dispatch(toggleAllSelectedAction(flagState));
+ };
+
+ const dispatchSelection = (toSelect) => {
+ if (customSelector) {
+ customSelector(toSelect);
+ } else {
+ dispatch(selectionDispatcher(toSelect));
+ }
+ };
+
+ const { selectNone, selectPage, selectAll } = createSelectors(
+ createSelectedRow,
+ dispatchSelection,
+ toggleAllSystemsSelected,
+ );
+
+ const onSelect = useCallback(async (event, selected, rowId, setBulkLoading = () => {}) => {
+ switch (event) {
+ case 'none': {
+ selectNone(selectedRows);
+ break;
+ }
+
+ case 'page': {
+ selectPage(rawData);
+ break;
+ }
+
+ case 'all': {
+ selectAll(fetchIDs, queryParams).then(() => setBulkLoading(false));
+ break;
+ }
+
+ default: {
+ dispatchSelection([
+ {
+ id: transformKey ? transformKey(rawData[rowId]) : rawData[rowId].id,
+ selected: selected && (constructFilename ? constructFilename(rawData[rowId]) : true),
+ },
+ ]);
+ }
+ }
+ });
+
+ return onSelect;
};
diff --git a/src/Utilities/hooks/useOnSelect.test.js b/src/Utilities/hooks/useOnSelect.test.js
index fe7445b01..0465e0738 100644
--- a/src/Utilities/hooks/useOnSelect.test.js
+++ b/src/Utilities/hooks/useOnSelect.test.js
@@ -3,177 +3,166 @@ import { fetchIDs } from '../api';
import { useOnSelect } from './useOnSelect';
jest.mock('react-redux', () => ({
- ...jest.requireActual('react-redux'),
- useDispatch: jest.fn(() => () => {})
+ ...jest.requireActual('react-redux'),
+ useDispatch: jest.fn(() => () => {}),
}));
jest.mock('../api', () => ({
- ...jest.requireActual('../api'),
- fetchIDs: jest.fn(() => {
- return Promise.resolve({
- data: [{ id: 'db-item' }]
- });
- })
+ ...jest.requireActual('../api'),
+ fetchIDs: jest.fn(() =>
+ Promise.resolve({
+ data: [{ id: 'db-item' }],
+ }),
+ ),
}));
const rows = [
- {
- id: 'row-1',
- selected: true
- },
- {
- id: 'row-2',
- selected: true
- }
+ {
+ id: 'row-1',
+ selected: true,
+ },
+ {
+ id: 'row-2',
+ selected: true,
+ },
];
let selectedRows = {};
let config = {
- endpoint: '/some/api/endpoint',
- queryParams: { search: 'test-search' },
- selectionDispatcher: jest.fn((...args) => args)
+ endpoint: '/some/api/endpoint',
+ queryParams: { search: 'test-search' },
+ selectionDispatcher: jest.fn((...args) => args),
};
describe('useOnSelect', () => {
- it('Should select single item', () => {
- const { result } = renderHook(() =>
- useOnSelect(rows, selectedRows, config)
- );
-
- act(() => {
- result.current('default-single', { 'row-2': true }, 0);
- });
-
- expect(config.selectionDispatcher).toHaveBeenCalledWith([
- { id: 'row-1', selected: true }
- ]);
+ it('Should select single item', () => {
+ const { result } = renderHook(() => useOnSelect(rows, selectedRows, config));
+
+ act(() => {
+ result.current('default-single', { 'row-2': true }, 0);
});
- it('Should select single item while constructing new selection name', () => {
- config.constructFilename = jest.fn(() => 'constructed-name');
+ expect(config.selectionDispatcher).toHaveBeenCalledWith([{ id: 'row-1', selected: true }]);
+ });
- const { result } = renderHook(() =>
- useOnSelect(rows, selectedRows, config)
- );
+ it('Should select single item while constructing new selection name', () => {
+ config.constructFilename = jest.fn(() => 'constructed-name');
- act(() => {
- result.current('default-single', { 'row-2': true }, 0);
- });
+ const { result } = renderHook(() => useOnSelect(rows, selectedRows, config));
- expect(config.selectionDispatcher).toHaveBeenCalledWith([
- { id: 'row-1', selected: 'constructed-name' }
- ]);
+ act(() => {
+ result.current('default-single', { 'row-2': true }, 0);
});
- it('Should select single item while transforming the selection id', () => {
- config.transformKey = jest.fn(() => 'transformed-name');
+ expect(config.selectionDispatcher).toHaveBeenCalledWith([
+ { id: 'row-1', selected: 'constructed-name' },
+ ]);
+ });
- const { result } = renderHook(() =>
- useOnSelect(rows, selectedRows, config)
- );
+ it('Should select single item while transforming the selection id', () => {
+ config.transformKey = jest.fn(() => 'transformed-name');
- act(() => {
- result.current('default-single', {}, 0);
- });
+ const { result } = renderHook(() => useOnSelect(rows, selectedRows, config));
- expect(config.selectionDispatcher).toHaveBeenCalledWith([
- { id: 'transformed-name', selected: 'constructed-name' }
- ]);
+ act(() => {
+ result.current('default-single', {}, 0);
});
- it('Should should use custom selector if provided', () => {
- config.customSelector = jest.fn(() => {});
+ expect(config.selectionDispatcher).toHaveBeenCalledWith([
+ { id: 'transformed-name', selected: 'constructed-name' },
+ ]);
+ });
- const { result } = renderHook(() =>
- useOnSelect(rows, selectedRows, config)
- );
+ it('Should should use custom selector if provided', () => {
+ config.customSelector = jest.fn(() => {});
- act(() => {
- result.current('default-single', {}, 0);
- });
+ const { result } = renderHook(() => useOnSelect(rows, selectedRows, config));
- expect(config.customSelector).toHaveBeenCalledWith([
- { id: 'transformed-name', selected: 'constructed-name' }
- ]);
+ act(() => {
+ result.current('default-single', {}, 0);
});
- it('Should deselect all', () => {
- const { result } = renderHook(() =>
- useOnSelect(rows, { 'row-1': true, 'row-2': true }, config)
- );
+ expect(config.customSelector).toHaveBeenCalledWith([
+ { id: 'transformed-name', selected: 'constructed-name' },
+ ]);
+ });
- act(() => {
- result.current('none', {}, 0);
- });
+ it('Should deselect all', () => {
+ const { result } = renderHook(() =>
+ useOnSelect(rows, { 'row-1': true, 'row-2': true }, config),
+ );
- expect(config.customSelector).toHaveBeenCalledWith([
- { id: 'row-1', selected: false },
- { id: 'row-2', selected: false }
- ]);
+ act(() => {
+ result.current('none', {}, 0);
});
- it('Should select page', () => {
- config.transformKey = undefined;
- config.constructFilename = undefined;
+ expect(config.customSelector).toHaveBeenCalledWith([
+ { id: 'row-1', selected: false },
+ { id: 'row-2', selected: false },
+ ]);
+ });
- const { result } = renderHook(() =>
- useOnSelect(rows, {}, config)
- );
+ it('Should select page', () => {
+ config.transformKey = undefined;
+ config.constructFilename = undefined;
- act(() => {
- result.current('page', {});
- });
+ const { result } = renderHook(() => useOnSelect(rows, {}, config));
- expect(config.customSelector).toHaveBeenCalledWith([
- { id: 'row-1', selected: 'row-1' },
- { id: 'row-2', selected: 'row-2' }
- ]);
+ act(() => {
+ result.current('page', {});
});
- it('Should select all items from db', async () => {
- config.totalItems = 102;
- const { result } = renderHook(() =>
- useOnSelect(rows, {}, config)
- );
-
- result.current('all', {});
-
- await waitFor(
- () => {
- expect(fetchIDs).toHaveBeenCalledTimes(2);
- expect(fetchIDs).toHaveBeenCalledWith('/some/api/endpoint', { limit: 100, offset: 0, search: 'test-search' });
- expect(fetchIDs).toHaveBeenCalledWith('/some/api/endpoint', { limit: 100, offset: 100, search: 'test-search' });
- }
- );
+ expect(config.customSelector).toHaveBeenCalledWith([
+ { id: 'row-1', selected: 'row-1' },
+ { id: 'row-2', selected: 'row-2' },
+ ]);
+ });
+
+ it('Should select all items from db', async () => {
+ config.totalItems = 102;
+ const { result } = renderHook(() => useOnSelect(rows, {}, config));
+
+ result.current('all', {});
+
+ await waitFor(() => {
+ expect(fetchIDs).toHaveBeenCalledTimes(2);
+ expect(fetchIDs).toHaveBeenCalledWith('/some/api/endpoint', {
+ limit: 100,
+ offset: 0,
+ search: 'test-search',
+ });
+ expect(fetchIDs).toHaveBeenCalledWith('/some/api/endpoint', {
+ limit: 100,
+ offset: 100,
+ search: 'test-search',
+ });
});
-
- it('Should skip invalid rows while selection', () => {
- const rows = [
- {
- id: 'valid-1',
- selected: true
- },
- {
- id: 'is-expanded-row',
- isExpandedRow: true
-
- },
- {
- id: 'valid-2',
- selected: true
- }
- ];
-
- const { result } = renderHook(() =>
- useOnSelect(rows, {}, config)
- );
-
- act(() => {
- result.current('page', {});
- });
-
- expect(config.customSelector).toHaveBeenCalledWith([
- { id: 'valid-1', selected: 'valid-1' },
- { id: 'valid-2', selected: 'valid-2' }
- ]);
+ });
+
+ it('Should skip invalid rows while selection', () => {
+ const rows = [
+ {
+ id: 'valid-1',
+ selected: true,
+ },
+ {
+ id: 'is-expanded-row',
+ isExpandedRow: true,
+ },
+ {
+ id: 'valid-2',
+ selected: true,
+ },
+ ];
+
+ const { result } = renderHook(() => useOnSelect(rows, {}, config));
+
+ act(() => {
+ result.current('page', {});
});
+
+ expect(config.customSelector).toHaveBeenCalledWith([
+ { id: 'valid-1', selected: 'valid-1' },
+ { id: 'valid-2', selected: 'valid-2' },
+ ]);
+ });
});
diff --git a/src/Utilities/hooks/usePatchSetState.js b/src/Utilities/hooks/usePatchSetState.js
index b730c0fbc..295f7ebb4 100644
--- a/src/Utilities/hooks/usePatchSetState.js
+++ b/src/Utilities/hooks/usePatchSetState.js
@@ -1,59 +1,57 @@
import { useState } from 'react';
-import {
- filterSelectedActiveSystemIDs
-} from '../Helpers';
+import { filterSelectedActiveSystemIDs } from '../Helpers';
/**
-* Manages unified state for patch set wizard and unassign modal.
-* @param {Object} [selectedRows] selected rows object to be removed.
-* @returns {patchSetState, setPatchSetState, openPatchSetAssignWizard, openUnassignSystemsModal, openPatchSetEditModal}
-*/
+ * Manages unified state for patch set wizard and unassign modal.
+ * @param {Object} [selectedRows] selected rows object to be removed.
+ * @returns {patchSetState, setPatchSetState, openPatchSetAssignWizard, openUnassignSystemsModal, openPatchSetEditModal}
+ */
export const usePatchSetState = (selectedRows) => {
- const [patchSetState, setPatchSetState] = useState({
- isPatchSetWizardOpen: false,
- isUnassignSystemsModalOpen: false,
- isAssignSystemsModalOpen: false,
- shouldRefresh: false,
- systemsIDs: {}
- });
+ const [patchSetState, setPatchSetState] = useState({
+ isPatchSetWizardOpen: false,
+ isUnassignSystemsModalOpen: false,
+ isAssignSystemsModalOpen: false,
+ shouldRefresh: false,
+ systemsIDs: {},
+ });
- const openPatchSetAssignWizard = (systemID) => {
- setPatchSetState({
- isPatchSetWizardOpen: true,
- systemsIDs: typeof systemID === 'string' && systemID !== ''
- ? [systemID]
- : filterSelectedActiveSystemIDs(selectedRows),
- shouldRefresh: false
- }
- );
- };
+ const openPatchSetAssignWizard = (systemID) => {
+ setPatchSetState({
+ isPatchSetWizardOpen: true,
+ systemsIDs:
+ typeof systemID === 'string' && systemID !== ''
+ ? [systemID]
+ : filterSelectedActiveSystemIDs(selectedRows),
+ shouldRefresh: false,
+ });
+ };
- const openUnassignSystemsModal = (systemsIDs) => {
- setPatchSetState({
- isUnassignSystemsModalOpen: true,
- systemsIDs,
- shouldRefresh: false
- });
- };
+ const openUnassignSystemsModal = (systemsIDs) => {
+ setPatchSetState({
+ isUnassignSystemsModalOpen: true,
+ systemsIDs,
+ shouldRefresh: false,
+ });
+ };
- const openAssignSystemsModal = (systemsIDs) => {
- setPatchSetState({
- isAssignSystemsModalOpen: true,
- systemsIDs,
- shouldRefresh: false
- });
- };
+ const openAssignSystemsModal = (systemsIDs) => {
+ setPatchSetState({
+ isAssignSystemsModalOpen: true,
+ systemsIDs,
+ shouldRefresh: false,
+ });
+ };
- const openPatchSetEditModal = (patchSetID) => {
- setPatchSetState({ isPatchSetWizardOpen: true, patchSetID });
- };
+ const openPatchSetEditModal = (patchSetID) => {
+ setPatchSetState({ isPatchSetWizardOpen: true, patchSetID });
+ };
- return {
- patchSetState,
- setPatchSetState,
- openPatchSetAssignWizard,
- openUnassignSystemsModal,
- openAssignSystemsModal,
- openPatchSetEditModal
- };
+ return {
+ patchSetState,
+ setPatchSetState,
+ openPatchSetAssignWizard,
+ openUnassignSystemsModal,
+ openAssignSystemsModal,
+ openPatchSetEditModal,
+ };
};
diff --git a/src/Utilities/hooks/usePromiseQueue.js b/src/Utilities/hooks/usePromiseQueue.js
index 409ee6011..2dfb78890 100644
--- a/src/Utilities/hooks/usePromiseQueue.js
+++ b/src/Utilities/hooks/usePromiseQueue.js
@@ -4,35 +4,35 @@ import pAll from 'p-all';
const DEFAULT_CONCURRENT_PROMISES = 2;
const usePromiseQueue = (limit = DEFAULT_CONCURRENT_PROMISES) => {
- const [results, setResults] = useState({
- isResolving: false,
- promiseResults: undefined
- });
+ const [results, setResults] = useState({
+ isResolving: false,
+ promiseResults: undefined,
+ });
- const resolve = useCallback(
- async (fns) => {
- setResults((state) => ({
- ...state,
- isResolving: true
- }));
- const results = await pAll(fns, {
- concurrency: limit
- });
- setResults({
- isResolving: false,
- promiseResults: results
- });
+ const resolve = useCallback(
+ async (fns) => {
+ setResults((state) => ({
+ ...state,
+ isResolving: true,
+ }));
+ const results = await pAll(fns, {
+ concurrency: limit,
+ });
+ setResults({
+ isResolving: false,
+ promiseResults: results,
+ });
- return results;
- },
- [limit]
- );
+ return results;
+ },
+ [limit],
+ );
- return {
- isResolving: results.isResolving,
- results: results.promiseResults,
- resolve
- };
+ return {
+ isResolving: results.isResolving,
+ results: results.promiseResults,
+ resolve,
+ };
};
export default usePromiseQueue;
diff --git a/src/Utilities/hooks/useRemediationDataProvider.js b/src/Utilities/hooks/useRemediationDataProvider.js
index 15c3e43cb..34af9ced7 100644
--- a/src/Utilities/hooks/useRemediationDataProvider.js
+++ b/src/Utilities/hooks/useRemediationDataProvider.js
@@ -1,80 +1,82 @@
import { useDispatch } from 'react-redux';
import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux';
import { useChrome } from '@redhat-cloud-services/frontend-components/useChrome';
-import {
- removeUndefinedObjectKeys
-} from '../Helpers';
+import { removeUndefinedObjectKeys } from '../Helpers';
const initializeWorker = () => {
- const worker = new Worker(new URL('../RemediationPairs.js', import.meta.url));
- return [worker, () => worker.terminate()];
+ const worker = new Worker(new URL('../RemediationPairs.js', import.meta.url));
+ return [worker, () => worker.terminate()];
};
const deligateWorkerTask = (worker, task) => {
- worker.postMessage(task);
+ worker.postMessage(task);
- //waits web worker response
- return new Promise((resolve, reject) => {
- worker.onmessage = ({ data: { status, error, result } } = {}) => {
- if (status === 'resolved') {
- resolve(result);
- }
+ // waits web worker response
+ return new Promise((resolve, reject) => {
+ worker.onmessage = ({ data: { status, error, result } } = {}) => {
+ if (status === 'resolved') {
+ resolve(result);
+ }
- reject(error);
- };
- });
+ reject(error);
+ };
+ });
};
export const prepareRemediationPairs = async (task, dispatch) => {
- const [worker, terminateWorker] = initializeWorker();
- const deligatedTask = deligateWorkerTask(worker, task);
+ const [worker, terminateWorker] = initializeWorker();
+ const deligatedTask = deligateWorkerTask(worker, task);
- const response = await deligatedTask.catch(err =>
- dispatch(
- addNotification(
- {
- title: `There was an error while processing.`,
- description: err,
- variant: 'danger'
- }
- )
- ));
+ const response = await deligatedTask.catch((err) =>
+ dispatch(
+ addNotification({
+ title: `There was an error while processing.`,
+ description: err,
+ variant: 'danger',
+ }),
+ ),
+ );
- terminateWorker();
+ terminateWorker();
- //displays NoDataModal when there is no patch updates available
- return response?.issues?.length ? response : false;
+ // displays NoDataModal when there is no patch updates available
+ return response?.issues?.length ? response : false;
};
/**
-* Provides remediation data, systems with all of their corresponding issues.
-* @param {Function} [setRemediationLoading] function to toggle remediation loading state
-* @param {Array} [selectedRows] array of systems to calculate
-* @returns {handleSystemsRemoval}
-*/
-export const useRemediationDataProvider = (selectedRows, setRemediationLoading, remediationType, areAllSelected) => {
- const dispatch = useDispatch();
- const chrome = useChrome();
- const remediationDataProvider = async () => {
- setRemediationLoading(true);
+ * Provides remediation data, systems with all of their corresponding issues.
+ * @param {Function} [setRemediationLoading] function to toggle remediation loading state
+ * @param {Array} [selectedRows] array of systems to calculate
+ * @returns {handleSystemsRemoval}
+ */
+export const useRemediationDataProvider = (
+ selectedRows,
+ setRemediationLoading,
+ remediationType,
+ areAllSelected,
+) => {
+ const dispatch = useDispatch();
+ const chrome = useChrome();
+ const remediationDataProvider = async () => {
+ setRemediationLoading(true);
- //Auth token must be added to webworker request as webworker does not have access
- //to default token by platform
- const authToken = await chrome.auth.getToken();
- const remediationPairs = await prepareRemediationPairs(
- {
- payload: removeUndefinedObjectKeys(selectedRows),
- remediationType,
- areAllSelected,
- authToken
- },
- dispatch
- );
+ // Auth token must be added to webworker request as webworker does not have access
+ // to default token by platform
+ const authToken = await chrome.auth.getToken();
+ const remediationPairs = await prepareRemediationPairs(
+ {
+ payload: removeUndefinedObjectKeys(selectedRows),
+ remediationType,
+ areAllSelected,
+ authToken,
+ },
+ dispatch,
+ );
- setRemediationLoading(false);
+ setRemediationLoading(false);
- return remediationPairs;
- };
+ return remediationPairs;
+ };
- return remediationDataProvider;
+ return remediationDataProvider;
};
diff --git a/src/Utilities/hooks/useRemediationDataProvider.test.js b/src/Utilities/hooks/useRemediationDataProvider.test.js
index fed014c19..62764036f 100644
--- a/src/Utilities/hooks/useRemediationDataProvider.test.js
+++ b/src/Utilities/hooks/useRemediationDataProvider.test.js
@@ -1,6 +1,7 @@
-describe('useRemediationDataProvider', () => it('temproray test', () => {
+describe('useRemediationDataProvider', () =>
+ it('temproray test', () => {
expect(true).toBeTruthy();
-}));
+ }));
// /**
// * @jest-environment jsdom
diff --git a/src/Utilities/unitTestingUtilities.js b/src/Utilities/unitTestingUtilities.js
index 55262c059..d7880589d 100644
--- a/src/Utilities/unitTestingUtilities.js
+++ b/src/Utilities/unitTestingUtilities.js
@@ -2,73 +2,71 @@
import { useSelector } from 'react-redux';
import { IntlProvider } from '@redhat-cloud-services/frontend-components-translations';
export const initMocks = () => {
- window.insights = {
- chrome: {
- appNavClick: () => {},
- init: jest.fn(),
- identifyApp: () => {},
- navigation: () => {},
- on: () => {
- return () => {};
- },
- isBeta: () => true,
- auth: {
- getUser: () =>
- new Promise((resolve) =>
- resolve({
- identity: {
- user: {}
- }
- })
- )
- },
- getUserPermissions: () => Promise.resolve([])
- },
- loadInventory: () => new Promise((resolve) => {
- resolve(({
- inventoryConnector: () => {
- const InventoryTable = ({ children }) => A mock passed! {children}
;
- const InventoryDetailHead = ({ children }) => A mock passed! {children}
;
- const AppInfo = ({ children }) => A mock passed! {children}
;
- const DetailWrapper = ({ children }) => A mock passed! {children}
;
-
- return ({ InventoryTable, InventoryDetailHead, AppInfo, DetailWrapper });
- },
- mergeWithEntities: () => {},
- mergeWithDetail: () => {}
- }));
- }),
- loadRemediations: () => new Promise((resolve) => {
+ window.insights = {
+ chrome: {
+ appNavClick: () => {},
+ init: jest.fn(),
+ identifyApp: () => {},
+ navigation: () => {},
+ on: () => () => {},
+ isBeta: () => true,
+ auth: {
+ getUser: () =>
+ new Promise((resolve) =>
resolve({
- openWizard: () => new Promise((resolve) => {
- resolve(true);
- })
- });
- })
- };
+ identity: {
+ user: {},
+ },
+ }),
+ ),
+ },
+ getUserPermissions: () => Promise.resolve([]),
+ },
+ loadInventory: () =>
+ new Promise((resolve) => {
+ resolve({
+ inventoryConnector: () => {
+ const InventoryTable = ({ children }) => A mock passed! {children}
;
+ const InventoryDetailHead = ({ children }) => A mock passed! {children}
;
+ const AppInfo = ({ children }) => A mock passed! {children}
;
+ const DetailWrapper = ({ children }) => A mock passed! {children}
;
+ return { InventoryTable, InventoryDetailHead, AppInfo, DetailWrapper };
+ },
+ mergeWithEntities: () => {},
+ mergeWithDetail: () => {},
+ });
+ }),
+ loadRemediations: () =>
+ new Promise((resolve) => {
+ resolve({
+ openWizard: () =>
+ new Promise((resolve) => {
+ resolve(true);
+ }),
+ });
+ }),
+ };
};
export const mockStore = (initialState, mutatedState) => {
- const customMiddleWare = () => next => action => {
- useSelector.mockImplementation(callback => {
- return callback(mutatedState);
- });
- next(action);
- };
+ const customMiddleWare = () => (next) => (action) => {
+ useSelector.mockImplementation((callback) => callback(mutatedState));
+ next(action);
+ };
- // eslint-disable-next-line no-undef
- const configuredMockStore = configureStore([customMiddleWare]);
+ // eslint-disable-next-line no-undef
+ const configuredMockStore = configureStore([customMiddleWare]);
- return configuredMockStore(initialState);
+ return configuredMockStore(initialState);
};
export const mountWithIntl = (Component) => {
- const wrapper = mount(Component, {
- wrappingComponent: IntlProvider
- });
- const provider = wrapper.getWrappingComponent();
- provider.setProps({ locale: 'en' });
+ const wrapper = mount(Component, {
+ wrappingComponent: IntlProvider,
+ });
+ const provider = wrapper.getWrappingComponent();
+ provider.setProps({ locale: 'en' });
- return wrapper;
+ return wrapper;
};
diff --git a/src/index.js b/src/index.js
index b4e6518e8..e5b2f4a61 100644
--- a/src/index.js
+++ b/src/index.js
@@ -7,25 +7,27 @@ import { Provider } from 'react-redux';
import PropTypes from 'prop-types';
const WrappedSystemDetail = ({ getRegistry, ...props }) => {
- const [Wrapper, setWrapper] = useState();
- useEffect(() => {
- if (getRegistry) {
- getRegistry()?.register?.({ SystemAdvisoryListStore, SystemPackageListStore });
- }
+ const [Wrapper, setWrapper] = useState();
+ useEffect(() => {
+ if (getRegistry) {
+ getRegistry()?.register?.({ SystemAdvisoryListStore, SystemPackageListStore });
+ }
- setWrapper(() => getRegistry ? Provider : Fragment);
- }, []);
- return (
- Wrapper ?
-
- :
-
-
- );
+ setWrapper(() => (getRegistry ? Provider : Fragment));
+ }, []);
+ return Wrapper ? (
+
+
+
+ ) : (
+
+
+
+ );
};
WrappedSystemDetail.propTypes = {
- getRegistry: PropTypes.func
+ getRegistry: PropTypes.func,
};
export { SystemPackageListStore, SystemAdvisoryListStore };
diff --git a/src/store/ActionTypes.js b/src/store/ActionTypes.js
index d109e1397..cac9efe15 100644
--- a/src/store/ActionTypes.js
+++ b/src/store/ActionTypes.js
@@ -2,19 +2,15 @@ export const FETCH_APPLICABLE_ADVISORIES = 'FETCH_APPLICABLE_ADVISORIES';
export const EXPAND_ADVISORY_ROW = 'EXPAND_ADVISORY_ROW';
export const SELECT_ADVISORY_ROW = 'SELECT_ADVISORY_ROW';
export const CHANGE_ADVISORY_LIST_PARAMS = 'CHANGE_ADVISORY_LIST_PARAMS';
-export const CHANGE_SYSTEM_ADVISORY_LIST_PARAMS =
- 'CHANGE_SYSTEM_SYSTEMS_LIST_PARAMS';
+export const CHANGE_SYSTEM_ADVISORY_LIST_PARAMS = 'CHANGE_SYSTEM_SYSTEMS_LIST_PARAMS';
export const EXPAND_SYSTEM_ADVISORY_ROW = 'EXPAND_SYSTEM_ADVISORY_ROW';
-export const FETCH_APPLICABLE_SYSTEM_ADVISORIES =
- 'FETCH_APPLICABLE_SYSTEM_ADVISORIES';
+export const FETCH_APPLICABLE_SYSTEM_ADVISORIES = 'FETCH_APPLICABLE_SYSTEM_ADVISORIES';
export const SELECT_SYSTEM_ADVISORY_ROW = 'SELECT_SYSTEM_ADVISORY_ROW';
export const CLEAR_SYSTEM_ADVISORIES = 'CLEAR_SYSTEM_ADVISORIES';
export const FETCH_ADVISORY_DETAILS = 'FETCH_ADVISORY_DETAILS';
export const CLEAR_ADVISORY_DETAILS = 'CLEAR_ADVISORY_DETAILS';
-export const CHANGE_SYSTEM_PACKAGES_LIST_PARAMS =
- 'CHANGE_SYSTEM_PACKAGES_LIST_PARAMS';
-export const FETCH_APPLICABLE_SYSTEM_PACKAGES =
- 'FETCH_APPLICABLE_SYSTEM_PACKAGES';
+export const CHANGE_SYSTEM_PACKAGES_LIST_PARAMS = 'CHANGE_SYSTEM_PACKAGES_LIST_PARAMS';
+export const FETCH_APPLICABLE_SYSTEM_PACKAGES = 'FETCH_APPLICABLE_SYSTEM_PACKAGES';
export const SELECT_SYSTEM_PACKAGES_ROW = 'SELECT_SYSTEM_PACKAGES_ROW';
export const CLEAR_SYSTEM_PACKAGES = 'CLEAR_SYSTEM_PACKAGES';
export const TRIGGER_GLOBAL_FILTER = 'TRIGGER_GLOBAL_FILTER';
diff --git a/src/store/Actions/Actions.js b/src/store/Actions/Actions.js
index 23ad9b79c..38c99cd05 100644
--- a/src/store/Actions/Actions.js
+++ b/src/store/Actions/Actions.js
@@ -1,297 +1,305 @@
import {
- fetchAdvisoryDetailsApi, fetchApplicableAdvisoriesApi,
- fetchApplicablePackagesApi, fetchApplicableSystemAdvisoriesApi, fetchPackageDetailsApi,
- fetchPackagesList, fetchPackageSystems, fetchCvesInfo, fetchSystemDetails, fetchPatchSets, fetchPatchSet,
- fetchPatchSetSystems
+ fetchAdvisoryDetailsApi,
+ fetchApplicableAdvisoriesApi,
+ fetchApplicablePackagesApi,
+ fetchApplicableSystemAdvisoriesApi,
+ fetchPackageDetailsApi,
+ fetchPackagesList,
+ fetchPackageSystems,
+ fetchCvesInfo,
+ fetchSystemDetails,
+ fetchPatchSets,
+ fetchPatchSet,
+ fetchPatchSetSystems,
} from '../../Utilities/api';
import * as ActionTypes from '../ActionTypes';
-export const fetchApplicableAdvisories = params => ({
- type: ActionTypes.FETCH_APPLICABLE_ADVISORIES,
- payload: new Promise(resolve => {
- resolve(fetchApplicableAdvisoriesApi(params));
- }).then(result => result)
+export const fetchApplicableAdvisories = (params) => ({
+ type: ActionTypes.FETCH_APPLICABLE_ADVISORIES,
+ payload: new Promise((resolve) => {
+ resolve(fetchApplicableAdvisoriesApi(params));
+ }).then((result) => result),
});
-export const fetchApplicableSystemAdvisories = params => ({
- type: ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES,
- payload: new Promise(resolve => {
- resolve(fetchApplicableSystemAdvisoriesApi(params));
- }).then(result => result)
+export const fetchApplicableSystemAdvisories = (params) => ({
+ type: ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES,
+ payload: new Promise((resolve) => {
+ resolve(fetchApplicableSystemAdvisoriesApi(params));
+ }).then((result) => result),
});
-export const fetchAvisoryDetails = params => ({
- type: ActionTypes.FETCH_ADVISORY_DETAILS,
- payload: new Promise(resolve => {
- resolve(fetchAdvisoryDetailsApi(params));
- }).then(result => result),
- noError: true
+export const fetchAvisoryDetails = (params) => ({
+ type: ActionTypes.FETCH_ADVISORY_DETAILS,
+ payload: new Promise((resolve) => {
+ resolve(fetchAdvisoryDetailsApi(params));
+ }).then((result) => result),
+ noError: true,
});
-export const fetchPackageDetails = params => ({
- type: ActionTypes.FETCH_PACKAGE_DETAILS,
- payload: new Promise(resolve => {
- resolve(fetchPackageDetailsApi(params));
- }).then(result => result)
+export const fetchPackageDetails = (params) => ({
+ type: ActionTypes.FETCH_PACKAGE_DETAILS,
+ payload: new Promise((resolve) => {
+ resolve(fetchPackageDetailsApi(params));
+ }).then((result) => result),
});
-export const changeAdvisoryListParams = params => ({
- type: ActionTypes.CHANGE_ADVISORY_LIST_PARAMS,
- payload: params
+export const changeAdvisoryListParams = (params) => ({
+ type: ActionTypes.CHANGE_ADVISORY_LIST_PARAMS,
+ payload: params,
});
-export const changeSystemAdvisoryListParams = params => ({
- type: ActionTypes.CHANGE_SYSTEM_ADVISORY_LIST_PARAMS,
- payload: params
+export const changeSystemAdvisoryListParams = (params) => ({
+ type: ActionTypes.CHANGE_SYSTEM_ADVISORY_LIST_PARAMS,
+ payload: params,
});
-export const changeAdvisorySystemsParams = params => ({
- type: ActionTypes.CHANGE_AFFECTED_SYSTEMS_PARAMS,
- payload: params
+export const changeAdvisorySystemsParams = (params) => ({
+ type: ActionTypes.CHANGE_AFFECTED_SYSTEMS_PARAMS,
+ payload: params,
});
-export const expandAdvisoryRow = rowState => ({
- type: ActionTypes.EXPAND_ADVISORY_ROW,
- payload: rowState
+export const expandAdvisoryRow = (rowState) => ({
+ type: ActionTypes.EXPAND_ADVISORY_ROW,
+ payload: rowState,
});
-export const expandSystemAdvisoryRow = rowState => ({
- type: ActionTypes.EXPAND_SYSTEM_ADVISORY_ROW,
- payload: rowState
+export const expandSystemAdvisoryRow = (rowState) => ({
+ type: ActionTypes.EXPAND_SYSTEM_ADVISORY_ROW,
+ payload: rowState,
});
-export const selectAdvisoryRow = rowState => ({
- type: ActionTypes.SELECT_ADVISORY_ROW,
- payload: rowState
+export const selectAdvisoryRow = (rowState) => ({
+ type: ActionTypes.SELECT_ADVISORY_ROW,
+ payload: rowState,
});
-export const selectSystemAdvisoryRow = rowState => ({
- type: ActionTypes.SELECT_SYSTEM_ADVISORY_ROW,
- payload: rowState
+export const selectSystemAdvisoryRow = (rowState) => ({
+ type: ActionTypes.SELECT_SYSTEM_ADVISORY_ROW,
+ payload: rowState,
});
export const clearSystemAdvisoriesStore = () => ({
- type: ActionTypes.CLEAR_SYSTEM_ADVISORIES,
- payload: []
+ type: ActionTypes.CLEAR_SYSTEM_ADVISORIES,
+ payload: [],
});
export const clearSystemPackagesStore = () => ({
- type: ActionTypes.CLEAR_SYSTEM_PACKAGES,
- payload: []
+ type: ActionTypes.CLEAR_SYSTEM_PACKAGES,
+ payload: [],
});
export const clearAdvisoryDetailStore = () => ({
- type: ActionTypes.CLEAR_ADVISORY_DETAILS,
- payload: []
+ type: ActionTypes.CLEAR_ADVISORY_DETAILS,
+ payload: [],
});
export const clearPackageDetailStore = () => ({
- type: ActionTypes.CLEAR_PACKAGE_DETAILS,
- payload: []
+ type: ActionTypes.CLEAR_PACKAGE_DETAILS,
+ payload: [],
});
-export const fetchPackageSystemsAction = params => ({
- type: ActionTypes.FETCH_PACKAGE_SYSTEMS,
- payload: new Promise(resolve => {
- resolve(fetchPackageSystems(params));
- }).then(result => result)
+export const fetchPackageSystemsAction = (params) => ({
+ type: ActionTypes.FETCH_PACKAGE_SYSTEMS,
+ payload: new Promise((resolve) => {
+ resolve(fetchPackageSystems(params));
+ }).then((result) => result),
});
-export const fetchApplicableSystemPackages = params => ({
- type: ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES,
- payload: new Promise(resolve => {
- resolve(fetchApplicablePackagesApi(params));
- }).then(result => result)
+export const fetchApplicableSystemPackages = (params) => ({
+ type: ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES,
+ payload: new Promise((resolve) => {
+ resolve(fetchApplicablePackagesApi(params));
+ }).then((result) => result),
});
-export const selectSystemPackagesRow = rowState => ({
- type: ActionTypes.SELECT_SYSTEM_PACKAGES_ROW,
- payload: rowState
+export const selectSystemPackagesRow = (rowState) => ({
+ type: ActionTypes.SELECT_SYSTEM_PACKAGES_ROW,
+ payload: rowState,
});
-export const changeSystemPackagesParams = params => ({
- type: ActionTypes.CHANGE_SYSTEM_PACKAGES_LIST_PARAMS,
- payload: params
+export const changeSystemPackagesParams = (params) => ({
+ type: ActionTypes.CHANGE_SYSTEM_PACKAGES_LIST_PARAMS,
+ payload: params,
});
-export const globalFilter = params => ({
- type: ActionTypes.TRIGGER_GLOBAL_FILTER,
- payload: params
+export const globalFilter = (params) => ({
+ type: ActionTypes.TRIGGER_GLOBAL_FILTER,
+ payload: params,
});
-export const changeGlobalTags = params => ({
- type: ActionTypes.CHANGE_GLOBAL_TAGS,
- payload: params
+export const changeGlobalTags = (params) => ({
+ type: ActionTypes.CHANGE_GLOBAL_TAGS,
+ payload: params,
});
-export const changeTags = params => ({
- type: ActionTypes.CHANGE_TAGS,
- payload: params
+export const changeTags = (params) => ({
+ type: ActionTypes.CHANGE_TAGS,
+ payload: params,
});
-export const changeProfile = params => ({
- type: ActionTypes.CHANGE_PROFILE,
- payload: params
+export const changeProfile = (params) => ({
+ type: ActionTypes.CHANGE_PROFILE,
+ payload: params,
});
-export const fetchPackagesAction = params => ({
- type: ActionTypes.FETCH_PACKAGES_LIST,
- payload: new Promise(resolve => {
- resolve(fetchPackagesList(params));
- }).then(result => result)
+export const fetchPackagesAction = (params) => ({
+ type: ActionTypes.FETCH_PACKAGES_LIST,
+ payload: new Promise((resolve) => {
+ resolve(fetchPackagesList(params));
+ }).then((result) => result),
});
-export const changePackagesListParams = params => ({
- type: ActionTypes.CHANGE_PACKAGES_LIST_PARAMS,
- payload: params
+export const changePackagesListParams = (params) => ({
+ type: ActionTypes.CHANGE_PACKAGES_LIST_PARAMS,
+ payload: params,
});
-export const changePackageSystemsParams = params => ({
- type: ActionTypes.CHANGE_PACKAGE_SYSTEMS_PARAMS,
- payload: params
+export const changePackageSystemsParams = (params) => ({
+ type: ActionTypes.CHANGE_PACKAGE_SYSTEMS_PARAMS,
+ payload: params,
});
export const fetchCves = (params) => ({
- type: ActionTypes.FETCH_CVES_INFO,
- payload: new Promise(resolve => {
- resolve(fetchCvesInfo(params));
- }).then(result => result)
+ type: ActionTypes.FETCH_CVES_INFO,
+ payload: new Promise((resolve) => {
+ resolve(fetchCvesInfo(params));
+ }).then((result) => result),
});
-export const changeCvesListParams = params => ({
- type: ActionTypes.CHANGE_CVES_STORE_PARAMS,
- payload: params
+export const changeCvesListParams = (params) => ({
+ type: ActionTypes.CHANGE_CVES_STORE_PARAMS,
+ payload: params,
});
-export const fetchSystemDetailsAction = params => ({
- type: ActionTypes.FETCH_SYSTEM_DETAIL,
- payload: new Promise(resolve => {
- resolve(fetchSystemDetails(params));
- }).then(result => result),
- meta: { noError: true }
+export const fetchSystemDetailsAction = (params) => ({
+ type: ActionTypes.FETCH_SYSTEM_DETAIL,
+ payload: new Promise((resolve) => {
+ resolve(fetchSystemDetails(params));
+ }).then((result) => result),
+ meta: { noError: true },
});
export const clearEntitiesStore = () => ({
- type: ActionTypes.CLEAR_ENTITIES,
- payload: []
+ type: ActionTypes.CLEAR_ENTITIES,
+ payload: [],
});
export const clearInventoryReducer = () => ({
- type: ActionTypes.CLEAR_INVENTORY_REDUCER,
- payload: []
+ type: ActionTypes.CLEAR_INVENTORY_REDUCER,
+ payload: [],
});
-export const changeEntitiesParams = params => ({
- type: ActionTypes.CHANGE_ENTITIES_PARAMS,
- payload: params
+export const changeEntitiesParams = (params) => ({
+ type: ActionTypes.CHANGE_ENTITIES_PARAMS,
+ payload: params,
});
-export const changeSystemsParams = params => ({
- type: ActionTypes.CHANGE_SYSTEMS_PARAMS,
- payload: params
+export const changeSystemsParams = (params) => ({
+ type: ActionTypes.CHANGE_SYSTEMS_PARAMS,
+ payload: params,
});
-export const changeAffectedSystemsParams = params => ({
- type: ActionTypes.CHANGE_AFFECTED_SYSTEMS_PARAMS,
- payload: params
+export const changeAffectedSystemsParams = (params) => ({
+ type: ActionTypes.CHANGE_AFFECTED_SYSTEMS_PARAMS,
+ payload: params,
});
export const clearPackageSystemsReducer = () => ({
- type: ActionTypes.CLEAR_PACKAGE_SYSTEMS_REDUCER,
- payload: []
+ type: ActionTypes.CLEAR_PACKAGE_SYSTEMS_REDUCER,
+ payload: [],
});
export const clearAdvisorySystemsReducer = () => ({
- type: ActionTypes.CLEAR_ADVISORY_SYSTEMS_REDUCER,
- payload: []
+ type: ActionTypes.CLEAR_ADVISORY_SYSTEMS_REDUCER,
+ payload: [],
});
export const changeSystemsMetadata = (params) => ({
- type: ActionTypes.CHANGE_SYSTEMS_METADATA,
- payload: params
+ type: ActionTypes.CHANGE_SYSTEMS_METADATA,
+ payload: params,
});
-export const fetchPatchSetsAction = params => ({
- type: ActionTypes.FETCH_ALL_PATCH_SETS,
- payload: new Promise(resolve => {
- resolve(fetchPatchSets(params));
- }).then(result => result)
+export const fetchPatchSetsAction = (params) => ({
+ type: ActionTypes.FETCH_ALL_PATCH_SETS,
+ payload: new Promise((resolve) => {
+ resolve(fetchPatchSets(params));
+ }).then((result) => result),
});
export const changePatchSetsParams = (params) => ({
- type: ActionTypes.CHANGE_PATCH_SET_PARAMS,
- payload: params
+ type: ActionTypes.CHANGE_PATCH_SET_PARAMS,
+ payload: params,
});
-export const selectPatchSetRow = rowState => ({
- type: ActionTypes.SELECT_PATCH_SET_ROW,
- payload: rowState
+export const selectPatchSetRow = (rowState) => ({
+ type: ActionTypes.SELECT_PATCH_SET_ROW,
+ payload: rowState,
});
export const fetchPatchSetAction = (id) => ({
- type: ActionTypes.FETCH_PATCH_SET,
- payload: new Promise(resolve => {
- resolve(fetchPatchSet(id));
- }).then(result => result)
+ type: ActionTypes.FETCH_PATCH_SET,
+ payload: new Promise((resolve) => {
+ resolve(fetchPatchSet(id));
+ }).then((result) => result),
});
export const fetchTemplateDetail = (id) => ({
- type: ActionTypes.FETCH_TEMPLATE_DETAIL,
- payload: new Promise(resolve => {
- resolve(fetchPatchSet(id));
- }).then(result => result)
+ type: ActionTypes.FETCH_TEMPLATE_DETAIL,
+ payload: new Promise((resolve) => {
+ resolve(fetchPatchSet(id));
+ }).then((result) => result),
});
export const clearTemplateDetail = () => ({
- type: ActionTypes.CLEAR_TEMPLATE_DETAIL,
- payload: []
+ type: ActionTypes.CLEAR_TEMPLATE_DETAIL,
+ payload: [],
});
export const fetchPatchSetDetailSystemsAction = (id, params) => ({
- type: ActionTypes.FETCH_PATCH_SET_DETAIL_SYSTEMS,
- payload: new Promise(resolve => {
- resolve(fetchPatchSetSystems(id, params));
- }).then(result => result)
+ type: ActionTypes.FETCH_PATCH_SET_DETAIL_SYSTEMS,
+ payload: new Promise((resolve) => {
+ resolve(fetchPatchSetSystems(id, params));
+ }).then((result) => result),
});
export const changePatchSetDetailsSystemsParams = (params) => ({
- type: ActionTypes.CHANGE_PATCH_SET_DETAIL_SYSTEMS_PARAMS,
- payload: params
+ type: ActionTypes.CHANGE_PATCH_SET_DETAIL_SYSTEMS_PARAMS,
+ payload: params,
});
export const changePatchSetDetailsSystemsMetadata = (params) => ({
- type: ActionTypes.CHANGE_PATCH_SET_DETAIL_SYSTEMS_METADATA,
- payload: params
+ type: ActionTypes.CHANGE_PATCH_SET_DETAIL_SYSTEMS_METADATA,
+ payload: params,
});
export const clearPatchSetDetailsSystems = () => ({
- type: ActionTypes.CLEAR_PATCH_SET_DETAIL_SYSTEMS,
- payload: []
+ type: ActionTypes.CLEAR_PATCH_SET_DETAIL_SYSTEMS,
+ payload: [],
});
export const clearPatchSetAction = () => ({
- type: ActionTypes.CLEAR_PATCH_SET,
- payload: []
+ type: ActionTypes.CLEAR_PATCH_SET,
+ payload: [],
});
export const fetchPatchSetSystemsNoFiltersAction = (params) => ({
- type: ActionTypes.FETCH_PATCH_SET_SYSTEMS_NO_FILTERS,
- payload: new Promise(resolve => {
- resolve(fetchPatchSetSystems(params));
- }).then(result => result)
+ type: ActionTypes.FETCH_PATCH_SET_SYSTEMS_NO_FILTERS,
+ payload: new Promise((resolve) => {
+ resolve(fetchPatchSetSystems(params));
+ }).then((result) => result),
});
export const clearPatchSetsAction = () => ({
- type: ActionTypes.CLEAR_PATCH_SETS,
- payload: []
+ type: ActionTypes.CLEAR_PATCH_SETS,
+ payload: [],
});
export const toggleAllSelectedAction = (state) => ({
- type: ActionTypes.TOGGLE_ALL_SELECTED,
- payload: state
+ type: ActionTypes.TOGGLE_ALL_SELECTED,
+ payload: state,
});
export const systemSelectAction = (toSelect) => ({
- type: 'SELECT_ENTITY',
- payload: toSelect
+ type: 'SELECT_ENTITY',
+ payload: toSelect,
});
diff --git a/src/store/Reducers/AdvisoryDetailStore.js b/src/store/Reducers/AdvisoryDetailStore.js
index f8ead15e2..280ee0308 100644
--- a/src/store/Reducers/AdvisoryDetailStore.js
+++ b/src/store/Reducers/AdvisoryDetailStore.js
@@ -1,37 +1,33 @@
import { CLEAR_ADVISORY_DETAILS, FETCH_ADVISORY_DETAILS } from '../ActionTypes';
-import {
-
- fetchPending,
- fetchRejected
-} from './HelperReducers';
+import { fetchPending, fetchRejected } from './HelperReducers';
export let initialState = {
- data: { attributes: {} },
- status: { isLoading: true }
+ data: { attributes: {} },
+ status: { isLoading: true },
};
// Reducer
export const AdvisoryDetailStore = (state = initialState, action) => {
- let newState = { ...state };
- switch (action.type) {
- case FETCH_ADVISORY_DETAILS + '_FULFILLED':
- return {
- ...state,
- status: { isLoading: false },
- data: action.payload.data,
- error: {}
- };
+ let newState = { ...state };
+ switch (action.type) {
+ case FETCH_ADVISORY_DETAILS + '_FULFILLED':
+ return {
+ ...state,
+ status: { isLoading: false },
+ data: action.payload.data,
+ error: {},
+ };
- case FETCH_ADVISORY_DETAILS + '_PENDING':
- return fetchPending(newState);
+ case FETCH_ADVISORY_DETAILS + '_PENDING':
+ return fetchPending(newState);
- case FETCH_ADVISORY_DETAILS + '_REJECTED':
- return fetchRejected(newState, action);
+ case FETCH_ADVISORY_DETAILS + '_REJECTED':
+ return fetchRejected(newState, action);
- case CLEAR_ADVISORY_DETAILS:
- return initialState;
+ case CLEAR_ADVISORY_DETAILS:
+ return initialState;
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/AdvisoryDetailStore.test.js b/src/store/Reducers/AdvisoryDetailStore.test.js
index 06b47ffd0..0aca8e295 100644
--- a/src/store/Reducers/AdvisoryDetailStore.test.js
+++ b/src/store/Reducers/AdvisoryDetailStore.test.js
@@ -8,22 +8,22 @@ const action_rejected = FETCH_ADVISORY_DETAILS + '_REJECTED';
const action_pending = FETCH_ADVISORY_DETAILS + '_PENDING';
const fulfilled_payload = {
- data: []
-}
+ data: [],
+};
-const error = "Error";
+const error = 'Error';
describe('AdvisoryDetailStore tests', () => {
- it.each`
- state | action | result
- ${initialState} | ${{type: action_fulfilled, payload: fulfilled_payload}} | ${{...fulfilled_payload, status: { isLoading: false }, error: {}}}
- ${initialState} | ${{ type: action_pending, payload: {} }} | ${{ ...initialState, status: { code: undefined, isLoading: true, hasError: false }, error: {}}}
- ${initialState} | ${{type: CLEAR_ADVISORY_DETAILS, payload: {}}} | ${initialState}
- ${initialState} | ${{type: "NONSENSE", payload: {}}} | ${initialState}
- `('$action',({state, action: {type, payload}, result}) => {
- const res = AdvisoryDetailStore(state, {type, payload})
- expect(res).toEqual(result);
- });
+ it.each`
+ state | action | result
+ ${initialState} | ${{ type: action_fulfilled, payload: fulfilled_payload }} | ${{ ...fulfilled_payload, status: { isLoading: false }, error: {} }}
+ ${initialState} | ${{ type: action_pending, payload: {} }} | ${{ ...initialState, status: { code: undefined, isLoading: true, hasError: false }, error: {} }}
+ ${initialState} | ${{ type: CLEAR_ADVISORY_DETAILS, payload: {} }} | ${initialState}
+ ${initialState} | ${{ type: 'NONSENSE', payload: {} }} | ${initialState}
+ `('$action', ({ state, action: { type, payload }, result }) => {
+ const res = AdvisoryDetailStore(state, { type, payload });
+ expect(res).toEqual(result);
+ });
});
// ${initialState} | ${{type: action_rejected, payload: error}} | ${{...initialState, status: STATUS_REJECTED, error: error}}
diff --git a/src/store/Reducers/AdvisoryListStore.js b/src/store/Reducers/AdvisoryListStore.js
index ce426e85e..6c5fb18f0 100644
--- a/src/store/Reducers/AdvisoryListStore.js
+++ b/src/store/Reducers/AdvisoryListStore.js
@@ -1,49 +1,48 @@
import { storeListDefaults } from '../../Utilities/constants';
import * as ActionTypes from '../ActionTypes';
import {
- changeFilters,
- selectRows,
- expandRows,
- fetchPending,
- fetchRejected,
- fetchFulfilled
+ changeFilters,
+ selectRows,
+ expandRows,
+ fetchPending,
+ fetchRejected,
+ fetchFulfilled,
} from './HelperReducers';
-// eslint-disable-next-line
const storeListDefaultsModified = {
- ...storeListDefaults,
- queryParams: {}
+ ...storeListDefaults,
+ queryParams: {},
};
export const AdvisoryListStore = (state = storeListDefaultsModified, action) => {
- let newState = { ...state };
- switch (action.type) {
- case ActionTypes.FETCH_APPLICABLE_ADVISORIES + '_FULFILLED':
- return fetchFulfilled(newState, action);
+ let newState = { ...state };
+ switch (action.type) {
+ case ActionTypes.FETCH_APPLICABLE_ADVISORIES + '_FULFILLED':
+ return fetchFulfilled(newState, action);
- case ActionTypes.FETCH_APPLICABLE_ADVISORIES + '_PENDING':
- return fetchPending(newState);
+ case ActionTypes.FETCH_APPLICABLE_ADVISORIES + '_PENDING':
+ return fetchPending(newState);
- case ActionTypes.FETCH_APPLICABLE_ADVISORIES + '_REJECTED':
- return fetchRejected(newState, action);
+ case ActionTypes.FETCH_APPLICABLE_ADVISORIES + '_REJECTED':
+ return fetchRejected(newState, action);
- case ActionTypes.CHANGE_ADVISORY_LIST_PARAMS:
- return changeFilters(newState, action);
+ case ActionTypes.CHANGE_ADVISORY_LIST_PARAMS:
+ return changeFilters(newState, action);
- case ActionTypes.EXPAND_ADVISORY_ROW:
- return expandRows(newState, action);
+ case ActionTypes.EXPAND_ADVISORY_ROW:
+ return expandRows(newState, action);
- case ActionTypes.SELECT_ADVISORY_ROW:
- return selectRows(newState, action);
+ case ActionTypes.SELECT_ADVISORY_ROW:
+ return selectRows(newState, action);
- case ActionTypes.TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
+ case ActionTypes.TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
- case ActionTypes.TOGGLE_ALL_SELECTED:
- newState.areAllSelected = action.payload;
- return newState;
+ case ActionTypes.TOGGLE_ALL_SELECTED:
+ newState.areAllSelected = action.payload;
+ return newState;
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/AdvisoryListStore.test.js b/src/store/Reducers/AdvisoryListStore.test.js
index f02504665..114b8cf33 100644
--- a/src/store/Reducers/AdvisoryListStore.test.js
+++ b/src/store/Reducers/AdvisoryListStore.test.js
@@ -1,43 +1,51 @@
-
/* eslint-disable */
-import { STATUS_LOADING, STATUS_REJECTED, STATUS_RESOLVED, storeListDefaults } from '../../Utilities/constants';
-import { CHANGE_ADVISORY_LIST_PARAMS, EXPAND_ADVISORY_ROW, FETCH_APPLICABLE_ADVISORIES, SELECT_ADVISORY_ROW } from '../ActionTypes';
+import {
+ STATUS_LOADING,
+ STATUS_REJECTED,
+ STATUS_RESOLVED,
+ storeListDefaults,
+} from '../../Utilities/constants';
+import {
+ CHANGE_ADVISORY_LIST_PARAMS,
+ EXPAND_ADVISORY_ROW,
+ FETCH_APPLICABLE_ADVISORIES,
+ SELECT_ADVISORY_ROW,
+} from '../ActionTypes';
import { AdvisoryListStore } from './AdvisoryListStore';
const action_fulfilled = FETCH_APPLICABLE_ADVISORIES + '_FULFILLED';
const action_rejected = FETCH_APPLICABLE_ADVISORIES + '_REJECTED';
const action_pending = FETCH_APPLICABLE_ADVISORIES + '_PENDING';
const fulfilled_payload = {
- data: [],
- meta: {
- limit: 50,
- offset: 25,
- total_items: 50
- }
+ data: [],
+ meta: {
+ limit: 50,
+ offset: 25,
+ total_items: 50,
+ },
};
-// eslint-disable-next-line
const advisoryListStoreDefaults = {
- ...storeListDefaults,
- queryParams: {}
+ ...storeListDefaults,
+ queryParams: {},
};
const error = 'Error';
describe('AdvisoryListStore tests', () => {
- it.each`
- state | action | result
+ it.each`
+ state | action | result
${advisoryListStoreDefaults} | ${{ type: action_fulfilled, payload: fulfilled_payload }} | ${{ ...advisoryListStoreDefaults, metadata: fulfilled_payload.meta, rows: fulfilled_payload.data, status: { code: undefined, isLoading: false, hasError: false }, error: {} }}
${advisoryListStoreDefaults} | ${{ type: action_pending, payload: {} }} | ${{ ...advisoryListStoreDefaults, status: { code: undefined, isLoading: true, hasError: false }, error: {} }}
${advisoryListStoreDefaults} | ${{ type: EXPAND_ADVISORY_ROW, payload: { rowId: 1, value: true } }} | ${{ ...advisoryListStoreDefaults, expandedRows: { 1: true } }}
${advisoryListStoreDefaults} | ${{ type: CHANGE_ADVISORY_LIST_PARAMS, payload: { limit: 10 } }} | ${{ ...advisoryListStoreDefaults, queryParams: { limit: 10, offset: 0 } }}
${advisoryListStoreDefaults} | ${{ type: SELECT_ADVISORY_ROW, payload: { id: 1, selected: true } }} | ${{ ...advisoryListStoreDefaults, selectedRows: { 1: true } }}
${advisoryListStoreDefaults} | ${{ type: 'NONSENSE', payload: {} }} | ${advisoryListStoreDefaults}
- ${undefined} | ${{ type: 'NONSENSE', payload: {} }} | ${advisoryListStoreDefaults}
- `('$action', ({ state, action: { type, payload }, result }) => {
+ ${undefined} | ${{ type: 'NONSENSE', payload: {} }} | ${advisoryListStoreDefaults}
+ `('$action', ({ state, action: { type, payload }, result }) => {
const res = AdvisoryListStore(state, { type, payload });
expect(res).toEqual(result);
-});
+ });
});
// ${ storeListDefaults } | ${ { type: action_rejected, payload: error } } | ${ { ...storeListDefaults, status: STATUS_REJECTED, error } }
diff --git a/src/store/Reducers/AdvisorySystemsStore.js b/src/store/Reducers/AdvisorySystemsStore.js
index ce1749957..c41c5ed63 100644
--- a/src/store/Reducers/AdvisorySystemsStore.js
+++ b/src/store/Reducers/AdvisorySystemsStore.js
@@ -4,30 +4,28 @@ import { changeListParams } from '../../Utilities/Helpers';
// Initial State. It should not include page and perPage to persist them dynamically
export const initialState = {
- selectedRows: {},
- queryParams: {
- page: 1,
- perPage: 20
- }
+ selectedRows: {},
+ queryParams: {
+ page: 1,
+ perPage: 20,
+ },
};
// Reducer
export const AdvisorySystemsStore = (state = initialState, action) => {
- let newState = { ...state };
- switch (action.type) {
+ let newState = { ...state };
+ switch (action.type) {
+ case ActionTypes.CHANGE_AFFECTED_SYSTEMS_PARAMS:
+ newState.queryParams = changeListParams(newState.queryParams, action.payload);
+ return newState;
- case ActionTypes.CHANGE_AFFECTED_SYSTEMS_PARAMS:
- newState.queryParams = changeListParams(newState.queryParams, action.payload);
- return newState;
+ case ActionTypes.TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
- case ActionTypes.TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
+ case ActionTypes.CLEAR_ADVISORY_SYSTEMS_REDUCER:
+ return initialState;
- case ActionTypes.CLEAR_ADVISORY_SYSTEMS_REDUCER:
- return initialState;
-
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
-
diff --git a/src/store/Reducers/CvesListStore.js b/src/store/Reducers/CvesListStore.js
index cf69ae84c..6d1ed4dde 100644
--- a/src/store/Reducers/CvesListStore.js
+++ b/src/store/Reducers/CvesListStore.js
@@ -1,28 +1,23 @@
import { storeListDefaults } from '../../Utilities/constants';
import * as ActionTypes from '../ActionTypes';
-import {
- changeFilters,
- fetchPending,
- fetchRejected,
- fetchFulfilled
-} from './HelperReducers';
+import { changeFilters, fetchPending, fetchRejected, fetchFulfilled } from './HelperReducers';
export const CvesListStore = (state = storeListDefaults, action) => {
- let newState = { ...state };
- switch (action.type) {
- case ActionTypes.FETCH_CVES_INFO + '_FULFILLED':
- return fetchFulfilled(newState, action);
+ let newState = { ...state };
+ switch (action.type) {
+ case ActionTypes.FETCH_CVES_INFO + '_FULFILLED':
+ return fetchFulfilled(newState, action);
- case ActionTypes.FETCH_CVES_INFO + '_PENDING':
- return fetchPending(newState);
+ case ActionTypes.FETCH_CVES_INFO + '_PENDING':
+ return fetchPending(newState);
- case ActionTypes.FETCH_CVES_INFO + '_REJECTED':
- return fetchRejected(newState, action);
+ case ActionTypes.FETCH_CVES_INFO + '_REJECTED':
+ return fetchRejected(newState, action);
- case ActionTypes.CHANGE_CVES_STORE_PARAMS:
- return changeFilters(newState, action);
+ case ActionTypes.CHANGE_CVES_STORE_PARAMS:
+ return changeFilters(newState, action);
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/CvesListStore.test.js b/src/store/Reducers/CvesListStore.test.js
index fd30e01b0..417991d7c 100644
--- a/src/store/Reducers/CvesListStore.test.js
+++ b/src/store/Reducers/CvesListStore.test.js
@@ -1,15 +1,13 @@
-/* eslint-disable new-cap */
import { changeFilters, fetchFulfilled, fetchPending, fetchRejected } from './HelperReducers';
import { CvesListStore } from './CvesListStore';
import { FETCH_CVES_INFO } from '../ActionTypes';
jest.mock('./HelperReducers', () => ({
- ...jest.requireActual('./HelperReducers'),
- changeFilters: jest.fn(),
- fetchFulfilled: jest.fn(),
- fetchPending: jest.fn(),
- fetchRejected: jest.fn()
-})
-);
+ ...jest.requireActual('./HelperReducers'),
+ changeFilters: jest.fn(),
+ fetchFulfilled: jest.fn(),
+ fetchPending: jest.fn(),
+ fetchRejected: jest.fn(),
+}));
const state = { testObj: 'testVal' };
const actionFulfilled = FETCH_CVES_INFO + '_FULFILLED';
@@ -17,23 +15,30 @@ const actionRejected = FETCH_CVES_INFO + '_REJECTED';
const actionPending = FETCH_CVES_INFO + '_PENDING';
describe('PackageListStore', () => {
- it('should start fetching package list', () => {
- CvesListStore(state, { type: actionFulfilled, payload: { search: 'testSearch' } });
- expect(fetchFulfilled).toHaveBeenCalledWith(state, { type: actionFulfilled, payload: { search: 'testSearch' } });
+ it('should start fetching package list', () => {
+ CvesListStore(state, { type: actionFulfilled, payload: { search: 'testSearch' } });
+ expect(fetchFulfilled).toHaveBeenCalledWith(state, {
+ type: actionFulfilled,
+ payload: { search: 'testSearch' },
});
- it('should fetch package list', () => {
- CvesListStore(state, { type: actionPending, payload: { search: 'testSearch' } });
- expect(fetchPending).toHaveBeenCalledWith(state);
+ });
+ it('should fetch package list', () => {
+ CvesListStore(state, { type: actionPending, payload: { search: 'testSearch' } });
+ expect(fetchPending).toHaveBeenCalledWith(state);
+ });
+ it('should handle rejected call', () => {
+ CvesListStore(state, { type: actionRejected, payload: { search: 'testSearch' } });
+ expect(fetchRejected).toHaveBeenCalledWith(state, {
+ type: actionRejected,
+ payload: { search: 'testSearch' },
});
- it('should handle rejected call', () => {
- CvesListStore(state, { type: actionRejected, payload: { search: 'testSearch' } });
- expect(fetchRejected).toHaveBeenCalledWith(state, { type: actionRejected, payload: { search: 'testSearch' } });
+ });
+ it('should change params', () => {
+ CvesListStore(state, { type: 'CHANGE_CVES_STORE_PARAMS', payload: { search: 'testSearch' } });
+ expect(changeFilters).toHaveBeenCalledWith(state, {
+ type: 'CHANGE_CVES_STORE_PARAMS',
+ payload: { search: 'testSearch' },
});
-
- it('should change params', () => {
- CvesListStore(state, { type: 'CHANGE_CVES_STORE_PARAMS', payload: { search: 'testSearch' } });
- expect(changeFilters).toHaveBeenCalledWith(state,
- { type: 'CHANGE_CVES_STORE_PARAMS', payload: { search: 'testSearch' } });
- });
+ });
});
diff --git a/src/store/Reducers/GlobalFilterStore.js b/src/store/Reducers/GlobalFilterStore.js
index 593924ccc..795e6c6d8 100644
--- a/src/store/Reducers/GlobalFilterStore.js
+++ b/src/store/Reducers/GlobalFilterStore.js
@@ -1,32 +1,32 @@
import * as ActionTypes from '../ActionTypes';
const initialState = {
- selectedGlobalTags: [],
- selectedTags: [],
- systemProfile: undefined
+ selectedGlobalTags: [],
+ selectedTags: [],
+ systemProfile: undefined,
};
export const GlobalFilterStore = (state = initialState, action) => {
- switch (action.type) {
- case ActionTypes.CHANGE_TAGS:
- return {
- ...state,
- selectedTags: action.payload
- };
+ switch (action.type) {
+ case ActionTypes.CHANGE_TAGS:
+ return {
+ ...state,
+ selectedTags: action.payload,
+ };
- case ActionTypes.CHANGE_GLOBAL_TAGS:
- return {
- ...state,
- selectedGlobalTags: action.payload
- };
+ case ActionTypes.CHANGE_GLOBAL_TAGS:
+ return {
+ ...state,
+ selectedGlobalTags: action.payload,
+ };
- case ActionTypes.CHANGE_PROFILE:
- return {
- ...state,
- systemProfile: action.payload
- };
+ case ActionTypes.CHANGE_PROFILE:
+ return {
+ ...state,
+ systemProfile: action.payload,
+ };
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/HelperReducers.js b/src/store/Reducers/HelperReducers.js
index c5f3970f4..31878150c 100644
--- a/src/store/Reducers/HelperReducers.js
+++ b/src/store/Reducers/HelperReducers.js
@@ -1,46 +1,44 @@
-import { addOrRemoveItemFromSet, changeListParams, getNewSelectedItems } from '../../Utilities/Helpers';
+import {
+ addOrRemoveItemFromSet,
+ changeListParams,
+ getNewSelectedItems,
+} from '../../Utilities/Helpers';
export const changeFilters = (state, action) => {
- state.queryParams = changeListParams(
- state.queryParams,
- action.payload
- );
+ state.queryParams = changeListParams(state.queryParams, action.payload);
- return state;
+ return state;
};
export const selectRows = (state, action) => {
- const selectedUpdated = getNewSelectedItems(action.payload, state.selectedRows);
- state = { ...state, selectedRows: selectedUpdated };
- return state;
+ const selectedUpdated = getNewSelectedItems(action.payload, state.selectedRows);
+ state = { ...state, selectedRows: selectedUpdated };
+ return state;
};
export const expandRows = (state, action) => {
- const expandedUpdated = addOrRemoveItemFromSet(
- state.expandedRows,
- [].concat(action.payload)
- );
- state = { ...state, expandedRows: expandedUpdated };
- return state;
+ const expandedUpdated = addOrRemoveItemFromSet(state.expandedRows, [].concat(action.payload));
+ state = { ...state, expandedRows: expandedUpdated };
+ return state;
};
export const fetchPending = (state) => {
- state.error = {};
- state.status = { isLoading: true, hasError: false, code: undefined };
- return state;
+ state.error = {};
+ state.status = { isLoading: true, hasError: false, code: undefined };
+ return state;
};
export const fetchRejected = (state, action) => {
- state.metadata = action.payload.meta || {};
- state.error = action.payload;
- state.status = { code: action.payload.status, isLoading: false, hasError: true };
- return state;
+ state.metadata = action.payload.meta || {};
+ state.error = action.payload;
+ state.status = { code: action.payload.status, isLoading: false, hasError: true };
+ return state;
};
export const fetchFulfilled = (state, action) => {
- state.rows = action.payload.data;
- state.metadata = action.payload.meta || {};
- state.error = {};
- state.status = { code: action.payload.status, isLoading: false, hasError: false };
- return state;
+ state.rows = action.payload.data;
+ state.metadata = action.payload.meta || {};
+ state.error = {};
+ state.status = { code: action.payload.status, isLoading: false, hasError: false };
+ return state;
};
diff --git a/src/store/Reducers/InventoryEntitiesReducer.js b/src/store/Reducers/InventoryEntitiesReducer.js
index 5e3359f2b..d2bb0ba34 100644
--- a/src/store/Reducers/InventoryEntitiesReducer.js
+++ b/src/store/Reducers/InventoryEntitiesReducer.js
@@ -1,120 +1,128 @@
-import { createAdvisorySystemsRows, createSystemsRows, createPatchSetDetailRows } from '../../Utilities/DataMappers';
-import { createPackageSystemsRows } from '../../Utilities/DataMappers';
+import {
+ createAdvisorySystemsRows,
+ createSystemsRows,
+ createPatchSetDetailRows,
+ createPackageSystemsRows,
+} from '../../Utilities/DataMappers';
import { selectRows, fetchRejected } from './HelperReducers';
import * as ActionTypes from '../ActionTypes';
// Initial State. It should not include page and perPage to persist them dynamically
const initialState = {
- rows: [],
- entities: [],
- selectedRows: {},
- status: {},
- page: 1,
- perPage: 20,
- metadata: {
- limit: 20,
- offset: 0,
- total_items: 0
- }
+ rows: [],
+ entities: [],
+ selectedRows: {},
+ status: {},
+ page: 1,
+ perPage: 20,
+ metadata: {
+ limit: 20,
+ offset: 0,
+ total_items: 0,
+ },
};
// Reducer
export const modifyInventory = (columns, state) => {
- if (state.loaded) {
- return {
- ...state,
- status: { isLoading: false, hasError: false },
- rows: createSystemsRows(state.rows, state.selectedRows)
- };
- }
-
- return state;
+ if (state.loaded) {
+ return {
+ ...state,
+ status: { isLoading: false, hasError: false },
+ rows: createSystemsRows(state.rows, state.selectedRows),
+ };
+ }
+
+ return state;
};
export const modifyPackageSystems = (columns, state, lastAction) => {
- // this is pretty scuffed, but trust me it cannot be solved more elegantly because
- // single item select actions are triggered by Inventory and contain only system id
- // but we also need to match available_evra for each selected system for remediations
- // this does not happen with bulk select action because they are implemented by Patchman
- // the id-evra mapping is cached to minimize O(n^2) time complexity of id-evra matching
- if (lastAction === 'SELECT_ENTITY') {
- let idToEvraMapping = state.packageEvraCache;
-
- if (idToEvraMapping === undefined) {
- idToEvraMapping = {};
- state.rows.forEach(row => idToEvraMapping[row.id] = row.available_evra);
- state.packageEvraCache = idToEvraMapping;
- }
-
- state.selectedRows = state.selectedRows ? Object.fromEntries(
- Object.entries(state.selectedRows).map(([id, value]) =>
- value === true ? [id, idToEvraMapping[id]] : [id, value]
- )
- ) : state.selectedRows;
- }
-
- if (lastAction === 'LOAD_ENTITIES_FULFILLED') {
- state.packageEvraCache = undefined;
- }
-
- if (state.loaded) {
- return {
- ...state,
- columns,
- rows: createPackageSystemsRows(state.rows, state.selectedRows)
- };
+ // this is pretty scuffed, but trust me it cannot be solved more elegantly because
+ // single item select actions are triggered by Inventory and contain only system id
+ // but we also need to match available_evra for each selected system for remediations
+ // this does not happen with bulk select action because they are implemented by Patchman
+ // the id-evra mapping is cached to minimize O(n^2) time complexity of id-evra matching
+ if (lastAction === 'SELECT_ENTITY') {
+ let idToEvraMapping = state.packageEvraCache;
+
+ if (idToEvraMapping === undefined) {
+ idToEvraMapping = {};
+ state.rows.forEach((row) => (idToEvraMapping[row.id] = row.available_evra));
+ state.packageEvraCache = idToEvraMapping;
}
- return state;
+ state.selectedRows = state.selectedRows
+ ? Object.fromEntries(
+ Object.entries(state.selectedRows).map(([id, value]) =>
+ value === true ? [id, idToEvraMapping[id]] : [id, value],
+ ),
+ )
+ : state.selectedRows;
+ }
+
+ if (lastAction === 'LOAD_ENTITIES_FULFILLED') {
+ state.packageEvraCache = undefined;
+ }
+
+ if (state.loaded) {
+ return {
+ ...state,
+ columns,
+ rows: createPackageSystemsRows(state.rows, state.selectedRows),
+ };
+ }
+
+ return state;
};
export const modifyTemplateDetailSystems = (columns, state) => {
- if (state.loaded) {
- return {
- ...state,
- status: { isLoading: false, hasError: false },
- rows: createPatchSetDetailRows(state.rows, state.selectedRows)
- };
- }
-
- return state;
+ if (state.loaded) {
+ return {
+ ...state,
+ status: { isLoading: false, hasError: false },
+ rows: createPatchSetDetailRows(state.rows, state.selectedRows),
+ };
+ }
+
+ return state;
};
export const modifyAdvisorySystems = (columns, state) => {
- if (state.loaded) {
- return {
- ...state,
- status: { isLoading: false, hasError: false },
- rows: createAdvisorySystemsRows(state.rows, state.selectedRows)
- };
- }
-
- return state;
+ if (state.loaded) {
+ return {
+ ...state,
+ status: { isLoading: false, hasError: false },
+ rows: createAdvisorySystemsRows(state.rows, state.selectedRows),
+ };
+ }
+
+ return state;
};
-export const inventoryEntitiesReducer = (columns, inventoryModifier) => (state = initialState, action) => {
+export const inventoryEntitiesReducer =
+ (columns, inventoryModifier) =>
+ (state = initialState, action) => {
let newState = { ...state };
switch (action.type) {
- case 'LOAD_ENTITIES_FULFILLED':
- return inventoryModifier(columns, newState, action.type);
+ case 'LOAD_ENTITIES_FULFILLED':
+ return inventoryModifier(columns, newState, action.type);
- case 'LOAD_ENTITIES_PENDING':
- newState.status = { isLoading: true, hasError: false };
- return newState;
+ case 'LOAD_ENTITIES_PENDING':
+ newState.status = { isLoading: true, hasError: false };
+ return newState;
- case 'LOAD_ENTITIES_REJECTED':
- return fetchRejected(newState, action);
+ case 'LOAD_ENTITIES_REJECTED':
+ return fetchRejected(newState, action);
- case 'SELECT_ENTITY': {
- const stateAfterSelection = selectRows(newState, action);
- return inventoryModifier(columns, stateAfterSelection, action.type);
- }
+ case 'SELECT_ENTITY': {
+ const stateAfterSelection = selectRows(newState, action);
+ return inventoryModifier(columns, stateAfterSelection, action.type);
+ }
- case ActionTypes.CLEAR_INVENTORY_REDUCER:
- return initialState;
+ case ActionTypes.CLEAR_INVENTORY_REDUCER:
+ return initialState;
- default:
- return state;
+ default:
+ return state;
}
-};
+ };
diff --git a/src/store/Reducers/InventoryEntitiesReducer.test.js b/src/store/Reducers/InventoryEntitiesReducer.test.js
index 28d91697e..0a91cff22 100644
--- a/src/store/Reducers/InventoryEntitiesReducer.test.js
+++ b/src/store/Reducers/InventoryEntitiesReducer.test.js
@@ -1,76 +1,84 @@
-import { inventoryEntitiesReducer, initialState } from './InventoryEntitiesReducer';
-import { modifyInventory, modifyPackageSystems } from './InventoryEntitiesReducer';
+import {
+ inventoryEntitiesReducer,
+ initialState,
+ modifyInventory,
+ modifyPackageSystems,
+} from './InventoryEntitiesReducer';
import { systemRows } from '../../Utilities/RawDataForTesting';
-/* eslint-disable */
describe('InventoryEntitiesReducer tests', () => {
- it.each`
- columns | state | action | result
- ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_FULFILLED', payload: {} }} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }}
- ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_PENDING', payload: {} }} | ${{ ...initialState, loaded: false, status: { isLoading: true, hasError: false, }, columns: [{ key: 'testCol' }] }}
- ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_REJECTED', payload: { status: 400 } }} | ${{ ...initialState, loaded: false, status: { isLoading: false, code: 400, hasError: true }, error: { status: 400 }, metadata: {}, columns: [{ key: 'testCol' }] }}
- ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'SELECT_ENTITY', payload: [{ id: '83e97cde-74b4-4752-819d-704687bbc286' }] }}} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }], selectedRows: { "83e97cde-74b4-4752-819d-704687bbc286": undefined } }}
+ it.each`
+ columns | state | action | result
+ ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_FULFILLED', payload: {} }} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }}
+ ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_PENDING', payload: {} }} | ${{ ...initialState, loaded: false, status: { isLoading: true, hasError: false }, columns: [{ key: 'testCol' }] }}
+ ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_REJECTED', payload: { status: 400 } }} | ${{ ...initialState, loaded: false, status: { isLoading: false, code: 400, hasError: true }, error: { status: 400 }, metadata: {}, columns: [{ key: 'testCol' }] }}
+ ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'SELECT_ENTITY', payload: [{ id: '83e97cde-74b4-4752-819d-704687bbc286' }] }} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }], selectedRows: { '83e97cde-74b4-4752-819d-704687bbc286': undefined } }}
+ `('$action', ({ columns, state, action: { type, payload }, result }) => {
+ const wrapperReducer = inventoryEntitiesReducer(columns, modifyInventory);
+ const res = wrapperReducer(state, { type, payload });
+ expect(res).toEqual(result);
+ });
- `('$action', ({ columns, state, action: { type, payload }, result }) => {
- const wrapperReducer = inventoryEntitiesReducer(columns, modifyInventory);
- const res = wrapperReducer(state, { type, payload })
- expect(res).toEqual(result);
- });
-
- it.each`
- columns | state | action | result
- ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_FULFILLED', payload: {} }} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }}
-
- `('$action', ({ columns, state, action: { type, payload }, result }) => {
- const wrapperReducer = inventoryEntitiesReducer(columns, modifyPackageSystems);
- const res = wrapperReducer(state, { type, payload })
- expect(res).toEqual(result);
- });
+ it.each`
+ columns | state | action | result
+ ${[]} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }} | ${{ type: 'LOAD_ENTITIES_FULFILLED', payload: {} }} | ${{ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }}
+ `('$action', ({ columns, state, action: { type, payload }, result }) => {
+ const wrapperReducer = inventoryEntitiesReducer(columns, modifyPackageSystems);
+ const res = wrapperReducer(state, { type, payload });
+ expect(res).toEqual(result);
+ });
- it('should modifyInventory nicely', () => {
- const wrapperReducer = inventoryEntitiesReducer([{ key: 'updated' }], modifyInventory);
- const res = wrapperReducer({ ...initialState, loaded: true, columns: [{ key: 'testCol' }], rows: systemRows }, { type: 'LOAD_ENTITIES_FULFILLED', payload: {} });
- expect(res).toEqual({
- ...initialState,
- loaded: true,
- columns: [{ key: 'testCol' }],
- rows: expect.any(Object),
- status: {
- hasError: false,
- isLoading: false,
- }
- });
+ it('should modifyInventory nicely', () => {
+ const wrapperReducer = inventoryEntitiesReducer([{ key: 'updated' }], modifyInventory);
+ const res = wrapperReducer(
+ { ...initialState, loaded: true, columns: [{ key: 'testCol' }], rows: systemRows },
+ { type: 'LOAD_ENTITIES_FULFILLED', payload: {} },
+ );
+ expect(res).toEqual({
+ ...initialState,
+ loaded: true,
+ columns: [{ key: 'testCol' }],
+ rows: expect.any(Object),
+ status: {
+ hasError: false,
+ isLoading: false,
+ },
});
+ });
- it('should use modifyPackageSystems nicely', () => {
- const wrapperReducer = inventoryEntitiesReducer([], modifyPackageSystems);
- const res = wrapperReducer({ ...initialState, loaded: true, rows: systemRows }, { type: 'LOAD_ENTITIES_FULFILLED', payload: {} });
- expect(res).toEqual({
- ...initialState,
- loaded: true,
- columns: [],
- rows: expect.any(Object)
- });
+ it('should use modifyPackageSystems nicely', () => {
+ const wrapperReducer = inventoryEntitiesReducer([], modifyPackageSystems);
+ const res = wrapperReducer(
+ { ...initialState, loaded: true, rows: systemRows },
+ { type: 'LOAD_ENTITIES_FULFILLED', payload: {} },
+ );
+ expect(res).toEqual({
+ ...initialState,
+ loaded: true,
+ columns: [],
+ rows: expect.any(Object),
});
+ });
+ it('should return initial state on clear', () => {
+ const wrapperReducer = inventoryEntitiesReducer([], modifyPackageSystems);
- it('should return initial state on clear', () => {
- const wrapperReducer = inventoryEntitiesReducer([], modifyPackageSystems);
-
- const res = wrapperReducer({ ...initialState, loaded: false, columns: [{ key: 'testCol' }] }, { type: 'CLEAR_INVENTORY_REDUCER', payload: {} });
- expect(res).toEqual({
- entities:[],
- metadata: {
- limit: 20,
- offset: 0,
- total_items: 0,
- },
- page: 1,
- perPage: 20,
- rows: [],
- selectedRows: {},
- status: {},
- });
- });
+ const res = wrapperReducer(
+ { ...initialState, loaded: false, columns: [{ key: 'testCol' }] },
+ { type: 'CLEAR_INVENTORY_REDUCER', payload: {} },
+ );
+ expect(res).toEqual({
+ entities: [],
+ metadata: {
+ limit: 20,
+ offset: 0,
+ total_items: 0,
+ },
+ page: 1,
+ perPage: 20,
+ rows: [],
+ selectedRows: {},
+ status: {},
+ });
+ });
});
-/* eslint-enable */
diff --git a/src/store/Reducers/InventoryReducers.test.js b/src/store/Reducers/InventoryReducers.test.js
index e365a50f7..13b7837a9 100644
--- a/src/store/Reducers/InventoryReducers.test.js
+++ b/src/store/Reducers/InventoryReducers.test.js
@@ -1,4 +1,3 @@
-/* eslint-disable no-unused-vars */
import { AdvisorySystemsStore, initialState } from './AdvisorySystemsStore';
import { SystemsStore } from './SystemsStore';
import { PackageSystemsStore } from './PackageSystemsStore';
@@ -6,54 +5,73 @@ import { systemRows, systemsStoreState } from '../../Utilities/RawDataForTesting
const state = { ...initialState, loaded: true, columns: [{ key: 'testCol' }], rows: systemRows };
-/* eslint-disable */
describe('InventoryEntitiesReducer tests', () => {
-
- it('should change AdvisorySystemsStore nicely', () => {
- const res = AdvisorySystemsStore(state, { type: 'CHANGE_AFFECTED_SYSTEMS_PARAMS', payload: { search: 'testSearch' } });
- expect(res).toEqual(systemsStoreState);
- });
-
- it('should change SystemsStore nicely', () => {
- const res = SystemsStore(state, { type: 'CHANGE_SYSTEMS_PARAMS', payload: { search: 'testSearch' } });
- expect(res).toEqual(systemsStoreState);
+ it('should change AdvisorySystemsStore nicely', () => {
+ const res = AdvisorySystemsStore(state, {
+ type: 'CHANGE_AFFECTED_SYSTEMS_PARAMS',
+ payload: { search: 'testSearch' },
});
+ expect(res).toEqual(systemsStoreState);
+ });
- it('should change PackageSystemsStore nicely', () => {
- const res = PackageSystemsStore(state, { type: 'CHANGE_PACKAGE_SYSTEMS_PARAMS', payload: { search: 'testSearch' } });
- expect(res).toEqual(systemsStoreState);
+ it('should change SystemsStore nicely', () => {
+ const res = SystemsStore(state, {
+ type: 'CHANGE_SYSTEMS_PARAMS',
+ payload: { search: 'testSearch' },
});
+ expect(res).toEqual(systemsStoreState);
+ });
- it('should change AdvisorySystemsStore on global filter', () => {
- const res = AdvisorySystemsStore(state, { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
- expect(res).toEqual(systemsStoreState);
+ it('should change PackageSystemsStore nicely', () => {
+ const res = PackageSystemsStore(state, {
+ type: 'CHANGE_PACKAGE_SYSTEMS_PARAMS',
+ payload: { search: 'testSearch' },
});
+ expect(res).toEqual(systemsStoreState);
+ });
- it('should change SystemsStore on global filter', () => {
- const res = SystemsStore(state, { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
- expect(res).toEqual(systemsStoreState);
+ it('should change AdvisorySystemsStore on global filter', () => {
+ const res = AdvisorySystemsStore(state, {
+ type: 'TRIGGER_GLOBAL_FILTER',
+ payload: { search: 'testSearch' },
});
+ expect(res).toEqual(systemsStoreState);
+ });
- it('should change PackageSystemsStore on global filter', () => {
- const res = PackageSystemsStore(state, { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
- expect(res).toEqual(systemsStoreState);
+ it('should change SystemsStore on global filter', () => {
+ const res = SystemsStore(state, {
+ type: 'TRIGGER_GLOBAL_FILTER',
+ payload: { search: 'testSearch' },
});
+ expect(res).toEqual(systemsStoreState);
+ });
-
- it('should clear AdvisorySystemsStore nicely', () => {
- const res = AdvisorySystemsStore(state, { type: 'CLEAR_ADVISORY_SYSTEMS_REDUCER', payload: {} });
- expect(res).toEqual(initialState);
+ it('should change PackageSystemsStore on global filter', () => {
+ const res = PackageSystemsStore(state, {
+ type: 'TRIGGER_GLOBAL_FILTER',
+ payload: { search: 'testSearch' },
});
+ expect(res).toEqual(systemsStoreState);
+ });
- it('should clear PackageSystemsStore nicely', () => {
- const res = PackageSystemsStore(state, { type: 'CLEAR_PACKAGE_SYSTEMS_REDUCER', payload: {} });
- expect(res).toEqual(initialState);
+ it('should clear AdvisorySystemsStore nicely', () => {
+ const res = AdvisorySystemsStore(state, {
+ type: 'CLEAR_ADVISORY_SYSTEMS_REDUCER',
+ payload: {},
});
+ expect(res).toEqual(initialState);
+ });
+ it('should clear PackageSystemsStore nicely', () => {
+ const res = PackageSystemsStore(state, { type: 'CLEAR_PACKAGE_SYSTEMS_REDUCER', payload: {} });
+ expect(res).toEqual(initialState);
+ });
- it('should change SystemsStore metadata on CHANGE_SYSTEMS_METADATA', () => {
- const res = SystemsStore(state, { type: 'CHANGE_SYSTEMS_METADATA', payload: { metadata: 'testMetadata' } });
- expect(res).toEqual({ ...state, metadata: { metadata : 'testMetadata' } }) ;
+ it('should change SystemsStore metadata on CHANGE_SYSTEMS_METADATA', () => {
+ const res = SystemsStore(state, {
+ type: 'CHANGE_SYSTEMS_METADATA',
+ payload: { metadata: 'testMetadata' },
});
+ expect(res).toEqual({ ...state, metadata: { metadata: 'testMetadata' } });
+ });
});
-/* eslint-enable */
diff --git a/src/store/Reducers/PackageDetailStore.js b/src/store/Reducers/PackageDetailStore.js
index a3d812eec..015456303 100644
--- a/src/store/Reducers/PackageDetailStore.js
+++ b/src/store/Reducers/PackageDetailStore.js
@@ -2,32 +2,32 @@ import { CLEAR_PACKAGE_DETAILS, FETCH_PACKAGE_DETAILS } from '../ActionTypes';
import { fetchPending, fetchRejected } from './HelperReducers';
export let initialState = {
- data: { attributes: {} },
- status: { isLoading: true }
+ data: { attributes: {} },
+ status: { isLoading: true },
};
// Reducer
export const PackageDetailStore = (state = initialState, action) => {
- let newState = { ...state };
- switch (action.type) {
- case FETCH_PACKAGE_DETAILS + '_FULFILLED':
- return {
- ...state,
- status: { isLoading: false },
- data: action.payload.data,
- error: {}
- };
+ let newState = { ...state };
+ switch (action.type) {
+ case FETCH_PACKAGE_DETAILS + '_FULFILLED':
+ return {
+ ...state,
+ status: { isLoading: false },
+ data: action.payload.data,
+ error: {},
+ };
- case FETCH_PACKAGE_DETAILS + '_PENDING':
- return fetchPending(newState);
+ case FETCH_PACKAGE_DETAILS + '_PENDING':
+ return fetchPending(newState);
- case FETCH_PACKAGE_DETAILS + '_REJECTED':
- return fetchRejected(newState, action);
+ case FETCH_PACKAGE_DETAILS + '_REJECTED':
+ return fetchRejected(newState, action);
- case CLEAR_PACKAGE_DETAILS:
- return initialState;
+ case CLEAR_PACKAGE_DETAILS:
+ return initialState;
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/PackageDetailStore.test.js b/src/store/Reducers/PackageDetailStore.test.js
index b2e80cf71..712ccd6f9 100644
--- a/src/store/Reducers/PackageDetailStore.test.js
+++ b/src/store/Reducers/PackageDetailStore.test.js
@@ -1,14 +1,12 @@
-/* eslint-disable new-cap */
import { fetchPending, fetchRejected } from './HelperReducers';
import { PackageDetailStore } from './PackageDetailStore';
import { FETCH_PACKAGE_DETAILS } from '../ActionTypes';
jest.mock('./HelperReducers', () => ({
- ...jest.requireActual('./HelperReducers'),
- fetchFulfilled: jest.fn(),
- fetchPending: jest.fn(),
- fetchRejected: jest.fn()
-})
-);
+ ...jest.requireActual('./HelperReducers'),
+ fetchFulfilled: jest.fn(),
+ fetchPending: jest.fn(),
+ fetchRejected: jest.fn(),
+}));
const state = { testObj: 'testVal' };
const actionFulfilled = FETCH_PACKAGE_DETAILS + '_FULFILLED';
@@ -16,45 +14,51 @@ const actionRejected = FETCH_PACKAGE_DETAILS + '_REJECTED';
const actionPending = FETCH_PACKAGE_DETAILS + '_PENDING';
describe('PackageListStore', () => {
- it('should start fetching package list', () => {
- const res = PackageDetailStore(state, { type: actionFulfilled, payload: { data: 'testData' } });
- expect(res).toEqual({
- ...state, status: { isLoading: false },
- data: 'testData',
- error: {}
- });
+ it('should start fetching package list', () => {
+ const res = PackageDetailStore(state, { type: actionFulfilled, payload: { data: 'testData' } });
+ expect(res).toEqual({
+ ...state,
+ status: { isLoading: false },
+ data: 'testData',
+ error: {},
});
+ });
- it('should fetch package detail', () => {
- PackageDetailStore(state, { type: actionPending, payload: { search: 'testSearch' } });
- expect(fetchPending).toHaveBeenCalledWith(state);
+ it('should fetch package detail', () => {
+ PackageDetailStore(state, { type: actionPending, payload: { search: 'testSearch' } });
+ expect(fetchPending).toHaveBeenCalledWith(state);
+ });
+ it('should handle rejected call', () => {
+ PackageDetailStore(state, { type: actionRejected, payload: { search: 'testSearch' } });
+ expect(fetchRejected).toHaveBeenCalledWith(state, {
+ type: actionRejected,
+ payload: { search: 'testSearch' },
});
- it('should handle rejected call', () => {
- PackageDetailStore(state, { type: actionRejected, payload: { search: 'testSearch' } });
- expect(fetchRejected).toHaveBeenCalledWith(state, { type: actionRejected, payload: { search: 'testSearch' } });
-
+ });
+ it('should handle clear call', () => {
+ const res = PackageDetailStore(state, {
+ type: 'CLEAR_PACKAGE_DETAILS',
+ payload: { search: 'testSearch' },
});
- it('should handle clear call', () => {
- const res = PackageDetailStore(state, { type: 'CLEAR_PACKAGE_DETAILS', payload: { search: 'testSearch' } });
- expect(res).toEqual({
- data: {
- attributes: {}
- },
- status: {
- isLoading: true
- }
- });
+ expect(res).toEqual({
+ data: {
+ attributes: {},
+ },
+ status: {
+ isLoading: true,
+ },
});
+ });
- // it('should change params', () => {
- // PackageDetailStore(state, { type: 'CHANGE_PACKAGES_LIST_PARAMS', payload: { search: 'testSearch' } });
- // expect(changeFilters).toHaveBeenCalledWith(state,
- // { type: 'CHANGE_PACKAGES_LIST_PARAMS', payload: { search: 'testSearch' } });
- // });
+ // it('should change params', () => {
+ // PackageDetailStore(state, { type: 'CHANGE_PACKAGES_LIST_PARAMS', payload: { search: 'testSearch' } });
+ // expect(changeFilters).toHaveBeenCalledWith(state,
+ // { type: 'CHANGE_PACKAGES_LIST_PARAMS', payload: { search: 'testSearch' } });
+ // });
- // it('should apply global filter', () => {
- // PackagesListStore(state, { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
- // expect(changeFilters).toHaveBeenCalledWith(state,
- // { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
- // });
+ // it('should apply global filter', () => {
+ // PackagesListStore(state, { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
+ // expect(changeFilters).toHaveBeenCalledWith(state,
+ // { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
+ // });
});
diff --git a/src/store/Reducers/PackageListStore.test.js b/src/store/Reducers/PackageListStore.test.js
index a8c7d4643..a73ce9c62 100644
--- a/src/store/Reducers/PackageListStore.test.js
+++ b/src/store/Reducers/PackageListStore.test.js
@@ -1,15 +1,13 @@
-/* eslint-disable new-cap */
import { changeFilters, fetchFulfilled, fetchPending, fetchRejected } from './HelperReducers';
import { PackagesListStore } from './PackagesListStore';
import { FETCH_PACKAGES_LIST } from '../ActionTypes';
jest.mock('./HelperReducers', () => ({
- ...jest.requireActual('./HelperReducers'),
- changeFilters: jest.fn(),
- fetchFulfilled: jest.fn(),
- fetchPending: jest.fn(),
- fetchRejected: jest.fn()
-})
-);
+ ...jest.requireActual('./HelperReducers'),
+ changeFilters: jest.fn(),
+ fetchFulfilled: jest.fn(),
+ fetchPending: jest.fn(),
+ fetchRejected: jest.fn(),
+}));
const state = { testObj: 'testVal' };
const actionFulfilled = FETCH_PACKAGES_LIST + '_FULFILLED';
@@ -17,29 +15,41 @@ const actionRejected = FETCH_PACKAGES_LIST + '_REJECTED';
const actionPending = FETCH_PACKAGES_LIST + '_PENDING';
describe('PackageListStore', () => {
- it('should start fetching package list', () => {
- PackagesListStore(state, { type: actionFulfilled, payload: { search: 'testSearch' } });
- expect(fetchFulfilled).toHaveBeenCalledWith(state, { type: actionFulfilled, payload: { search: 'testSearch' } });
+ it('should start fetching package list', () => {
+ PackagesListStore(state, { type: actionFulfilled, payload: { search: 'testSearch' } });
+ expect(fetchFulfilled).toHaveBeenCalledWith(state, {
+ type: actionFulfilled,
+ payload: { search: 'testSearch' },
});
- it('should fetch package list', () => {
- PackagesListStore(state, { type: actionPending, payload: { search: 'testSearch' } });
- expect(fetchPending).toHaveBeenCalledWith(state);
+ });
+ it('should fetch package list', () => {
+ PackagesListStore(state, { type: actionPending, payload: { search: 'testSearch' } });
+ expect(fetchPending).toHaveBeenCalledWith(state);
+ });
+ it('should handle rejected call', () => {
+ PackagesListStore(state, { type: actionRejected, payload: { search: 'testSearch' } });
+ expect(fetchRejected).toHaveBeenCalledWith(state, {
+ type: actionRejected,
+ payload: { search: 'testSearch' },
});
- it('should handle rejected call', () => {
- PackagesListStore(state, { type: actionRejected, payload: { search: 'testSearch' } });
- expect(fetchRejected).toHaveBeenCalledWith(state, { type: actionRejected, payload: { search: 'testSearch' } });
+ });
+ it('should change params', () => {
+ PackagesListStore(state, {
+ type: 'CHANGE_PACKAGES_LIST_PARAMS',
+ payload: { search: 'testSearch' },
});
-
- it('should change params', () => {
- PackagesListStore(state, { type: 'CHANGE_PACKAGES_LIST_PARAMS', payload: { search: 'testSearch' } });
- expect(changeFilters).toHaveBeenCalledWith(state,
- { type: 'CHANGE_PACKAGES_LIST_PARAMS', payload: { search: 'testSearch' } });
+ expect(changeFilters).toHaveBeenCalledWith(state, {
+ type: 'CHANGE_PACKAGES_LIST_PARAMS',
+ payload: { search: 'testSearch' },
});
+ });
- it('should apply global filter', () => {
- PackagesListStore(state, { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
- expect(changeFilters).toHaveBeenCalledWith(state,
- { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
+ it('should apply global filter', () => {
+ PackagesListStore(state, { type: 'TRIGGER_GLOBAL_FILTER', payload: { search: 'testSearch' } });
+ expect(changeFilters).toHaveBeenCalledWith(state, {
+ type: 'TRIGGER_GLOBAL_FILTER',
+ payload: { search: 'testSearch' },
});
+ });
});
diff --git a/src/store/Reducers/PackageSystemsStore.js b/src/store/Reducers/PackageSystemsStore.js
index 368b0e342..7a1453f4b 100644
--- a/src/store/Reducers/PackageSystemsStore.js
+++ b/src/store/Reducers/PackageSystemsStore.js
@@ -4,28 +4,27 @@ import { changeListParams } from '../../Utilities/Helpers';
// Initial State. It should not include page and perPage to persist them dynamically
export const initialState = {
- selectedRows: {},
- queryParams: {
- page: 1,
- perPage: 20
- }
+ selectedRows: {},
+ queryParams: {
+ page: 1,
+ perPage: 20,
+ },
};
export const PackageSystemsStore = (state = initialState, action) => {
- let newState = { ...state };
- switch (action.type) {
+ let newState = { ...state };
+ switch (action.type) {
+ case ActionTypes.CHANGE_PACKAGE_SYSTEMS_PARAMS:
+ newState.queryParams = changeListParams(newState.queryParams, action.payload);
+ return newState;
- case ActionTypes.CHANGE_PACKAGE_SYSTEMS_PARAMS:
- newState.queryParams = changeListParams(newState.queryParams, action.payload);
- return newState;
+ case ActionTypes.TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
- case ActionTypes.TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
+ case ActionTypes.CLEAR_PACKAGE_SYSTEMS_REDUCER:
+ return initialState;
- case ActionTypes.CLEAR_PACKAGE_SYSTEMS_REDUCER:
- return initialState;
-
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/PackagesListStore.js b/src/store/Reducers/PackagesListStore.js
index 417d05a95..3069a8386 100644
--- a/src/store/Reducers/PackagesListStore.js
+++ b/src/store/Reducers/PackagesListStore.js
@@ -2,27 +2,27 @@ import { storeListDefaults, packagesListDefaultFilters } from '../../Utilities/c
import * as ActionTypes from '../ActionTypes';
import { changeFilters, fetchFulfilled, fetchPending, fetchRejected } from './HelperReducers';
-const initialStore = { ...storeListDefaults, queryParams: packagesListDefaultFilters };
+const initialStore = { ...storeListDefaults, queryParams: packagesListDefaultFilters };
export const PackagesListStore = (state = initialStore, action) => {
- let newState = { ...state };
- switch (action.type) {
- case ActionTypes.FETCH_PACKAGES_LIST + '_PENDING':
- return fetchPending(newState);
+ let newState = { ...state };
+ switch (action.type) {
+ case ActionTypes.FETCH_PACKAGES_LIST + '_PENDING':
+ return fetchPending(newState);
- case ActionTypes.FETCH_PACKAGES_LIST + '_FULFILLED':
- return fetchFulfilled(newState, action);
+ case ActionTypes.FETCH_PACKAGES_LIST + '_FULFILLED':
+ return fetchFulfilled(newState, action);
- case ActionTypes.FETCH_PACKAGES_LIST + '_REJECTED':
- return fetchRejected(newState, action);
+ case ActionTypes.FETCH_PACKAGES_LIST + '_REJECTED':
+ return fetchRejected(newState, action);
- case ActionTypes.CHANGE_PACKAGES_LIST_PARAMS:
- return changeFilters(newState, action);
+ case ActionTypes.CHANGE_PACKAGES_LIST_PARAMS:
+ return changeFilters(newState, action);
- case ActionTypes.TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
+ case ActionTypes.TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/PatchSetDetailStore.js b/src/store/Reducers/PatchSetDetailStore.js
index 6bcebcb5d..c1e6809b3 100644
--- a/src/store/Reducers/PatchSetDetailStore.js
+++ b/src/store/Reducers/PatchSetDetailStore.js
@@ -2,32 +2,32 @@ import { FETCH_TEMPLATE_DETAIL, CLEAR_TEMPLATE_DETAIL } from '../ActionTypes';
import { fetchPending, fetchRejected } from './HelperReducers';
export let initialState = {
- data: { attributes: {} },
- status: { isLoading: true }
+ data: { attributes: {} },
+ status: { isLoading: true },
};
export const PatchSetDetailStore = (state = initialState, action) => {
- let newState = { ...state };
+ let newState = { ...state };
- switch (action.type) {
- case FETCH_TEMPLATE_DETAIL + '_FULFILLED':
- return {
- ...state,
- status: { isLoading: false },
- data: action.payload.data,
- error: {}
- };
+ switch (action.type) {
+ case FETCH_TEMPLATE_DETAIL + '_FULFILLED':
+ return {
+ ...state,
+ status: { isLoading: false },
+ data: action.payload.data,
+ error: {},
+ };
- case FETCH_TEMPLATE_DETAIL + '_PENDING':
- return fetchPending(newState);
+ case FETCH_TEMPLATE_DETAIL + '_PENDING':
+ return fetchPending(newState);
- case FETCH_TEMPLATE_DETAIL + '_REJECTED':
- return fetchRejected(newState, action);
+ case FETCH_TEMPLATE_DETAIL + '_REJECTED':
+ return fetchRejected(newState, action);
- case CLEAR_TEMPLATE_DETAIL:
- return initialState;
+ case CLEAR_TEMPLATE_DETAIL:
+ return initialState;
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/PatchSetDetailSystemsStore.js b/src/store/Reducers/PatchSetDetailSystemsStore.js
index be0fc14b9..568b6b97c 100644
--- a/src/store/Reducers/PatchSetDetailSystemsStore.js
+++ b/src/store/Reducers/PatchSetDetailSystemsStore.js
@@ -1,61 +1,60 @@
import { changeListParams } from '../../Utilities/Helpers';
import {
- CHANGE_PATCH_SET_DETAIL_SYSTEMS_PARAMS,
- TRIGGER_GLOBAL_FILTER,
- CHANGE_PATCH_SET_DETAIL_SYSTEMS_METADATA,
- FETCH_PATCH_SET_SYSTEMS_NO_FILTERS
+ CHANGE_PATCH_SET_DETAIL_SYSTEMS_PARAMS,
+ TRIGGER_GLOBAL_FILTER,
+ CHANGE_PATCH_SET_DETAIL_SYSTEMS_METADATA,
+ FETCH_PATCH_SET_SYSTEMS_NO_FILTERS,
} from '../ActionTypes';
import { changeFilters } from './HelperReducers';
const initialState = {
- selectedRows: {},
- queryParams: {
- page: 1,
- perPage: 20
- },
- templateHasSystemsLoading: true,
- templateHasSystems: null
+ selectedRows: {},
+ queryParams: {
+ page: 1,
+ perPage: 20,
+ },
+ templateHasSystemsLoading: true,
+ templateHasSystems: null,
};
export const PatchSetDetailSystemsStore = (state = initialState, action) => {
- let newState = { ...state };
-
- switch (action.type) {
- case CHANGE_PATCH_SET_DETAIL_SYSTEMS_PARAMS:
- newState.queryParams = changeListParams(newState.queryParams, action.payload);
- return newState;
-
- case TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
-
- case CHANGE_PATCH_SET_DETAIL_SYSTEMS_METADATA:
- newState.metadata = action.payload;
- return newState;
-
- case FETCH_PATCH_SET_SYSTEMS_NO_FILTERS + '_PENDING':
- return {
- ...state,
- templateHasSystemsLoading: true,
- templateHasSystems: null
- };
-
- case FETCH_PATCH_SET_SYSTEMS_NO_FILTERS + '_FULFILLED':
- return {
- ...state,
- templateHasSystemsLoading: false,
- templateHasSystems: action.payload.data.length > 0
- };
-
- case FETCH_PATCH_SET_SYSTEMS_NO_FILTERS + '_REJECTED':
- return {
- ...state,
- templateHasSystemsLoading: false,
- // if we set this to true, Inventory table is shown, which has better error handling
- templateHasSystems: true
- };
-
- default:
- return state;
- }
+ let newState = { ...state };
+
+ switch (action.type) {
+ case CHANGE_PATCH_SET_DETAIL_SYSTEMS_PARAMS:
+ newState.queryParams = changeListParams(newState.queryParams, action.payload);
+ return newState;
+
+ case TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
+
+ case CHANGE_PATCH_SET_DETAIL_SYSTEMS_METADATA:
+ newState.metadata = action.payload;
+ return newState;
+
+ case FETCH_PATCH_SET_SYSTEMS_NO_FILTERS + '_PENDING':
+ return {
+ ...state,
+ templateHasSystemsLoading: true,
+ templateHasSystems: null,
+ };
+
+ case FETCH_PATCH_SET_SYSTEMS_NO_FILTERS + '_FULFILLED':
+ return {
+ ...state,
+ templateHasSystemsLoading: false,
+ templateHasSystems: action.payload.data.length > 0,
+ };
+
+ case FETCH_PATCH_SET_SYSTEMS_NO_FILTERS + '_REJECTED':
+ return {
+ ...state,
+ templateHasSystemsLoading: false,
+ // if we set this to true, Inventory table is shown, which has better error handling
+ templateHasSystems: true,
+ };
+
+ default:
+ return state;
+ }
};
-
diff --git a/src/store/Reducers/PatchSetsReducer.js b/src/store/Reducers/PatchSetsReducer.js
index 89008597c..dec646bfc 100644
--- a/src/store/Reducers/PatchSetsReducer.js
+++ b/src/store/Reducers/PatchSetsReducer.js
@@ -1,59 +1,54 @@
import * as ActionTypes from '../ActionTypes';
-import {
- changeFilters,
- selectRows,
- fetchPending,
- fetchRejected
-} from './HelperReducers';
+import { changeFilters, selectRows, fetchPending, fetchRejected } from './HelperReducers';
// Initial State. It should not include page and perPage to persist them dynamically
export const initialState = {
- rows: [],
- selectedRows: [],
- queryParams: {
- page: 1,
- perPage: 20,
- offset: 0,
- filter: {}
- },
- status: { isLoading: true },
- metadata: {
- limit: 20,
- offset: 0,
- total_items: 0
- },
- error: {}
+ rows: [],
+ selectedRows: [],
+ queryParams: {
+ page: 1,
+ perPage: 20,
+ offset: 0,
+ filter: {},
+ },
+ status: { isLoading: true },
+ metadata: {
+ limit: 20,
+ offset: 0,
+ total_items: 0,
+ },
+ error: {},
};
export const PatchSetsReducer = (state = initialState, action) => {
- let newState = { ...state };
+ let newState = { ...state };
- switch (action.type) {
- case ActionTypes.FETCH_ALL_PATCH_SETS + '_FULFILLED':
- return {
- ...newState,
- rows: action.payload.data?.map(set => ({ ...set.attributes, id: set.id })),
- metadata: action.payload.meta || {},
- error: {},
- status: { code: action.payload.status, isLoading: false, hasError: false }
- };
+ switch (action.type) {
+ case ActionTypes.FETCH_ALL_PATCH_SETS + '_FULFILLED':
+ return {
+ ...newState,
+ rows: action.payload.data?.map((set) => ({ ...set.attributes, id: set.id })),
+ metadata: action.payload.meta || {},
+ error: {},
+ status: { code: action.payload.status, isLoading: false, hasError: false },
+ };
- case ActionTypes.FETCH_ALL_PATCH_SETS + '_PENDING':
- return fetchPending(newState);
+ case ActionTypes.FETCH_ALL_PATCH_SETS + '_PENDING':
+ return fetchPending(newState);
- case ActionTypes.FETCH_ALL_PATCH_SETS + '_REJECTED':
- return fetchRejected(newState, action);
+ case ActionTypes.FETCH_ALL_PATCH_SETS + '_REJECTED':
+ return fetchRejected(newState, action);
- case ActionTypes.CHANGE_PATCH_SET_PARAMS:
- return changeFilters(newState, action);
+ case ActionTypes.CHANGE_PATCH_SET_PARAMS:
+ return changeFilters(newState, action);
- case ActionTypes.SELECT_PATCH_SET_ROW:
- return selectRows(newState, action);
+ case ActionTypes.SELECT_PATCH_SET_ROW:
+ return selectRows(newState, action);
- case ActionTypes.CLEAR_PATCH_SETS:
- return initialState;
+ case ActionTypes.CLEAR_PATCH_SETS:
+ return initialState;
- default:
- return newState;
- }
+ default:
+ return newState;
+ }
};
diff --git a/src/store/Reducers/SpecificPatchSetReducer.js b/src/store/Reducers/SpecificPatchSetReducer.js
index d6bd990a6..414125c46 100644
--- a/src/store/Reducers/SpecificPatchSetReducer.js
+++ b/src/store/Reducers/SpecificPatchSetReducer.js
@@ -1,40 +1,40 @@
import * as ActionTypes from '../ActionTypes';
-import {
- fetchPending,
- fetchRejected
-} from './HelperReducers';
+import { fetchPending, fetchRejected } from './HelperReducers';
export const initialState = {
- patchSet: {
- config: {}
- },
- assignedSystems: [],
- status: {},
- error: {}
+ patchSet: {
+ config: {},
+ },
+ assignedSystems: [],
+ status: {},
+ error: {},
};
export const SpecificPatchSetReducer = (state = initialState, action) => {
- switch (action.type) {
- case ActionTypes.FETCH_PATCH_SET + '_FULFILLED': {
- const { attributes: { config, name, description }, id } = action.payload?.data || { config: {} };
+ switch (action.type) {
+ case ActionTypes.FETCH_PATCH_SET + '_FULFILLED': {
+ const {
+ attributes: { config, name, description },
+ id,
+ } = action.payload?.data || { config: {} };
- return {
- ...state,
- patchSet: { name, description, config: config || {}, id },
- status: { code: action.payload.status, isLoading: false, hasError: false }
- };
- }
+ return {
+ ...state,
+ patchSet: { name, description, config: config || {}, id },
+ status: { code: action.payload.status, isLoading: false, hasError: false },
+ };
+ }
- case ActionTypes.FETCH_PATCH_SET + '_PENDING':
- return fetchPending(state);
+ case ActionTypes.FETCH_PATCH_SET + '_PENDING':
+ return fetchPending(state);
- case ActionTypes.FETCH_PATCH_SET + '_REJECTED':
- return fetchRejected(state, action);
+ case ActionTypes.FETCH_PATCH_SET + '_REJECTED':
+ return fetchRejected(state, action);
- case ActionTypes.CLEAR_PATCH_SET:
- return initialState;
+ case ActionTypes.CLEAR_PATCH_SET:
+ return initialState;
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/SystemAdvisoryListStore.js b/src/store/Reducers/SystemAdvisoryListStore.js
index 2401b4dd7..50b2cc936 100644
--- a/src/store/Reducers/SystemAdvisoryListStore.js
+++ b/src/store/Reducers/SystemAdvisoryListStore.js
@@ -1,42 +1,42 @@
import { storeListDefaults } from '../../Utilities/constants';
import * as ActionTypes from '../ActionTypes';
import {
- changeFilters,
- selectRows,
- fetchPending,
- fetchRejected,
- fetchFulfilled,
- expandRows
+ changeFilters,
+ selectRows,
+ fetchPending,
+ fetchRejected,
+ fetchFulfilled,
+ expandRows,
} from './HelperReducers';
export const SystemAdvisoryListStore = (state = storeListDefaults, action) => {
- let newState = { ...state };
- switch (action.type) {
- case ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_FULFILLED':
- return fetchFulfilled(newState, action);
+ let newState = { ...state };
+ switch (action.type) {
+ case ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_FULFILLED':
+ return fetchFulfilled(newState, action);
- case ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_PENDING':
- return fetchPending(newState);
+ case ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_PENDING':
+ return fetchPending(newState);
- case ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_REJECTED':
- return fetchRejected(newState, action);
+ case ActionTypes.FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_REJECTED':
+ return fetchRejected(newState, action);
- case ActionTypes.CHANGE_SYSTEM_ADVISORY_LIST_PARAMS:
- return changeFilters(newState, action);
+ case ActionTypes.CHANGE_SYSTEM_ADVISORY_LIST_PARAMS:
+ return changeFilters(newState, action);
- case ActionTypes.EXPAND_SYSTEM_ADVISORY_ROW:
- return expandRows(newState, action);
+ case ActionTypes.EXPAND_SYSTEM_ADVISORY_ROW:
+ return expandRows(newState, action);
- case ActionTypes.SELECT_SYSTEM_ADVISORY_ROW:
- return selectRows(newState, action);
+ case ActionTypes.SELECT_SYSTEM_ADVISORY_ROW:
+ return selectRows(newState, action);
- case ActionTypes.CLEAR_SYSTEM_ADVISORIES:
- return storeListDefaults;
+ case ActionTypes.CLEAR_SYSTEM_ADVISORIES:
+ return storeListDefaults;
- case ActionTypes.TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
+ case ActionTypes.TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/SystemAdvisoryListStore.test.js b/src/store/Reducers/SystemAdvisoryListStore.test.js
index c982db9e9..c62d9088e 100644
--- a/src/store/Reducers/SystemAdvisoryListStore.test.js
+++ b/src/store/Reducers/SystemAdvisoryListStore.test.js
@@ -1,25 +1,35 @@
-
/* eslint-disable */
-import { STATUS_LOADING, STATUS_REJECTED, STATUS_RESOLVED, storeListDefaults } from '../../Utilities/constants';
-import { CHANGE_SYSTEM_ADVISORY_LIST_PARAMS, CLEAR_SYSTEM_ADVISORIES, EXPAND_SYSTEM_ADVISORY_ROW, FETCH_APPLICABLE_SYSTEM_ADVISORIES, SELECT_SYSTEM_ADVISORY_ROW } from '../ActionTypes';
+import {
+ STATUS_LOADING,
+ STATUS_REJECTED,
+ STATUS_RESOLVED,
+ storeListDefaults,
+} from '../../Utilities/constants';
+import {
+ CHANGE_SYSTEM_ADVISORY_LIST_PARAMS,
+ CLEAR_SYSTEM_ADVISORIES,
+ EXPAND_SYSTEM_ADVISORY_ROW,
+ FETCH_APPLICABLE_SYSTEM_ADVISORIES,
+ SELECT_SYSTEM_ADVISORY_ROW,
+} from '../ActionTypes';
import { SystemAdvisoryListStore } from './SystemAdvisoryListStore';
const action_fulfilled = FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_FULFILLED';
const action_rejected = FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_REJECTED';
const action_pending = FETCH_APPLICABLE_SYSTEM_ADVISORIES + '_PENDING';
const fulfilled_payload = {
- data: [],
- meta: {
- limit: 50,
- offset: 25,
- total_items: 50
- }
+ data: [],
+ meta: {
+ limit: 50,
+ offset: 25,
+ total_items: 50,
+ },
};
const error = 'Error';
describe('SystemAdvisoryListStore tests', () => {
- it.each`
+ it.each`
state | action | result
${storeListDefaults} | ${{ type: action_fulfilled, payload: fulfilled_payload }} | ${{ ...storeListDefaults, metadata: fulfilled_payload.meta, rows: fulfilled_payload.data, status: { code: undefined, isLoading: false, hasError: false }, error: {} }}
${storeListDefaults} | ${{ type: action_pending, payload: {} }} | ${{ ...storeListDefaults, status: { code: undefined, isLoading: true, hasError: false }, error: {} }}
@@ -28,11 +38,11 @@ describe('SystemAdvisoryListStore tests', () => {
${storeListDefaults} | ${{ type: SELECT_SYSTEM_ADVISORY_ROW, payload: { id: 1, selected: true } }} | ${{ ...storeListDefaults, selectedRows: { 1: true } }}
${storeListDefaults} | ${{ type: 'NONSENSE', payload: {} }} | ${storeListDefaults}
${undefined} | ${{ type: 'NONSENSE', payload: {} }} | ${storeListDefaults}
- ${storeListDefaults} | ${{type: CLEAR_SYSTEM_ADVISORIES, payload: {}}} | ${storeListDefaults}
- `('$action', ({ state, action: { type, payload }, result }) => {
+ ${storeListDefaults} | ${{ type: CLEAR_SYSTEM_ADVISORIES, payload: {} }} | ${storeListDefaults}
+ `('$action', ({ state, action: { type, payload }, result }) => {
const res = SystemAdvisoryListStore(state, { type, payload });
expect(res).toEqual(result);
-});
+ });
});
// ${ storeListDefaults } | ${ { type: action_rejected, payload: error } } | ${ { ...storeListDefaults, status: STATUS_REJECTED, error } }
diff --git a/src/store/Reducers/SystemDetailStore.js b/src/store/Reducers/SystemDetailStore.js
index 70a78a79e..e6a7cf2c8 100644
--- a/src/store/Reducers/SystemDetailStore.js
+++ b/src/store/Reducers/SystemDetailStore.js
@@ -1,36 +1,36 @@
let initialState = {
- loaded: false
+ loaded: false,
};
// Reducer
export const SystemDetailStore = (state = initialState, { type, payload }) => {
- switch (type) {
- case 'FETCH_SYSTEM_DETAIL_FULFILLED':
- return {
- ...state,
- hasThirdPartyRepo: payload.data?.attributes.third_party,
- satelliteManaged: payload.data?.attributes.satellite_managed,
- patchSetName: payload.data?.attributes.baseline_name,
- patchSetId: payload.data?.attributes.baseline_id,
- templateName: payload.data?.attributes.template_name,
- templateUUID: payload.data?.attributes.template_uuid
- };
- case 'LOAD_ENTITY_PENDING':
- return {
- ...state,
- loaded: false
- };
- case 'LOAD_ENTITY_FULFILLED':
- return {
- ...state,
- loaded: true
- };
- case 'LOAD_ENTITY_REJECTED':
- return {
- ...state,
- loaded: true
- };
- default:
- return state;
- }
+ switch (type) {
+ case 'FETCH_SYSTEM_DETAIL_FULFILLED':
+ return {
+ ...state,
+ hasThirdPartyRepo: payload.data?.attributes.third_party,
+ satelliteManaged: payload.data?.attributes.satellite_managed,
+ patchSetName: payload.data?.attributes.baseline_name,
+ patchSetId: payload.data?.attributes.baseline_id,
+ templateName: payload.data?.attributes.template_name,
+ templateUUID: payload.data?.attributes.template_uuid,
+ };
+ case 'LOAD_ENTITY_PENDING':
+ return {
+ ...state,
+ loaded: false,
+ };
+ case 'LOAD_ENTITY_FULFILLED':
+ return {
+ ...state,
+ loaded: true,
+ };
+ case 'LOAD_ENTITY_REJECTED':
+ return {
+ ...state,
+ loaded: true,
+ };
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/SystemDetailStore.test.js b/src/store/Reducers/SystemDetailStore.test.js
index dae148686..f8c4b225f 100644
--- a/src/store/Reducers/SystemDetailStore.test.js
+++ b/src/store/Reducers/SystemDetailStore.test.js
@@ -1,23 +1,19 @@
import { initialState, SystemDetailStore } from './SystemDetailStore';
-/* eslint-disable */
-
const stateAfterAction = {
- loaded: true
+ loaded: true,
};
describe('SystemDetailStore', () => {
- it.each`
- state | action | result
- ${initialState} | ${{ type: 'TEST_INVALID_ACTION', payload: {} }} | ${{ loaded: false }}
- ${undefined} | ${{ type: 'LOAD_ENTITY_FULFILLED', payload: {} }} | ${{ ...initialState, ...stateAfterAction }}
- ${{ ...initialState, test: 'testState' }} | ${{ type: 'LOAD_ENTITY_FULFILLED', payload: {} }} | ${{ ...initialState, ...stateAfterAction, test: 'testState' }}
- ${undefined} | ${{ type: 'LOAD_ENTITY_REJECTED', payload: {} }} | ${{ ...initialState, ...stateAfterAction, }}
- ${{ ...initialState, test: 'testState' }} | ${{ type: 'LOAD_ENTITY_REJECTED', payload: {} }} | ${{ ...initialState, ...stateAfterAction, test: 'testState' }}
- ${initialState} | ${{ type: 'LOAD_ENTITY_FULFILLED', payload: { data: { attributes: { third_party: true } } } }} | ${{ ...initialState, loaded: true }}
- `('$action', ({ state, action: { type, payload }, result }) => {
- const res = SystemDetailStore(state, { type, payload });
- expect(res).toEqual(result);
- });
+ it.each`
+ state | action | result
+ ${initialState} | ${{ type: 'TEST_INVALID_ACTION', payload: {} }} | ${{ loaded: false }}
+ ${undefined} | ${{ type: 'LOAD_ENTITY_FULFILLED', payload: {} }} | ${{ ...initialState, ...stateAfterAction }}
+ ${{ ...initialState, test: 'testState' }} | ${{ type: 'LOAD_ENTITY_FULFILLED', payload: {} }} | ${{ ...initialState, ...stateAfterAction, test: 'testState' }}
+ ${undefined} | ${{ type: 'LOAD_ENTITY_REJECTED', payload: {} }} | ${{ ...initialState, ...stateAfterAction }}
+ ${{ ...initialState, test: 'testState' }} | ${{ type: 'LOAD_ENTITY_REJECTED', payload: {} }} | ${{ ...initialState, ...stateAfterAction, test: 'testState' }}
+ ${initialState} | ${{ type: 'LOAD_ENTITY_FULFILLED', payload: { data: { attributes: { third_party: true } } } }} | ${{ ...initialState, loaded: true }}
+ `('$action', ({ state, action: { type, payload }, result }) => {
+ const res = SystemDetailStore(state, { type, payload });
+ expect(res).toEqual(result);
+ });
});
-
-/* eslint-enable */
diff --git a/src/store/Reducers/SystemPackageListStore.js b/src/store/Reducers/SystemPackageListStore.js
index 760a75285..03ee34e3e 100644
--- a/src/store/Reducers/SystemPackageListStore.js
+++ b/src/store/Reducers/SystemPackageListStore.js
@@ -1,34 +1,43 @@
import { storeListDefaults, systemPackagesDefaultFilters } from '../../Utilities/constants';
import * as ActionTypes from '../ActionTypes';
-import { changeFilters, fetchFulfilled, fetchPending, fetchRejected, selectRows } from './HelperReducers';
+import {
+ changeFilters,
+ fetchFulfilled,
+ fetchPending,
+ fetchRejected,
+ selectRows,
+} from './HelperReducers';
let initializeState = { queryParams: systemPackagesDefaultFilters };
-export const SystemPackageListStore = (state = { ...storeListDefaults, ...initializeState }, action) => {
- let newState = { ...state };
- switch (action.type) {
- case ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES + '_FULFILLED':
- return fetchFulfilled(newState, action);
+export const SystemPackageListStore = (
+ state = { ...storeListDefaults, ...initializeState },
+ action,
+) => {
+ let newState = { ...state };
+ switch (action.type) {
+ case ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES + '_FULFILLED':
+ return fetchFulfilled(newState, action);
- case ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES + '_PENDING':
- return fetchPending(newState);
+ case ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES + '_PENDING':
+ return fetchPending(newState);
- case ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES + '_REJECTED':
- return fetchRejected(newState, action);
+ case ActionTypes.FETCH_APPLICABLE_SYSTEM_PACKAGES + '_REJECTED':
+ return fetchRejected(newState, action);
- case ActionTypes.CHANGE_SYSTEM_PACKAGES_LIST_PARAMS:
- return changeFilters(newState, action);
+ case ActionTypes.CHANGE_SYSTEM_PACKAGES_LIST_PARAMS:
+ return changeFilters(newState, action);
- case ActionTypes.SELECT_SYSTEM_PACKAGES_ROW:
- return selectRows(newState, action);
+ case ActionTypes.SELECT_SYSTEM_PACKAGES_ROW:
+ return selectRows(newState, action);
- case ActionTypes.CLEAR_SYSTEM_PACKAGES:
- return { ...storeListDefaults, ...initializeState };
+ case ActionTypes.CLEAR_SYSTEM_PACKAGES:
+ return { ...storeListDefaults, ...initializeState };
- case ActionTypes.TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
+ case ActionTypes.TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
diff --git a/src/store/Reducers/SystemPackageListStore.test.js b/src/store/Reducers/SystemPackageListStore.test.js
index bd8631b42..d0a9f0b97 100644
--- a/src/store/Reducers/SystemPackageListStore.test.js
+++ b/src/store/Reducers/SystemPackageListStore.test.js
@@ -1,42 +1,42 @@
-
-/* eslint-disable */
import { storeListDefaults } from '../../Utilities/constants';
-import { CHANGE_SYSTEM_PACKAGES_LIST_PARAMS, SELECT_SYSTEM_PACKAGES_ROW,
- FETCH_APPLICABLE_SYSTEM_PACKAGES, TRIGGER_GLOBAL_FILTER, CLEAR_SYSTEM_PACKAGES } from '../ActionTypes';
+import {
+ CHANGE_SYSTEM_PACKAGES_LIST_PARAMS,
+ SELECT_SYSTEM_PACKAGES_ROW,
+ FETCH_APPLICABLE_SYSTEM_PACKAGES,
+ TRIGGER_GLOBAL_FILTER,
+ CLEAR_SYSTEM_PACKAGES,
+} from '../ActionTypes';
import { SystemPackageListStore } from './SystemPackageListStore';
const action_fulfilled = FETCH_APPLICABLE_SYSTEM_PACKAGES + '_FULFILLED';
const action_rejected = FETCH_APPLICABLE_SYSTEM_PACKAGES + '_REJECTED';
const action_pending = FETCH_APPLICABLE_SYSTEM_PACKAGES + '_PENDING';
const fulfilled_payload = {
- data: [],
- meta: {
- limit: 50,
- offset: 25,
- total_items: 50
- }
+ data: [],
+ meta: {
+ limit: 50,
+ offset: 25,
+ total_items: 50,
+ },
};
const error = 'Error';
describe('SystemPackageListStore tests', () => {
- it.each`
- state | action | result
- ${storeListDefaults} | ${{ type: action_fulfilled, payload: fulfilled_payload }} | ${{ ...storeListDefaults, metadata: fulfilled_payload.meta, rows: fulfilled_payload.data, status: { code: undefined, isLoading: false, hasError: false }, error: {} }}
- ${storeListDefaults} | ${{ type: action_pending, payload: {} }} | ${{ ...storeListDefaults, status: { code: undefined, isLoading: true, hasError: false }, error: {} }}
- ${storeListDefaults} | ${{ type: CLEAR_SYSTEM_PACKAGES, payload: {} }} | ${{ ...storeListDefaults, status: { isLoading: true }, error: {}, queryParams: { filter: { update_status: ['Installable']} } }}
- ${ storeListDefaults} | ${{ type: action_rejected, payload: error }} | ${{ ...storeListDefaults, status: { isLoading: false, hasError: true, code: undefined }, error, metadata: {} }}
- ${storeListDefaults} | ${{ type: action_rejected, payload: error }} | ${{ ...storeListDefaults, status: { isLoading: false, hasError: true, code: undefined }, error, metadata: {} } }
-
+ it.each`
+ state | action | result
+ ${storeListDefaults} | ${{ type: action_fulfilled, payload: fulfilled_payload }} | ${{ ...storeListDefaults, metadata: fulfilled_payload.meta, rows: fulfilled_payload.data, status: { code: undefined, isLoading: false, hasError: false }, error: {} }}
+ ${storeListDefaults} | ${{ type: action_pending, payload: {} }} | ${{ ...storeListDefaults, status: { code: undefined, isLoading: true, hasError: false }, error: {} }}
+ ${storeListDefaults} | ${{ type: CLEAR_SYSTEM_PACKAGES, payload: {} }} | ${{ ...storeListDefaults, status: { isLoading: true }, error: {}, queryParams: { filter: { update_status: ['Installable'] } } }}
+ ${storeListDefaults} | ${{ type: action_rejected, payload: error }} | ${{ ...storeListDefaults, status: { isLoading: false, hasError: true, code: undefined }, error, metadata: {} }}
+ ${storeListDefaults} | ${{ type: action_rejected, payload: error }} | ${{ ...storeListDefaults, status: { isLoading: false, hasError: true, code: undefined }, error, metadata: {} }}
${storeListDefaults} | ${{ type: CHANGE_SYSTEM_PACKAGES_LIST_PARAMS, payload: { limit: 10 } }} | ${{ ...storeListDefaults, queryParams: { limit: 10, offset: 0, page: 1, page_size: 20 } }}
- ${storeListDefaults} | ${{ type: TRIGGER_GLOBAL_FILTER, payload: { limit: 10 } }} | ${{ ...storeListDefaults, queryParams: { limit: 10, offset: 0, page: 1, page_size: 20 } }}
+ ${storeListDefaults} | ${{ type: TRIGGER_GLOBAL_FILTER, payload: { limit: 10 } }} | ${{ ...storeListDefaults, queryParams: { limit: 10, offset: 0, page: 1, page_size: 20 } }}
${storeListDefaults} | ${{ type: SELECT_SYSTEM_PACKAGES_ROW, payload: { id: 1, selected: true } }} | ${{ ...storeListDefaults, selectedRows: { 1: true } }}
- ${storeListDefaults} | ${{ type: 'NONSENSE', payload: {} }} | ${storeListDefaults}
- ${undefined} | ${{ type: 'NONSENSE', payload: {} }} | ${{ ...storeListDefaults, queryParams: { filter: { update_status: ['Installable'] } } }}
- `('$action', ({ state, action: { type, payload }, result }) => {
- const res = SystemPackageListStore(state, { type, payload });
- expect(res).toEqual(result);
- });
+ ${storeListDefaults} | ${{ type: 'NONSENSE', payload: {} }} | ${storeListDefaults}
+ ${undefined} | ${{ type: 'NONSENSE', payload: {} }} | ${{ ...storeListDefaults, queryParams: { filter: { update_status: ['Installable'] } } }}
+ `('$action', ({ state, action: { type, payload }, result }) => {
+ const res = SystemPackageListStore(state, { type, payload });
+ expect(res).toEqual(result);
+ });
});
-
-/* eslint-enable */
diff --git a/src/store/Reducers/SystemsStore.js b/src/store/Reducers/SystemsStore.js
index 99d7fdf5f..412ed3c41 100644
--- a/src/store/Reducers/SystemsStore.js
+++ b/src/store/Reducers/SystemsStore.js
@@ -4,38 +4,37 @@ import { changeListParams } from '../../Utilities/Helpers';
// Initial State. It should not include page and perPage to persist them dynamically
const initialState = {
- selectedRows: {},
- queryParams: {
- page: 1,
- perPage: 20,
- filter: {
- stale: [true, false]
- }
- }
+ selectedRows: {},
+ queryParams: {
+ page: 1,
+ perPage: 20,
+ filter: {
+ stale: [true, false],
+ },
+ },
};
// Reducer
export const SystemsStore = (state = initialState, action) => {
- let newState = { ...state };
+ let newState = { ...state };
- switch (action.type) {
- case ActionTypes.CHANGE_SYSTEMS_PARAMS:
- newState.queryParams = changeListParams(newState.queryParams, action.payload);
- return newState;
+ switch (action.type) {
+ case ActionTypes.CHANGE_SYSTEMS_PARAMS:
+ newState.queryParams = changeListParams(newState.queryParams, action.payload);
+ return newState;
- case ActionTypes.TRIGGER_GLOBAL_FILTER:
- return changeFilters(newState, action);
+ case ActionTypes.TRIGGER_GLOBAL_FILTER:
+ return changeFilters(newState, action);
- case ActionTypes.CHANGE_SYSTEMS_METADATA:
- newState.metadata = action.payload;
- return newState;
+ case ActionTypes.CHANGE_SYSTEMS_METADATA:
+ newState.metadata = action.payload;
+ return newState;
- case ActionTypes.TOGGLE_ALL_SELECTED:
- newState.areAllSelected = action.payload;
- return newState;
+ case ActionTypes.TOGGLE_ALL_SELECTED:
+ newState.areAllSelected = action.payload;
+ return newState;
- default:
- return state;
- }
+ default:
+ return state;
+ }
};
-
diff --git a/src/store/index.js b/src/store/index.js
index 25b8069ae..89044cb5e 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -17,31 +17,36 @@ import { PatchSetsReducer } from './Reducers/PatchSetsReducer';
import { PatchSetDetailStore } from './Reducers/PatchSetDetailStore';
import { PatchSetDetailSystemsStore } from './Reducers/PatchSetDetailSystemsStore';
import { SpecificPatchSetReducer } from './Reducers/SpecificPatchSetReducer';
-import { legacy_createStore as createStore, applyMiddleware, combineReducers, compose } from 'redux';
+import {
+ legacy_createStore as createStore,
+ applyMiddleware,
+ combineReducers,
+ compose,
+} from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export const defaultReducers = {
- AdvisoryListStore,
- SystemDetailStore,
- SystemAdvisoryListStore,
- AdvisoryDetailStore,
- SystemPackageListStore,
- PackagesListStore,
- PackageDetailStore,
- CvesListStore,
- SystemsStore,
- PackageSystemsStore,
- AdvisorySystemsStore,
- GlobalFilterStore,
- PatchSetsStore: PatchSetsReducer,
- PatchSetDetailStore,
- PatchSetDetailSystemsStore,
- SpecificPatchSetReducer,
- notifications: notificationsReducer
+ AdvisoryListStore,
+ SystemDetailStore,
+ SystemAdvisoryListStore,
+ AdvisoryDetailStore,
+ SystemPackageListStore,
+ PackagesListStore,
+ PackageDetailStore,
+ CvesListStore,
+ SystemsStore,
+ PackageSystemsStore,
+ AdvisorySystemsStore,
+ GlobalFilterStore,
+ PatchSetsStore: PatchSetsReducer,
+ PatchSetDetailStore,
+ PatchSetDetailSystemsStore,
+ SpecificPatchSetReducer,
+ notifications: notificationsReducer,
};
export const store = createStore(
- combineReducers(defaultReducers),
- composeEnhancers(applyMiddleware(promiseMiddleware, notificationsMiddleware()))
+ combineReducers(defaultReducers),
+ composeEnhancers(applyMiddleware(promiseMiddleware, notificationsMiddleware())),
);