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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/inventory_upload/report_actions.rb +8 -1
- data/app/controllers/foreman_inventory_upload/accounts_controller.rb +82 -7
- data/app/controllers/foreman_inventory_upload/api/tasks_controller.rb +110 -0
- data/app/controllers/foreman_inventory_upload/reports_controller.rb +41 -17
- data/app/controllers/foreman_inventory_upload/uploads_controller.rb +0 -9
- data/config/routes.rb +4 -2
- data/db/migrate/20251209163012_drop_task_output_tables.foreman_rh_cloud.rb +24 -0
- data/lib/foreman_inventory_upload/async/generate_all_reports_job.rb +1 -1
- data/lib/foreman_inventory_upload/async/host_inventory_report_job.rb +39 -0
- data/lib/foreman_inventory_upload/async/upload_report_direct_job.rb +28 -57
- data/lib/foreman_rh_cloud/plugin.rb +1 -0
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/tasks/rh_cloud_inventory.rake +4 -2
- data/package.json +1 -1
- data/test/controllers/accounts_controller_test.rb +10 -11
- data/test/controllers/insights_cloud/api/cloud_request_controller_test.rb +1 -2
- data/test/jobs/host_inventory_report_job_test.rb +161 -97
- data/test/jobs/single_host_report_job_test.rb +36 -54
- data/test/jobs/upload_report_direct_job_test.rb +132 -132
- data/test/unit/rh_cloud_permissions_test.rb +2 -0
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.fixtures.js +6 -6
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountList.js +49 -34
- data/webpack/ForemanInventoryUpload/Components/AccountList/AccountListActions.js +2 -2
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.fixtures.js +2 -2
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/ListItem.js +15 -9
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/__snapshots__/ListItem.test.js.snap +6 -5
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.fixtures.js +2 -2
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatus.js +10 -14
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/ListItemStatusHelper.js +9 -4
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/__tests__/__snapshots__/ListItemStatus.test.js.snap +4 -4
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountList.test.js.snap +15 -9
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListActions.test.js.snap +7 -7
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListReducer.test.js.snap +6 -6
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListSelectors.test.js.snap +12 -12
- data/webpack/ForemanInventoryUpload/Components/Dashboard/Dashboard.js +36 -132
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/Dashboard.test.js +60 -17
- data/webpack/ForemanInventoryUpload/Components/Dashboard/index.js +1 -34
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +0 -1
- data/webpack/ForemanInventoryUpload/Components/NavContainer/NavContainer.js +1 -26
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +2 -2
- data/webpack/ForemanInventoryUpload/Components/TabHeader/TabHeader.js +22 -9
- data/webpack/ForemanInventoryUpload/Components/TabHeader/__tests__/TabHeader.test.js +67 -4
- data/webpack/ForemanInventoryUpload/Components/TaskHistory/TaskHistory.js +140 -0
- data/webpack/ForemanInventoryUpload/Components/TaskHistory/index.js +1 -0
- data/webpack/ForemanInventoryUpload/Components/TaskHistory/taskHistory.scss +40 -0
- data/webpack/ForemanInventoryUpload/Components/TaskProgress/TaskProgress.js +340 -0
- data/webpack/ForemanInventoryUpload/Components/TaskProgress/index.js +1 -0
- data/webpack/ForemanInventoryUpload/Components/TaskProgress/taskProgress.scss +8 -0
- data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +2 -2
- data/webpack/ForemanInventoryUpload/ForemanInventoryUploadReducers.js +0 -2
- data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryHelpers.test.js.snap +1 -1
- data/webpack/ForemanRhCloudPages.js +0 -1
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationHelpers.js +1 -2
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +2 -4
- data/webpack/__mocks__/foremanReact/components/common/dates/RelativeDateTime.js +14 -0
- data/webpack/__tests__/ForemanRhCloudHelpers.test.js +5 -1
- metadata +10 -61
- data/app/models/task_output_line.rb +0 -2
- data/app/models/task_output_status.rb +0 -2
- data/lib/foreman_inventory_upload/async/generate_report_job.rb +0 -61
- data/lib/foreman_inventory_upload/async/progress_output.rb +0 -38
- data/lib/foreman_inventory_upload/async/shell_process.rb +0 -77
- data/test/controllers/reports_controller_test.rb +0 -21
- data/test/controllers/uploads_controller_test.rb +0 -21
- data/test/jobs/generate_report_job_test.rb +0 -146
- data/test/unit/shell_process_job_test.rb +0 -29
- data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardActions.js +0 -88
- data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardConstants.js +0 -9
- data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardReducer.js +0 -68
- data/webpack/ForemanInventoryUpload/Components/Dashboard/DashboardSelectors.js +0 -17
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardActions.test.js +0 -51
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardIntegration.test.js +0 -17
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardReducer.test.js +0 -64
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/DashboardSelectors.test.js +0 -46
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/Dashboard.test.js.snap +0 -36
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/DashboardActions.test.js.snap +0 -76
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/DashboardReducer.test.js.snap +0 -44
- data/webpack/ForemanInventoryUpload/Components/Dashboard/__tests__/__snapshots__/DashboardSelectors.test.js.snap +0 -42
- data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModal.fixtures.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModal.js +0 -55
- data/webpack/ForemanInventoryUpload/Components/FullScreenModal/FullScreenModalHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/FullScreenModal/__tests__/FullScreenModal.test.js +0 -13
- data/webpack/ForemanInventoryUpload/Components/FullScreenModal/__tests__/__snapshots__/FullScreenModal.test.js.snap +0 -65
- data/webpack/ForemanInventoryUpload/Components/FullScreenModal/fullScreenModal.scss +0 -20
- data/webpack/ForemanInventoryUpload/Components/FullScreenModal/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/ReportGenerate/ReportGenerate.fixtures.js +0 -18
- data/webpack/ForemanInventoryUpload/Components/ReportGenerate/ReportGenerate.js +0 -65
- data/webpack/ForemanInventoryUpload/Components/ReportGenerate/ReportGenerateHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/ReportGenerate/__tests__/ReportGenerate.test.js +0 -14
- data/webpack/ForemanInventoryUpload/Components/ReportGenerate/__tests__/__snapshots__/ReportGenerate.test.js.snap +0 -47
- data/webpack/ForemanInventoryUpload/Components/ReportGenerate/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/ReportGenerate/reportGenerate.scss +0 -0
- data/webpack/ForemanInventoryUpload/Components/ReportUpload/ReportUpload.fixtures.js +0 -18
- data/webpack/ForemanInventoryUpload/Components/ReportUpload/ReportUpload.js +0 -46
- data/webpack/ForemanInventoryUpload/Components/ReportUpload/ReportUploadHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/ReportUpload/__tests__/ReportUpload.test.js +0 -14
- data/webpack/ForemanInventoryUpload/Components/ReportUpload/__tests__/__snapshots__/ReportUpload.test.js.snap +0 -47
- data/webpack/ForemanInventoryUpload/Components/ReportUpload/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/ReportUpload/reportUpload.scss +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabBody/TabBody.fixtures.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabBody/TabBody.js +0 -31
- data/webpack/ForemanInventoryUpload/Components/TabBody/TabBodyHelper.js +0 -0
- data/webpack/ForemanInventoryUpload/Components/TabBody/__tests__/TabBody.test.js +0 -13
- data/webpack/ForemanInventoryUpload/Components/TabBody/__tests__/__snapshots__/TabBody.test.js.snap +0 -19
- data/webpack/ForemanInventoryUpload/Components/TabBody/index.js +0 -1
- data/webpack/ForemanInventoryUpload/Components/TabBody/tabBody.scss +0 -5
- data/webpack/ForemanInventoryUpload/Components/Terminal/Terminal.fixtures.js +0 -10
- data/webpack/ForemanInventoryUpload/Components/Terminal/Terminal.js +0 -110
- data/webpack/ForemanInventoryUpload/Components/Terminal/TerminalHelper.js +0 -6
- data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/Terminal.test.js +0 -34
- data/webpack/ForemanInventoryUpload/Components/Terminal/__tests__/__snapshots__/Terminal.test.js.snap +0 -98
- data/webpack/ForemanInventoryUpload/Components/Terminal/index.js +0 -1
- 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
|
-
"
|
|
21
|
+
"generated_status": "unknown",
|
|
22
22
|
"id": 1,
|
|
23
23
|
"report_file_paths": Array [],
|
|
24
|
-
"
|
|
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
|
-
<
|
|
33
|
+
<Dashboard
|
|
34
34
|
account={
|
|
35
35
|
Object {
|
|
36
|
-
"
|
|
36
|
+
"generated_status": "unknown",
|
|
37
37
|
"id": 1,
|
|
38
38
|
"report_file_paths": Array [],
|
|
39
|
-
"
|
|
39
|
+
"uploaded_status": "unknown",
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
accountID={1}
|
|
43
|
+
onTaskStart={null}
|
|
43
44
|
/>
|
|
44
45
|
</AccordionContent>
|
|
45
46
|
</AccordionItem>
|
|
@@ -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
|
|
9
|
-
|
|
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>{__('
|
|
18
|
-
{
|
|
13
|
+
<p>{__('Generated')}</p>
|
|
14
|
+
{generatedStatusIcon}
|
|
19
15
|
</GridItem>
|
|
20
16
|
<GridItem span={6} className="item">
|
|
21
|
-
<p>{__('
|
|
22
|
-
{
|
|
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
|
-
|
|
31
|
-
|
|
26
|
+
generated_status: PropTypes.string,
|
|
27
|
+
uploaded_status: PropTypes.string,
|
|
32
28
|
}),
|
|
33
29
|
};
|
|
34
30
|
|
|
35
31
|
ListItemStatus.defaultProps = {
|
|
36
32
|
account: {
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
18
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
10
|
+
"generated_status": "running",
|
|
11
11
|
"id": 1,
|
|
12
|
-
"
|
|
12
|
+
"uploaded_status": "running",
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
|
|
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
|
-
"
|
|
23
|
+
"generated_status": "failure",
|
|
22
24
|
"id": 2,
|
|
23
|
-
"
|
|
25
|
+
"uploaded_status": "unknown",
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
|
-
|
|
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
|
-
"
|
|
36
|
+
"generated_status": "running",
|
|
33
37
|
"id": 3,
|
|
34
|
-
"
|
|
38
|
+
"uploaded_status": "success",
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
|
-
|
|
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
|
-
"
|
|
16
|
+
"generated_status": "running",
|
|
17
17
|
"id": 1,
|
|
18
|
-
"
|
|
18
|
+
"uploaded_status": "running",
|
|
19
19
|
},
|
|
20
20
|
"Account2": Object {
|
|
21
|
-
"
|
|
21
|
+
"generated_status": "failure",
|
|
22
22
|
"id": 2,
|
|
23
|
-
"
|
|
23
|
+
"uploaded_status": "unknown",
|
|
24
24
|
},
|
|
25
25
|
"Account3": Object {
|
|
26
|
-
"
|
|
26
|
+
"generated_status": "running",
|
|
27
27
|
"id": 3,
|
|
28
|
-
"
|
|
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": "
|
|
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
|
-
"
|
|
13
|
+
"generated_status": "running",
|
|
14
14
|
"id": 1,
|
|
15
|
-
"
|
|
15
|
+
"uploaded_status": "running",
|
|
16
16
|
},
|
|
17
17
|
"Account2": Object {
|
|
18
|
-
"
|
|
18
|
+
"generated_status": "failure",
|
|
19
19
|
"id": 2,
|
|
20
|
-
"
|
|
20
|
+
"uploaded_status": "unknown",
|
|
21
21
|
},
|
|
22
22
|
"Account3": Object {
|
|
23
|
-
"
|
|
23
|
+
"generated_status": "running",
|
|
24
24
|
"id": 3,
|
|
25
|
-
"
|
|
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
|
-
"
|
|
6
|
+
"generated_status": "running",
|
|
7
7
|
"id": 1,
|
|
8
|
-
"
|
|
8
|
+
"uploaded_status": "running",
|
|
9
9
|
},
|
|
10
10
|
"Account2": Object {
|
|
11
|
-
"
|
|
11
|
+
"generated_status": "failure",
|
|
12
12
|
"id": 2,
|
|
13
|
-
"
|
|
13
|
+
"uploaded_status": "unknown",
|
|
14
14
|
},
|
|
15
15
|
"Account3": Object {
|
|
16
|
-
"
|
|
16
|
+
"generated_status": "running",
|
|
17
17
|
"id": 3,
|
|
18
|
-
"
|
|
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
|
-
"
|
|
29
|
+
"generated_status": "running",
|
|
30
30
|
"id": 1,
|
|
31
|
-
"
|
|
31
|
+
"uploaded_status": "running",
|
|
32
32
|
},
|
|
33
33
|
"Account2": Object {
|
|
34
|
-
"
|
|
34
|
+
"generated_status": "failure",
|
|
35
35
|
"id": 2,
|
|
36
|
-
"
|
|
36
|
+
"uploaded_status": "unknown",
|
|
37
37
|
},
|
|
38
38
|
"Account3": Object {
|
|
39
|
-
"
|
|
39
|
+
"generated_status": "running",
|
|
40
40
|
"id": 3,
|
|
41
|
-
"
|
|
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
|
|
6
|
-
import ReportUpload from '../ReportUpload';
|
|
7
|
-
import NavContainer from '../NavContainer';
|
|
4
|
+
import TaskProgress from '../TaskProgress';
|
|
8
5
|
import './dashboard.scss';
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
127
|
-
toggleFullScreen: PropTypes.func,
|
|
128
|
-
activeTab: PropTypes.string,
|
|
48
|
+
onTaskStart: PropTypes.func,
|
|
129
49
|
};
|
|
130
50
|
|
|
131
51
|
Dashboard.defaultProps = {
|
|
132
|
-
|
|
133
|
-
|
|
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
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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';
|