@ministryofjustice/hmpps-digital-prison-reporting-frontend 3.18.2 → 3.19.0
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.
- package/dpr/assets/js/all.mjs +159 -12
- package/dpr/components/async-filters/utils.ts +0 -1
- package/dpr/components/async-polling/utils.js +11 -38
- package/dpr/components/async-polling/utils.ts +12 -38
- package/dpr/components/async-polling/view.njk +12 -1
- package/dpr/components/async-request-list/utils.js +131 -0
- package/dpr/components/async-request-list/utils.ts +133 -0
- package/dpr/components/async-request-list/view.njk +12 -0
- package/dpr/components/recently-viewed-list/utils.js +94 -0
- package/dpr/components/recently-viewed-list/utils.ts +91 -0
- package/dpr/components/recently-viewed-list/view.njk +12 -0
- package/dpr/components/reports-list/view.njk +2 -2
- package/dpr/components/search/view.njk +2 -1
- package/dpr/components/table-card-group/types.d.ts +12 -0
- package/dpr/routes/asyncReports.js +12 -2
- package/dpr/routes/asyncReports.ts +12 -3
- package/dpr/routes/recentlyViewed.js +12 -2
- package/dpr/routes/recentlyViewed.ts +13 -2
- package/dpr/utils/reportStatusHelper.js +86 -0
- package/dpr/utils/reportStatusHelper.ts +108 -0
- package/dpr/utils/reportsListHelper.js +76 -0
- package/dpr/utils/reportsListHelper.ts +82 -0
- package/package.json +1 -1
- package/package.zip +0 -0
- package/dpr/utils/asyncReportsUtils.js +0 -164
- package/dpr/utils/asyncReportsUtils.ts +0 -190
- package/dpr/utils/recentlyViewedUtils.js +0 -99
- package/dpr/utils/recentlyViewedUtils.ts +0 -134
- package/dpr/utils/reportStatusUtils.js +0 -42
- package/dpr/utils/reportStatusUtils.ts +0 -64
package/dpr/assets/js/all.mjs
CHANGED
|
@@ -488,12 +488,13 @@ class ToggleButton extends DprClientClass {
|
|
|
488
488
|
const urlParams = new URLSearchParams(window.location.search);
|
|
489
489
|
|
|
490
490
|
urlParams.keys().forEach((key) => {
|
|
491
|
-
const
|
|
492
|
-
if (toggle) {
|
|
491
|
+
const element = document.getElementById(key);
|
|
492
|
+
if (element && element.classList.contains('dpr-toggle-button')) {
|
|
493
|
+
console.log('is toggle', key);
|
|
493
494
|
const value = urlParams.get(key);
|
|
494
|
-
const icons = Array.from(
|
|
495
|
+
const icons = Array.from(element.getElementsByClassName('dpr-icon-wrapper'));
|
|
495
496
|
|
|
496
|
-
const toggleContainer =
|
|
497
|
+
const toggleContainer = element.parentNode.parentNode;
|
|
497
498
|
const contentContainers = Array.from(toggleContainer.getElementsByClassName('dpr-toggle-content'));
|
|
498
499
|
|
|
499
500
|
icons.forEach((icon) => {
|
|
@@ -719,31 +720,82 @@ class DataTable extends DprClientClass {
|
|
|
719
720
|
}
|
|
720
721
|
}
|
|
721
722
|
|
|
723
|
+
class DprPollingStatusClass extends DprClientClass {
|
|
724
|
+
getPollingFrquency () {
|
|
725
|
+
return '2000' // 2 seconds
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
getPollingStatuses () {
|
|
729
|
+
return ['SUBMITTED', 'STARTED', 'PICKED']
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
getEndStatuses () {
|
|
733
|
+
return ['FINISHED', 'FAILED', 'EXPIRED']
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
async getRequestStatus (metaData, csrfToken) {
|
|
737
|
+
return this.getStatus('/getStatus/', metaData, csrfToken)
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
async getExpiredStatus (metaData, csrfToken) {
|
|
741
|
+
return this.getStatus('/getExpiredStatus/', metaData, csrfToken)
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
async getStatus (endpoint, body, csrfToken) {
|
|
745
|
+
let response;
|
|
746
|
+
await fetch(endpoint, {
|
|
747
|
+
method: 'post',
|
|
748
|
+
headers: {
|
|
749
|
+
Accept: 'application/json',
|
|
750
|
+
'Content-Type': 'application/json',
|
|
751
|
+
'CSRF-Token': csrfToken,
|
|
752
|
+
},
|
|
753
|
+
body: JSON.stringify({
|
|
754
|
+
...body,
|
|
755
|
+
}),
|
|
756
|
+
})
|
|
757
|
+
.then((res) => res.json())
|
|
758
|
+
.then((res) => {
|
|
759
|
+
response = res;
|
|
760
|
+
})
|
|
761
|
+
.catch((error) => console.error('Error:', error));
|
|
762
|
+
|
|
763
|
+
return response
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
722
767
|
/* eslint-disable class-methods-use-this */
|
|
723
768
|
|
|
724
|
-
class
|
|
769
|
+
class DprAsyncPolling extends DprPollingStatusClass {
|
|
725
770
|
static getModuleName () {
|
|
726
771
|
return 'async-polling-content'
|
|
727
772
|
}
|
|
728
773
|
|
|
729
|
-
|
|
730
|
-
this.POLLING_STATUSES =
|
|
731
|
-
this.POLLING_FREQUENCY =
|
|
774
|
+
initialise () {
|
|
775
|
+
this.POLLING_STATUSES = this.getPollingStatuses();
|
|
776
|
+
this.POLLING_FREQUENCY = this.getPollingFrquency();
|
|
732
777
|
|
|
733
778
|
this.statusSection = document.getElementById('async-request-polling-status');
|
|
734
779
|
this.retryRequestButton = document.getElementById('retry-async-request');
|
|
735
780
|
this.cancelRequestButton = document.getElementById('cancel-async-request');
|
|
736
781
|
this.viewReportButton = document.getElementById('view-async-report-button');
|
|
737
782
|
|
|
783
|
+
this.requestData = this.statusSection.getAttribute('data-request-data');
|
|
784
|
+
|
|
738
785
|
this.initCancelRequestButton();
|
|
739
786
|
this.initPollingStatus();
|
|
740
787
|
}
|
|
741
788
|
|
|
742
789
|
initPollingStatus () {
|
|
743
790
|
const status = this.statusSection.getAttribute('data-current-status');
|
|
791
|
+
|
|
744
792
|
if (this.POLLING_STATUSES.includes(status)) {
|
|
745
|
-
|
|
746
|
-
|
|
793
|
+
setInterval(async () => {
|
|
794
|
+
if (this.requestData) {
|
|
795
|
+
const meta = JSON.parse(this.requestData);
|
|
796
|
+
await this.getRequestStatus(meta, this.csrfToken);
|
|
797
|
+
window.location.reload();
|
|
798
|
+
}
|
|
747
799
|
}, this.POLLING_FREQUENCY);
|
|
748
800
|
}
|
|
749
801
|
}
|
|
@@ -819,11 +871,29 @@ class Search extends DprClientClass {
|
|
|
819
871
|
if (searchBox) {
|
|
820
872
|
searchBox.addEventListener('keyup', (e) => {
|
|
821
873
|
this.updateSearchListing(e.target.value);
|
|
874
|
+
|
|
875
|
+
// Update Query Params
|
|
876
|
+
const queryParams = new URLSearchParams(window.location.search);
|
|
877
|
+
queryParams.set(searchBox.id, e.target.value);
|
|
878
|
+
window.history.replaceState(null, null, `?${queryParams.toString()}`);
|
|
822
879
|
});
|
|
823
880
|
|
|
824
|
-
this.
|
|
881
|
+
this.initInputFromQueryParams();
|
|
825
882
|
}
|
|
826
883
|
}
|
|
884
|
+
|
|
885
|
+
// eslint-disable-next-line
|
|
886
|
+
initInputFromQueryParams () {
|
|
887
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
888
|
+
|
|
889
|
+
urlParams.forEach((value, key) => {
|
|
890
|
+
const element = document.getElementById(key);
|
|
891
|
+
if (element && element.classList.contains('dpr-search-box')) {
|
|
892
|
+
element.value = value;
|
|
893
|
+
this.updateSearchListing(element.value);
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
}
|
|
827
897
|
}
|
|
828
898
|
|
|
829
899
|
class BookmarkToggle extends DprClientClass {
|
|
@@ -959,6 +1029,81 @@ class DateInput extends DprClientClass {
|
|
|
959
1029
|
}
|
|
960
1030
|
}
|
|
961
1031
|
|
|
1032
|
+
/* eslint-disable class-methods-use-this */
|
|
1033
|
+
|
|
1034
|
+
class DprAsyncRequestList extends DprPollingStatusClass {
|
|
1035
|
+
static getModuleName () {
|
|
1036
|
+
return 'async-request-list'
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
initialise () {
|
|
1040
|
+
this.END_STATUSES = this.getEndStatuses();
|
|
1041
|
+
this.POLLING_FREQUENCY = this.getPollingFrquency();
|
|
1042
|
+
|
|
1043
|
+
this.requestList = document.getElementById('dpr-async-request-component');
|
|
1044
|
+
this.requestData = this.requestList.getAttribute('data-request-data');
|
|
1045
|
+
this.csrfToken = this.requestList.getAttribute('data-csrf-token');
|
|
1046
|
+
this.initPollingStatus();
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
initPollingStatus () {
|
|
1050
|
+
setInterval(async () => {
|
|
1051
|
+
if (this.requestData) {
|
|
1052
|
+
const meta = JSON.parse(this.requestData);
|
|
1053
|
+
await Promise.all(
|
|
1054
|
+
meta.map(async (metaData) => {
|
|
1055
|
+
// Don't poll if current state is an end state
|
|
1056
|
+
if (!this.END_STATUSES.includes(metaData.status)) {
|
|
1057
|
+
const response = await this.getRequestStatus(metaData, this.csrfToken);
|
|
1058
|
+
|
|
1059
|
+
// Reload if new status is an end state
|
|
1060
|
+
if (this.END_STATUSES.includes(response.status)) {
|
|
1061
|
+
window.location.reload();
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}),
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
}, this.POLLING_FREQUENCY);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
/* eslint-disable class-methods-use-this */
|
|
1072
|
+
|
|
1073
|
+
class DprRecentlyViewedList extends DprPollingStatusClass {
|
|
1074
|
+
static getModuleName () {
|
|
1075
|
+
return 'recently-viewed-list'
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
initialise () {
|
|
1079
|
+
this.POLLING_STATUSES = [];
|
|
1080
|
+
this.POLLING_FREQUENCY = '300000'; // 5 mins
|
|
1081
|
+
|
|
1082
|
+
this.viewedList = document.getElementById('dpr-recently-viewed-component');
|
|
1083
|
+
this.viewedReportData = this.viewedList.getAttribute('data-request-data');
|
|
1084
|
+
this.csrfToken = this.viewedList.getAttribute('data-csrf-token');
|
|
1085
|
+
this.initPollingStatus();
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
initPollingStatus () {
|
|
1089
|
+
setInterval(async () => {
|
|
1090
|
+
if (this.viewedReportData) {
|
|
1091
|
+
const meta = JSON.parse(this.viewedReportData);
|
|
1092
|
+
await Promise.all(
|
|
1093
|
+
meta.map(async (metaData) => {
|
|
1094
|
+
if (metaData.status !== 'EXPIRED') {
|
|
1095
|
+
const response = await this.getExpiredStatus(metaData, this.csrfToken);
|
|
1096
|
+
if (response.isExpired) {
|
|
1097
|
+
window.location.reload();
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}),
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
}, this.POLLING_FREQUENCY);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
|
|
962
1107
|
/* eslint-disable no-new */
|
|
963
1108
|
|
|
964
1109
|
/**
|
|
@@ -981,10 +1126,12 @@ function initAll () {
|
|
|
981
1126
|
Pagination,
|
|
982
1127
|
IconButtonList,
|
|
983
1128
|
DataTable,
|
|
984
|
-
|
|
1129
|
+
DprAsyncPolling,
|
|
985
1130
|
Search,
|
|
986
1131
|
BookmarkToggle,
|
|
987
1132
|
DateInput,
|
|
1133
|
+
DprAsyncRequestList,
|
|
1134
|
+
DprRecentlyViewedList,
|
|
988
1135
|
];
|
|
989
1136
|
|
|
990
1137
|
components.forEach((Component) => {
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
const AsyncReport_1 = require("../../types/AsyncReport");
|
|
7
|
-
const reportStatusUtils_1 = __importDefault(require("../../utils/reportStatusUtils"));
|
|
8
4
|
exports.default = {
|
|
9
5
|
cancelRequest: async ({ req, res, services }) => {
|
|
10
6
|
var _a;
|
|
@@ -16,49 +12,26 @@ exports.default = {
|
|
|
16
12
|
}
|
|
17
13
|
},
|
|
18
14
|
renderPolling: async ({ req, res, services }) => {
|
|
19
|
-
var _a
|
|
15
|
+
var _a;
|
|
20
16
|
const csrfToken = res.locals.csrfToken || 'csrfToken';
|
|
21
|
-
const token = ((_a = res.locals.user) === null || _a === void 0 ? void 0 : _a.token) ? res.locals.user.token : 'token';
|
|
22
17
|
const { reportId, variantId, executionId } = req.params;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (reportStatusUtils_1.default.timeoutRequest(reportData.timestamp.requested) && reportData.status !== AsyncReport_1.RequestStatus.READY) {
|
|
26
|
-
statusResponse = {
|
|
27
|
-
status: AsyncReport_1.RequestStatus.FAILED,
|
|
28
|
-
errorMessage: 'Request taking too long. Request Halted',
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
else if (reportData.status === AsyncReport_1.RequestStatus.FAILED) {
|
|
32
|
-
statusResponse = {
|
|
33
|
-
status: AsyncReport_1.RequestStatus.FAILED,
|
|
34
|
-
errorMessage: reportData.errorMessage,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
else if (reportData.status === AsyncReport_1.RequestStatus.ABORTED) {
|
|
38
|
-
statusResponse = {
|
|
39
|
-
status: AsyncReport_1.RequestStatus.ABORTED,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
statusResponse = await reportStatusUtils_1.default.getStatus(token, reportId, variantId, executionId, reportData.status, services, reportData.dataProductDefinitionsPath);
|
|
44
|
-
}
|
|
45
|
-
const { status, errorMessage } = statusResponse;
|
|
46
|
-
if (statusResponse.reportData)
|
|
47
|
-
reportData = statusResponse.reportData;
|
|
18
|
+
const reportData = await services.asyncReportsStore.getReportByExecutionId(executionId);
|
|
19
|
+
const { reportName, name, description, status, tableId, query, timestamp, url, errorMessage } = reportData;
|
|
48
20
|
return {
|
|
49
21
|
pollingRenderData: {
|
|
50
|
-
reportName
|
|
51
|
-
variantName:
|
|
52
|
-
description
|
|
22
|
+
reportName,
|
|
23
|
+
variantName: name,
|
|
24
|
+
description,
|
|
53
25
|
executionId,
|
|
54
26
|
reportId,
|
|
55
27
|
variantId,
|
|
56
28
|
status,
|
|
57
|
-
tableId
|
|
58
|
-
querySummary:
|
|
29
|
+
tableId,
|
|
30
|
+
querySummary: query.summary,
|
|
31
|
+
requestedAt: timestamp.requested,
|
|
59
32
|
csrfToken,
|
|
60
|
-
...(((
|
|
61
|
-
...(
|
|
33
|
+
...(((_a = url.report) === null || _a === void 0 ? void 0 : _a.fullUrl) && { reportUrl: url.report.fullUrl }),
|
|
34
|
+
...(url.request.fullUrl && { requestUrl: url.request.fullUrl }),
|
|
62
35
|
...(errorMessage && { errorMessage }),
|
|
63
36
|
},
|
|
64
37
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { RequestStatus } from '../../types/AsyncReport'
|
|
2
2
|
import { AsyncReportUtilsParams } from '../../types/AsyncReportUtils'
|
|
3
|
-
import ReportStatusUtils from '../../utils/reportStatusUtils'
|
|
4
3
|
|
|
5
4
|
export default {
|
|
6
5
|
cancelRequest: async ({ req, res, services }: AsyncReportUtilsParams) => {
|
|
7
6
|
const token = res.locals.user?.token ? res.locals.user.token : 'token'
|
|
8
7
|
const { reportId, variantId, executionId } = req.body
|
|
8
|
+
|
|
9
9
|
const response = await services.reportingService.cancelAsyncRequest(token, reportId, variantId, executionId)
|
|
10
10
|
if (response && response.cancellationSucceeded) {
|
|
11
11
|
await services.asyncReportsStore.updateStatus(executionId, RequestStatus.ABORTED)
|
|
@@ -14,52 +14,26 @@ export default {
|
|
|
14
14
|
|
|
15
15
|
renderPolling: async ({ req, res, services }: AsyncReportUtilsParams) => {
|
|
16
16
|
const csrfToken = (res.locals.csrfToken as unknown as string) || 'csrfToken'
|
|
17
|
-
const token = res.locals.user?.token ? res.locals.user.token : 'token'
|
|
18
17
|
const { reportId, variantId, executionId } = req.params
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
statusResponse = {
|
|
23
|
-
status: RequestStatus.FAILED,
|
|
24
|
-
errorMessage: 'Request taking too long. Request Halted',
|
|
25
|
-
}
|
|
26
|
-
} else if (reportData.status === RequestStatus.FAILED) {
|
|
27
|
-
statusResponse = {
|
|
28
|
-
status: RequestStatus.FAILED,
|
|
29
|
-
errorMessage: reportData.errorMessage,
|
|
30
|
-
}
|
|
31
|
-
} else if (reportData.status === RequestStatus.ABORTED) {
|
|
32
|
-
statusResponse = {
|
|
33
|
-
status: RequestStatus.ABORTED,
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
statusResponse = await ReportStatusUtils.getStatus(
|
|
37
|
-
token,
|
|
38
|
-
reportId,
|
|
39
|
-
variantId,
|
|
40
|
-
executionId,
|
|
41
|
-
reportData.status,
|
|
42
|
-
services,
|
|
43
|
-
reportData.dataProductDefinitionsPath,
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
const { status, errorMessage } = statusResponse
|
|
47
|
-
if (statusResponse.reportData) reportData = statusResponse.reportData
|
|
18
|
+
|
|
19
|
+
const reportData = await services.asyncReportsStore.getReportByExecutionId(executionId)
|
|
20
|
+
const { reportName, name, description, status, tableId, query, timestamp, url, errorMessage } = reportData
|
|
48
21
|
|
|
49
22
|
return {
|
|
50
23
|
pollingRenderData: {
|
|
51
|
-
reportName
|
|
52
|
-
variantName:
|
|
53
|
-
description
|
|
24
|
+
reportName,
|
|
25
|
+
variantName: name,
|
|
26
|
+
description,
|
|
54
27
|
executionId,
|
|
55
28
|
reportId,
|
|
56
29
|
variantId,
|
|
57
30
|
status,
|
|
58
|
-
tableId
|
|
59
|
-
querySummary:
|
|
31
|
+
tableId,
|
|
32
|
+
querySummary: query.summary,
|
|
33
|
+
requestedAt: timestamp.requested,
|
|
60
34
|
csrfToken,
|
|
61
|
-
...(
|
|
62
|
-
...(
|
|
35
|
+
...(url.report?.fullUrl && { reportUrl: url.report.fullUrl }),
|
|
36
|
+
...(url.request.fullUrl && { requestUrl: url.request.fullUrl }),
|
|
63
37
|
...(errorMessage && { errorMessage }),
|
|
64
38
|
},
|
|
65
39
|
}
|
|
@@ -18,10 +18,21 @@
|
|
|
18
18
|
{% set errorMessage = data.errorMessage %}
|
|
19
19
|
{% set executionId = data.executionId %}
|
|
20
20
|
{% set csrfToken = data.csrfToken %}
|
|
21
|
+
{% set requestedAt = data.requestedAt %}
|
|
21
22
|
{% set descriptionClasses = 'govuk-!-margin-top-4 govuk-!-margin-bottom-6'%}
|
|
22
23
|
|
|
24
|
+
{% set meta = {
|
|
25
|
+
reportId: reportId,
|
|
26
|
+
variantId: variantId,
|
|
27
|
+
executionId: executionId,
|
|
28
|
+
status: status,
|
|
29
|
+
requestedAt: requestedAt
|
|
30
|
+
}%}
|
|
31
|
+
|
|
23
32
|
<div id="async-request-polling-status"
|
|
24
|
-
data-current-status={{ status }}
|
|
33
|
+
data-current-status='{{ status }}'
|
|
34
|
+
data-request-data='{{ meta | dump | safe }}'
|
|
35
|
+
data-csrf-token="{{ csrfToken }}"
|
|
25
36
|
data-dpr-module="async-polling-content">
|
|
26
37
|
|
|
27
38
|
{% set filtersHtml %}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.filterReports = exports.setDataFromStatus = exports.formatCardData = void 0;
|
|
27
|
+
const AsyncReport_1 = require("../../types/AsyncReport");
|
|
28
|
+
const reportStatusHelper_1 = require("../../utils/reportStatusHelper");
|
|
29
|
+
const ReportListHelper = __importStar(require("../../utils/reportsListHelper"));
|
|
30
|
+
const formatCardData = (requestedReportsData) => {
|
|
31
|
+
const reportData = JSON.parse(JSON.stringify(requestedReportsData));
|
|
32
|
+
const { executionId, reportId, variantId, name: text, description, query, status, timestamp, dataProductDefinitionsPath, } = reportData;
|
|
33
|
+
const summary = query.summary;
|
|
34
|
+
return {
|
|
35
|
+
id: executionId,
|
|
36
|
+
text,
|
|
37
|
+
description,
|
|
38
|
+
...(0, exports.setDataFromStatus)(status, reportData),
|
|
39
|
+
tag: 'MIS',
|
|
40
|
+
summary,
|
|
41
|
+
status,
|
|
42
|
+
meta: {
|
|
43
|
+
reportId,
|
|
44
|
+
variantId,
|
|
45
|
+
executionId,
|
|
46
|
+
status,
|
|
47
|
+
requestedAt: timestamp.requested,
|
|
48
|
+
dataProductDefinitionsPath,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
exports.formatCardData = formatCardData;
|
|
53
|
+
const setDataFromStatus = (status, requestedReportsData) => {
|
|
54
|
+
let timestamp;
|
|
55
|
+
let href;
|
|
56
|
+
const { url, timestamp: time } = requestedReportsData;
|
|
57
|
+
const retryParam = `&retryId=${requestedReportsData.executionId}`;
|
|
58
|
+
switch (status) {
|
|
59
|
+
case AsyncReport_1.RequestStatus.FAILED: {
|
|
60
|
+
const failedTime = time.failed ? new Date(time.failed).toLocaleString() : new Date().toLocaleString();
|
|
61
|
+
href = `${url.polling.fullUrl}`;
|
|
62
|
+
timestamp = `Failed at: ${failedTime}`;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case AsyncReport_1.RequestStatus.ABORTED: {
|
|
66
|
+
href = `${url.request.fullUrl}${retryParam}`;
|
|
67
|
+
timestamp = `Aborted at: ${new Date(time.aborted).toLocaleString()}`;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case AsyncReport_1.RequestStatus.FINISHED:
|
|
71
|
+
href = url.report.fullUrl;
|
|
72
|
+
timestamp = `Ready at: ${new Date(time.completed).toLocaleString()}`;
|
|
73
|
+
break;
|
|
74
|
+
case AsyncReport_1.RequestStatus.EXPIRED: {
|
|
75
|
+
href = `${url.request.fullUrl}${retryParam}`;
|
|
76
|
+
timestamp = `Expired at: ${new Date(time.expired).toLocaleString()}`;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
case AsyncReport_1.RequestStatus.SUBMITTED:
|
|
80
|
+
case AsyncReport_1.RequestStatus.STARTED:
|
|
81
|
+
case AsyncReport_1.RequestStatus.PICKED:
|
|
82
|
+
href = url.polling.fullUrl;
|
|
83
|
+
timestamp = `Requested at: ${new Date(time.requested).toLocaleString()}`;
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
timestamp = `Last viewed: ${new Date(time.lastViewed).toLocaleString()}`;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
timestamp,
|
|
91
|
+
href,
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
exports.setDataFromStatus = setDataFromStatus;
|
|
95
|
+
const filterReports = (report) => {
|
|
96
|
+
return !report.timestamp.lastViewed && !report.timestamp.retried;
|
|
97
|
+
};
|
|
98
|
+
exports.filterReports = filterReports;
|
|
99
|
+
exports.default = {
|
|
100
|
+
getRequestStatus: async ({ req, res, services }) => {
|
|
101
|
+
const { executionId, status: currentStatus } = req.body;
|
|
102
|
+
const response = await (0, reportStatusHelper_1.getStatus)({ req, res, services });
|
|
103
|
+
if (currentStatus !== response.status) {
|
|
104
|
+
await services.asyncReportsStore.updateStatus(executionId, response.status, response.errorMessage);
|
|
105
|
+
response.reportData = await services.asyncReportsStore.getReportByExecutionId(executionId);
|
|
106
|
+
}
|
|
107
|
+
return response;
|
|
108
|
+
},
|
|
109
|
+
renderList: async ({ services, res, maxRows, }) => {
|
|
110
|
+
const csrfToken = res.locals.csrfToken || 'csrfToken';
|
|
111
|
+
const requestedReportsData = await services.asyncReportsStore.getAllReports();
|
|
112
|
+
let cardData = await ReportListHelper.formatCards(requestedReportsData, exports.filterReports, exports.formatCardData);
|
|
113
|
+
if (maxRows)
|
|
114
|
+
cardData = cardData.slice(0, maxRows);
|
|
115
|
+
const head = {
|
|
116
|
+
title: 'Requested Reports',
|
|
117
|
+
icon: 'hourglass',
|
|
118
|
+
id: 'requested-reports',
|
|
119
|
+
...(cardData.length && { href: './async-reports/requested' }),
|
|
120
|
+
...(!cardData.length && { emptyMessage: 'You have 0 requested reports' }),
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
head,
|
|
124
|
+
cardData,
|
|
125
|
+
tableData: ReportListHelper.formatTable(cardData),
|
|
126
|
+
total: ReportListHelper.getTotals(cardData, maxRows),
|
|
127
|
+
meta: ReportListHelper.getMeta(cardData),
|
|
128
|
+
csrfToken,
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { CardData, RenderTableListResponse } from '../table-card-group/types'
|
|
2
|
+
import { AsyncReportUtilsParams } from '../../types/AsyncReportUtils'
|
|
3
|
+
import { AsyncReportData, RequestStatus } from '../../types/AsyncReport'
|
|
4
|
+
import { getStatus } from '../../utils/reportStatusHelper'
|
|
5
|
+
import * as ReportListHelper from '../../utils/reportsListHelper'
|
|
6
|
+
|
|
7
|
+
export const formatCardData = (requestedReportsData: AsyncReportData): CardData => {
|
|
8
|
+
const reportData: AsyncReportData = JSON.parse(JSON.stringify(requestedReportsData))
|
|
9
|
+
const {
|
|
10
|
+
executionId,
|
|
11
|
+
reportId,
|
|
12
|
+
variantId,
|
|
13
|
+
name: text,
|
|
14
|
+
description,
|
|
15
|
+
query,
|
|
16
|
+
status,
|
|
17
|
+
timestamp,
|
|
18
|
+
dataProductDefinitionsPath,
|
|
19
|
+
} = reportData
|
|
20
|
+
const summary = query.summary as { name: string; value: string }[]
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
id: executionId,
|
|
24
|
+
text,
|
|
25
|
+
description,
|
|
26
|
+
...setDataFromStatus(status, reportData),
|
|
27
|
+
tag: 'MIS',
|
|
28
|
+
summary,
|
|
29
|
+
status,
|
|
30
|
+
meta: {
|
|
31
|
+
reportId,
|
|
32
|
+
variantId,
|
|
33
|
+
executionId,
|
|
34
|
+
status,
|
|
35
|
+
requestedAt: timestamp.requested,
|
|
36
|
+
dataProductDefinitionsPath,
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const setDataFromStatus = (status: RequestStatus, requestedReportsData: AsyncReportData) => {
|
|
42
|
+
let timestamp
|
|
43
|
+
let href
|
|
44
|
+
const { url, timestamp: time } = requestedReportsData
|
|
45
|
+
const retryParam = `&retryId=${requestedReportsData.executionId}`
|
|
46
|
+
switch (status) {
|
|
47
|
+
case RequestStatus.FAILED: {
|
|
48
|
+
const failedTime = time.failed ? new Date(time.failed).toLocaleString() : new Date().toLocaleString()
|
|
49
|
+
href = `${url.polling.fullUrl}`
|
|
50
|
+
timestamp = `Failed at: ${failedTime}`
|
|
51
|
+
break
|
|
52
|
+
}
|
|
53
|
+
case RequestStatus.ABORTED: {
|
|
54
|
+
href = `${url.request.fullUrl}${retryParam}`
|
|
55
|
+
timestamp = `Aborted at: ${new Date(time.aborted).toLocaleString()}`
|
|
56
|
+
break
|
|
57
|
+
}
|
|
58
|
+
case RequestStatus.FINISHED:
|
|
59
|
+
href = url.report.fullUrl
|
|
60
|
+
timestamp = `Ready at: ${new Date(time.completed).toLocaleString()}`
|
|
61
|
+
break
|
|
62
|
+
case RequestStatus.EXPIRED: {
|
|
63
|
+
href = `${url.request.fullUrl}${retryParam}`
|
|
64
|
+
timestamp = `Expired at: ${new Date(time.expired).toLocaleString()}`
|
|
65
|
+
break
|
|
66
|
+
}
|
|
67
|
+
case RequestStatus.SUBMITTED:
|
|
68
|
+
case RequestStatus.STARTED:
|
|
69
|
+
case RequestStatus.PICKED:
|
|
70
|
+
href = url.polling.fullUrl
|
|
71
|
+
timestamp = `Requested at: ${new Date(time.requested).toLocaleString()}`
|
|
72
|
+
break
|
|
73
|
+
default:
|
|
74
|
+
timestamp = `Last viewed: ${new Date(time.lastViewed).toLocaleString()}`
|
|
75
|
+
break
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
timestamp,
|
|
80
|
+
href,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const filterReports = (report: AsyncReportData) => {
|
|
85
|
+
return !report.timestamp.lastViewed && !report.timestamp.retried
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default {
|
|
89
|
+
getRequestStatus: async ({ req, res, services }: AsyncReportUtilsParams) => {
|
|
90
|
+
const { executionId, status: currentStatus } = req.body
|
|
91
|
+
const response = await getStatus({ req, res, services })
|
|
92
|
+
|
|
93
|
+
if (currentStatus !== response.status) {
|
|
94
|
+
await services.asyncReportsStore.updateStatus(
|
|
95
|
+
executionId,
|
|
96
|
+
response.status as RequestStatus,
|
|
97
|
+
response.errorMessage,
|
|
98
|
+
)
|
|
99
|
+
response.reportData = await services.asyncReportsStore.getReportByExecutionId(executionId)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return response
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
renderList: async ({
|
|
106
|
+
services,
|
|
107
|
+
res,
|
|
108
|
+
maxRows,
|
|
109
|
+
}: { maxRows?: number } & AsyncReportUtilsParams): Promise<RenderTableListResponse> => {
|
|
110
|
+
const csrfToken = (res.locals.csrfToken as unknown as string) || 'csrfToken'
|
|
111
|
+
const requestedReportsData: AsyncReportData[] = await services.asyncReportsStore.getAllReports()
|
|
112
|
+
|
|
113
|
+
let cardData = await ReportListHelper.formatCards(requestedReportsData, filterReports, formatCardData)
|
|
114
|
+
if (maxRows) cardData = cardData.slice(0, maxRows)
|
|
115
|
+
|
|
116
|
+
const head = {
|
|
117
|
+
title: 'Requested Reports',
|
|
118
|
+
icon: 'hourglass',
|
|
119
|
+
id: 'requested-reports',
|
|
120
|
+
...(cardData.length && { href: './async-reports/requested' }),
|
|
121
|
+
...(!cardData.length && { emptyMessage: 'You have 0 requested reports' }),
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
head,
|
|
126
|
+
cardData,
|
|
127
|
+
tableData: ReportListHelper.formatTable(cardData),
|
|
128
|
+
total: ReportListHelper.getTotals(cardData, maxRows),
|
|
129
|
+
meta: ReportListHelper.getMeta(cardData),
|
|
130
|
+
csrfToken,
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{% from "components/table-card-group/view.njk" import dprTableCardGroup %}
|
|
2
|
+
|
|
3
|
+
{% macro dprAsyncRequestList(head, cardData, tableData, total, meta, csrfToken) %}
|
|
4
|
+
<div id="dpr-async-request-component" data-dpr-module="async-request-list" data-request-data='{{ meta | dump | safe }}' data-csrf-token="{{ csrfToken }}">
|
|
5
|
+
{{ dprTableCardGroup(
|
|
6
|
+
head,
|
|
7
|
+
cardData,
|
|
8
|
+
tableData,
|
|
9
|
+
total
|
|
10
|
+
)}}
|
|
11
|
+
</div>
|
|
12
|
+
{% endmacro %}
|