foreman_puppet 3.0.7 → 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/lib/foreman_puppet/engine.rb +1 -0
  4. data/lib/foreman_puppet/register.rb +2 -2
  5. data/lib/foreman_puppet/version.rb +1 -1
  6. data/package.json +7 -7
  7. data/test/controllers/foreman_puppet/api/v2/override_values_controller_test.rb +6 -2
  8. data/test/models/foreman_puppet/host_test.rb +6 -0
  9. data/webpack/global_index.js +11 -0
  10. data/webpack/index.js +0 -7
  11. data/webpack/legacy.js +31 -0
  12. data/webpack/src/Extends/Fills/index.js +26 -0
  13. data/webpack/src/Extends/Host/PuppetTab/Routes.js +46 -0
  14. data/webpack/src/Extends/Host/PuppetTab/SubTabs/ENCPreview/ENCTab.js +61 -0
  15. data/webpack/src/Extends/Host/PuppetTab/SubTabs/ENCPreview/index.js +56 -0
  16. data/webpack/src/Extends/Host/PuppetTab/SubTabs/EmptyPage.js +20 -0
  17. data/webpack/src/Extends/Host/PuppetTab/SubTabs/Reports/components/DescriptionCard.js +88 -0
  18. data/webpack/src/Extends/Host/PuppetTab/SubTabs/Reports/index.js +50 -0
  19. data/webpack/src/Extends/Host/PuppetTab/SubTabs/Reports/styles.scss +7 -0
  20. data/webpack/src/Extends/Host/PuppetTab/constants.js +8 -0
  21. data/webpack/src/Extends/Host/PuppetTab/helpers.js +3 -0
  22. data/webpack/src/Extends/Host/PuppetTab/index.js +51 -0
  23. metadata +62 -88
  24. data/locale/ca/foreman_puppet.edit.po +0 -1221
  25. data/locale/ca/foreman_puppet.po.time_stamp +0 -0
  26. data/locale/cs_CZ/foreman_puppet.edit.po +0 -1208
  27. data/locale/cs_CZ/foreman_puppet.po.time_stamp +0 -0
  28. data/locale/de/foreman_puppet.edit.po +0 -1300
  29. data/locale/de/foreman_puppet.po.time_stamp +0 -0
  30. data/locale/en/foreman_puppet.edit.po +0 -998
  31. data/locale/en/foreman_puppet.po.time_stamp +0 -0
  32. data/locale/en/foreman_puppet.pox +0 -0
  33. data/locale/en_GB/foreman_puppet.edit.po +0 -1197
  34. data/locale/en_GB/foreman_puppet.po.time_stamp +0 -0
  35. data/locale/es/foreman_puppet.edit.po +0 -1275
  36. data/locale/es/foreman_puppet.po.time_stamp +0 -0
  37. data/locale/fr/foreman_puppet.edit.po +0 -1290
  38. data/locale/fr/foreman_puppet.po.time_stamp +0 -0
  39. data/locale/gl/foreman_puppet.edit.po +0 -1203
  40. data/locale/gl/foreman_puppet.po.time_stamp +0 -0
  41. data/locale/it/foreman_puppet.edit.po +0 -1233
  42. data/locale/it/foreman_puppet.po.time_stamp +0 -0
  43. data/locale/ja/foreman_puppet.edit.po +0 -1223
  44. data/locale/ja/foreman_puppet.po.time_stamp +0 -0
  45. data/locale/ko/foreman_puppet.edit.po +0 -1197
  46. data/locale/ko/foreman_puppet.po.time_stamp +0 -0
  47. data/locale/messages.mo +0 -0
  48. data/locale/nl_NL/foreman_puppet.edit.po +0 -1228
  49. data/locale/nl_NL/foreman_puppet.po.time_stamp +0 -0
  50. data/locale/pl/foreman_puppet.edit.po +0 -1238
  51. data/locale/pl/foreman_puppet.po.time_stamp +0 -0
  52. data/locale/pt_BR/foreman_puppet.edit.po +0 -1281
  53. data/locale/pt_BR/foreman_puppet.po.time_stamp +0 -0
  54. data/locale/ru/foreman_puppet.edit.po +0 -1240
  55. data/locale/ru/foreman_puppet.po.time_stamp +0 -0
  56. data/locale/sv_SE/foreman_puppet.edit.po +0 -1205
  57. data/locale/sv_SE/foreman_puppet.po.time_stamp +0 -0
  58. data/locale/zh_CN/foreman_puppet.edit.po +0 -1212
  59. data/locale/zh_CN/foreman_puppet.po.time_stamp +0 -0
  60. data/locale/zh_TW/foreman_puppet.edit.po +0 -1197
  61. data/locale/zh_TW/foreman_puppet.po.time_stamp +0 -0
  62. data/webpack/fills_index.js +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 772e941b4202bbfdde858905799bfeea60fa6709ba5e473041b514f8a90697a8
4
- data.tar.gz: 967448785c3adaddf2987365df7f990794d5c354160d78feb4e546472399bca4
3
+ metadata.gz: ad4345e5b4481b1263e0d9a6af568f6d899288fb6e25843dbc0bb5cabf86b5b9
4
+ data.tar.gz: 61e41f2886a32d9b73b42513b69d1eb5f0ba28b3151a68c0be21a14b62ca039f
5
5
  SHA512:
6
- metadata.gz: 742a59e022663c55a15838049c8eaf5827180a0abcfa8989759a409c40b3bf59f912e8deeaf5ebd730dbb16787698968e0ed71879d9183c2f14c99a7780e648a
7
- data.tar.gz: 4c32122d44b7cf75abdcfa1119c9cda80771b43511fa575bb8f155015ee5b191f3d1f8420072a32e749487da777bd719ca301bbc794e65d50af8edddf90f00ce
6
+ metadata.gz: ae6266081bbf344be643d88bbd57dfa2a8028f897dee6df45d6e08d5c7bddc451cae45b49759c484d8561a84fd8d96b35636fc5aa4165df49193e5b17d65edc8
7
+ data.tar.gz: 829314db4098020a1471276f94f6f1e8bc3421f7f3c1af3d5d08228f4ac811e999c5ce48bade42871a86775f9e630f40e991044a4411a07fb343a9ed8f9a2811
data/README.md CHANGED
@@ -37,6 +37,7 @@ You can install it on Foreman 2.5 to prepare for the Foreman update.
37
37
 
38
38
  |Foreman version|Plugin version|Notes |
39
39
  |---------------|--------------|------------------------------------------|
40
+ | >= 3.3 | ~> 4.0 | Required |
40
41
  | >= 3.2 | ~> 3.0 | Required |
41
42
  | ~> 3.1 | ~> 2.0 | Required |
42
43
  | ~> 3.0 | ~> 1.0 | Required |
@@ -78,7 +79,7 @@ Fork and send a Pull Request. Thanks!
78
79
 
79
80
  ## Copyright
80
81
 
81
- Copyright (c) *2021* *The Foreman developers*
82
+ Copyright (c) *2022* *The Foreman developers*
82
83
 
83
84
  This program is free software: you can redistribute it and/or modify
84
85
  it under the terms of the GNU General Public License as published by
@@ -58,6 +58,7 @@ module ForemanPuppet
58
58
  ::Api::V2::TemplateCombinationsController.include ForemanPuppet::Extensions::ApiTemplateCombinationsController
59
59
  ::Api::V2::HostsController.include ForemanPuppet::Extensions::ParametersHost
60
60
  ::Api::V2::HostgroupsController.include ForemanPuppet::Extensions::ParametersHostgroup
61
+ ::ComputeResourcesVmsController.helper ForemanPuppet::HostsAndHostgroupsHelper
61
62
  ::OperatingsystemsController.prepend ForemanPuppet::Extensions::OperatingsystemsController
62
63
  ::HostsController.include ForemanPuppet::Extensions::HostsControllerExtensions
63
64
  ::HostsController.include ForemanPuppet::Extensions::ParametersHost
@@ -1,7 +1,7 @@
1
1
  Foreman::Plugin.register :foreman_puppet do
2
- requires_foreman '>= 3.0.0'
2
+ requires_foreman '>= 3.3.0'
3
3
  # Add Global JS file for extending foreman-core components and routes
4
- register_global_js_file 'fills'
4
+ register_global_js_file 'global'
5
5
 
6
6
  settings do
7
7
  category(:facts, N_('Facts')) do
@@ -1,3 +1,3 @@
1
1
  module ForemanPuppet
2
- VERSION = '3.0.7'.freeze
2
+ VERSION = '4.0.2'.freeze
3
3
  end
data/package.json CHANGED
@@ -21,17 +21,17 @@
21
21
  "url": "http://projects.theforeman.org/projects/foreman_puppet/issues"
22
22
  },
23
23
  "peerDependencies": {
24
- "@theforeman/vendor": "^8.15.0"
24
+ "@theforeman/vendor": "^10.1.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@babel/core": "^7.7.0",
28
28
  "@sheerun/mutationobserver-shim": "^0.3.3",
29
- "@theforeman/builder": "^8.15.0",
30
- "@theforeman/eslint-plugin-foreman": "^8.15.0",
31
- "@theforeman/find-foreman": "^8.15.0",
32
- "@theforeman/stories": "^8.15.0",
33
- "@theforeman/test": "^8.15.0",
34
- "@theforeman/vendor-dev": "^8.15.0",
29
+ "@theforeman/builder": "^10.1.0",
30
+ "@theforeman/eslint-plugin-foreman": "^10.1.0",
31
+ "@theforeman/find-foreman": "^10.1.0",
32
+ "@theforeman/stories": "^10.1.0",
33
+ "@theforeman/test": "^10.1.0",
34
+ "@theforeman/vendor-dev": "^10.1.0",
35
35
  "babel-eslint": "^10.0.3",
36
36
  "eslint": "^6.7.2",
37
37
  "jed": "^1.1.1",
@@ -75,8 +75,12 @@ module ForemanPuppet
75
75
  post :create, params: { smart_class_parameter_id: lookup_key.id, override_value: override_value }
76
76
  end
77
77
  response = ActiveSupport::JSON.decode(@response.body)
78
- param_not_posted = (override_value.keys.first.to_s == 'match') ? 'Value' : 'Match' # The opposite of override_value is missing
79
- assert_match(/Validation failed: #{param_not_posted} can't be blank/, response['error']['message'])
78
+ if override_value.keys.first.to_s == 'match'
79
+ # The opposite of override_value is missing and should fail
80
+ assert_match(/Validation failed: Value can't be blank/, response['error']['message'])
81
+ else # match is missing
82
+ assert_match(/Failed to save the record/, response['error']['message'])
83
+ end
80
84
  assert_response :error
81
85
  end
82
86
  end
@@ -110,6 +110,12 @@ module ForemanPuppet
110
110
  end
111
111
 
112
112
  describe '#info puppet bits' do
113
+ test 'ENC YAML omits environment if no puppet facet' do
114
+ host = FactoryBot.build_stubbed(:host)
115
+ enc = host.info
116
+ assert_not_includes enc.keys, 'environment'
117
+ end
118
+
113
119
  test 'ENC YAML uses Classification::ClassParam for parameterized output' do
114
120
  skip 'No idea whats wrong here'
115
121
  host = FactoryBot.build_stubbed(:host, :with_environment)
@@ -0,0 +1,11 @@
1
+ import { registerReducer } from 'foremanReact/common/MountingService';
2
+ import reducers from './src/reducers';
3
+ import { registerFills } from './src/Extends/Fills';
4
+ import { registerLegacy } from './legacy';
5
+
6
+ // register reducers
7
+ registerReducer('puppet', reducers);
8
+ // add fills
9
+ registerFills();
10
+ // TODO: the checkForUnavailablePuppetclasses is very nasty
11
+ registerLegacy();
data/webpack/index.js CHANGED
@@ -2,16 +2,9 @@
2
2
  /* eslint-disable import/no-extraneous-dependencies */
3
3
  /* eslint-disable import/extensions */
4
4
  import componentRegistry from 'foremanReact/components/componentRegistry';
5
- import { registerReducer } from 'foremanReact/common/MountingService';
6
- import reducers from './src/reducers';
7
5
  import ForemanPuppet from './src/ForemanPuppet';
8
6
  import { WelcomeEnv } from './src/Components/Environments/Welcome';
9
7
 
10
- // register reducers
11
- Object.entries(reducers).forEach(([key, reducer]) =>
12
- registerReducer(key, reducer)
13
- );
14
-
15
8
  // register components for erb mounting
16
9
  componentRegistry.register({ name: 'WelcomeEnv', type: WelcomeEnv });
17
10
  componentRegistry.register({ name: 'ForemanPuppet', type: ForemanPuppet });
data/webpack/legacy.js ADDED
@@ -0,0 +1,31 @@
1
+ import $ from 'jquery';
2
+ import * as classEditor from './src/foreman_class_edit';
3
+ import * as hostForm from './src/foreman_puppet_host_form';
4
+
5
+ export const registerLegacy = () => {
6
+ window.tfm = Object.assign(window.tfm || {}, {
7
+ classEditor,
8
+ puppetEnc: {
9
+ hostForm,
10
+ },
11
+ });
12
+
13
+ // TODO: the checkForUnavailablePuppetclasses is very nasty
14
+ $(document)
15
+ .on('change', '.hostgroup-select', evt => {
16
+ const form = $('form.host-form')[0];
17
+ if (form && form.dataset.id) hostForm.updatePuppetclasses(evt.target);
18
+ })
19
+ .on('change', '.interface_domain', evt => {
20
+ hostForm.reloadPuppetclassParams();
21
+ })
22
+ .on('change', '.host-architecture-os-select', evt => {
23
+ hostForm.reloadPuppetclassParams();
24
+ })
25
+ .on('ContentLoad', evt => {
26
+ hostForm.checkForUnavailablePuppetclasses();
27
+ });
28
+ $(window).on('load', evt => {
29
+ hostForm.checkForUnavailablePuppetclasses();
30
+ });
31
+ };
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { translate as __ } from 'foremanReact/common/I18n';
3
+ import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
4
+ import PuppetTab from '../Host/PuppetTab';
5
+
6
+ const fills = [
7
+ {
8
+ slot: 'host-details-page-tabs',
9
+ name: 'Puppet',
10
+ component: props => <PuppetTab {...props} />,
11
+ weight: 500,
12
+ metadata: { title: __('Puppet') },
13
+ },
14
+ ];
15
+
16
+ export const registerFills = () => {
17
+ fills.forEach(({ slot, name, component: Component, weight, metadata }) =>
18
+ addGlobalFill(
19
+ slot,
20
+ name,
21
+ <Component key={`puppet-fill-${name}`} />,
22
+ weight,
23
+ metadata
24
+ )
25
+ );
26
+ };
@@ -0,0 +1,46 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+ import { Route, Switch, Redirect } from 'react-router-dom';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+ import { route } from './helpers';
6
+ import EmptyPage from './SubTabs/EmptyPage';
7
+ import Reports from './SubTabs/Reports';
8
+ import ENCPreview from './SubTabs/ENCPreview';
9
+
10
+ const SecondaryTabRoutes = ({ hostName, hostInfo, status }) => (
11
+ <Switch>
12
+ <Route path={route('reports')}>
13
+ <Reports hostName={hostName} hostInfo={hostInfo} status={status} />
14
+ </Route>
15
+ <Route path={route('assigned')}>
16
+ <EmptyPage
17
+ header={__('Assigned classes')}
18
+ description={__('This tab is still a work in progress')}
19
+ />
20
+ </Route>
21
+ <Route path={route('smart-classes')}>
22
+ <EmptyPage
23
+ header={__('Smart class parameters')}
24
+ description={__('This tab is still a work in progress')}
25
+ />
26
+ </Route>
27
+ <Route path={route('yaml')}>
28
+ <ENCPreview hostName={hostName} />
29
+ </Route>
30
+ <Redirect to={route('reports')} />
31
+ </Switch>
32
+ );
33
+
34
+ SecondaryTabRoutes.propTypes = {
35
+ hostName: PropTypes.string,
36
+ hostInfo: PropTypes.object,
37
+ status: PropTypes.string,
38
+ };
39
+
40
+ SecondaryTabRoutes.defaultProps = {
41
+ hostName: '',
42
+ hostInfo: {},
43
+ status: undefined,
44
+ };
45
+
46
+ export default SecondaryTabRoutes;
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import {
4
+ CodeBlock,
5
+ CodeBlockAction,
6
+ CodeBlockCode,
7
+ ClipboardCopyButton,
8
+ } from '@patternfly/react-core';
9
+
10
+ export const ENCTab = ({ encData }) => {
11
+ const [copied, setCopied] = React.useState(false);
12
+
13
+ const code = `${encData}`;
14
+
15
+ const clipboardCopyFunc = (event, text) => {
16
+ const clipboard = event.currentTarget.parentElement;
17
+ const el = document.createElement('textarea');
18
+ el.value = text.toString();
19
+ clipboard.appendChild(el);
20
+ el.select();
21
+ document.execCommand('copy');
22
+ clipboard.removeChild(el);
23
+ };
24
+
25
+ const onClick = (event, text) => {
26
+ clipboardCopyFunc(event, text);
27
+ setCopied(true);
28
+ };
29
+
30
+ const actions = (
31
+ <CodeBlockAction>
32
+ <ClipboardCopyButton
33
+ id="copy-button"
34
+ textId="code-content"
35
+ aria-label="Copy to clipboard"
36
+ onClick={e => onClick(e, code)}
37
+ exitDelay={600}
38
+ maxWidth="110px"
39
+ variant="plain"
40
+ >
41
+ {copied ? 'Successfully copied to clipboard!' : 'Copy to clipboard'}
42
+ </ClipboardCopyButton>
43
+ </CodeBlockAction>
44
+ );
45
+
46
+ return (
47
+ <CodeBlock actions={actions}>
48
+ <CodeBlockCode id="code-content">{code}</CodeBlockCode>
49
+ </CodeBlock>
50
+ );
51
+ };
52
+
53
+ ENCTab.propTypes = {
54
+ encData: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
55
+ };
56
+
57
+ ENCTab.defaultProps = {
58
+ encData: undefined,
59
+ };
60
+
61
+ export default ENCTab;
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
3
+ import PropTypes from 'prop-types';
4
+
5
+ import Skeleton from 'react-loading-skeleton';
6
+ import EmptyState from 'foremanReact/components/common/EmptyState/EmptyStatePattern';
7
+ import { STATUS } from 'foremanReact/constants';
8
+ import { EmptyStateIcon } from '@patternfly/react-core';
9
+ import { ExclamationCircleIcon } from '@patternfly/react-icons';
10
+ import { global_danger_color_200 as dangerColor } from '@patternfly/react-tokens';
11
+ import { translate as __ } from 'foremanReact/common/I18n';
12
+ import { ENCTab } from './ENCTab';
13
+
14
+ const ENCPreview = ({ hostName }) => {
15
+ const options = {
16
+ params: { name: hostName, format: 'yml' },
17
+ key: 'PUPPET_ENC_PREVIEW',
18
+ };
19
+ const url = `${window.location.origin.toString()}/foreman_puppet/hosts/${hostName}/externalNodes`;
20
+ const { response, status } = useAPI('get', url, options);
21
+
22
+ if (status === STATUS.PENDING) {
23
+ return <Skeleton count={5} />;
24
+ }
25
+
26
+ if (status === STATUS.ERROR || !hostName) {
27
+ const description = !hostName
28
+ ? __("Couldn't find any ENC data for this host")
29
+ : response?.response?.data?.message;
30
+ const icon = (
31
+ <EmptyStateIcon icon={ExclamationCircleIcon} color={dangerColor.value} />
32
+ );
33
+ return (
34
+ <EmptyState header={__('Error!')} icon={icon} description={description} />
35
+ );
36
+ }
37
+ if (response !== '' || response !== undefined) {
38
+ return (
39
+ <div className="enc-preview-tab" padding="16px 24px">
40
+ <ENCTab encData={response} />
41
+ </div>
42
+ );
43
+ }
44
+
45
+ return null;
46
+ };
47
+
48
+ ENCPreview.propTypes = {
49
+ hostName: PropTypes.string,
50
+ };
51
+
52
+ ENCPreview.defaultProps = {
53
+ hostName: undefined,
54
+ };
55
+
56
+ export default ENCPreview;
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import PFEmptyPage from 'foremanReact/components/common/EmptyState/EmptyStatePattern';
4
+
5
+ const EmptyPage = ({ header, description }) => (
6
+ <div className="host-details-tab-item">
7
+ <PFEmptyPage icon="enterprise" header={header} description={description} />
8
+ </div>
9
+ );
10
+
11
+ EmptyPage.propTypes = {
12
+ header: PropTypes.string.isRequired,
13
+ description: PropTypes.string,
14
+ };
15
+
16
+ EmptyPage.defaultProps = {
17
+ description: null,
18
+ };
19
+
20
+ export default EmptyPage;
@@ -0,0 +1,88 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+ import CardTemplate from 'foremanReact/components/HostDetails/Templates/CardItem/CardTemplate';
4
+ import {
5
+ DescriptionList,
6
+ DescriptionListTerm,
7
+ DescriptionListGroup,
8
+ DescriptionListDescription,
9
+ } from '@patternfly/react-core';
10
+ import SkeletonLoader from 'foremanReact/components/common/SkeletonLoader';
11
+ import DefaultLoaderEmptyState from 'foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState';
12
+ import { STATUS } from 'foremanReact/constants';
13
+ import { translate as __ } from 'foremanReact/common/I18n';
14
+
15
+ const DescriptionCard = ({
16
+ proxyName,
17
+ caProxy,
18
+ proxyId,
19
+ caProxyId,
20
+ env,
21
+ status,
22
+ }) => (
23
+ <CardTemplate header={__('Puppet details')} expandable>
24
+ <DescriptionList isCompact>
25
+ <DescriptionListGroup>
26
+ <DescriptionListTerm>{__('Puppet environment')}</DescriptionListTerm>
27
+ <DescriptionListDescription>
28
+ <SkeletonLoader
29
+ emptyState={<DefaultLoaderEmptyState />}
30
+ status={status}
31
+ >
32
+ {env && (
33
+ <a href={`/foreman_puppet/environments/?search=name+%3D+${env}`}>
34
+ {env}
35
+ </a>
36
+ )}
37
+ </SkeletonLoader>
38
+ </DescriptionListDescription>
39
+ </DescriptionListGroup>
40
+ <DescriptionListGroup>
41
+ <DescriptionListTerm>{__('Puppet Smart Proxy')}</DescriptionListTerm>
42
+ <DescriptionListDescription>
43
+ <SkeletonLoader
44
+ emptyState={<DefaultLoaderEmptyState />}
45
+ status={status}
46
+ >
47
+ {proxyName && (
48
+ <a href={`/smart_proxies/${proxyId}#puppet`}>{proxyName}</a>
49
+ )}
50
+ </SkeletonLoader>
51
+ </DescriptionListDescription>
52
+ </DescriptionListGroup>
53
+ <DescriptionListGroup>
54
+ <DescriptionListTerm>{__('Puppet CA Smart Proxy')}</DescriptionListTerm>
55
+ <DescriptionListDescription>
56
+ <SkeletonLoader
57
+ emptyState={<DefaultLoaderEmptyState />}
58
+ status={status}
59
+ >
60
+ {caProxy && (
61
+ <a href={`/smart_proxies/${caProxyId}#puppet-ca`}>{caProxy}</a>
62
+ )}
63
+ </SkeletonLoader>
64
+ </DescriptionListDescription>
65
+ </DescriptionListGroup>
66
+ </DescriptionList>
67
+ </CardTemplate>
68
+ );
69
+
70
+ DescriptionCard.propTypes = {
71
+ caProxy: PropTypes.string,
72
+ caProxyId: PropTypes.number,
73
+ env: PropTypes.string,
74
+ proxyId: PropTypes.number,
75
+ proxyName: PropTypes.string,
76
+ status: PropTypes.string,
77
+ };
78
+
79
+ DescriptionCard.defaultProps = {
80
+ caProxy: undefined,
81
+ caProxyId: undefined,
82
+ env: undefined,
83
+ proxyId: undefined,
84
+ proxyName: undefined,
85
+ status: STATUS.PENDING,
86
+ };
87
+
88
+ export default DescriptionCard;
@@ -0,0 +1,50 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+ import { Grid, GridItem } from '@patternfly/react-core';
4
+ import ReportsTab from 'foremanReact/components/HostDetails/Tabs/ReportsTab';
5
+ import DescriptionCard from './components/DescriptionCard';
6
+ import './styles.scss';
7
+
8
+ const Reports = ({
9
+ hostName,
10
+ status,
11
+ hostInfo: {
12
+ puppet_proxy_name: proxyName,
13
+ puppet_ca_proxy_name: caProxy,
14
+ environment_name: env,
15
+ puppet_proxy_id: proxyId,
16
+ puppet_ca_proxy_id: caProxyId,
17
+ },
18
+ }) => (
19
+ <div className="report-tab">
20
+ <Grid hasGutter>
21
+ <GridItem span={4}>
22
+ <DescriptionCard
23
+ proxyName={proxyName}
24
+ caProxy={caProxy}
25
+ proxyId={proxyId}
26
+ caProxyId={caProxyId}
27
+ env={env}
28
+ status={status}
29
+ />
30
+ </GridItem>
31
+ <GridItem span={12}>
32
+ <ReportsTab hostName={hostName} origin="Puppet" />
33
+ </GridItem>
34
+ </Grid>
35
+ </div>
36
+ );
37
+
38
+ Reports.propTypes = {
39
+ hostName: PropTypes.string,
40
+ hostInfo: PropTypes.object,
41
+ status: PropTypes.string,
42
+ };
43
+
44
+ Reports.defaultProps = {
45
+ hostName: undefined,
46
+ hostInfo: {},
47
+ status: undefined,
48
+ };
49
+
50
+ export default Reports;
@@ -0,0 +1,7 @@
1
+ .report-tab {
2
+ padding: 16px 24px;
3
+
4
+ .pf-c-card {
5
+ height: 100%;
6
+ }
7
+ }
@@ -0,0 +1,8 @@
1
+ import { translate as __ } from 'foremanReact/common/I18n';
2
+
3
+ export const SECONDARY_TABS = [
4
+ { key: 'reports', title: __('Reports') },
5
+ { key: 'assigned', title: __('Assigned classes') },
6
+ { key: 'smart-classes', title: __('Smart class parameters') },
7
+ { key: 'yaml', title: __('ENC Preview') },
8
+ ];
@@ -0,0 +1,3 @@
1
+ export const hashRoute = subpath => `#/Puppet/${subpath}`;
2
+ export const route = subpath => hashRoute(subpath).substring(1);
3
+ export const activeTab = path => path.split('/')[2];
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useHistory } from 'react-router-dom';
4
+ import { Tabs, Tab, TabTitleText } from '@patternfly/react-core';
5
+ import { STATUS } from 'foremanReact/constants';
6
+
7
+ import SecondaryTabRoutes from './Routes';
8
+ import { activeTab } from './helpers';
9
+ import { SECONDARY_TABS } from './constants';
10
+
11
+ const PuppetTab = ({ response, status, location: { pathname } }) => {
12
+ const hashHistory = useHistory();
13
+ return (
14
+ <>
15
+ <Tabs
16
+ className="margin-0-24"
17
+ onSelect={(evt, subTab) => hashHistory.push(subTab)}
18
+ isSecondary
19
+ activeKey={activeTab(pathname)}
20
+ >
21
+ {SECONDARY_TABS.map(({ key, title }) => (
22
+ <Tab
23
+ key={key}
24
+ eventKey={key}
25
+ title={<TabTitleText>{title}</TabTitleText>}
26
+ />
27
+ ))}
28
+ </Tabs>
29
+ <SecondaryTabRoutes
30
+ hostName={response.name}
31
+ hostInfo={response}
32
+ status={status}
33
+ />
34
+ </>
35
+ );
36
+ };
37
+
38
+ PuppetTab.propTypes = {
39
+ response: PropTypes.object,
40
+ status: PropTypes.string,
41
+ location: PropTypes.shape({
42
+ pathname: PropTypes.string,
43
+ }),
44
+ };
45
+ PuppetTab.defaultProps = {
46
+ location: { pathname: '' },
47
+ response: { name: '' },
48
+ status: STATUS.PENDING,
49
+ };
50
+
51
+ export default PuppetTab;