foreman_openscap 12.1.2 → 13.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/foreman_openscap/scap_breakdown_chart.css +15 -0
  3. data/app/models/foreman_openscap/compliance_status.rb +2 -2
  4. data/app/views/compliance_hosts/show.html.erb +5 -3
  5. data/lib/foreman_openscap/engine.rb +1 -1
  6. data/lib/foreman_openscap/version.rb +1 -1
  7. data/test/unit/compliance_status_test.rb +50 -0
  8. data/webpack/components/LineChart/LineChart.fixtures.js +28 -0
  9. data/webpack/components/LineChart/LineChart.scss +7 -0
  10. data/webpack/components/LineChart/LineChart.test.js +266 -0
  11. data/webpack/components/LineChart/LineChartHelpers.js +206 -0
  12. data/webpack/components/LineChart/index.js +324 -0
  13. data/webpack/components/OpenscapRemediationWizard/constants.js +3 -0
  14. data/webpack/components/OpenscapRemediationWizard/steps/Finish.js +2 -2
  15. data/webpack/components/OpenscapRemediationWizard/steps/ReviewRemediation.js +10 -2
  16. data/webpack/components/OpenscapRemediationWizard/steps/SnippetSelect.js +3 -1
  17. data/webpack/global_index.js +3 -1
  18. data/webpack/index.js +2 -0
  19. data/webpack/test_setup.js +1 -0
  20. metadata +8 -19
  21. data/app/assets/javascripts/foreman_openscap/scap_hosts_show.js +0 -4
  22. data/webpack/components/ConfirmModal.js +0 -66
  23. data/webpack/components/ConfirmModal.scss +0 -3
  24. data/webpack/components/IndexLayout.js +0 -44
  25. data/webpack/components/IndexTable/IndexTableHelper.js +0 -6
  26. data/webpack/components/IndexTable/index.js +0 -73
  27. data/webpack/components/LinkButton.js +0 -42
  28. data/webpack/components/withDeleteModal.js +0 -51
  29. data/webpack/components/withLoading.js +0 -107
  30. data/webpack/helpers/commonHelper.js +0 -1
  31. data/webpack/helpers/globalIdHelper.js +0 -15
  32. data/webpack/helpers/mutationHelper.js +0 -68
  33. data/webpack/helpers/pageParamsHelper.js +0 -31
  34. data/webpack/helpers/permissionsHelper.js +0 -42
  35. data/webpack/helpers/tableHelper.js +0 -9
  36. data/webpack/helpers/toastHelper.js +0 -3
  37. data/webpack/testHelper.js +0 -127
@@ -1,42 +0,0 @@
1
- import React from 'react';
2
- import { Link } from 'react-router-dom';
3
- import { Button } from '@patternfly/react-core';
4
- import PropTypes from 'prop-types';
5
-
6
- const LinkButton = ({
7
- path,
8
- btnVariant,
9
- btnText,
10
- isDisabled,
11
- btnAriaLabel,
12
- ouiaId,
13
- }) => (
14
- <Link to={path}>
15
- <Button
16
- ouiaId={ouiaId}
17
- variant={btnVariant}
18
- isDisabled={isDisabled}
19
- aria-label={btnAriaLabel}
20
- >
21
- {btnText}
22
- </Button>
23
- </Link>
24
- );
25
-
26
- LinkButton.propTypes = {
27
- path: PropTypes.string.isRequired,
28
- btnText: PropTypes.string.isRequired,
29
- btnVariant: PropTypes.string,
30
- isDisabled: PropTypes.bool,
31
- btnAriaLabel: PropTypes.string,
32
- ouiaId: PropTypes.string,
33
- };
34
-
35
- LinkButton.defaultProps = {
36
- btnVariant: 'primary',
37
- isDisabled: false,
38
- btnAriaLabel: null,
39
- ouiaId: 'oscap-link-button',
40
- };
41
-
42
- export default LinkButton;
@@ -1,51 +0,0 @@
1
- import React, { useState } from 'react';
2
- import PropTypes from 'prop-types';
3
- import { translate as __, sprintf } from 'foremanReact/common/I18n';
4
- import ConfirmModal from './ConfirmModal';
5
-
6
- const withDelete = Component => {
7
- const Subcomponent = ({
8
- confirmDeleteTitle,
9
- submitDelete,
10
- prepareMutation,
11
- ...rest
12
- }) => {
13
- const [toDelete, setToDelete] = useState(null);
14
-
15
- const toggleModal = (item = null) => {
16
- setToDelete(item);
17
- };
18
-
19
- return (
20
- <React.Fragment>
21
- <Component {...rest} toggleModal={toggleModal} />
22
- <ConfirmModal
23
- title={confirmDeleteTitle}
24
- text={
25
- toDelete
26
- ? sprintf(
27
- __('Are you sure you want to delete %s?'),
28
- toDelete.name
29
- )
30
- : ''
31
- }
32
- onClose={toggleModal}
33
- isOpen={!!toDelete}
34
- onConfirm={submitDelete}
35
- prepareMutation={() => prepareMutation(toggleModal)}
36
- record={toDelete}
37
- />
38
- </React.Fragment>
39
- );
40
- };
41
-
42
- Subcomponent.propTypes = {
43
- confirmDeleteTitle: PropTypes.string.isRequired,
44
- submitDelete: PropTypes.func.isRequired,
45
- prepareMutation: PropTypes.func.isRequired,
46
- };
47
-
48
- return Subcomponent;
49
- };
50
-
51
- export default withDelete;
@@ -1,107 +0,0 @@
1
- import React, { useEffect } from 'react';
2
- import PropTypes from 'prop-types';
3
- import { translate as __ } from 'foremanReact/common/I18n';
4
- import Loading from 'foremanReact/components/Loading';
5
- import {
6
- permissionCheck,
7
- permissionDeniedMsg,
8
- } from '../helpers/permissionsHelper';
9
-
10
- import EmptyState from './EmptyState';
11
-
12
- const errorStateTitle = __('Error!');
13
-
14
- const pluckData = (data, path) => {
15
- const split = path.split('.');
16
- return split.reduce((memo, item) => {
17
- if (item) {
18
- return memo[item];
19
- }
20
- throw new Error('Unexpected empty segment in response data path');
21
- }, data);
22
- };
23
-
24
- const withLoading = Component => {
25
- const Subcomponent = ({
26
- fetchFn,
27
- resultPath,
28
- renameData,
29
- emptyStateTitle,
30
- emptyStateBody,
31
- permissions,
32
- primaryButton,
33
- shouldRefetch,
34
- ...rest
35
- }) => {
36
- const { loading, error, data, refetch } = fetchFn(rest);
37
-
38
- useEffect(() => {
39
- if (shouldRefetch) {
40
- refetch();
41
- }
42
- }, [shouldRefetch, refetch]);
43
-
44
- if (loading) {
45
- return <Loading />;
46
- }
47
-
48
- if (error) {
49
- return (
50
- <EmptyState
51
- error={error}
52
- title={errorStateTitle}
53
- body={error.message}
54
- />
55
- );
56
- }
57
-
58
- const check = permissionCheck(data.currentUser, permissions);
59
-
60
- if (!check.allowed) {
61
- return (
62
- <EmptyState
63
- lock
64
- title={__('Permission denied')}
65
- body={permissionDeniedMsg(check.permissions.map(item => item.name))}
66
- />
67
- );
68
- }
69
-
70
- const result = pluckData(data, resultPath);
71
-
72
- if ((Array.isArray(result) && result.length === 0) || !result) {
73
- return (
74
- <EmptyState
75
- title={emptyStateTitle}
76
- body={emptyStateBody}
77
- primaryButton={primaryButton}
78
- />
79
- );
80
- }
81
-
82
- return <Component {...rest} {...renameData(data)} />;
83
- };
84
-
85
- Subcomponent.propTypes = {
86
- fetchFn: PropTypes.func.isRequired,
87
- resultPath: PropTypes.string.isRequired,
88
- renameData: PropTypes.func,
89
- emptyStateTitle: PropTypes.string.isRequired,
90
- emptyStateBody: PropTypes.string,
91
- permissions: PropTypes.array,
92
- primaryButton: PropTypes.node,
93
- shouldRefetch: PropTypes.bool,
94
- };
95
-
96
- Subcomponent.defaultProps = {
97
- renameData: data => data,
98
- permissions: [],
99
- primaryButton: null,
100
- shouldRefetch: false,
101
- emptyStateBody: '',
102
- };
103
-
104
- return Subcomponent;
105
- };
106
-
107
- export default withLoading;
@@ -1 +0,0 @@
1
- export const last = array => array[array.length - 1];
@@ -1,15 +0,0 @@
1
- import { last } from './commonHelper';
2
-
3
- const idSeparator = '-';
4
- const versionSeparator = ':';
5
- const defaultVersion = '01';
6
-
7
- export const decodeModelId = model => decodeId(model.id);
8
-
9
- export const decodeId = globalId => {
10
- const split = atob(globalId).split(idSeparator);
11
- return parseInt(last(split), 10);
12
- };
13
-
14
- export const encodeId = (typename, id) =>
15
- btoa([defaultVersion, versionSeparator, typename, idSeparator, id].join(''));
@@ -1,68 +0,0 @@
1
- import { useMutation } from '@apollo/client';
2
- import { translate as __, sprintf } from 'foremanReact/common/I18n';
3
-
4
- import { useCurrentPagination, pageToVars } from './pageParamsHelper';
5
-
6
- const formatError = (error, name) =>
7
- sprintf(__('There was a following error when deleting %(name)s: %(error)s'), {
8
- name,
9
- error,
10
- });
11
-
12
- const joinErrors = errors => errors.map(err => err.message).join(', ');
13
-
14
- const onError = (showToast, resourceName) => error => {
15
- showToast({ type: 'error', message: formatError(error, resourceName) });
16
- };
17
-
18
- const onCompleted = (
19
- toggleModal,
20
- showToast,
21
- mutationName,
22
- successMsg,
23
- resourceName
24
- ) => data => {
25
- toggleModal();
26
- const { errors } = data[mutationName];
27
- if (Array.isArray(errors) && errors.length > 0) {
28
- showToast({
29
- type: 'error',
30
- message: formatError(joinErrors(errors), resourceName),
31
- });
32
- } else {
33
- showToast({
34
- type: 'success',
35
- message: successMsg,
36
- });
37
- }
38
- };
39
-
40
- export const prepareMutation = (
41
- history,
42
- showToast,
43
- refetchQuery,
44
- mutationName,
45
- successMsg,
46
- mutation,
47
- resourceName
48
- ) => toggleModal => {
49
- const pagination = pageToVars(useCurrentPagination(history));
50
-
51
- const options = {
52
- refetchQueries: [{ query: refetchQuery, variables: pagination }],
53
- onCompleted: onCompleted(
54
- toggleModal,
55
- showToast,
56
- mutationName,
57
- successMsg,
58
- resourceName
59
- ),
60
- onError: onError(showToast, resourceName),
61
- };
62
-
63
- return useMutation(mutation, options);
64
- };
65
-
66
- export const submitDelete = (mutation, id) => {
67
- mutation({ variables: { id } });
68
- };
@@ -1,31 +0,0 @@
1
- import URI from 'urijs';
2
- import { useForemanSettings } from 'foremanReact/Root/Context/ForemanContext';
3
-
4
- const parsePageParams = history => URI.parseQuery(history.location.search);
5
-
6
- export const addSearch = (basePath, params) => {
7
- let stringyfied = '';
8
- if (Object.keys(params).length > 0) {
9
- stringyfied = `?${URI.buildQuery(params)}`;
10
- }
11
-
12
- return `${basePath}${stringyfied}`;
13
- };
14
-
15
- export const useCurrentPagination = history => {
16
- const pageParams = parsePageParams(history);
17
- const uiSettings = useForemanSettings();
18
-
19
- return {
20
- page: parseInt(pageParams.page, 10) || 1,
21
- perPage: parseInt(pageParams.perPage, 10) || uiSettings.perPage,
22
- };
23
- };
24
-
25
- export const pageToVars = pagination => ({
26
- first: pagination.page * pagination.perPage,
27
- last: pagination.perPage,
28
- });
29
-
30
- export const useParamsToVars = history =>
31
- pageToVars(useCurrentPagination(history));
@@ -1,42 +0,0 @@
1
- import { translate as __, sprintf } from 'foremanReact/common/I18n';
2
-
3
- export const permissionCheck = (user, permissionsRequired) => {
4
- if (permissionsRequired.length === 0) {
5
- return { allowed: true };
6
- }
7
-
8
- if (!user) {
9
- throw new Error(
10
- 'No user data when loading the page - cannot determine if current user is allowed to view the page.'
11
- );
12
- }
13
-
14
- if (user.admin) {
15
- return { allowed: true };
16
- }
17
-
18
- const permList = permissionsRequired.reduce((memo, item) => {
19
- const found = user.permissions.nodes.find(
20
- permission => permission.name === item
21
- );
22
- memo.push({ name: item, present: !!found });
23
- return memo;
24
- }, []);
25
-
26
- if (permList.reduce((memo, item) => memo && item.present, true)) {
27
- return { allowed: true, permissions: permList };
28
- }
29
-
30
- return { allowed: false, permissions: permList };
31
- };
32
-
33
- export const permissionDeniedMsg = permissions => {
34
- let msg = __('You are not authorized to view the page. ');
35
- if (permissions?.length > 0) {
36
- msg += sprintf(
37
- __('Request the following permissions from administrator: %s.'),
38
- permissions.join(', ')
39
- );
40
- }
41
- return msg;
42
- };
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { Link } from 'react-router-dom';
3
- import { TableText } from '@patternfly/react-table';
4
-
5
- export const linkCell = (path, text) => (
6
- <TableText>
7
- <Link to={path}>{text}</Link>
8
- </TableText>
9
- );
@@ -1,3 +0,0 @@
1
- import { addToast } from 'foremanReact/components/ToastsList';
2
-
3
- export const showToast = dispatch => toast => dispatch(addToast(toast));
@@ -1,127 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { Provider } from 'react-redux';
3
- import store from 'foremanReact/redux';
4
- import { MockedProvider } from '@apollo/react-testing';
5
- import { MemoryRouter } from 'react-router-dom';
6
- import { getForemanContext } from 'foremanReact/Root/Context/ForemanContext';
7
- import { waitFor } from '@testing-library/react';
8
-
9
- export const withRedux = Component => props => (
10
- <Provider store={store}>
11
- <Component {...props} />
12
- </Provider>
13
- );
14
-
15
- export const withRouter = Component => props => (
16
- <MemoryRouter>
17
- <Component {...props} />
18
- </MemoryRouter>
19
- );
20
-
21
- export const withMockedProvider = Component => props => {
22
- // eslint-disable-next-line react/prop-types
23
- const { mocks, ...rest } = props;
24
-
25
- const [context, setContext] = useState({
26
- metadata: {
27
- UISettings: {
28
- perPage: 20,
29
- },
30
- },
31
- });
32
-
33
- const contextData = { context, setContext };
34
- const ForemanContext = getForemanContext(contextData);
35
- return (
36
- <ForemanContext.Provider value={contextData}>
37
- <MockedProvider mocks={mocks}>
38
- <Component {...rest} />
39
- </MockedProvider>
40
- </ForemanContext.Provider>
41
- );
42
- };
43
-
44
- // use to resolve async mock requests for apollo MockedProvider
45
- export const tick = () => new Promise(resolve => setTimeout(resolve, 0));
46
-
47
- export const wait = async (tickCount = 1) => {
48
- for (let i = 1; i < tickCount; i++) {
49
- // eslint-disable-next-line no-await-in-loop
50
- await waitFor(tick);
51
- }
52
- return waitFor(tick);
53
- };
54
-
55
- export const historyMock = {
56
- location: {
57
- search: '',
58
- },
59
- };
60
-
61
- export const admin = {
62
- __typename: 'User',
63
- id: 'MDE6VXNlci00',
64
- login: 'admin',
65
- admin: true,
66
- permissions: {
67
- nodes: [],
68
- },
69
- };
70
-
71
- export const userFactory = (login, permissions = []) => ({
72
- __typename: 'User',
73
- id: 'MDE6VXNlci01',
74
- login,
75
- admin: false,
76
- permissions: {
77
- nodes: permissions,
78
- },
79
- });
80
-
81
- export const intruder = userFactory('intruder', [
82
- {
83
- __typename: 'Permission',
84
- id: 'MDE6UGVybWlzc2lvbi0x',
85
- name: 'view_architectures',
86
- },
87
- ]);
88
-
89
- export const viewer = userFactory('viewer', [
90
- {
91
- __typename: 'Permission',
92
- id: 'MDE6UGVybWlzc2lvbi0yOTY=',
93
- name: 'view_oval_contents',
94
- },
95
- {
96
- __typename: 'Permission',
97
- id: 'MDE6UGVybWlzc2lvbi0yNzU=',
98
- name: 'view_oval_policies',
99
- },
100
- ]);
101
-
102
- export const mockFactory = (resultName, query) => (
103
- variables,
104
- modelResults,
105
- { errors = [], currentUser = null } = {}
106
- ) => {
107
- const mock = {
108
- request: {
109
- query,
110
- variables,
111
- },
112
- result: {
113
- data: {
114
- [resultName]: modelResults,
115
- },
116
- },
117
- };
118
-
119
- if (errors.length !== 0) {
120
- mock.result.errors = errors;
121
- }
122
-
123
- if (currentUser) {
124
- mock.result.data.currentUser = currentUser;
125
- }
126
- return [mock];
127
- };