@ministryofjustice/hmpps-digital-prison-reporting-frontend 3.10.2 → 3.10.3
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/components/async-filters/utils.js +15 -0
- package/dpr/components/async-filters/utils.ts +17 -0
- package/dpr/components/async-polling/utils.js +31 -35
- package/dpr/components/async-polling/utils.ts +38 -43
- package/dpr/components/async-report-list/utils.js +14 -24
- package/dpr/components/async-report-list/utils.ts +45 -54
- package/dpr/components/async-reports-list/utils/asyncReportsUtils.js +1 -2
- package/dpr/components/async-reports-list/utils/asyncReportsUtils.ts +1 -2
- package/dpr/routes/asyncReports.js +65 -39
- package/dpr/routes/asyncReports.ts +67 -40
- package/dpr/views/async-error.njk +7 -3
- package/package.json +1 -1
- package/package.zip +0 -0
|
@@ -136,4 +136,19 @@ exports.default = {
|
|
|
136
136
|
}
|
|
137
137
|
return redirect;
|
|
138
138
|
},
|
|
139
|
+
handleError: (error, req) => {
|
|
140
|
+
const filters = Object.keys(req.body)
|
|
141
|
+
.filter((attr) => attr.includes('filters.'))
|
|
142
|
+
.filter((attr) => !!req.body[attr])
|
|
143
|
+
.map((attr) => {
|
|
144
|
+
return { name: attr, value: req.body[attr] };
|
|
145
|
+
});
|
|
146
|
+
return {
|
|
147
|
+
title: 'Request Failed',
|
|
148
|
+
description: 'Your report has failed to generate. The issue has been reported to admin staff',
|
|
149
|
+
retry: true,
|
|
150
|
+
error: error.data,
|
|
151
|
+
filters,
|
|
152
|
+
};
|
|
153
|
+
},
|
|
139
154
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Request } from 'express'
|
|
1
2
|
import Dict = NodeJS.Dict
|
|
2
3
|
import { components } from '../../types/api'
|
|
3
4
|
import FilterUtils from '../filters/utils'
|
|
@@ -161,4 +162,20 @@ export default {
|
|
|
161
162
|
|
|
162
163
|
return redirect
|
|
163
164
|
},
|
|
165
|
+
|
|
166
|
+
handleError: (error: Dict<string>, req: Request) => {
|
|
167
|
+
const filters = Object.keys(req.body)
|
|
168
|
+
.filter((attr) => attr.includes('filters.'))
|
|
169
|
+
.filter((attr) => !!req.body[attr])
|
|
170
|
+
.map((attr) => {
|
|
171
|
+
return { name: attr, value: req.body[attr] }
|
|
172
|
+
})
|
|
173
|
+
return {
|
|
174
|
+
title: 'Request Failed',
|
|
175
|
+
description: 'Your report has failed to generate. The issue has been reported to admin staff',
|
|
176
|
+
retry: true,
|
|
177
|
+
error: error.data,
|
|
178
|
+
filters,
|
|
179
|
+
}
|
|
180
|
+
},
|
|
164
181
|
}
|
|
@@ -17,6 +17,8 @@ const getStatus = async (token, reportId, variantId, executionId, currentStatus,
|
|
|
17
17
|
errorMessage = data.userMessage;
|
|
18
18
|
status = currentStatus === AsyncReport_1.RequestStatus.FINISHED ? AsyncReport_1.RequestStatus.EXPIRED : AsyncReport_1.RequestStatus.FAILED;
|
|
19
19
|
}
|
|
20
|
+
if (typeof status === 'number')
|
|
21
|
+
status = AsyncReport_1.RequestStatus.FAILED;
|
|
20
22
|
const res = {
|
|
21
23
|
status,
|
|
22
24
|
...(errorMessage && { errorMessage }),
|
|
@@ -42,43 +44,37 @@ exports.default = {
|
|
|
42
44
|
getStatus,
|
|
43
45
|
renderPolling: async ({ req, res, dataSources, asyncReportsStore, next }) => {
|
|
44
46
|
var _a;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
errorMessage: 'Request taking too long. Request Halted',
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
statusResponse = await getStatus(token, reportId, variantId, executionId, reportData.status, dataSources, asyncReportsStore, reportData.dataProductDefinitionsPath);
|
|
58
|
-
}
|
|
59
|
-
const { status, errorMessage } = statusResponse;
|
|
60
|
-
if (statusResponse.reportData)
|
|
61
|
-
reportData = statusResponse.reportData;
|
|
62
|
-
return {
|
|
63
|
-
pollingRenderData: {
|
|
64
|
-
reportName: reportData.reportName,
|
|
65
|
-
variantName: reportData.name,
|
|
66
|
-
variantDescription: reportData.description,
|
|
67
|
-
executionId,
|
|
68
|
-
reportId,
|
|
69
|
-
variantId,
|
|
70
|
-
status,
|
|
71
|
-
tableId: reportData.tableId,
|
|
72
|
-
querySummary: reportData.query.summary,
|
|
73
|
-
...(((_a = reportData.url.report) === null || _a === void 0 ? void 0 : _a.fullUrl) && { reportUrl: reportData.url.report.fullUrl }),
|
|
74
|
-
...(reportData.url.request.fullUrl && { requestUrl: reportData.url.request.fullUrl }),
|
|
75
|
-
...(errorMessage && { errorMessage }),
|
|
76
|
-
},
|
|
47
|
+
const { token } = res.locals.user || 'token';
|
|
48
|
+
const { reportId, variantId, executionId } = req.params;
|
|
49
|
+
let reportData = await asyncReportsStore.getReportByExecutionId(executionId);
|
|
50
|
+
let statusResponse;
|
|
51
|
+
if ((0, exports.timeoutRequest)(reportData.timestamp.requested)) {
|
|
52
|
+
statusResponse = {
|
|
53
|
+
status: AsyncReport_1.RequestStatus.FAILED,
|
|
54
|
+
errorMessage: 'Request taking too long. Request Halted',
|
|
77
55
|
};
|
|
78
56
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return false;
|
|
57
|
+
else {
|
|
58
|
+
statusResponse = await getStatus(token, reportId, variantId, executionId, reportData.status, dataSources, asyncReportsStore, reportData.dataProductDefinitionsPath);
|
|
82
59
|
}
|
|
60
|
+
const { status, errorMessage } = statusResponse;
|
|
61
|
+
if (statusResponse.reportData)
|
|
62
|
+
reportData = statusResponse.reportData;
|
|
63
|
+
return {
|
|
64
|
+
pollingRenderData: {
|
|
65
|
+
reportName: reportData.reportName,
|
|
66
|
+
variantName: reportData.name,
|
|
67
|
+
variantDescription: reportData.description,
|
|
68
|
+
executionId,
|
|
69
|
+
reportId,
|
|
70
|
+
variantId,
|
|
71
|
+
status,
|
|
72
|
+
tableId: reportData.tableId,
|
|
73
|
+
querySummary: reportData.query.summary,
|
|
74
|
+
...(((_a = reportData.url.report) === null || _a === void 0 ? void 0 : _a.fullUrl) && { reportUrl: reportData.url.report.fullUrl }),
|
|
75
|
+
...(reportData.url.request.fullUrl && { requestUrl: reportData.url.request.fullUrl }),
|
|
76
|
+
...(errorMessage && { errorMessage }),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
83
79
|
},
|
|
84
80
|
};
|
|
@@ -35,6 +35,7 @@ const getStatus = async (
|
|
|
35
35
|
status = currentStatus === RequestStatus.FINISHED ? RequestStatus.EXPIRED : RequestStatus.FAILED
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
if (typeof status === 'number') status = RequestStatus.FAILED
|
|
38
39
|
const res: GetStatusUtilsResponse = {
|
|
39
40
|
status,
|
|
40
41
|
...(errorMessage && { errorMessage }),
|
|
@@ -57,7 +58,6 @@ export const timeoutRequest = (requestTime: Date) => {
|
|
|
57
58
|
const diffMins = Math.round(((diffMs % 86400000) % 3600000) / 60000)
|
|
58
59
|
return diffMins >= TIMEOUT_MINS_MAX
|
|
59
60
|
}
|
|
60
|
-
|
|
61
61
|
interface GetStatusUtilsResponse {
|
|
62
62
|
status: RequestStatus
|
|
63
63
|
errorMessage: string
|
|
@@ -67,51 +67,46 @@ interface GetStatusUtilsResponse {
|
|
|
67
67
|
export default {
|
|
68
68
|
getStatus,
|
|
69
69
|
renderPolling: async ({ req, res, dataSources, asyncReportsStore, next }: AsyncReportUtilsParams) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
let reportData = await asyncReportsStore.getReportByExecutionId(executionId)
|
|
70
|
+
const { token } = res.locals.user || 'token'
|
|
71
|
+
const { reportId, variantId, executionId } = req.params
|
|
72
|
+
let reportData = await asyncReportsStore.getReportByExecutionId(executionId)
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
} else {
|
|
82
|
-
statusResponse = await getStatus(
|
|
83
|
-
token,
|
|
84
|
-
reportId,
|
|
85
|
-
variantId,
|
|
86
|
-
executionId,
|
|
87
|
-
reportData.status,
|
|
88
|
-
dataSources,
|
|
89
|
-
asyncReportsStore,
|
|
90
|
-
reportData.dataProductDefinitionsPath,
|
|
91
|
-
)
|
|
74
|
+
let statusResponse
|
|
75
|
+
if (timeoutRequest(reportData.timestamp.requested)) {
|
|
76
|
+
statusResponse = {
|
|
77
|
+
status: RequestStatus.FAILED,
|
|
78
|
+
errorMessage: 'Request taking too long. Request Halted',
|
|
92
79
|
}
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
} else {
|
|
81
|
+
statusResponse = await getStatus(
|
|
82
|
+
token,
|
|
83
|
+
reportId,
|
|
84
|
+
variantId,
|
|
85
|
+
executionId,
|
|
86
|
+
reportData.status,
|
|
87
|
+
dataSources,
|
|
88
|
+
asyncReportsStore,
|
|
89
|
+
reportData.dataProductDefinitionsPath,
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
const { status, errorMessage } = statusResponse
|
|
93
|
+
if (statusResponse.reportData) reportData = statusResponse.reportData
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
} catch (error) {
|
|
113
|
-
next(error)
|
|
114
|
-
return false
|
|
95
|
+
return {
|
|
96
|
+
pollingRenderData: {
|
|
97
|
+
reportName: reportData.reportName,
|
|
98
|
+
variantName: reportData.name,
|
|
99
|
+
variantDescription: reportData.description,
|
|
100
|
+
executionId,
|
|
101
|
+
reportId,
|
|
102
|
+
variantId,
|
|
103
|
+
status,
|
|
104
|
+
tableId: reportData.tableId,
|
|
105
|
+
querySummary: reportData.query.summary,
|
|
106
|
+
...(reportData.url.report?.fullUrl && { reportUrl: reportData.url.report.fullUrl }),
|
|
107
|
+
...(reportData.url.request.fullUrl && { requestUrl: reportData.url.request.fullUrl }),
|
|
108
|
+
...(errorMessage && { errorMessage }),
|
|
109
|
+
},
|
|
115
110
|
}
|
|
116
111
|
},
|
|
117
112
|
}
|
|
@@ -11,25 +11,19 @@ const utils_2 = __importDefault(require("../async-columns/utils"));
|
|
|
11
11
|
const utils_3 = __importDefault(require("../pagination/utils"));
|
|
12
12
|
const utils_4 = __importDefault(require("../icon-button-list/utils"));
|
|
13
13
|
const initDataSources = ({ req, res, next, asyncReportsStore, dataSources }) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return [reportDefinitionPromise, reportDataPromise, reportDataCountPromise, stateDataPromise];
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
next(error);
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
14
|
+
const { token } = res.locals.user || 'token';
|
|
15
|
+
const { reportId, reportVariantId, tableId } = req.params;
|
|
16
|
+
const { selectedPage = 1, pageSize = 10 } = req.query;
|
|
17
|
+
const dataProductDefinitionsPath = req.query.dataProductDefinitionsPath;
|
|
18
|
+
const reportDefinitionPromise = dataSources.getDefinition(token, reportId, reportVariantId, dataProductDefinitionsPath);
|
|
19
|
+
const reportDataPromise = dataSources.getAsyncReport(token, reportId, reportVariantId, tableId, {
|
|
20
|
+
selectedPage: +selectedPage,
|
|
21
|
+
pageSize: +pageSize,
|
|
22
|
+
dataProductDefinitionsPath,
|
|
23
|
+
});
|
|
24
|
+
const reportDataCountPromise = dataSources.getAsyncCount(token, tableId);
|
|
25
|
+
const stateDataPromise = asyncReportsStore.getReportByTableId(tableId);
|
|
26
|
+
return [reportDefinitionPromise, reportDataPromise, reportDataCountPromise, stateDataPromise];
|
|
33
27
|
};
|
|
34
28
|
exports.initDataSources = initDataSources;
|
|
35
29
|
const renderReport = async ({ req, res, next, asyncReportsStore, recentlyViewedStoreService, dataSources, }) => {
|
|
@@ -38,8 +32,7 @@ const renderReport = async ({ req, res, next, asyncReportsStore, recentlyViewedS
|
|
|
38
32
|
let renderData = {};
|
|
39
33
|
let reportStateData;
|
|
40
34
|
if (dataPromises) {
|
|
41
|
-
await Promise.all(dataPromises)
|
|
42
|
-
.then((resolvedData) => {
|
|
35
|
+
await Promise.all(dataPromises).then((resolvedData) => {
|
|
43
36
|
const definition = resolvedData[0];
|
|
44
37
|
const reportData = resolvedData[1];
|
|
45
38
|
const count = resolvedData[2];
|
|
@@ -65,9 +58,6 @@ const renderReport = async ({ req, res, next, asyncReportsStore, recentlyViewedS
|
|
|
65
58
|
appliedFilters: query.summary,
|
|
66
59
|
classification,
|
|
67
60
|
};
|
|
68
|
-
})
|
|
69
|
-
.catch((err) => {
|
|
70
|
-
next(err);
|
|
71
61
|
});
|
|
72
62
|
}
|
|
73
63
|
if (Object.keys(renderData).length && Object.keys(reportStateData).length) {
|
|
@@ -11,30 +11,25 @@ import { AsyncReportUtilsParams } from '../../types/AsyncReportUtils'
|
|
|
11
11
|
import { AsyncReportData } from '../../types/AsyncReport'
|
|
12
12
|
|
|
13
13
|
export const initDataSources = ({ req, res, next, asyncReportsStore, dataSources }: AsyncReportUtilsParams) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const stateDataPromise = asyncReportsStore.getReportByTableId(tableId)
|
|
14
|
+
const { token } = res.locals.user || 'token'
|
|
15
|
+
const { reportId, reportVariantId, tableId } = req.params
|
|
16
|
+
const { selectedPage = 1, pageSize = 10 } = req.query
|
|
17
|
+
const dataProductDefinitionsPath = <string>req.query.dataProductDefinitionsPath
|
|
18
|
+
const reportDefinitionPromise = dataSources.getDefinition(
|
|
19
|
+
token,
|
|
20
|
+
reportId,
|
|
21
|
+
reportVariantId,
|
|
22
|
+
dataProductDefinitionsPath,
|
|
23
|
+
)
|
|
24
|
+
const reportDataPromise = dataSources.getAsyncReport(token, reportId, reportVariantId, tableId, {
|
|
25
|
+
selectedPage: +selectedPage,
|
|
26
|
+
pageSize: +pageSize,
|
|
27
|
+
dataProductDefinitionsPath,
|
|
28
|
+
})
|
|
29
|
+
const reportDataCountPromise = dataSources.getAsyncCount(token, tableId)
|
|
30
|
+
const stateDataPromise = asyncReportsStore.getReportByTableId(tableId)
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
} catch (error) {
|
|
35
|
-
next(error)
|
|
36
|
-
return false
|
|
37
|
-
}
|
|
32
|
+
return [reportDefinitionPromise, reportDataPromise, reportDataCountPromise, stateDataPromise]
|
|
38
33
|
}
|
|
39
34
|
|
|
40
35
|
export const renderReport = async ({
|
|
@@ -52,40 +47,36 @@ export const renderReport = async ({
|
|
|
52
47
|
let renderData = {}
|
|
53
48
|
let reportStateData: AsyncReportData
|
|
54
49
|
if (dataPromises) {
|
|
55
|
-
await Promise.all(dataPromises)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
reportStateData = <AsyncReportData>resolvedData[3]
|
|
50
|
+
await Promise.all(dataPromises).then((resolvedData) => {
|
|
51
|
+
const definition = resolvedData[0] as unknown as components['schemas']['SingleVariantReportDefinition']
|
|
52
|
+
const reportData = <Array<Dict<string>>>resolvedData[1]
|
|
53
|
+
const count = <number>resolvedData[2]
|
|
54
|
+
reportStateData = <AsyncReportData>resolvedData[3]
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
const fieldDefinition = definition.variant.specification.fields
|
|
57
|
+
const { classification } = definition.variant
|
|
64
58
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
59
|
+
const columns = ColumnUtils.getColumns(fieldDefinition, <string[]>reqColumns)
|
|
60
|
+
const url = parseUrl(req)
|
|
61
|
+
const pagination = PaginationUtils.getPaginationData(url, count)
|
|
62
|
+
const actions = ReportActionsUtils.initReportActions(definition.variant, reportStateData)
|
|
63
|
+
const rows = DataTableUtils.mapData(reportData, fieldDefinition, columns.value)
|
|
64
|
+
const head = DataTableUtils.mapAsyncHeader(fieldDefinition, columns.value)
|
|
65
|
+
const { reportName, name: variantName, query, description } = reportStateData
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
.catch((err) => {
|
|
87
|
-
next(err)
|
|
88
|
-
})
|
|
67
|
+
renderData = {
|
|
68
|
+
variantName,
|
|
69
|
+
reportName,
|
|
70
|
+
description,
|
|
71
|
+
rows,
|
|
72
|
+
head,
|
|
73
|
+
columns,
|
|
74
|
+
pagination,
|
|
75
|
+
actions,
|
|
76
|
+
appliedFilters: query.summary,
|
|
77
|
+
classification,
|
|
78
|
+
}
|
|
79
|
+
})
|
|
89
80
|
}
|
|
90
81
|
|
|
91
82
|
if (Object.keys(renderData).length && Object.keys(reportStateData).length) {
|
|
@@ -61,8 +61,7 @@ const setDataFromStatus = (status, requestedReportsData) => {
|
|
|
61
61
|
let href;
|
|
62
62
|
switch (status) {
|
|
63
63
|
case AsyncReport_1.RequestStatus.FAILED: {
|
|
64
|
-
|
|
65
|
-
href = `${requestedReportsData.url.request.fullUrl}${retryParam}`;
|
|
64
|
+
href = `${requestedReportsData.url.polling.fullUrl}`;
|
|
66
65
|
timestamp = `Failed at: ${new Date(requestedReportsData.timestamp.failed).toLocaleString()}`;
|
|
67
66
|
break;
|
|
68
67
|
}
|
|
@@ -58,8 +58,7 @@ const setDataFromStatus = (status: RequestStatus, requestedReportsData: AsyncRep
|
|
|
58
58
|
let href
|
|
59
59
|
switch (status) {
|
|
60
60
|
case RequestStatus.FAILED: {
|
|
61
|
-
|
|
62
|
-
href = `${requestedReportsData.url.request.fullUrl}${retryParam}`
|
|
61
|
+
href = `${requestedReportsData.url.polling.fullUrl}`
|
|
63
62
|
timestamp = `Failed at: ${new Date(requestedReportsData.timestamp.failed).toLocaleString()}`
|
|
64
63
|
break
|
|
65
64
|
}
|
|
@@ -30,16 +30,29 @@ const utils_1 = __importDefault(require("../components/async-filters/utils"));
|
|
|
30
30
|
const AsyncReportListUtils = __importStar(require("../components/async-report-list/utils"));
|
|
31
31
|
const utils_2 = __importDefault(require("../components/async-polling/utils"));
|
|
32
32
|
function routes({ router, asyncReportsStore, recentlyViewedStoreService, dataSources, layoutPath, templatePath = 'dpr/views/', }) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
res.render(`${templatePath}async-request`, {
|
|
36
|
-
title: 'Request Report',
|
|
33
|
+
const asyncErrorHandler = async (req, res) => {
|
|
34
|
+
res.render(`${templatePath}/async-error`, {
|
|
37
35
|
layoutPath,
|
|
38
|
-
|
|
39
|
-
...(await utils_1.default.renderFilters({ req, res, dataSources, next })),
|
|
36
|
+
...req.body,
|
|
40
37
|
});
|
|
41
|
-
}
|
|
42
|
-
|
|
38
|
+
};
|
|
39
|
+
const getReportFiltersHandler = async (req, res, next) => {
|
|
40
|
+
try {
|
|
41
|
+
const filtersRenderData = await utils_1.default.renderFilters({ req, res, dataSources, next });
|
|
42
|
+
res.render(`${templatePath}async-request`, {
|
|
43
|
+
title: 'Request Report',
|
|
44
|
+
layoutPath,
|
|
45
|
+
postEndpoint: '/requestReport/',
|
|
46
|
+
...filtersRenderData,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
req.body.title = 'Report Failed';
|
|
51
|
+
req.body.description = 'Your report has failed to generate. The issue has been reported to admin staff';
|
|
52
|
+
req.body.error = error.data;
|
|
53
|
+
next();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
43
56
|
const asyncRequestHandler = async (req, res, next) => {
|
|
44
57
|
try {
|
|
45
58
|
const redirectToPollingPage = await utils_1.default.requestReport({
|
|
@@ -58,46 +71,59 @@ function routes({ router, asyncReportsStore, recentlyViewedStoreService, dataSou
|
|
|
58
71
|
}
|
|
59
72
|
}
|
|
60
73
|
catch (error) {
|
|
61
|
-
req.body
|
|
74
|
+
req.body = {
|
|
75
|
+
...req.body,
|
|
76
|
+
...utils_1.default.handleError(error, req),
|
|
77
|
+
};
|
|
62
78
|
next();
|
|
63
79
|
}
|
|
64
80
|
};
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
const pollingHandler = async (req, res, next) => {
|
|
82
|
+
try {
|
|
83
|
+
const pollingRenderData = await utils_2.default.renderPolling({
|
|
84
|
+
req,
|
|
85
|
+
res,
|
|
86
|
+
dataSources,
|
|
87
|
+
asyncReportsStore,
|
|
88
|
+
next,
|
|
89
|
+
});
|
|
90
|
+
res.render(`${templatePath}/async-polling`, {
|
|
91
|
+
title: 'Report Request Status',
|
|
92
|
+
layoutPath,
|
|
93
|
+
...pollingRenderData,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
req.body.title = 'Failed to retrieve Report status';
|
|
98
|
+
req.body.description = 'We were unable to retrieve the report status:';
|
|
99
|
+
req.body.error = error.data;
|
|
100
|
+
next();
|
|
101
|
+
}
|
|
78
102
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
res.render(`${templatePath}/async-polling`, {
|
|
83
|
-
title: 'Report Requested',
|
|
84
|
-
layoutPath,
|
|
85
|
-
...(await utils_2.default.renderPolling({ req, res, dataSources, asyncReportsStore, next })),
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
// 3 - load the report data
|
|
89
|
-
router.get('/async-reports/:reportId/:reportVariantId/request/:tableId/report', async (req, res, next) => {
|
|
90
|
-
res.render(`${templatePath}async-report`, {
|
|
91
|
-
layoutPath,
|
|
92
|
-
...(await AsyncReportListUtils.renderReport({
|
|
103
|
+
const getReportListHandler = async (req, res, next) => {
|
|
104
|
+
try {
|
|
105
|
+
const reportRenderData = await AsyncReportListUtils.renderReport({
|
|
93
106
|
req,
|
|
94
107
|
res,
|
|
95
108
|
dataSources,
|
|
96
109
|
asyncReportsStore,
|
|
97
110
|
recentlyViewedStoreService,
|
|
98
111
|
next,
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
|
|
112
|
+
});
|
|
113
|
+
res.render(`${templatePath}async-report`, {
|
|
114
|
+
layoutPath,
|
|
115
|
+
...reportRenderData,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
req.body.title = 'Failed to retrieve Report';
|
|
120
|
+
req.body.description = 'We were unable to retrieve this report for the following reason:';
|
|
121
|
+
next();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
router.get('/async-reports/:reportId/:variantId/request', getReportFiltersHandler, asyncErrorHandler);
|
|
125
|
+
router.post('/requestReport/', asyncRequestHandler, asyncErrorHandler);
|
|
126
|
+
router.get('/async-reports/:reportId/:variantId/request/:executionId', pollingHandler, asyncErrorHandler);
|
|
127
|
+
router.get('/async-reports/:reportId/:reportVariantId/request/:tableId/report', getReportListHandler, asyncErrorHandler);
|
|
102
128
|
}
|
|
103
129
|
exports.default = routes;
|
|
@@ -21,17 +21,30 @@ export default function routes({
|
|
|
21
21
|
layoutPath: string
|
|
22
22
|
templatePath?: string
|
|
23
23
|
}) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
res.render(`${templatePath}async-request`, {
|
|
27
|
-
title: 'Request Report',
|
|
24
|
+
const asyncErrorHandler: RequestHandler = async (req, res) => {
|
|
25
|
+
res.render(`${templatePath}/async-error`, {
|
|
28
26
|
layoutPath,
|
|
29
|
-
|
|
30
|
-
...(await AsyncFiltersUtils.renderFilters({ req, res, dataSources, next })),
|
|
27
|
+
...req.body,
|
|
31
28
|
})
|
|
32
|
-
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const getReportFiltersHandler: RequestHandler = async (req, res, next) => {
|
|
32
|
+
try {
|
|
33
|
+
const filtersRenderData = await AsyncFiltersUtils.renderFilters({ req, res, dataSources, next })
|
|
34
|
+
res.render(`${templatePath}async-request`, {
|
|
35
|
+
title: 'Request Report',
|
|
36
|
+
layoutPath,
|
|
37
|
+
postEndpoint: '/requestReport/',
|
|
38
|
+
...filtersRenderData,
|
|
39
|
+
})
|
|
40
|
+
} catch (error) {
|
|
41
|
+
req.body.title = 'Report Failed'
|
|
42
|
+
req.body.description = 'Your report has failed to generate. The issue has been reported to admin staff'
|
|
43
|
+
req.body.error = error.data
|
|
44
|
+
next()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
33
47
|
|
|
34
|
-
// 2 - handle the post request to request the report data
|
|
35
48
|
const asyncRequestHandler: RequestHandler = async (req, res, next) => {
|
|
36
49
|
try {
|
|
37
50
|
const redirectToPollingPage = await AsyncFiltersUtils.requestReport({
|
|
@@ -48,49 +61,63 @@ export default function routes({
|
|
|
48
61
|
res.end()
|
|
49
62
|
}
|
|
50
63
|
} catch (error) {
|
|
51
|
-
req.body
|
|
64
|
+
req.body = {
|
|
65
|
+
...req.body,
|
|
66
|
+
...AsyncFiltersUtils.handleError(error, req),
|
|
67
|
+
}
|
|
52
68
|
next()
|
|
53
69
|
}
|
|
54
70
|
}
|
|
55
71
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
const pollingHandler: RequestHandler = async (req, res, next) => {
|
|
73
|
+
try {
|
|
74
|
+
const pollingRenderData = await AsyncPollingUtils.renderPolling({
|
|
75
|
+
req,
|
|
76
|
+
res,
|
|
77
|
+
dataSources,
|
|
78
|
+
asyncReportsStore,
|
|
79
|
+
next,
|
|
62
80
|
})
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
})
|
|
81
|
+
res.render(`${templatePath}/async-polling`, {
|
|
82
|
+
title: 'Report Request Status',
|
|
83
|
+
layoutPath,
|
|
84
|
+
...pollingRenderData,
|
|
85
|
+
})
|
|
86
|
+
} catch (error) {
|
|
87
|
+
req.body.title = 'Failed to retrieve Report status'
|
|
88
|
+
req.body.description = 'We were unable to retrieve the report status:'
|
|
89
|
+
req.body.error = error.data
|
|
90
|
+
next()
|
|
91
|
+
}
|
|
69
92
|
}
|
|
70
93
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
router.get('/async-reports/:reportId/:variantId/request/:executionId', async (req, res, next) => {
|
|
75
|
-
res.render(`${templatePath}/async-polling`, {
|
|
76
|
-
title: 'Report Requested',
|
|
77
|
-
layoutPath,
|
|
78
|
-
...(await AsyncPollingUtils.renderPolling({ req, res, dataSources, asyncReportsStore, next })),
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
// 3 - load the report data
|
|
83
|
-
router.get('/async-reports/:reportId/:reportVariantId/request/:tableId/report', async (req, res, next) => {
|
|
84
|
-
res.render(`${templatePath}async-report`, {
|
|
85
|
-
layoutPath,
|
|
86
|
-
...(await AsyncReportListUtils.renderReport({
|
|
94
|
+
const getReportListHandler: RequestHandler = async (req, res, next) => {
|
|
95
|
+
try {
|
|
96
|
+
const reportRenderData = await AsyncReportListUtils.renderReport({
|
|
87
97
|
req,
|
|
88
98
|
res,
|
|
89
99
|
dataSources,
|
|
90
100
|
asyncReportsStore,
|
|
91
101
|
recentlyViewedStoreService,
|
|
92
102
|
next,
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
})
|
|
104
|
+
res.render(`${templatePath}async-report`, {
|
|
105
|
+
layoutPath,
|
|
106
|
+
...reportRenderData,
|
|
107
|
+
})
|
|
108
|
+
} catch (error) {
|
|
109
|
+
req.body.title = 'Failed to retrieve Report'
|
|
110
|
+
req.body.description = 'We were unable to retrieve this report for the following reason:'
|
|
111
|
+
next()
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
router.get('/async-reports/:reportId/:variantId/request', getReportFiltersHandler, asyncErrorHandler)
|
|
116
|
+
router.post('/requestReport/', asyncRequestHandler, asyncErrorHandler)
|
|
117
|
+
router.get('/async-reports/:reportId/:variantId/request/:executionId', pollingHandler, asyncErrorHandler)
|
|
118
|
+
router.get(
|
|
119
|
+
'/async-reports/:reportId/:reportVariantId/request/:tableId/report',
|
|
120
|
+
getReportListHandler,
|
|
121
|
+
asyncErrorHandler,
|
|
122
|
+
)
|
|
96
123
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<p>Status: {{ dprRequestStatusTag(error.status) }}</p>
|
|
13
13
|
|
|
14
14
|
{{ govukErrorSummary({
|
|
15
|
-
titleText:
|
|
15
|
+
titleText: description,
|
|
16
16
|
classes: "govuk-!-margin-top-6",
|
|
17
17
|
errorList: [
|
|
18
18
|
{
|
|
@@ -31,12 +31,16 @@
|
|
|
31
31
|
{% endif %}
|
|
32
32
|
{% endset %}
|
|
33
33
|
|
|
34
|
-
{
|
|
34
|
+
{% if reportName %}
|
|
35
|
+
{{ dprAsyncRequestDetails( reportName, variantName, description, filtersHtml )}}
|
|
36
|
+
{% endif %}
|
|
35
37
|
|
|
36
|
-
{
|
|
38
|
+
{% if retry %}
|
|
39
|
+
{{ govukButton({
|
|
37
40
|
id: "retry-async-request",
|
|
38
41
|
text: "Retry",
|
|
39
42
|
classes: "govuk-button govuk-!-margin-top-5",
|
|
40
43
|
href: href
|
|
41
44
|
}) }}
|
|
45
|
+
{% endif %}
|
|
42
46
|
{% endblock %}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ministryofjustice/hmpps-digital-prison-reporting-frontend",
|
|
3
3
|
"description": "The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.",
|
|
4
|
-
"version": "3.10.
|
|
4
|
+
"version": "3.10.3",
|
|
5
5
|
"main": "dpr/assets/js/all.mjs",
|
|
6
6
|
"sass": "dpr/all.scss",
|
|
7
7
|
"engines": {
|
package/package.zip
CHANGED
|
Binary file
|