foreman_rh_cloud 13.0.9 → 13.0.10

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/inventory_upload/report_actions.rb +8 -1
  3. data/app/controllers/foreman_inventory_upload/accounts_controller.rb +82 -7
  4. data/app/controllers/foreman_inventory_upload/api/tasks_controller.rb +110 -0
  5. data/app/controllers/foreman_inventory_upload/reports_controller.rb +41 -17
  6. data/app/controllers/foreman_inventory_upload/uploads_controller.rb +0 -9
  7. data/config/routes.rb +4 -2
  8. data/db/migrate/20251209163012_drop_task_output_tables.foreman_rh_cloud.rb +24 -0
  9. data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +1 -1
  10. data/lib/foreman_inventory_upload/async/host_inventory_report_job.rb +39 -0
  11. data/lib/foreman_inventory_upload/async/upload_report_direct_job.rb +28 -57
  12. data/lib/foreman_rh_cloud/plugin.rb +1 -0
  13. data/lib/foreman_rh_cloud/version.rb +1 -1
  14. data/lib/tasks/rh_cloud_inventory.rake +4 -2
  15. data/package.json +1 -1
  16. data/test/controllers/accounts_controller_test.rb +10 -11
  17. data/test/controllers/insights_cloud/api/cloud_request_controller_test.rb +1 -2
  18. data/test/jobs/host_inventory_report_job_test.rb +161 -97
  19. data/test/jobs/single_host_report_job_test.rb +36 -54
  20. data/test/jobs/upload_report_direct_job_test.rb +132 -132
  21. data/test/unit/rh_cloud_permissions_test.rb +2 -0
  22. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.fixtures.js +6 -6
  23. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.js +49 -34
  24. data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListActions.js +2 -2
  25. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.fixtures.js +2 -2
  26. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.js +15 -9
  27. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/__snapshots__/ListItem.test.js.snap +6 -5
  28. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.fixtures.js +2 -2
  29. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.js +10 -14
  30. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatusHelper.js +9 -4
  31. data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/__tests__/__snapshots__/ListItemStatus.test.js.snap +4 -4
  32. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountList.test.js.snap +15 -9
  33. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListActions.test.js.snap +7 -7
  34. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListReducer.test.js.snap +6 -6
  35. data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListSelectors.test.js.snap +12 -12
  36. data/webpack/ForemanInventoryUpload/Components/Dashboard/Dashboard.js +36 -132
  37. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/Dashboard.test.js +60 -17
  38. data/webpack/ForemanInventoryUpload/Components/Dashboard/index.js +1 -34
  39. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +0 -1
  40. data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.js +1 -26
  41. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +2 -2
  42. data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.js +22 -9
  43. data/webpack/ForemanInventoryUpload/Components/TabHeader/__tests__/TabHeader.test.js +67 -4
  44. data/webpack/ForemanInventoryUpload/Components/TaskHistory/TaskHistory.js +140 -0
  45. data/webpack/ForemanInventoryUpload/Components/TaskHistory/index.js +1 -0
  46. data/webpack/ForemanInventoryUpload/Components/TaskHistory/taskHistory.scss +40 -0
  47. data/webpack/ForemanInventoryUpload/Components/TaskProgress/TaskProgress.js +340 -0
  48. data/webpack/ForemanInventoryUpload/Components/TaskProgress/index.js +1 -0
  49. data/webpack/ForemanInventoryUpload/Components/TaskProgress/taskProgress.scss +8 -0
  50. data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +2 -2
  51. data/webpack/ForemanInventoryUpload/ForemanInventoryUploadReducers.js +0 -2
  52. data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryHelpers.test.js.snap +1 -1
  53. data/webpack/ForemanRhCloudPages.js +0 -1
  54. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationHelpers.js +1 -2
  55. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +2 -4
  56. data/webpack/__mocks__/foremanReact/components/common/dates/RelativeDateTime.js +14 -0
  57. data/webpack/__tests__/ForemanRhCloudHelpers.test.js +5 -1
  58. metadata +10 -61
  59. data/app/models/task_output_line.rb +0 -2
  60. data/app/models/task_output_status.rb +0 -2
  61. data/lib/foreman_inventory_upload/async/generate_report_job.rb +0 -61
  62. data/lib/foreman_inventory_upload/async/progress_output.rb +0 -38
  63. data/lib/foreman_inventory_upload/async/shell_process.rb +0 -77
  64. data/test/controllers/reports_controller_test.rb +0 -21
  65. data/test/controllers/uploads_controller_test.rb +0 -21
  66. data/test/jobs/generate_report_job_test.rb +0 -146
  67. data/test/unit/shell_process_job_test.rb +0 -29
  68. data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardActions.js +0 -88
  69. data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardConstants.js +0 -9
  70. data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardReducer.js +0 -68
  71. data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardSelectors.js +0 -17
  72. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardActions.test.js +0 -51
  73. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardIntegration.test.js +0 -17
  74. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardReducer.test.js +0 -64
  75. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardSelectors.test.js +0 -46
  76. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/Dashboard.test.js.snap +0 -36
  77. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/DashboardActions.test.js.snap +0 -76
  78. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/DashboardReducer.test.js.snap +0 -44
  79. data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/DashboardSelectors.test.js.snap +0 -42
  80. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModal.fixtures.js +0 -0
  81. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModal.js +0 -55
  82. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModalHelper.js +0 -0
  83. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/__tests__/FullScreenModal.test.js +0 -13
  84. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/__tests__/__snapshots__/FullScreenModal.test.js.snap +0 -65
  85. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/fullScreenModal.scss +0 -20
  86. data/webpack/ForemanInventoryUpload/Components/FullScreenModal/index.js +0 -1
  87. data/webpack/ForemanInventoryUpload/Components/ReportGenerate/ReportGenerate.fixtures.js +0 -18
  88. data/webpack/ForemanInventoryUpload/Components/ReportGenerate/ReportGenerate.js +0 -65
  89. data/webpack/ForemanInventoryUpload/Components/ReportGenerate/ReportGenerateHelper.js +0 -0
  90. data/webpack/ForemanInventoryUpload/Components/ReportGenerate/__tests__/ReportGenerate.test.js +0 -14
  91. data/webpack/ForemanInventoryUpload/Components/ReportGenerate/__tests__/__snapshots__/ReportGenerate.test.js.snap +0 -47
  92. data/webpack/ForemanInventoryUpload/Components/ReportGenerate/index.js +0 -1
  93. data/webpack/ForemanInventoryUpload/Components/ReportGenerate/reportGenerate.scss +0 -0
  94. data/webpack/ForemanInventoryUpload/Components/ReportUpload/ReportUpload.fixtures.js +0 -18
  95. data/webpack/ForemanInventoryUpload/Components/ReportUpload/ReportUpload.js +0 -46
  96. data/webpack/ForemanInventoryUpload/Components/ReportUpload/ReportUploadHelper.js +0 -0
  97. data/webpack/ForemanInventoryUpload/Components/ReportUpload/__tests__/ReportUpload.test.js +0 -14
  98. data/webpack/ForemanInventoryUpload/Components/ReportUpload/__tests__/__snapshots__/ReportUpload.test.js.snap +0 -47
  99. data/webpack/ForemanInventoryUpload/Components/ReportUpload/index.js +0 -1
  100. data/webpack/ForemanInventoryUpload/Components/ReportUpload/reportUpload.scss +0 -0
  101. data/webpack/ForemanInventoryUpload/Components/TabBody/TabBody.fixtures.js +0 -0
  102. data/webpack/ForemanInventoryUpload/Components/TabBody/TabBody.js +0 -31
  103. data/webpack/ForemanInventoryUpload/Components/TabBody/TabBodyHelper.js +0 -0
  104. data/webpack/ForemanInventoryUpload/Components/TabBody/__tests__/TabBody.test.js +0 -13
  105. data/webpack/ForemanInventoryUpload/Components/TabBody/__tests__/__snapshots__/TabBody.test.js.snap +0 -19
  106. data/webpack/ForemanInventoryUpload/Components/TabBody/index.js +0 -1
  107. data/webpack/ForemanInventoryUpload/Components/TabBody/tabBody.scss +0 -5
  108. data/webpack/ForemanInventoryUpload/Components/Terminal/Terminal.fixtures.js +0 -10
  109. data/webpack/ForemanInventoryUpload/Components/Terminal/Terminal.js +0 -110
  110. data/webpack/ForemanInventoryUpload/Components/Terminal/TerminalHelper.js +0 -6
  111. data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/Terminal.test.js +0 -34
  112. data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/__snapshots__/Terminal.test.js.snap +0 -98
  113. data/webpack/ForemanInventoryUpload/Components/Terminal/index.js +0 -1
  114. data/webpack/ForemanInventoryUpload/Components/Terminal/terminal.scss +0 -32
@@ -18,10 +18,10 @@ exports[`ListItem rendering render with Props 1`] = `
18
18
  <ListItemStatus
19
19
  account={
20
20
  Object {
21
- "generate_report_status": "unknown",
21
+ "generated_status": "unknown",
22
22
  "id": 1,
23
23
  "report_file_paths": Array [],
24
- "upload_report_status": "unknown",
24
+ "uploaded_status": "unknown",
25
25
  }
26
26
  }
27
27
  key="test_status"
@@ -30,16 +30,17 @@ exports[`ListItem rendering render with Props 1`] = `
30
30
  <AccordionContent
31
31
  isHidden={true}
32
32
  >
33
- <Connect(Dashboard)
33
+ <Dashboard
34
34
  account={
35
35
  Object {
36
- "generate_report_status": "unknown",
36
+ "generated_status": "unknown",
37
37
  "id": 1,
38
38
  "report_file_paths": Array [],
39
- "upload_report_status": "unknown",
39
+ "uploaded_status": "unknown",
40
40
  }
41
41
  }
42
42
  accountID={1}
43
+ onTaskStart={null}
43
44
  />
44
45
  </AccordionContent>
45
46
  </AccordionItem>
@@ -1,7 +1,7 @@
1
1
  export const props = {
2
2
  account: {
3
- generate_report_status: 'Exit Code: pid 22191 exit 0',
4
- upload_report_status: 'Exit Code: Running in pid 22376',
3
+ generated_status: 'success',
4
+ uploaded_status: 'running',
5
5
  label: 'Default Org',
6
6
  },
7
7
  };
@@ -5,21 +5,17 @@ import { translate as __ } from 'foremanReact/common/I18n';
5
5
  import { getStatusIconByRegex } from './ListItemStatusHelper';
6
6
 
7
7
  const ListItemStatus = ({ account }) => {
8
- const generatingStatusIcon = getStatusIconByRegex(
9
- account.generate_report_status
10
- );
11
- const uploadingStatusIcon = getStatusIconByRegex(
12
- account.upload_report_status
13
- );
8
+ const generatedStatusIcon = getStatusIconByRegex(account.generated_status);
9
+ const uploadedStatusIcon = getStatusIconByRegex(account.uploaded_status);
14
10
  return (
15
11
  <Grid hasGutter className="status">
16
12
  <GridItem span={6} className="item">
17
- <p>{__('Generating')}</p>
18
- {generatingStatusIcon}
13
+ <p>{__('Generated')}</p>
14
+ {generatedStatusIcon}
19
15
  </GridItem>
20
16
  <GridItem span={6} className="item">
21
- <p>{__('Uploading')}</p>
22
- {uploadingStatusIcon}
17
+ <p>{__('Uploaded')}</p>
18
+ {uploadedStatusIcon}
23
19
  </GridItem>
24
20
  </Grid>
25
21
  );
@@ -27,15 +23,15 @@ const ListItemStatus = ({ account }) => {
27
23
 
28
24
  ListItemStatus.propTypes = {
29
25
  account: PropTypes.shape({
30
- generate_report_status: PropTypes.string,
31
- upload_report_status: PropTypes.string,
26
+ generated_status: PropTypes.string,
27
+ uploaded_status: PropTypes.string,
32
28
  }),
33
29
  };
34
30
 
35
31
  ListItemStatus.defaultProps = {
36
32
  account: {
37
- generate_report_status: 'unknown',
38
- uploupload_report_statusading: 'unknown',
33
+ generated_status: 'unknown',
34
+ uploaded_status: 'unknown',
39
35
  },
40
36
  };
41
37
 
@@ -14,17 +14,22 @@ export const getStatusIconByRegex = status => {
14
14
  return STATUS_ICONS.unknown;
15
15
  }
16
16
 
17
- const statusCopy = status.toLowerCase();
18
- if (statusCopy.indexOf('exit 0') !== -1) {
17
+ const statusLower = status.toLowerCase();
18
+
19
+ // Success states
20
+ if (statusLower === 'success') {
19
21
  return STATUS_ICONS.success;
20
22
  }
21
23
 
24
+ // Running states
22
25
  if (
23
- statusCopy.indexOf('running') !== -1 ||
24
- statusCopy.indexOf('restarting') !== -1
26
+ statusLower === 'running' ||
27
+ statusLower === 'pending' ||
28
+ statusLower === 'scheduled'
25
29
  ) {
26
30
  return STATUS_ICONS.running;
27
31
  }
28
32
 
33
+ // Failure states (error, warning, or anything else)
29
34
  return STATUS_ICONS.failure;
30
35
  };
@@ -10,7 +10,7 @@ exports[`ListItemStatus rendering render with Props 1`] = `
10
10
  span={6}
11
11
  >
12
12
  <p>
13
- Generating
13
+ Generated
14
14
  </p>
15
15
  <CheckIcon />
16
16
  </GridItem>
@@ -19,7 +19,7 @@ exports[`ListItemStatus rendering render with Props 1`] = `
19
19
  span={6}
20
20
  >
21
21
  <p>
22
- Uploading
22
+ Uploaded
23
23
  </p>
24
24
  <Spinner
25
25
  size="sm"
@@ -38,7 +38,7 @@ exports[`ListItemStatus rendering render without Props 1`] = `
38
38
  span={6}
39
39
  >
40
40
  <p>
41
- Generating
41
+ Generated
42
42
  </p>
43
43
  <span>
44
44
  --
@@ -49,7 +49,7 @@ exports[`ListItemStatus rendering render without Props 1`] = `
49
49
  span={6}
50
50
  >
51
51
  <p>
52
- Uploading
52
+ Uploaded
53
53
  </p>
54
54
  <span>
55
55
  --
@@ -7,35 +7,41 @@ exports[`AccountList rendering render with props 1`] = `
7
7
  <ListItem
8
8
  account={
9
9
  Object {
10
- "generate_report_status": "running",
10
+ "generated_status": "running",
11
11
  "id": 1,
12
- "upload_report_status": "running",
12
+ "uploaded_status": "running",
13
13
  }
14
14
  }
15
- key="0"
15
+ defaultExpanded={true}
16
+ key="Account1"
16
17
  label="Account1"
18
+ onTaskStart={[Function]}
17
19
  />
18
20
  <ListItem
19
21
  account={
20
22
  Object {
21
- "generate_report_status": "failure",
23
+ "generated_status": "failure",
22
24
  "id": 2,
23
- "upload_report_status": "unknown",
25
+ "uploaded_status": "unknown",
24
26
  }
25
27
  }
26
- key="1"
28
+ defaultExpanded={false}
29
+ key="Account2"
27
30
  label="Account2"
31
+ onTaskStart={[Function]}
28
32
  />
29
33
  <ListItem
30
34
  account={
31
35
  Object {
32
- "generate_report_status": "running",
36
+ "generated_status": "running",
33
37
  "id": 3,
34
- "upload_report_status": "success",
38
+ "uploaded_status": "success",
35
39
  }
36
40
  }
37
- key="2"
41
+ defaultExpanded={false}
42
+ key="Account3"
38
43
  label="Account3"
44
+ onTaskStart={[Function]}
39
45
  />
40
46
  </Accordion>
41
47
  `;
@@ -13,19 +13,19 @@ Array [
13
13
  },
14
14
  "accounts": Object {
15
15
  "Account1": Object {
16
- "generate_report_status": "running",
16
+ "generated_status": "running",
17
17
  "id": 1,
18
- "upload_report_status": "running",
18
+ "uploaded_status": "running",
19
19
  },
20
20
  "Account2": Object {
21
- "generate_report_status": "failure",
21
+ "generated_status": "failure",
22
22
  "id": 2,
23
- "upload_report_status": "unknown",
23
+ "uploaded_status": "unknown",
24
24
  },
25
25
  "Account3": Object {
26
- "generate_report_status": "running",
26
+ "generated_status": "running",
27
27
  "id": 3,
28
- "upload_report_status": "success",
28
+ "uploaded_status": "success",
29
29
  },
30
30
  },
31
31
  },
@@ -58,7 +58,7 @@ Array [
58
58
  Object {
59
59
  "payload": Object {
60
60
  "accountID": "some-account-ID",
61
- "processStatusName": "generate_report_status",
61
+ "processStatusName": "generated_status",
62
62
  },
63
63
  "type": "INVENTORY_PROCESS_RESTART",
64
64
  },
@@ -10,19 +10,19 @@ Object {
10
10
  },
11
11
  "accounts": Object {
12
12
  "Account1": Object {
13
- "generate_report_status": "running",
13
+ "generated_status": "running",
14
14
  "id": 1,
15
- "upload_report_status": "running",
15
+ "uploaded_status": "running",
16
16
  },
17
17
  "Account2": Object {
18
- "generate_report_status": "failure",
18
+ "generated_status": "failure",
19
19
  "id": 2,
20
- "upload_report_status": "unknown",
20
+ "uploaded_status": "unknown",
21
21
  },
22
22
  "Account3": Object {
23
- "generate_report_status": "running",
23
+ "generated_status": "running",
24
24
  "id": 3,
25
- "upload_report_status": "success",
25
+ "uploaded_status": "success",
26
26
  },
27
27
  },
28
28
  "error": null,
@@ -3,19 +3,19 @@
3
3
  exports[`AccountList selectors should return AccountList accounts 1`] = `
4
4
  Object {
5
5
  "Account1": Object {
6
- "generate_report_status": "running",
6
+ "generated_status": "running",
7
7
  "id": 1,
8
- "upload_report_status": "running",
8
+ "uploaded_status": "running",
9
9
  },
10
10
  "Account2": Object {
11
- "generate_report_status": "failure",
11
+ "generated_status": "failure",
12
12
  "id": 2,
13
- "upload_report_status": "unknown",
13
+ "uploaded_status": "unknown",
14
14
  },
15
15
  "Account3": Object {
16
- "generate_report_status": "running",
16
+ "generated_status": "running",
17
17
  "id": 3,
18
- "upload_report_status": "success",
18
+ "uploaded_status": "success",
19
19
  },
20
20
  }
21
21
  `;
@@ -26,19 +26,19 @@ exports[`AccountList selectors should return AccountsList 1`] = `
26
26
  Object {
27
27
  "accounts": Object {
28
28
  "Account1": Object {
29
- "generate_report_status": "running",
29
+ "generated_status": "running",
30
30
  "id": 1,
31
- "upload_report_status": "running",
31
+ "uploaded_status": "running",
32
32
  },
33
33
  "Account2": Object {
34
- "generate_report_status": "failure",
34
+ "generated_status": "failure",
35
35
  "id": 2,
36
- "upload_report_status": "unknown",
36
+ "uploaded_status": "unknown",
37
37
  },
38
38
  "Account3": Object {
39
- "generate_report_status": "running",
39
+ "generated_status": "running",
40
40
  "id": 3,
41
- "upload_report_status": "success",
41
+ "uploaded_status": "success",
42
42
  },
43
43
  },
44
44
  "pollingProcessID": 0,
@@ -1,152 +1,56 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { noop } from 'foremanReact/common/helpers';
4
3
  import { translate as __ } from 'foremanReact/common/I18n';
5
- import ReportGenerate from '../ReportGenerate';
6
- import ReportUpload from '../ReportUpload';
7
- import NavContainer from '../NavContainer';
4
+ import TaskProgress from '../TaskProgress';
8
5
  import './dashboard.scss';
9
6
 
10
- class Dashboard extends React.Component {
11
- componentDidMount() {
12
- const { startPolling, fetchLogs, accountID } = this.props;
13
- fetchLogs(accountID);
14
- const pollingProcessID = setInterval(() => fetchLogs(accountID), 5000);
15
- startPolling(accountID, pollingProcessID);
16
- }
17
-
18
- componentWillUnmount() {
19
- const { stopPolling, pollingProcessID, accountID } = this.props;
20
- stopPolling(accountID, pollingProcessID);
21
- }
22
-
23
- handleDownload = () => {
24
- const { downloadReports, accountID } = this.props;
25
- downloadReports(accountID);
26
- };
27
-
28
- handleRestart = () => {
29
- const { restartProcess, accountID, activeTab } = this.props;
30
- restartProcess(accountID, activeTab);
31
- };
32
-
33
- handleTabChange = async tabName => {
34
- const { setActiveTab, accountID, fetchLogs } = this.props;
35
- await setActiveTab(accountID, tabName);
36
- fetchLogs(accountID);
37
- };
38
-
39
- handleToggleFullScreen = () => {
40
- const { toggleFullScreen, accountID } = this.props;
41
- toggleFullScreen(accountID);
42
- };
43
-
44
- render() {
45
- const {
46
- uploading,
47
- generating,
48
- account,
49
- showFullScreen,
50
- activeTab,
51
- } = this.props;
52
- const downloadButtonDisabled = () =>
53
- !account.report_file_paths || account.report_file_paths.length === 0;
7
+ const Dashboard = ({ account, onTaskStart }) => {
8
+ // Defensive handling for missing or malformed account data
9
+ if (!account) {
54
10
  return (
55
- <NavContainer
56
- items={[
57
- {
58
- icon: 'database',
59
- name: __('Generating'),
60
- component: ReportGenerate,
61
- props: {
62
- ...generating,
63
- restartProcess: this.handleRestart,
64
- exitCode: account.generate_report_status,
65
- downloadReports: this.handleDownload,
66
- downloadButtonDisabled,
67
- toggleFullScreen: this.handleToggleFullScreen,
68
- },
69
- onClick: () => this.handleTabChange('generating'),
70
- },
71
- {
72
- icon: 'cloud-upload',
73
- name: __('Uploading'),
74
- component: ReportUpload,
75
- props: {
76
- ...uploading,
77
- exitCode: account.upload_report_status,
78
- toggleFullScreen: this.handleToggleFullScreen,
79
- },
80
- onClick: () => this.handleTabChange('uploading'),
81
- },
82
- ]}
83
- toggleFullScreen={this.handleToggleFullScreen}
84
- showFullScreen={showFullScreen}
85
- terminalProps={this.props[activeTab]}
11
+ <TaskProgress
12
+ task={null}
13
+ title={__('Report Generation')}
14
+ emptyMessage={__('No account data available.')}
15
+ organizationId={null}
16
+ taskType="generate"
17
+ onTaskStart={onTaskStart}
86
18
  />
87
19
  );
88
20
  }
89
- }
21
+
22
+ return (
23
+ <TaskProgress
24
+ task={account.generate_task || null}
25
+ title={__('Report Generation')}
26
+ emptyMessage={__('No report generation tasks have been run yet.')}
27
+ organizationId={account.id || null}
28
+ taskType="generate"
29
+ onTaskStart={onTaskStart}
30
+ />
31
+ );
32
+ };
90
33
 
91
34
  Dashboard.propTypes = {
92
- accountID: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
93
- .isRequired,
94
- startPolling: PropTypes.func,
95
- fetchLogs: PropTypes.func,
96
- stopPolling: PropTypes.func,
97
- setActiveTab: PropTypes.func,
98
- uploading: PropTypes.shape({
99
- exitCode: PropTypes.string,
100
- logs: PropTypes.oneOfType([
101
- PropTypes.arrayOf(PropTypes.string),
102
- PropTypes.string,
103
- ]),
104
- completed: PropTypes.number,
105
- files: PropTypes.arrayOf(PropTypes.string),
106
- error: PropTypes.string,
107
- }),
108
- generating: PropTypes.shape({
109
- exitCode: PropTypes.string,
110
- logs: PropTypes.oneOfType([
111
- PropTypes.arrayOf(PropTypes.string),
112
- PropTypes.string,
113
- ]),
114
- completed: PropTypes.number,
115
- error: PropTypes.string,
116
- }),
117
- restartProcess: PropTypes.func,
118
- downloadReports: PropTypes.func,
119
- pollingProcessID: PropTypes.number,
120
35
  account: PropTypes.shape({
121
- generate_report_status: PropTypes.string,
122
- upload_report_status: PropTypes.string,
123
- report_file_paths: PropTypes.arrayOf(PropTypes.string),
124
36
  id: PropTypes.number,
37
+ generate_task: PropTypes.shape({
38
+ id: PropTypes.string,
39
+ state: PropTypes.string,
40
+ result: PropTypes.string,
41
+ progress: PropTypes.number,
42
+ started_at: PropTypes.string,
43
+ ended_at: PropTypes.string,
44
+ duration: PropTypes.number,
45
+ report_file_path: PropTypes.string,
46
+ }),
125
47
  }),
126
- showFullScreen: PropTypes.bool,
127
- toggleFullScreen: PropTypes.func,
128
- activeTab: PropTypes.string,
48
+ onTaskStart: PropTypes.func,
129
49
  };
130
50
 
131
51
  Dashboard.defaultProps = {
132
- uploading: {},
133
- generating: {},
134
- startPolling: noop,
135
- fetchLogs: noop,
136
- stopPolling: noop,
137
- setActiveTab: noop,
138
- restartProcess: noop,
139
- downloadReports: noop,
140
- pollingProcessID: 0,
141
- account: {
142
- generate_report_status: 'unknown',
143
- upload_report_status: 'unknown',
144
- report_file_paths: [],
145
- id: 0,
146
- },
147
- showFullScreen: false,
148
- toggleFullScreen: noop,
149
- activeTab: 'generating',
52
+ account: null,
53
+ onTaskStart: null,
150
54
  };
151
55
 
152
56
  export default Dashboard;
@@ -1,24 +1,67 @@
1
1
  import React from 'react';
2
- import { shallow, testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
+ import { shallow } from '@theforeman/test';
3
3
  import Dashboard from '../Dashboard';
4
- import { props } from '../Dashboard.fixtures';
5
-
6
- const fixtures = {
7
- 'with props': props,
8
- };
9
4
 
10
5
  describe('Dashboard', () => {
11
- describe('rendering', () =>
12
- testComponentSnapshotsWithFixtures(Dashboard, fixtures));
13
-
14
- it('componentWillUnmount should call "stopPolling"', () => {
15
- const stopPolling = jest.fn();
16
- const modifiedProps = {
17
- ...props,
18
- stopPolling,
6
+ it('should render TaskProgress component with correct props', () => {
7
+ const account = {
8
+ id: 1,
9
+ generate_task: {
10
+ id: 'task-1',
11
+ state: 'running',
12
+ result: null,
13
+ progress: 50,
14
+ },
19
15
  };
20
- const wrapper = shallow(<Dashboard {...modifiedProps} />);
21
- wrapper.unmount();
22
- expect(stopPolling).toBeCalled();
16
+ const onTaskStart = jest.fn();
17
+
18
+ const wrapper = shallow(
19
+ <Dashboard account={account} onTaskStart={onTaskStart} />
20
+ );
21
+
22
+ const taskProgress = wrapper.find('TaskProgress');
23
+ expect(taskProgress).toHaveLength(1);
24
+ expect(taskProgress.prop('task')).toEqual(account.generate_task);
25
+ expect(taskProgress.prop('title')).toBe('Report Generation');
26
+ expect(taskProgress.prop('organizationId')).toBe(1);
27
+ expect(taskProgress.prop('taskType')).toBe('generate');
28
+ expect(taskProgress.prop('onTaskStart')).toBe(onTaskStart);
29
+ });
30
+
31
+ it('should handle missing account gracefully', () => {
32
+ const wrapper = shallow(<Dashboard account={null} onTaskStart={null} />);
33
+
34
+ const taskProgress = wrapper.find('TaskProgress');
35
+ expect(taskProgress).toHaveLength(1);
36
+ expect(taskProgress.prop('task')).toBeNull();
37
+ expect(taskProgress.prop('organizationId')).toBeNull();
38
+ expect(taskProgress.prop('emptyMessage')).toBe(
39
+ 'No account data available.'
40
+ );
41
+ });
42
+
43
+ it('should handle missing generate_task gracefully', () => {
44
+ const account = { id: 1, generate_task: null };
45
+ const wrapper = shallow(<Dashboard account={account} onTaskStart={null} />);
46
+
47
+ const taskProgress = wrapper.find('TaskProgress');
48
+ expect(taskProgress).toHaveLength(1);
49
+ expect(taskProgress.prop('task')).toBeNull();
50
+ expect(taskProgress.prop('organizationId')).toBe(1);
51
+ });
52
+
53
+ it('should handle missing account.id gracefully', () => {
54
+ const account = {
55
+ generate_task: {
56
+ id: 'task-1',
57
+ state: 'running',
58
+ },
59
+ };
60
+ const wrapper = shallow(<Dashboard account={account} onTaskStart={null} />);
61
+
62
+ const taskProgress = wrapper.find('TaskProgress');
63
+ expect(taskProgress).toHaveLength(1);
64
+ expect(taskProgress.prop('organizationId')).toBeNull();
65
+ expect(taskProgress.prop('task')).toEqual(account.generate_task);
23
66
  });
24
67
  });
@@ -1,34 +1 @@
1
- import { bindActionCreators } from 'redux';
2
- import { connect } from 'react-redux';
3
-
4
- import * as actions from './DashboardActions';
5
- import { restartProcess } from '../AccountList/AccountListActions';
6
- import reducer from './DashboardReducer';
7
-
8
- import Dashboard from './Dashboard';
9
- import {
10
- selectUploading,
11
- selectGenerating,
12
- selectPollingProcessID,
13
- selectActiveTab,
14
- selectShowFullScreen,
15
- } from './DashboardSelectors';
16
-
17
- // map state to props
18
- const mapStateToProps = (state, { accountID }) => ({
19
- uploading: selectUploading(state, accountID),
20
- generating: selectGenerating(state, accountID),
21
- pollingProcessID: selectPollingProcessID(state, accountID),
22
- activeTab: selectActiveTab(state, accountID),
23
- showFullScreen: selectShowFullScreen(state, accountID),
24
- });
25
-
26
- // map action dispatchers to props
27
- const mapDispatchToProps = dispatch =>
28
- bindActionCreators({ ...actions, restartProcess }, dispatch);
29
-
30
- // export reducers
31
- export const reducers = { dashboard: reducer };
32
-
33
- // export connected component
34
- export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
1
+ export { default } from './Dashboard';
@@ -33,7 +33,6 @@ Object {
33
33
  "error": null,
34
34
  "pollingProcessID": 0,
35
35
  },
36
- "dashboard": Object {},
37
36
  "inventoryFilter": Object {
38
37
  "filterTerm": "some-org",
39
38
  },