foreman_templates 7.0.1 → 7.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.babelrc +16 -0
  3. data/lib/foreman_templates/version.rb +1 -1
  4. data/package.json +68 -0
  5. data/webpack/ForemanTemplates.js +29 -0
  6. data/webpack/Routes.js +33 -0
  7. data/webpack/__mocks__/foremanReact/common/helpers.js +27 -0
  8. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
  9. data/webpack/__mocks__/foremanReact/components/common/forms/CommonForm.js +2 -0
  10. data/webpack/__mocks__/foremanReact/components/common/forms/Form.js +2 -0
  11. data/webpack/__mocks__/foremanReact/components/common/forms/TextField.js +2 -0
  12. data/webpack/__mocks__/foremanReact/redux/actions/common/forms.js +1 -0
  13. data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +2 -0
  14. data/webpack/__tests__/__snapshots__/helpers.test.js.snap +5 -0
  15. data/webpack/__tests__/helpers.test.js +17 -0
  16. data/webpack/components/NewTemplateSync/NewTemplateSync.js +60 -0
  17. data/webpack/components/NewTemplateSync/NewTemplateSync.scss +19 -0
  18. data/webpack/components/NewTemplateSync/NewTemplateSyncActions.js +39 -0
  19. data/webpack/components/NewTemplateSync/NewTemplateSyncReducer.js +34 -0
  20. data/webpack/components/NewTemplateSync/NewTemplateSyncSelectors.js +7 -0
  21. data/webpack/components/NewTemplateSync/__fixtures__/templateSyncSettings.fixtures.js +71 -0
  22. data/webpack/components/NewTemplateSync/__tests__/NewTemplateSync.test.js +31 -0
  23. data/webpack/components/NewTemplateSync/__tests__/NewTemplateSyncReducer.test.js +55 -0
  24. data/webpack/components/NewTemplateSync/__tests__/NewTemplateSyncSelectors.test.js +28 -0
  25. data/webpack/components/NewTemplateSync/__tests__/__snapshots__/NewTemplateSync.test.js.snap +53 -0
  26. data/webpack/components/NewTemplateSync/__tests__/__snapshots__/NewTemplateSyncReducer.test.js.snap +74 -0
  27. data/webpack/components/NewTemplateSync/__tests__/__snapshots__/NewTemplateSyncSelectors.test.js.snap +59 -0
  28. data/webpack/components/NewTemplateSync/components/ButtonTooltip.js +23 -0
  29. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncForm.js +145 -0
  30. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncFormConstants.js +1 -0
  31. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/NewTemplateSyncFormSelectors.js +24 -0
  32. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/NewTemplateSyncForm.test.js +42 -0
  33. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/NewTemplateSyncFormSelectors.test.js +37 -0
  34. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/__snapshots__/NewTemplateSyncForm.test.js.snap +176 -0
  35. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/__tests__/__snapshots__/NewTemplateSyncFormSelectors.test.js.snap +42 -0
  36. data/webpack/components/NewTemplateSync/components/NewTemplateSyncForm/index.js +44 -0
  37. data/webpack/components/NewTemplateSync/components/SyncSettingField.js +54 -0
  38. data/webpack/components/NewTemplateSync/components/SyncSettingFields.js +69 -0
  39. data/webpack/components/NewTemplateSync/components/SyncTypeRadios.js +52 -0
  40. data/webpack/components/NewTemplateSync/components/TextButtonField/BlankOption.js +19 -0
  41. data/webpack/components/NewTemplateSync/components/TextButtonField/CheckboxField.js +15 -0
  42. data/webpack/components/NewTemplateSync/components/TextButtonField/FieldType.js +46 -0
  43. data/webpack/components/NewTemplateSync/components/TextButtonField/InputField.js +14 -0
  44. data/webpack/components/NewTemplateSync/components/TextButtonField/RenderField.js +74 -0
  45. data/webpack/components/NewTemplateSync/components/TextButtonField/SelectField.js +24 -0
  46. data/webpack/components/NewTemplateSync/components/TextButtonField/index.js +69 -0
  47. data/webpack/components/NewTemplateSync/components/__tests__/SyncSettingField.test.js +34 -0
  48. data/webpack/components/NewTemplateSync/components/__tests__/SyncSettingFields.test.js +33 -0
  49. data/webpack/components/NewTemplateSync/components/__tests__/SyncTypeRadios.test.js +20 -0
  50. data/webpack/components/NewTemplateSync/components/__tests__/TextButtonField.test.js +65 -0
  51. data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/SyncSettingField.test.js.snap +131 -0
  52. data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/SyncSettingFields.test.js.snap +94 -0
  53. data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/SyncTypeRadios.test.js.snap +46 -0
  54. data/webpack/components/NewTemplateSync/components/__tests__/__snapshots__/TextButtonField.test.js.snap +112 -0
  55. data/webpack/components/NewTemplateSync/index.js +32 -0
  56. data/webpack/components/PageNotFound.js +13 -0
  57. data/webpack/components/PermissionDenied.js +33 -0
  58. data/webpack/components/TemplateSyncResult/TemplateSyncResult.js +61 -0
  59. data/webpack/components/TemplateSyncResult/TemplateSyncResult.scss +39 -0
  60. data/webpack/components/TemplateSyncResult/TemplateSyncResultActions.js +4 -0
  61. data/webpack/components/TemplateSyncResult/TemplateSyncResultHelpers.js +6 -0
  62. data/webpack/components/TemplateSyncResult/TemplateSyncResultReducer.js +33 -0
  63. data/webpack/components/TemplateSyncResult/TemplateSyncResultSelectors.js +1 -0
  64. data/webpack/components/TemplateSyncResult/__fixtures__/templateSyncResult.fixtures.js +86 -0
  65. data/webpack/components/TemplateSyncResult/__tests__/TemplateSyncResult.test.js +37 -0
  66. data/webpack/components/TemplateSyncResult/__tests__/TemplateSyncResultReducer.test.js +48 -0
  67. data/webpack/components/TemplateSyncResult/__tests__/__snapshots__/TemplateSyncResult.test.js.snap +112 -0
  68. data/webpack/components/TemplateSyncResult/__tests__/__snapshots__/TemplateSyncResultReducer.test.js.snap +88 -0
  69. data/webpack/components/TemplateSyncResult/components/EmptySyncResult.js +25 -0
  70. data/webpack/components/TemplateSyncResult/components/FinishedSyncResult.js +77 -0
  71. data/webpack/components/TemplateSyncResult/components/ListViewHeader.js +38 -0
  72. data/webpack/components/TemplateSyncResult/components/SyncResultList.js +41 -0
  73. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/EmptyInfoItem.js +16 -0
  74. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/IconInfoItem.js +21 -0
  75. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/InfoItem.js +34 -0
  76. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/LinkInfoItem.js +37 -0
  77. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/StringInfoItem.js +50 -0
  78. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/helpers.js +128 -0
  79. data/webpack/components/TemplateSyncResult/components/SyncedTemplate/index.js +33 -0
  80. data/webpack/components/TemplateSyncResult/components/__tests__/SyncResultList.test.js +27 -0
  81. data/webpack/components/TemplateSyncResult/components/__tests__/SyncedTemplate.test.js +30 -0
  82. data/webpack/components/TemplateSyncResult/components/__tests__/__snapshots__/SyncResultList.test.js.snap +102 -0
  83. data/webpack/components/TemplateSyncResult/components/__tests__/__snapshots__/SyncedTemplate.test.js.snap +548 -0
  84. data/webpack/components/TemplateSyncResult/index.js +13 -0
  85. data/webpack/consts.js +6 -0
  86. data/webpack/index.js +11 -0
  87. data/webpack/reducer.js +6 -0
  88. data/webpack/testSetup.js +11 -0
  89. data/webpack/withProtectedView.js +16 -0
  90. metadata +89 -2
@@ -0,0 +1,37 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import {
4
+ importTemplates,
5
+ exportTemplates,
6
+ } from '../__fixtures__/templateSyncResult.fixtures';
7
+ import TemplateSyncResult from '../TemplateSyncResult';
8
+
9
+ const fixtures = {
10
+ 'should render export result': {
11
+ syncResult: {
12
+ resultAction: 'export',
13
+ templates: exportTemplates,
14
+ repo: 'https://github.com/theforeman/community-templates.git',
15
+ branch: 'master',
16
+ gitUser: 'Admin',
17
+ },
18
+ history: {},
19
+ },
20
+ 'should render empty state when no templates synced': {
21
+ syncResult: {
22
+ templates: [],
23
+ },
24
+ history: {},
25
+ },
26
+ 'should render import result': {
27
+ syncResult: {
28
+ resultAction: 'import',
29
+ templates: importTemplates,
30
+ repo: '/home/vagrant/templates',
31
+ },
32
+ history: {},
33
+ },
34
+ };
35
+
36
+ describe('TemplateSyncResult', () =>
37
+ testComponentSnapshotsWithFixtures(TemplateSyncResult, fixtures));
@@ -0,0 +1,48 @@
1
+ import { testReducerSnapshotWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import reducer, { initialState } from '../TemplateSyncResultReducer';
4
+ import { importTemplates } from '../__fixtures__/templateSyncResult.fixtures';
5
+
6
+ import {
7
+ TEMPLATESYNC_FORM_SUBMITTED,
8
+ SYNC_RESULT_PAGINATION_CHANGE,
9
+ } from '../../../consts';
10
+
11
+ const fixtures = {
12
+ 'should return initial state': {
13
+ state: initialState,
14
+ action: {
15
+ type: undefined,
16
+ payload: {},
17
+ },
18
+ },
19
+ 'should set new pagination': {
20
+ state: initialState,
21
+ action: {
22
+ type: SYNC_RESULT_PAGINATION_CHANGE,
23
+ payload: {
24
+ pagination: {
25
+ page: 2,
26
+ perPage: 5,
27
+ },
28
+ },
29
+ },
30
+ },
31
+ 'should update state when form submitted': {
32
+ state: initialState,
33
+ action: {
34
+ type: TEMPLATESYNC_FORM_SUBMITTED,
35
+ payload: {
36
+ data: {
37
+ templates: importTemplates,
38
+ repo: 'https://github.com/theforeman/community-templates.git',
39
+ branch: 'master',
40
+ result_action: 'import',
41
+ },
42
+ },
43
+ },
44
+ },
45
+ };
46
+
47
+ describe('TemplateSyncResultReducer', () =>
48
+ testReducerSnapshotWithFixtures(reducer, fixtures));
@@ -0,0 +1,112 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`TemplateSyncResult should render empty state when no templates synced 1`] = `
4
+ <EmptySyncResult
5
+ primaryAction={[Function]}
6
+ />
7
+ `;
8
+
9
+ exports[`TemplateSyncResult should render export result 1`] = `
10
+ <FinishedSyncResult
11
+ branch="master"
12
+ editPaths={Object {}}
13
+ fileRepoStartWith={Array []}
14
+ gitUser="Admin"
15
+ pageChange={[Function]}
16
+ pagination={Object {}}
17
+ repo="https://github.com/theforeman/community-templates.git"
18
+ templates={
19
+ Array [
20
+ Object {
21
+ "additionalErrors": null,
22
+ "className": "JobTemplate",
23
+ "errors": Object {},
24
+ "humanizedClassName": "Job Template",
25
+ "locked": true,
26
+ "name": "random template",
27
+ "snippet": true,
28
+ "templateFile": "random_template.erb",
29
+ },
30
+ Object {
31
+ "additionalErrors": null,
32
+ "className": "Ptable",
33
+ "errors": Object {},
34
+ "humanizedClassName": "Ptable",
35
+ "locked": false,
36
+ "name": "CoreOS default",
37
+ "snippet": false,
38
+ "templateFile": "coreos_default.erb",
39
+ },
40
+ ]
41
+ }
42
+ type="export"
43
+ />
44
+ `;
45
+
46
+ exports[`TemplateSyncResult should render import result 1`] = `
47
+ <FinishedSyncResult
48
+ branch=""
49
+ editPaths={Object {}}
50
+ fileRepoStartWith={Array []}
51
+ gitUser=""
52
+ pageChange={[Function]}
53
+ pagination={Object {}}
54
+ repo="/home/vagrant/templates"
55
+ templates={
56
+ Array [
57
+ Object {
58
+ "additionalErrors": "No \\"name\\" found in metadata",
59
+ "errors": null,
60
+ "name": null,
61
+ "templateFile": "random_template.erb",
62
+ },
63
+ Object {
64
+ "additionalErrors": null,
65
+ "className": "ProvisioningTemplate",
66
+ "errors": Object {
67
+ "base": Array [
68
+ "This template is locked",
69
+ ],
70
+ },
71
+ "humanizedClassName": "Provisioning Template",
72
+ "kind": "Provision",
73
+ "locked": true,
74
+ "name": "EPEL",
75
+ "snippet": true,
76
+ "templateFile": "epel.erb",
77
+ },
78
+ Object {
79
+ "additionalErrors": null,
80
+ "className": "Ptable",
81
+ "errors": Object {},
82
+ "humanizedClassName": "Ptable",
83
+ "locked": false,
84
+ "name": "CoreOS default",
85
+ "snippet": false,
86
+ "templateFile": "coreos_default.erb",
87
+ },
88
+ Object {
89
+ "additionalErrors": "No \\"model\\" found in metadata",
90
+ "errors": null,
91
+ "name": null,
92
+ "templateFile": "no_model.erb",
93
+ },
94
+ Object {
95
+ "additionalErrors": null,
96
+ "className": "ProvisioningTemplate",
97
+ "errors": Object {
98
+ "name": Array [
99
+ "has already been taken",
100
+ ],
101
+ },
102
+ "humanizedClassName": "Provisioning Template",
103
+ "locked": true,
104
+ "name": "Kickstart fake",
105
+ "snippet": true,
106
+ "templateFile": "kickstart_fake.erb",
107
+ },
108
+ ]
109
+ }
110
+ type="import"
111
+ />
112
+ `;
@@ -0,0 +1,88 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`TemplateSyncResultReducer should return initial state 1`] = `
4
+ Object {
5
+ "pagination": Object {
6
+ "page": 1,
7
+ "perPage": 20,
8
+ },
9
+ "resultAction": "",
10
+ "templates": Array [],
11
+ }
12
+ `;
13
+
14
+ exports[`TemplateSyncResultReducer should set new pagination 1`] = `
15
+ Object {
16
+ "pagination": Object {
17
+ "page": 2,
18
+ "perPage": 5,
19
+ },
20
+ "resultAction": "",
21
+ "templates": Array [],
22
+ }
23
+ `;
24
+
25
+ exports[`TemplateSyncResultReducer should update state when form submitted 1`] = `
26
+ Object {
27
+ "branch": "master",
28
+ "pagination": Object {
29
+ "page": 1,
30
+ "perPage": 20,
31
+ },
32
+ "repo": "https://github.com/theforeman/community-templates.git",
33
+ "resultAction": "import",
34
+ "templates": Array [
35
+ Object {
36
+ "additionalErrors": "No \\"name\\" found in metadata",
37
+ "errors": null,
38
+ "name": null,
39
+ "templateFile": "random_template.erb",
40
+ },
41
+ Object {
42
+ "additionalErrors": null,
43
+ "className": "ProvisioningTemplate",
44
+ "errors": Object {
45
+ "base": Array [
46
+ "This template is locked",
47
+ ],
48
+ },
49
+ "humanizedClassName": "Provisioning Template",
50
+ "kind": "Provision",
51
+ "locked": true,
52
+ "name": "EPEL",
53
+ "snippet": true,
54
+ "templateFile": "epel.erb",
55
+ },
56
+ Object {
57
+ "additionalErrors": null,
58
+ "className": "Ptable",
59
+ "errors": Object {},
60
+ "humanizedClassName": "Ptable",
61
+ "locked": false,
62
+ "name": "CoreOS default",
63
+ "snippet": false,
64
+ "templateFile": "coreos_default.erb",
65
+ },
66
+ Object {
67
+ "additionalErrors": "No \\"model\\" found in metadata",
68
+ "errors": null,
69
+ "name": null,
70
+ "templateFile": "no_model.erb",
71
+ },
72
+ Object {
73
+ "additionalErrors": null,
74
+ "className": "ProvisioningTemplate",
75
+ "errors": Object {
76
+ "name": Array [
77
+ "has already been taken",
78
+ ],
79
+ },
80
+ "humanizedClassName": "Provisioning Template",
81
+ "locked": true,
82
+ "name": "Kickstart fake",
83
+ "snippet": true,
84
+ "templateFile": "kickstart_fake.erb",
85
+ },
86
+ ],
87
+ }
88
+ `;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { EmptyState, Button } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ const EmptySyncResult = ({ primaryAction }) => (
6
+ <EmptyState>
7
+ <EmptyState.Icon type="fa" name="refresh" />
8
+ <EmptyState.Title>No Template Sync Result</EmptyState.Title>
9
+ <EmptyState.Info>
10
+ To view results of a template sync, you must import/export the templates
11
+ first.
12
+ </EmptyState.Info>
13
+ <EmptyState.Action>
14
+ <Button bsStyle="primary" bsSize="large" onClick={primaryAction}>
15
+ Sync Templates
16
+ </Button>
17
+ </EmptyState.Action>
18
+ </EmptyState>
19
+ );
20
+
21
+ EmptySyncResult.propTypes = {
22
+ primaryAction: PropTypes.func.isRequired,
23
+ };
24
+
25
+ export default EmptySyncResult;
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { capitalize } from 'lodash';
4
+
5
+ import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
6
+ import { LinkContainer } from 'react-router-bootstrap';
7
+
8
+ import { Button } from 'patternfly-react';
9
+ import SyncResultList from './SyncResultList';
10
+
11
+ const titleString = (type, repo, branch, gitUser, fileRepoStartWith) => {
12
+ const prep = type === 'import' ? 'from' : 'to';
13
+ const isFileRepo = fileRepoStartWith.reduce(
14
+ (memo, item) => repo.startsWith(item) || memo,
15
+ false
16
+ );
17
+
18
+ const branchString = branch && !isFileRepo ? `and branch ${branch}` : '';
19
+ const userString = (gitUser && `as user ${gitUser}`) || '';
20
+
21
+ return `${capitalize(type)} ${prep} ${repo} ${branchString} ${userString}`;
22
+ };
23
+
24
+ const FinishedSyncResult = ({
25
+ templates,
26
+ type,
27
+ repo,
28
+ branch,
29
+ gitUser,
30
+ fileRepoStartWith,
31
+ pagination,
32
+ pageChange,
33
+ editPaths,
34
+ }) => (
35
+ <PageLayout
36
+ searchable={false}
37
+ header={titleString(type, repo, branch, gitUser, fileRepoStartWith)}
38
+ >
39
+ <div className="row">
40
+ <div className="title-filter col-md-4">&nbsp;</div>
41
+ <div id="title_action" className="col-md-8">
42
+ <div className="btn-toolbar pull-right">
43
+ <LinkContainer to="/template_syncs" activeClassName="">
44
+ <Button>{__('Back to sync form')}</Button>
45
+ </LinkContainer>
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ <SyncResultList
51
+ templates={templates}
52
+ pagination={pagination}
53
+ editPaths={editPaths}
54
+ pageChange={pageChange}
55
+ />
56
+ </PageLayout>
57
+ );
58
+
59
+ FinishedSyncResult.propTypes = {
60
+ templates: PropTypes.array.isRequired,
61
+ type: PropTypes.string.isRequired,
62
+ repo: PropTypes.string.isRequired,
63
+ branch: PropTypes.string,
64
+ gitUser: PropTypes.string,
65
+ pagination: PropTypes.object,
66
+ pageChange: PropTypes.func.isRequired,
67
+ editPaths: PropTypes.object.isRequired,
68
+ fileRepoStartWith: PropTypes.array.isRequired,
69
+ };
70
+
71
+ FinishedSyncResult.defaultProps = {
72
+ branch: '',
73
+ gitUser: '',
74
+ pagination: {},
75
+ };
76
+
77
+ export default FinishedSyncResult;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { ListView, Icon } from 'patternfly-react';
3
+ import classNames from 'classnames';
4
+
5
+ import InfoItem from './SyncedTemplate/InfoItem';
6
+
7
+ const ListViewHeader = props => {
8
+ const additionalInfo = [
9
+ 'Name',
10
+ 'Locked',
11
+ 'Snippet',
12
+ 'Template Class',
13
+ 'Kind',
14
+ 'File Name',
15
+ ].map((title, idx) => (
16
+ <InfoItem itemId={`${idx}`} key={idx}>
17
+ <strong>{title}</strong>
18
+ </InfoItem>
19
+ ));
20
+
21
+ // Use ListView.Item as a header to get a vertical alignment
22
+ return (
23
+ <ListView.Item
24
+ additionalInfo={additionalInfo}
25
+ className={classNames(
26
+ 'listViewItem--listItemVariants',
27
+ 'list-view-header'
28
+ )}
29
+ leftContent={<Icon name="ok" size="sm" type="pf" />}
30
+ hideCloseIcon
31
+ stacked
32
+ >
33
+ <span />
34
+ </ListView.Item>
35
+ );
36
+ };
37
+
38
+ export default ListViewHeader;
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { ListView } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ import Pagination from 'foremanReact/components/Pagination/PaginationWrapper';
6
+
7
+ import SyncedTemplate from './SyncedTemplate';
8
+ import { templatesPage } from '../TemplateSyncResultHelpers';
9
+ import ListViewHeader from './ListViewHeader';
10
+
11
+ const SyncResultList = ({ pagination, pageChange, templates, editPaths }) => (
12
+ <ListView>
13
+ <ListViewHeader />
14
+ {templatesPage(templates, pagination).map(template => (
15
+ <SyncedTemplate
16
+ template={template}
17
+ key={template.name}
18
+ editPath={editPaths[template.className]}
19
+ />
20
+ ))}
21
+ <Pagination
22
+ viewType="list"
23
+ itemCount={templates.length}
24
+ pagination={pagination}
25
+ onChange={pageChange}
26
+ dropdownButtonId="template-sync-result-dropdown"
27
+ />
28
+ </ListView>
29
+ );
30
+
31
+ SyncResultList.propTypes = {
32
+ pagination: PropTypes.shape({
33
+ page: PropTypes.number,
34
+ perPage: PropTypes.number,
35
+ }).isRequired,
36
+ pageChange: PropTypes.func.isRequired,
37
+ templates: PropTypes.array.isRequired,
38
+ editPaths: PropTypes.object.isRequired,
39
+ };
40
+
41
+ export default SyncResultList;
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import InfoItem from './InfoItem';
5
+ import { itemIteratorId } from './helpers';
6
+
7
+ const EmptyInfoItem = ({ template, attr }) => (
8
+ <InfoItem itemId={itemIteratorId(template, attr)} />
9
+ );
10
+
11
+ EmptyInfoItem.propTypes = {
12
+ template: PropTypes.object.isRequired,
13
+ attr: PropTypes.string.isRequired,
14
+ };
15
+
16
+ export default EmptyInfoItem;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { Icon } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ import InfoItem from './InfoItem';
6
+ import { itemIteratorId } from './helpers';
7
+
8
+ const IconInfoItem = ({ template, attr, iconName, tooltipText }) => (
9
+ <InfoItem itemId={itemIteratorId(template, attr)} tooltipText={tooltipText}>
10
+ <Icon type="fa" name={iconName} />
11
+ </InfoItem>
12
+ );
13
+
14
+ IconInfoItem.propTypes = {
15
+ template: PropTypes.object.isRequired,
16
+ attr: PropTypes.string.isRequired,
17
+ iconName: PropTypes.string.isRequired,
18
+ tooltipText: PropTypes.string.isRequired,
19
+ };
20
+
21
+ export default IconInfoItem;
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { ListView, OverlayTrigger, Tooltip } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ const InfoItem = ({ itemId, children, tooltipText }) => {
6
+ const overlay = (
7
+ <OverlayTrigger
8
+ overlay={tooltipText ? <Tooltip id={itemId}>{tooltipText}</Tooltip> : ''}
9
+ placement="top"
10
+ trigger={['hover', 'focus']}
11
+ rootClose={false}
12
+ >
13
+ {children}
14
+ </OverlayTrigger>
15
+ );
16
+ return (
17
+ <ListView.InfoItem key={itemId} className="additional-info-wide">
18
+ {tooltipText ? overlay : children}
19
+ </ListView.InfoItem>
20
+ );
21
+ };
22
+
23
+ InfoItem.propTypes = {
24
+ itemId: PropTypes.string.isRequired,
25
+ children: PropTypes.node,
26
+ tooltipText: PropTypes.string,
27
+ };
28
+
29
+ InfoItem.defaultProps = {
30
+ tooltipText: '',
31
+ children: undefined,
32
+ };
33
+
34
+ export default InfoItem;
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { ListView } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ import { itemIteratorId } from './helpers';
6
+
7
+ const wrapWithLink = (template, editPath) => {
8
+ if (template.id && template.canEdit) {
9
+ return (
10
+ <a
11
+ href={editPath.replace(':id', template.id)}
12
+ target="_blank"
13
+ rel="noopener noreferrer"
14
+ >
15
+ {template.name}
16
+ </a>
17
+ );
18
+ }
19
+ return template.name || ' ';
20
+ };
21
+
22
+ const LinkInfoItem = ({ template, editPath, attr }) => (
23
+ <ListView.InfoItem
24
+ key={itemIteratorId(template, attr)}
25
+ className="additional-info-wide"
26
+ >
27
+ {wrapWithLink(template, editPath)}
28
+ </ListView.InfoItem>
29
+ );
30
+
31
+ LinkInfoItem.propTypes = {
32
+ template: PropTypes.object.isRequired,
33
+ editPath: PropTypes.string.isRequired,
34
+ attr: PropTypes.string.isRequired,
35
+ };
36
+
37
+ export default LinkInfoItem;
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import EllipsisWithTooltip from 'react-ellipsis-with-tooltip';
3
+ import PropTypes from 'prop-types';
4
+
5
+ import InfoItem from './InfoItem';
6
+ import { itemIteratorId } from './helpers';
7
+
8
+ const StringInfoItem = ({
9
+ template,
10
+ attr,
11
+ tooltipText,
12
+ translate,
13
+ mapAttr,
14
+ elipsed,
15
+ }) => {
16
+ const inner = (
17
+ <span>
18
+ {translate ? __(mapAttr(template, attr)) : mapAttr(template, attr)}
19
+ </span>
20
+ );
21
+ const innerContent = elipsed ? (
22
+ <EllipsisWithTooltip placement="top">{inner}</EllipsisWithTooltip>
23
+ ) : (
24
+ inner
25
+ );
26
+
27
+ return (
28
+ <InfoItem itemId={itemIteratorId(template, attr)} tooltipText={tooltipText}>
29
+ {innerContent}
30
+ </InfoItem>
31
+ );
32
+ };
33
+
34
+ StringInfoItem.propTypes = {
35
+ template: PropTypes.object.isRequired,
36
+ attr: PropTypes.string.isRequired,
37
+ tooltipText: PropTypes.string,
38
+ translate: PropTypes.bool,
39
+ mapAttr: PropTypes.func,
40
+ elipsed: PropTypes.bool,
41
+ };
42
+
43
+ StringInfoItem.defaultProps = {
44
+ translate: false,
45
+ mapAttr: (template, attr) => template[attr],
46
+ elipsed: false,
47
+ tooltipText: undefined,
48
+ };
49
+
50
+ export default StringInfoItem;