@ministryofjustice/hmpps-digital-prison-reporting-frontend 4.28.1 → 4.28.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.
@@ -13,7 +13,7 @@
13
13
  {{ dprRequestDetails(renderData) }}
14
14
 
15
15
  {{ govukInsetText({
16
- html: "<p><strong>Please keep this window open to preserve your progress</strong></p> <p>Your" + type + " will be ready shortly.</p>"
16
+ html: "<p><strong>Please keep this window open to preserve your progress</strong></p> <p>Your " + type + " will be ready shortly.</p>"
17
17
  }) }}
18
18
 
19
19
  <form id="dpr-sync-loading-form" action="./{{ type }}" method="get"></form>
@@ -116,6 +116,17 @@ class ReportingClient {
116
116
  }
117
117
  }).then((response) => response);
118
118
  }
119
+ downloadAsyncReport(token, reportId, variantId, tableId, query, res) {
120
+ this.logInfo("Streaming download data", { reportId, variantId, tableId });
121
+ return this.restClient.getStream(
122
+ {
123
+ path: `/reports/${reportId}/${variantId}/tables/${tableId}/download`,
124
+ query,
125
+ token
126
+ },
127
+ res
128
+ );
129
+ }
119
130
  getAsyncReport(token, reportId, variantId, tableId, query) {
120
131
  this.logInfo("Get Data", { reportId, variantId, tableId });
121
132
  return this.restClient.get({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../dpr/data/reportingClient.ts"],
4
- "sourcesContent": ["import ReportQuery from '../types/ReportQuery'\nimport logger from '../utils/logger'\nimport RestClient from './restClient'\nimport Dict = NodeJS.Dict\nimport { components, operations } from '../types/api'\nimport { ApiConfig, Count, ListWithWarnings } from './types'\nimport type { ResultWithHeaders } from './restClient'\n\nclass ReportingClient {\n restClient: RestClient\n\n constructor(config: ApiConfig) {\n this.restClient = new RestClient('Reporting API Client', config)\n }\n\n getCount(resourceName: string, token: string, countRequest: ReportQuery): Promise<number> {\n logger.info(`Reporting client: Get count. { resourceName: ${resourceName} }`)\n\n return this.restClient\n .get({\n path: `/${resourceName}/count`,\n query: countRequest.toRecordWithFilterPrefix(true),\n token,\n })\n .then((response) => (<Count>response).count)\n }\n\n getList(resourceName: string, token: string, listRequest: ReportQuery): Promise<Array<Dict<string>>> {\n return this.getListWithWarnings(resourceName, token, listRequest).then((response) => response.data)\n }\n\n getListWithWarnings(resourceName: string, token: string, listRequest: ReportQuery): Promise<ListWithWarnings> {\n logger.info(`Reporting client: Get list. { resourceName: ${resourceName} }`)\n\n return this.restClient\n .getWithHeaders<Array<Dict<string>>>({\n path: `/${resourceName}`,\n query: listRequest.toRecordWithFilterPrefix(true),\n token,\n })\n .then((response: ResultWithHeaders<Array<Dict<string>>>) => ({\n data: response.data,\n warnings: {\n noDataAvailable: response.headers['x-no-data-warning'],\n },\n }))\n }\n\n getDefinitionSummary(\n token: string,\n reportId: string,\n definitionsPath?: string,\n ): Promise<components['schemas']['ReportDefinitionSummary']> {\n this.logInfo('Get definition summary', { reportId })\n\n const queryParams: operations['definitionSummary']['parameters']['query'] = {\n ...(definitionsPath && { dataProductDefinitionsPath: definitionsPath }),\n }\n\n return this.restClient\n .get({\n path: `/definitions/${reportId}`,\n query: queryParams,\n token,\n })\n .then((response) => <components['schemas']['ReportDefinitionSummary']>response)\n }\n\n getDefinitions(\n token: string,\n definitionsPath?: string,\n ): Promise<Array<components['schemas']['ReportDefinitionSummary']>> {\n this.logInfo('Get definitions')\n\n const queryParams: operations['definitions_1']['parameters']['query'] = {\n renderMethod: 'HTML',\n ...(definitionsPath && { dataProductDefinitionsPath: definitionsPath }),\n }\n\n return this.restClient\n .get({\n path: '/definitions',\n query: queryParams,\n token,\n })\n .then((response) => <Array<components['schemas']['ReportDefinitionSummary']>>response)\n }\n\n getDefinition(\n token: string,\n reportId: string,\n variantId: string,\n definitionsPath?: string,\n queryData?: Dict<string | string[]>,\n ): Promise<components['schemas']['SingleVariantReportDefinition']> {\n const query = {\n ...queryData,\n dataProductDefinitionsPath: definitionsPath,\n }\n\n this.logInfo('Get definition', { reportId, variantId, ...query })\n\n return this.restClient\n .get({\n path: `/definitions/${reportId}/${variantId}`,\n query,\n token,\n })\n .then((response) => <components['schemas']['SingleVariantReportDefinition']>response)\n }\n\n requestAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n query: Record<string, string | boolean | number>,\n ): Promise<Dict<string>> {\n this.logInfo('Request report', { reportId, variantId })\n\n return this.restClient\n .get({\n path: `/async/reports/${reportId}/${variantId}`,\n token,\n query,\n })\n .then((response) => <Dict<string>>response)\n }\n\n cancelAsyncRequest(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath?: string,\n ): Promise<Dict<string>> {\n this.logInfo('Cancel Request', { reportId, variantId, executionId })\n\n return this.restClient\n .delete({\n path: `/reports/${reportId}/${variantId}/statements/${executionId}`,\n token,\n query: {\n dataProductDefinitionsPath,\n },\n })\n .then((response) => <Dict<string>>response)\n }\n\n getAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n query: Record<string, string | string[]>,\n ): Promise<Array<Dict<string>>> {\n this.logInfo('Get Data', { reportId, variantId, tableId })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${variantId}/tables/${tableId}/result`,\n token,\n query,\n })\n .then((response) => <Array<Dict<string>>>response)\n }\n\n getAsyncSummaryReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n summaryId: string,\n query: Dict<string | number>,\n ): Promise<Array<Dict<string>>> {\n this.logInfo('Get summary data', { reportId, variantId, tableId, summaryId })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${variantId}/tables/${tableId}/result/summary/${summaryId}`,\n token,\n query,\n })\n .then((response) => <Array<Dict<string>>>response)\n }\n\n getAsyncReportStatus(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath?: string,\n tableId?: string,\n ): Promise<components['schemas']['StatementExecutionStatus']> {\n this.logInfo('Get status', { reportId, variantId, tableId, executionId })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${variantId}/statements/${executionId}/status`,\n token,\n query: {\n dataProductDefinitionsPath,\n tableId,\n },\n })\n .then((response) => <components['schemas']['StatementExecutionStatus']>response)\n }\n\n getAsyncCount(token: string, tableId: string, dataProductDefinitionsPath?: string): Promise<number> {\n this.logInfo('Get count', { tableId })\n\n return this.restClient\n .get({\n path: `/report/tables/${tableId}/count`,\n token,\n query: {\n dataProductDefinitionsPath,\n },\n })\n .then((response) => (<Count>response).count)\n }\n\n getAsyncInteractiveCount(\n token: string,\n tableId: string,\n reportId: string,\n id: string,\n filters: ReportQuery,\n ): Promise<number> {\n this.logInfo('Get interactive count', { tableId, reportId, id })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${id}/tables/${tableId}/count`,\n token,\n query: filters.toRecordWithFilterPrefix(true),\n })\n .then((response) => (<Count>response).count)\n }\n\n logInfo(title: string, args?: Dict<string>) {\n logger.info(`Reporting Client: ${title}:`)\n if (args && Object.keys(args).length) logger.info(JSON.stringify(args, null, 2))\n }\n}\n\nexport { ReportingClient }\nexport default ReportingClient\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Response } from 'express'\nimport ReportQuery from '../types/ReportQuery'\nimport logger from '../utils/logger'\nimport RestClient from './restClient'\nimport Dict = NodeJS.Dict\nimport { components, operations } from '../types/api'\nimport { ApiConfig, Count, ListWithWarnings } from './types'\nimport type { ResultWithHeaders } from './restClient'\n\nclass ReportingClient {\n restClient: RestClient\n\n constructor(config: ApiConfig) {\n this.restClient = new RestClient('Reporting API Client', config)\n }\n\n getCount(resourceName: string, token: string, countRequest: ReportQuery): Promise<number> {\n logger.info(`Reporting client: Get count. { resourceName: ${resourceName} }`)\n\n return this.restClient\n .get({\n path: `/${resourceName}/count`,\n query: countRequest.toRecordWithFilterPrefix(true),\n token,\n })\n .then((response) => (<Count>response).count)\n }\n\n getList(resourceName: string, token: string, listRequest: ReportQuery): Promise<Array<Dict<string>>> {\n return this.getListWithWarnings(resourceName, token, listRequest).then((response) => response.data)\n }\n\n getListWithWarnings(resourceName: string, token: string, listRequest: ReportQuery): Promise<ListWithWarnings> {\n logger.info(`Reporting client: Get list. { resourceName: ${resourceName} }`)\n\n return this.restClient\n .getWithHeaders<Array<Dict<string>>>({\n path: `/${resourceName}`,\n query: listRequest.toRecordWithFilterPrefix(true),\n token,\n })\n .then((response: ResultWithHeaders<Array<Dict<string>>>) => ({\n data: response.data,\n warnings: {\n noDataAvailable: response.headers['x-no-data-warning'],\n },\n }))\n }\n\n getDefinitionSummary(\n token: string,\n reportId: string,\n definitionsPath?: string,\n ): Promise<components['schemas']['ReportDefinitionSummary']> {\n this.logInfo('Get definition summary', { reportId })\n\n const queryParams: operations['definitionSummary']['parameters']['query'] = {\n ...(definitionsPath && { dataProductDefinitionsPath: definitionsPath }),\n }\n\n return this.restClient\n .get({\n path: `/definitions/${reportId}`,\n query: queryParams,\n token,\n })\n .then((response) => <components['schemas']['ReportDefinitionSummary']>response)\n }\n\n getDefinitions(\n token: string,\n definitionsPath?: string,\n ): Promise<Array<components['schemas']['ReportDefinitionSummary']>> {\n this.logInfo('Get definitions')\n\n const queryParams: operations['definitions_1']['parameters']['query'] = {\n renderMethod: 'HTML',\n ...(definitionsPath && { dataProductDefinitionsPath: definitionsPath }),\n }\n\n return this.restClient\n .get({\n path: '/definitions',\n query: queryParams,\n token,\n })\n .then((response) => <Array<components['schemas']['ReportDefinitionSummary']>>response)\n }\n\n getDefinition(\n token: string,\n reportId: string,\n variantId: string,\n definitionsPath?: string,\n queryData?: Dict<string | string[]>,\n ): Promise<components['schemas']['SingleVariantReportDefinition']> {\n const query = {\n ...queryData,\n dataProductDefinitionsPath: definitionsPath,\n }\n\n this.logInfo('Get definition', { reportId, variantId, ...query })\n\n return this.restClient\n .get({\n path: `/definitions/${reportId}/${variantId}`,\n query,\n token,\n })\n .then((response) => <components['schemas']['SingleVariantReportDefinition']>response)\n }\n\n requestAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n query: Record<string, string | boolean | number>,\n ): Promise<Dict<string>> {\n this.logInfo('Request report', { reportId, variantId })\n\n return this.restClient\n .get({\n path: `/async/reports/${reportId}/${variantId}`,\n token,\n query,\n })\n .then((response) => <Dict<string>>response)\n }\n\n cancelAsyncRequest(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath?: string,\n ): Promise<Dict<string>> {\n this.logInfo('Cancel Request', { reportId, variantId, executionId })\n\n return this.restClient\n .delete({\n path: `/reports/${reportId}/${variantId}/statements/${executionId}`,\n token,\n query: {\n dataProductDefinitionsPath,\n },\n })\n .then((response) => <Dict<string>>response)\n }\n\n downloadAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n query: Record<string, string | string[]>,\n res: Response,\n ): Promise<void> {\n this.logInfo('Streaming download data', { reportId, variantId, tableId })\n\n return this.restClient.getStream(\n {\n path: `/reports/${reportId}/${variantId}/tables/${tableId}/download`,\n query,\n token,\n },\n res,\n )\n }\n\n getAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n query: Record<string, string | string[]>,\n ): Promise<Array<Dict<string>>> {\n this.logInfo('Get Data', { reportId, variantId, tableId })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${variantId}/tables/${tableId}/result`,\n token,\n query,\n })\n .then((response) => <Array<Dict<string>>>response)\n }\n\n getAsyncSummaryReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n summaryId: string,\n query: Dict<string | number>,\n ): Promise<Array<Dict<string>>> {\n this.logInfo('Get summary data', { reportId, variantId, tableId, summaryId })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${variantId}/tables/${tableId}/result/summary/${summaryId}`,\n token,\n query,\n })\n .then((response) => <Array<Dict<string>>>response)\n }\n\n getAsyncReportStatus(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath?: string,\n tableId?: string,\n ): Promise<components['schemas']['StatementExecutionStatus']> {\n this.logInfo('Get status', { reportId, variantId, tableId, executionId })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${variantId}/statements/${executionId}/status`,\n token,\n query: {\n dataProductDefinitionsPath,\n tableId,\n },\n })\n .then((response) => <components['schemas']['StatementExecutionStatus']>response)\n }\n\n getAsyncCount(token: string, tableId: string, dataProductDefinitionsPath?: string): Promise<number> {\n this.logInfo('Get count', { tableId })\n\n return this.restClient\n .get({\n path: `/report/tables/${tableId}/count`,\n token,\n query: {\n dataProductDefinitionsPath,\n },\n })\n .then((response) => (<Count>response).count)\n }\n\n getAsyncInteractiveCount(\n token: string,\n tableId: string,\n reportId: string,\n id: string,\n filters: ReportQuery,\n ): Promise<number> {\n this.logInfo('Get interactive count', { tableId, reportId, id })\n\n return this.restClient\n .get({\n path: `/reports/${reportId}/${id}/tables/${tableId}/count`,\n token,\n query: filters.toRecordWithFilterPrefix(true),\n })\n .then((response) => (<Count>response).count)\n }\n\n logInfo(title: string, args?: Dict<string>) {\n logger.info(`Reporting Client: ${title}:`)\n if (args && Object.keys(args).length) logger.info(JSON.stringify(args, null, 2))\n }\n}\n\nexport { ReportingClient }\nexport default ReportingClient\n"],
5
+ "mappings": "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",
6
6
  "names": ["RestClient", "logger"]
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { Response } from 'express'
1
2
  import ReportQuery from '../types/ReportQuery'
2
3
  import logger from '../utils/logger'
3
4
  import RestClient from './restClient'
@@ -146,6 +147,26 @@ class ReportingClient {
146
147
  .then((response) => <Dict<string>>response)
147
148
  }
148
149
 
150
+ downloadAsyncReport(
151
+ token: string,
152
+ reportId: string,
153
+ variantId: string,
154
+ tableId: string,
155
+ query: Record<string, string | string[]>,
156
+ res: Response,
157
+ ): Promise<void> {
158
+ this.logInfo('Streaming download data', { reportId, variantId, tableId })
159
+
160
+ return this.restClient.getStream(
161
+ {
162
+ path: `/reports/${reportId}/${variantId}/tables/${tableId}/download`,
163
+ query,
164
+ token,
165
+ },
166
+ res,
167
+ )
168
+ }
169
+
149
170
  getAsyncReport(
150
171
  token: string,
151
172
  reportId: string,
@@ -52,6 +52,32 @@ class RestClient {
52
52
  async get(request) {
53
53
  return this.getWithHeaders(request).then((result) => result.data);
54
54
  }
55
+ async getStream({ path = "", query = {}, headers = {}, token }, res) {
56
+ import_logger.default.info(`${this.name} STREAM GET: ${this.apiUrl()}${path}`);
57
+ import_logger.default.info(`query: ${JSON.stringify(query)}`);
58
+ const req = import_superagent.default.get(`${this.apiUrl()}${path}`).agent(this.agent).query(query).auth(token, { type: "bearer" }).set(headers).timeout(this.timeoutConfig());
59
+ req.on("response", (upstream) => {
60
+ res.status(upstream.status);
61
+ Object.entries(upstream.headers).forEach(([key, value]) => {
62
+ if (value !== void 0) {
63
+ res.setHeader(key, value);
64
+ }
65
+ });
66
+ res.on("close", () => {
67
+ import_logger.default.info("Client disconnected, aborting upstream request.");
68
+ req.abort();
69
+ });
70
+ upstream.pipe(res);
71
+ });
72
+ req.on("error", (error) => {
73
+ import_logger.default.warn({ error }, `Error streaming from ${this.name}, path: '${path}'`);
74
+ if (!res.headersSent) {
75
+ res.status(502).end("Download request failed. Error streaming response");
76
+ } else {
77
+ res.destroy(error);
78
+ }
79
+ });
80
+ }
55
81
  async requestWithBody(method, { path, query = {}, headers = {}, responseType = "", data = {}, raw = false, retry = false }, token) {
56
82
  import_logger.default.info(`${this.name} ${method.toUpperCase()}: ${path}`);
57
83
  import_logger.default.info(`info about request: ${method} | ${path} | ${JSON.stringify(data)} | ${query}`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../dpr/data/restClient.ts"],
4
- "sourcesContent": ["import superagent, { ResponseError } from 'superagent'\nimport Agent, { HttpsAgent } from 'agentkeepalive'\n\nimport logger from '../utils/logger'\nimport sanitiseError from '../utils/sanitisedError'\nimport { ApiConfig, GetRequest } from './types'\nimport Dict = NodeJS.Dict\n\nexport interface ResultWithHeaders<T> {\n data: T\n headers: Dict<string>\n}\n\ninterface Request {\n path: string\n query?: object | string\n headers?: Record<string, string>\n responseType?: string\n raw?: boolean\n}\ninterface RequestWithBody extends Request {\n data?: Record<string, unknown> | string\n retry?: boolean\n}\n\nclass RestClient {\n agent: Agent\n\n constructor(private readonly name: string, private readonly config: ApiConfig) {\n this.agent = config.url.startsWith('https') ? new HttpsAgent(config.agent) : new Agent(config.agent)\n }\n\n private apiUrl() {\n return this.config.url\n }\n\n private timeoutConfig() {\n return this.config.agent.timeout\n }\n\n async get<T>(request: GetRequest): Promise<T> {\n return this.getWithHeaders<T>(request).then((result) => result.data)\n }\n\n private async requestWithBody<Response = unknown>(\n method: 'patch' | 'post' | 'put',\n { path, query = {}, headers = {}, responseType = '', data = {}, raw = false, retry = false }: RequestWithBody,\n token: string,\n ): Promise<Response> {\n logger.info(`${this.name} ${method.toUpperCase()}: ${path}`)\n logger.info(`info about request: ${method} | ${path} | ${JSON.stringify(data)} | ${query}`)\n try {\n const result = await superagent[method](`${this.apiUrl()}${path}`)\n .query(query)\n .send(data)\n .agent(this.agent)\n .retry(2, (err) => {\n if (retry === false) {\n return false\n }\n if (err) logger.info(`Retry handler found API error with ${err.code} ${err.message}`)\n return undefined // retry handler only for logging retries, not to influence retry logic\n })\n .auth(token, { type: 'bearer' })\n .set(headers)\n .responseType(responseType)\n .timeout(this.timeoutConfig())\n\n return raw ? (result as Response) : result.body\n } catch (error) {\n if (!(error instanceof Error)) {\n throw error\n }\n const sanitisedError = sanitiseError(error)\n logger.warn({ ...sanitisedError }, `Error calling ${this.name}, path: '${path}', verb: '${method.toUpperCase()}'`)\n throw sanitisedError\n }\n }\n\n async post<Response = unknown>(request: RequestWithBody, token: string): Promise<Response> {\n return this.requestWithBody('post', request, token)\n }\n\n async getWithHeaders<T>({\n path = '',\n query = {},\n headers = {},\n responseType = '',\n raw = false,\n token,\n }: GetRequest): Promise<ResultWithHeaders<T>> {\n const loggerData = {\n path: `${this.config.url}${path}`,\n query,\n }\n logger.info(`${this.name}: ${JSON.stringify(loggerData, null, 2)}`)\n try {\n const result = await superagent\n .get(`${this.apiUrl()}${path}`)\n .agent(this.agent)\n .retry(2, (err) => {\n if (err) logger.info(`Retry handler found API error with ${err.code} ${err.message}`)\n return undefined // retry handler only for logging retries, not to influence retry logic\n })\n .query(query)\n .auth(token, { type: 'bearer' })\n .set(headers)\n .responseType(responseType)\n .timeout(this.timeoutConfig())\n\n return {\n data: raw ? result : result.body,\n headers: result.headers,\n }\n } catch (error) {\n const sanitisedError = sanitiseError(<ResponseError>error)\n logger.warn({ ...sanitisedError, query }, `Error calling ${this.name}, path: '${path}', verb: 'GET'`)\n throw sanitisedError\n }\n }\n\n async deleteWithHeaders<T>({\n path = '',\n query = {},\n headers = {},\n responseType = '',\n raw = false,\n token,\n }: GetRequest): Promise<ResultWithHeaders<T>> {\n const loggerData = {\n path: `${this.config.url}${path}`,\n query,\n }\n logger.info(`${this.name}: ${JSON.stringify(loggerData, null, 2)}`)\n try {\n const result = await superagent\n .delete(`${this.apiUrl()}${path}`)\n .agent(this.agent)\n .retry(2, (err) => {\n if (err) logger.info(`Retry handler found API error with ${err.code} ${err.message}`)\n return undefined // retry handler only for logging retries, not to influence retry logic\n })\n .query(query)\n .auth(token, { type: 'bearer' })\n .set(headers)\n .responseType(responseType)\n .timeout(this.timeoutConfig())\n\n return {\n data: raw ? result : result.body,\n headers: result.headers,\n }\n } catch (error) {\n const sanitisedError = sanitiseError(<ResponseError>error)\n logger.warn({ ...sanitisedError, query }, `Error calling ${this.name}, path: '${path}', verb: 'GET'`)\n throw sanitisedError\n }\n }\n\n async delete<T>(request: GetRequest): Promise<T> {\n return this.deleteWithHeaders<T>(request).then((result) => result.data)\n }\n}\n\nexport { RestClient }\nexport default RestClient\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import superagent, { ResponseError } from 'superagent'\nimport Agent, { HttpsAgent } from 'agentkeepalive'\nimport { Response as ExpressResponse } from 'express'\n\nimport logger from '../utils/logger'\nimport sanitiseError from '../utils/sanitisedError'\nimport { ApiConfig, GetRequest } from './types'\nimport Dict = NodeJS.Dict\n\nexport interface ResultWithHeaders<T> {\n data: T\n headers: Dict<string>\n}\n\ninterface Request {\n path: string\n query?: object | string\n headers?: Record<string, string>\n responseType?: string\n raw?: boolean\n}\ninterface RequestWithBody extends Request {\n data?: Record<string, unknown> | string\n retry?: boolean\n}\n\nclass RestClient {\n agent: Agent\n\n constructor(private readonly name: string, private readonly config: ApiConfig) {\n this.agent = config.url.startsWith('https') ? new HttpsAgent(config.agent) : new Agent(config.agent)\n }\n\n private apiUrl() {\n return this.config.url\n }\n\n private timeoutConfig() {\n return this.config.agent.timeout\n }\n\n async get<T>(request: GetRequest): Promise<T> {\n return this.getWithHeaders<T>(request).then((result) => result.data)\n }\n\n async getStream({ path = '', query = {}, headers = {}, token }: GetRequest, res: ExpressResponse): Promise<void> {\n logger.info(`${this.name} STREAM GET: ${this.apiUrl()}${path}`)\n logger.info(`query: ${JSON.stringify(query)}`)\n\n const req = superagent\n .get(`${this.apiUrl()}${path}`)\n .agent(this.agent)\n .query(query)\n .auth(token, { type: 'bearer' })\n .set(headers)\n .timeout(this.timeoutConfig())\n\n req.on('response', (upstream) => {\n // Forward status\n res.status(upstream.status)\n\n // Forward headers\n Object.entries(upstream.headers).forEach(([key, value]) => {\n if (value !== undefined) {\n res.setHeader(key, value as string)\n }\n })\n res.on('close', () => {\n logger.info('Client disconnected, aborting upstream request.')\n req.abort()\n })\n upstream.pipe(res)\n })\n\n req.on('error', (error) => {\n logger.warn({ error }, `Error streaming from ${this.name}, path: '${path}'`)\n if (!res.headersSent) {\n res.status(502).end('Download request failed. Error streaming response')\n } else {\n res.destroy(error)\n }\n })\n }\n\n private async requestWithBody<Response = unknown>(\n method: 'patch' | 'post' | 'put',\n { path, query = {}, headers = {}, responseType = '', data = {}, raw = false, retry = false }: RequestWithBody,\n token: string,\n ): Promise<Response> {\n logger.info(`${this.name} ${method.toUpperCase()}: ${path}`)\n logger.info(`info about request: ${method} | ${path} | ${JSON.stringify(data)} | ${query}`)\n try {\n const result = await superagent[method](`${this.apiUrl()}${path}`)\n .query(query)\n .send(data)\n .agent(this.agent)\n .retry(2, (err) => {\n if (retry === false) {\n return false\n }\n if (err) logger.info(`Retry handler found API error with ${err.code} ${err.message}`)\n return undefined // retry handler only for logging retries, not to influence retry logic\n })\n .auth(token, { type: 'bearer' })\n .set(headers)\n .responseType(responseType)\n .timeout(this.timeoutConfig())\n\n return raw ? (result as Response) : result.body\n } catch (error) {\n if (!(error instanceof Error)) {\n throw error\n }\n const sanitisedError = sanitiseError(error)\n logger.warn({ ...sanitisedError }, `Error calling ${this.name}, path: '${path}', verb: '${method.toUpperCase()}'`)\n throw sanitisedError\n }\n }\n\n async post<Response = unknown>(request: RequestWithBody, token: string): Promise<Response> {\n return this.requestWithBody('post', request, token)\n }\n\n async getWithHeaders<T>({\n path = '',\n query = {},\n headers = {},\n responseType = '',\n raw = false,\n token,\n }: GetRequest): Promise<ResultWithHeaders<T>> {\n const loggerData = {\n path: `${this.config.url}${path}`,\n query,\n }\n logger.info(`${this.name}: ${JSON.stringify(loggerData, null, 2)}`)\n try {\n const result = await superagent\n .get(`${this.apiUrl()}${path}`)\n .agent(this.agent)\n .retry(2, (err) => {\n if (err) logger.info(`Retry handler found API error with ${err.code} ${err.message}`)\n return undefined // retry handler only for logging retries, not to influence retry logic\n })\n .query(query)\n .auth(token, { type: 'bearer' })\n .set(headers)\n .responseType(responseType)\n .timeout(this.timeoutConfig())\n\n return {\n data: raw ? result : result.body,\n headers: result.headers,\n }\n } catch (error) {\n const sanitisedError = sanitiseError(<ResponseError>error)\n logger.warn({ ...sanitisedError, query }, `Error calling ${this.name}, path: '${path}', verb: 'GET'`)\n throw sanitisedError\n }\n }\n\n async deleteWithHeaders<T>({\n path = '',\n query = {},\n headers = {},\n responseType = '',\n raw = false,\n token,\n }: GetRequest): Promise<ResultWithHeaders<T>> {\n const loggerData = {\n path: `${this.config.url}${path}`,\n query,\n }\n logger.info(`${this.name}: ${JSON.stringify(loggerData, null, 2)}`)\n try {\n const result = await superagent\n .delete(`${this.apiUrl()}${path}`)\n .agent(this.agent)\n .retry(2, (err) => {\n if (err) logger.info(`Retry handler found API error with ${err.code} ${err.message}`)\n return undefined // retry handler only for logging retries, not to influence retry logic\n })\n .query(query)\n .auth(token, { type: 'bearer' })\n .set(headers)\n .responseType(responseType)\n .timeout(this.timeoutConfig())\n\n return {\n data: raw ? result : result.body,\n headers: result.headers,\n }\n } catch (error) {\n const sanitisedError = sanitiseError(<ResponseError>error)\n logger.warn({ ...sanitisedError, query }, `Error calling ${this.name}, path: '${path}', verb: 'GET'`)\n throw sanitisedError\n }\n }\n\n async delete<T>(request: GetRequest): Promise<T> {\n return this.deleteWithHeaders<T>(request).then((result) => result.data)\n }\n}\n\nexport { RestClient }\nexport default RestClient\n"],
5
+ "mappings": "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",
6
6
  "names": ["Agent", "logger", "superagent", "sanitiseError"]
7
7
  }
@@ -1,5 +1,6 @@
1
1
  import superagent, { ResponseError } from 'superagent'
2
2
  import Agent, { HttpsAgent } from 'agentkeepalive'
3
+ import { Response as ExpressResponse } from 'express'
3
4
 
4
5
  import logger from '../utils/logger'
5
6
  import sanitiseError from '../utils/sanitisedError'
@@ -42,6 +43,45 @@ class RestClient {
42
43
  return this.getWithHeaders<T>(request).then((result) => result.data)
43
44
  }
44
45
 
46
+ async getStream({ path = '', query = {}, headers = {}, token }: GetRequest, res: ExpressResponse): Promise<void> {
47
+ logger.info(`${this.name} STREAM GET: ${this.apiUrl()}${path}`)
48
+ logger.info(`query: ${JSON.stringify(query)}`)
49
+
50
+ const req = superagent
51
+ .get(`${this.apiUrl()}${path}`)
52
+ .agent(this.agent)
53
+ .query(query)
54
+ .auth(token, { type: 'bearer' })
55
+ .set(headers)
56
+ .timeout(this.timeoutConfig())
57
+
58
+ req.on('response', (upstream) => {
59
+ // Forward status
60
+ res.status(upstream.status)
61
+
62
+ // Forward headers
63
+ Object.entries(upstream.headers).forEach(([key, value]) => {
64
+ if (value !== undefined) {
65
+ res.setHeader(key, value as string)
66
+ }
67
+ })
68
+ res.on('close', () => {
69
+ logger.info('Client disconnected, aborting upstream request.')
70
+ req.abort()
71
+ })
72
+ upstream.pipe(res)
73
+ })
74
+
75
+ req.on('error', (error) => {
76
+ logger.warn({ error }, `Error streaming from ${this.name}, path: '${path}'`)
77
+ if (!res.headersSent) {
78
+ res.status(502).end('Download request failed. Error streaming response')
79
+ } else {
80
+ res.destroy(error)
81
+ }
82
+ })
83
+ }
84
+
45
85
  private async requestWithBody<Response = unknown>(
46
86
  method: 'patch' | 'post' | 'put',
47
87
  { path, query = {}, headers = {}, responseType = '', data = {}, raw = false, retry = false }: RequestWithBody,
@@ -154,7 +154,7 @@ const populateRequestedReports = async (services, res) => {
154
154
  res.locals["bookmarkingEnabled"] = services.bookmarkService.enabled;
155
155
  res.locals["collectionsEnabled"] = services.productCollectionService.enabled;
156
156
  res.locals["requestMissingEnabled"] = services.missingReportService.enabled;
157
- res.locals["saveDefaultsEnabled"] = (0, import_featureFlagService.isBooleanFlagEnabled)("saveDefaultsEnabled", res.app);
157
+ res.locals["saveDefaultsEnabled"] = (0, import_featureFlagService.isBooleanFlagEnabledOrMissing)("saveDefaultsEnabled", res.app);
158
158
  if (res.locals["bookmarkingEnabled"]) {
159
159
  const bookmarks = await services.bookmarkService.getAllBookmarks(dprUser.id);
160
160
  res.locals["bookmarks"] = !definitionsPath ? bookmarks : bookmarks.filter((bookmark) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../dpr/middleware/setUpDprResources.ts"],
4
- "sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { RequestHandler, Response, Request, ErrorRequestHandler, NextFunction } from 'express'\nimport type { ParsedQs } from 'qs'\nimport { HTTPError } from 'superagent'\nimport type { Environment } from 'nunjucks'\nimport { captureException } from '@sentry/node'\nimport { Services } from '../types/Services'\nimport { RequestedReport, StoredReportData } from '../types/UserReports'\nimport DefinitionUtils from '../utils/definitionUtils'\nimport { BookmarkStoreData } from '../types/Bookmark'\nimport { DprConfig } from '../types/DprConfig'\nimport localsHelper from '../utils/localsHelper'\nimport { FeatureFlagService, isBooleanFlagEnabled } from '../services/featureFlagService'\n\nconst getQueryParamAsString = (query: ParsedQs, name: string) => (query[name] ? query[name].toString() : null)\nconst getDefinitionsPath = (query: ParsedQs) => getQueryParamAsString(query, 'dataProductDefinitionsPath')\n\nconst deriveDefinitionsPath = (query: ParsedQs): string | null => {\n const definitionsPath = getDefinitionsPath(query)\n if (definitionsPath) {\n return definitionsPath\n }\n\n return null\n}\n\nexport const errorRequestHandler =\n (layoutPath: string): ErrorRequestHandler =>\n (error: HTTPError, _req: Request, res: Response, next: NextFunction) => {\n if (error.status === 401 || error.status === 403) {\n return res.render('dpr/routes/authError.njk', {\n layoutPath,\n message: 'Sorry, there is a problem with authenticating your request',\n })\n }\n captureException(error)\n if (error.status >= 400) {\n return res.render('dpr/routes/serviceProblem.njk', {\n layoutPath,\n })\n }\n return next(error)\n }\n\nexport const setupResources = (\n services: Services,\n layoutPath: string,\n env: Environment,\n config?: DprConfig,\n): RequestHandler => {\n return async (req, res, next) => {\n populateValidationErrors(req, res)\n try {\n await setFeatures(res, services.featureFlagService)\n await populateDefinitions(services, req, res, config)\n await populateRequestedReports(services, res)\n setupRequestAwareNunjucks(env, res)\n return next()\n } catch (error) {\n return errorRequestHandler(layoutPath)(error, req, res, next)\n }\n }\n}\n\nconst setupRequestAwareNunjucks = (env: Environment, res: Response) => {\n env.addGlobal('getLocals', () => ({ locals: { ...res.locals, ...res.app.locals } }))\n}\n\nconst setFeatures = async (res: Response, featureFlagService: FeatureFlagService) => {\n if (res.app.locals.featureFlags === undefined) {\n res.app.locals.featureFlags = {\n flags: {},\n lastUpdated: new Date().getTime() - 601 * 1000,\n }\n }\n const { featureFlags } = res.app.locals\n const currentTime = new Date().getTime()\n const timeSinceLastUpdatedSeconds = (currentTime - featureFlags.lastUpdated) / 1000\n const shouldUpdate = timeSinceLastUpdatedSeconds > 600\n if (shouldUpdate) {\n // Refresh every 10 mins\n res.app.locals.featureFlags.lastUpdated = currentTime\n const flags = await featureFlagService.getFlags().catch((e) => {\n res.app.locals.featureFlags.lastUpdated = currentTime - 601 * 1000\n throw e\n })\n res.app.locals.featureFlags.flags = Object.fromEntries(flags.flags.map((flag) => [flag.key, flag]))\n }\n}\n\nconst populateValidationErrors = (req: Request, res: Response) => {\n const errors = req.flash(`DPR_ERRORS`)\n if (errors && errors[0]) {\n res.locals['validationErrors'] = JSON.parse(errors[0])\n }\n}\n\nexport const populateDefinitions = async (services: Services, req: Request, res: Response, config?: DprConfig) => {\n // Get the DPD path from the query\n const { token, dprUser } = localsHelper.getValues(res)\n\n const dpdPathFromQuery = deriveDefinitionsPath(req.query)\n const dpdPathFromBody = req.body?.dataProductDefinitionsPath\n const definitionsPathFromQuery = dpdPathFromQuery || dpdPathFromBody\n\n if (definitionsPathFromQuery) {\n res.locals['dpdPathFromQuery'] = true\n }\n\n // Get the DPD path from the config\n const dpdPathFromConfig = config?.dataProductDefinitionsPath\n if (dpdPathFromConfig) {\n res.locals['dpdPathFromConfig'] = true\n }\n\n // query takes presedence over config\n res.locals['definitionsPath'] = definitionsPathFromQuery || dpdPathFromConfig\n res.locals['pathSuffix'] = `?dataProductDefinitionsPath=${res.locals['definitionsPath']}`\n\n let selectedProductCollectionId: string | undefined\n if (token) {\n selectedProductCollectionId = await services.productCollectionStoreService.getSelectedProductCollectionId(\n dprUser.id,\n )\n }\n\n res.locals['definitions'] =\n (await Promise.all([\n services.reportingService.getDefinitions(token, res.locals['definitionsPath']),\n selectedProductCollectionId &&\n services.productCollectionService.getProductCollection(token, selectedProductCollectionId),\n ]).then(([defs, selectedProductCollection]) => {\n if (selectedProductCollection && selectedProductCollection) {\n const productIds = selectedProductCollection.products.map((product) => product.productId)\n return defs.filter((def) => productIds.includes(def.id))\n }\n return defs\n })) ?? []\n}\n\nexport const populateRequestedReports = async (services: Services, res: Response) => {\n const { dprUser } = localsHelper.getValues(res)\n if (dprUser.id) {\n const { definitions, definitionsPath } = res.locals\n\n const recent = await services.recentlyViewedService.getAllReports(dprUser.id)\n await services.requestedReportService.cleanList(dprUser.id, recent)\n const requested = await services.requestedReportService.getAllReports(dprUser.id)\n\n res.locals['requestedReports'] = !definitionsPath\n ? requested\n : requested.filter((report: RequestedReport) => {\n return DefinitionUtils.getCurrentVariantDefinition(definitions, report.reportId, report.id)\n })\n\n res.locals['recentlyViewedReports'] = !definitionsPath\n ? recent\n : recent.filter((report: StoredReportData) => {\n return DefinitionUtils.getCurrentVariantDefinition(definitions, report.reportId, report.id)\n })\n\n res.locals['downloadingEnabled'] = services.downloadPermissionService.enabled\n res.locals['bookmarkingEnabled'] = services.bookmarkService.enabled\n res.locals['collectionsEnabled'] = services.productCollectionService.enabled\n res.locals['requestMissingEnabled'] = services.missingReportService.enabled\n res.locals['saveDefaultsEnabled'] = isBooleanFlagEnabled('saveDefaultsEnabled', res.app)\n\n if (res.locals['bookmarkingEnabled']) {\n const bookmarks = await services.bookmarkService.getAllBookmarks(dprUser.id)\n res.locals['bookmarks'] = !definitionsPath\n ? bookmarks\n : bookmarks.filter((bookmark: BookmarkStoreData) => {\n return DefinitionUtils.getCurrentVariantDefinition(definitions, bookmark.reportId, bookmark.id)\n })\n }\n }\n}\n\nexport default setupResources\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { RequestHandler, Response, Request, ErrorRequestHandler, NextFunction } from 'express'\nimport type { ParsedQs } from 'qs'\nimport { HTTPError } from 'superagent'\nimport type { Environment } from 'nunjucks'\nimport { captureException } from '@sentry/node'\nimport { Services } from '../types/Services'\nimport { RequestedReport, StoredReportData } from '../types/UserReports'\nimport DefinitionUtils from '../utils/definitionUtils'\nimport { BookmarkStoreData } from '../types/Bookmark'\nimport { DprConfig } from '../types/DprConfig'\nimport localsHelper from '../utils/localsHelper'\nimport { FeatureFlagService, isBooleanFlagEnabledOrMissing } from '../services/featureFlagService'\n\nconst getQueryParamAsString = (query: ParsedQs, name: string) => (query[name] ? query[name].toString() : null)\nconst getDefinitionsPath = (query: ParsedQs) => getQueryParamAsString(query, 'dataProductDefinitionsPath')\n\nconst deriveDefinitionsPath = (query: ParsedQs): string | null => {\n const definitionsPath = getDefinitionsPath(query)\n if (definitionsPath) {\n return definitionsPath\n }\n\n return null\n}\n\nexport const errorRequestHandler =\n (layoutPath: string): ErrorRequestHandler =>\n (error: HTTPError, _req: Request, res: Response, next: NextFunction) => {\n if (error.status === 401 || error.status === 403) {\n return res.render('dpr/routes/authError.njk', {\n layoutPath,\n message: 'Sorry, there is a problem with authenticating your request',\n })\n }\n captureException(error)\n if (error.status >= 400) {\n return res.render('dpr/routes/serviceProblem.njk', {\n layoutPath,\n })\n }\n return next(error)\n }\n\nexport const setupResources = (\n services: Services,\n layoutPath: string,\n env: Environment,\n config?: DprConfig,\n): RequestHandler => {\n return async (req, res, next) => {\n populateValidationErrors(req, res)\n try {\n await setFeatures(res, services.featureFlagService)\n await populateDefinitions(services, req, res, config)\n await populateRequestedReports(services, res)\n setupRequestAwareNunjucks(env, res)\n return next()\n } catch (error) {\n return errorRequestHandler(layoutPath)(error, req, res, next)\n }\n }\n}\n\nconst setupRequestAwareNunjucks = (env: Environment, res: Response) => {\n env.addGlobal('getLocals', () => ({ locals: { ...res.locals, ...res.app.locals } }))\n}\n\nconst setFeatures = async (res: Response, featureFlagService: FeatureFlagService) => {\n if (res.app.locals.featureFlags === undefined) {\n res.app.locals.featureFlags = {\n flags: {},\n lastUpdated: new Date().getTime() - 601 * 1000,\n }\n }\n const { featureFlags } = res.app.locals\n const currentTime = new Date().getTime()\n const timeSinceLastUpdatedSeconds = (currentTime - featureFlags.lastUpdated) / 1000\n const shouldUpdate = timeSinceLastUpdatedSeconds > 600\n if (shouldUpdate) {\n // Refresh every 10 mins\n res.app.locals.featureFlags.lastUpdated = currentTime\n const flags = await featureFlagService.getFlags().catch((e) => {\n res.app.locals.featureFlags.lastUpdated = currentTime - 601 * 1000\n throw e\n })\n res.app.locals.featureFlags.flags = Object.fromEntries(flags.flags.map((flag) => [flag.key, flag]))\n }\n}\n\nconst populateValidationErrors = (req: Request, res: Response) => {\n const errors = req.flash(`DPR_ERRORS`)\n if (errors && errors[0]) {\n res.locals['validationErrors'] = JSON.parse(errors[0])\n }\n}\n\nexport const populateDefinitions = async (services: Services, req: Request, res: Response, config?: DprConfig) => {\n // Get the DPD path from the query\n const { token, dprUser } = localsHelper.getValues(res)\n\n const dpdPathFromQuery = deriveDefinitionsPath(req.query)\n const dpdPathFromBody = req.body?.dataProductDefinitionsPath\n const definitionsPathFromQuery = dpdPathFromQuery || dpdPathFromBody\n\n if (definitionsPathFromQuery) {\n res.locals['dpdPathFromQuery'] = true\n }\n\n // Get the DPD path from the config\n const dpdPathFromConfig = config?.dataProductDefinitionsPath\n if (dpdPathFromConfig) {\n res.locals['dpdPathFromConfig'] = true\n }\n\n // query takes presedence over config\n res.locals['definitionsPath'] = definitionsPathFromQuery || dpdPathFromConfig\n res.locals['pathSuffix'] = `?dataProductDefinitionsPath=${res.locals['definitionsPath']}`\n\n let selectedProductCollectionId: string | undefined\n if (token) {\n selectedProductCollectionId = await services.productCollectionStoreService.getSelectedProductCollectionId(\n dprUser.id,\n )\n }\n\n res.locals['definitions'] =\n (await Promise.all([\n services.reportingService.getDefinitions(token, res.locals['definitionsPath']),\n selectedProductCollectionId &&\n services.productCollectionService.getProductCollection(token, selectedProductCollectionId),\n ]).then(([defs, selectedProductCollection]) => {\n if (selectedProductCollection && selectedProductCollection) {\n const productIds = selectedProductCollection.products.map((product) => product.productId)\n return defs.filter((def) => productIds.includes(def.id))\n }\n return defs\n })) ?? []\n}\n\nexport const populateRequestedReports = async (services: Services, res: Response) => {\n const { dprUser } = localsHelper.getValues(res)\n if (dprUser.id) {\n const { definitions, definitionsPath } = res.locals\n\n const recent = await services.recentlyViewedService.getAllReports(dprUser.id)\n await services.requestedReportService.cleanList(dprUser.id, recent)\n const requested = await services.requestedReportService.getAllReports(dprUser.id)\n\n res.locals['requestedReports'] = !definitionsPath\n ? requested\n : requested.filter((report: RequestedReport) => {\n return DefinitionUtils.getCurrentVariantDefinition(definitions, report.reportId, report.id)\n })\n\n res.locals['recentlyViewedReports'] = !definitionsPath\n ? recent\n : recent.filter((report: StoredReportData) => {\n return DefinitionUtils.getCurrentVariantDefinition(definitions, report.reportId, report.id)\n })\n\n res.locals['downloadingEnabled'] = services.downloadPermissionService.enabled\n res.locals['bookmarkingEnabled'] = services.bookmarkService.enabled\n res.locals['collectionsEnabled'] = services.productCollectionService.enabled\n res.locals['requestMissingEnabled'] = services.missingReportService.enabled\n res.locals['saveDefaultsEnabled'] = isBooleanFlagEnabledOrMissing('saveDefaultsEnabled', res.app)\n\n if (res.locals['bookmarkingEnabled']) {\n const bookmarks = await services.bookmarkService.getAllBookmarks(dprUser.id)\n res.locals['bookmarks'] = !definitionsPath\n ? bookmarks\n : bookmarks.filter((bookmark: BookmarkStoreData) => {\n return DefinitionUtils.getCurrentVariantDefinition(definitions, bookmark.reportId, bookmark.id)\n })\n }\n }\n}\n\nexport default setupResources\n"],
5
+ "mappings": "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",
6
6
  "names": ["localsHelper", "DefinitionUtils"]
7
7
  }
@@ -10,7 +10,7 @@ import DefinitionUtils from '../utils/definitionUtils'
10
10
  import { BookmarkStoreData } from '../types/Bookmark'
11
11
  import { DprConfig } from '../types/DprConfig'
12
12
  import localsHelper from '../utils/localsHelper'
13
- import { FeatureFlagService, isBooleanFlagEnabled } from '../services/featureFlagService'
13
+ import { FeatureFlagService, isBooleanFlagEnabledOrMissing } from '../services/featureFlagService'
14
14
 
15
15
  const getQueryParamAsString = (query: ParsedQs, name: string) => (query[name] ? query[name].toString() : null)
16
16
  const getDefinitionsPath = (query: ParsedQs) => getQueryParamAsString(query, 'dataProductDefinitionsPath')
@@ -163,7 +163,7 @@ export const populateRequestedReports = async (services: Services, res: Response
163
163
  res.locals['bookmarkingEnabled'] = services.bookmarkService.enabled
164
164
  res.locals['collectionsEnabled'] = services.productCollectionService.enabled
165
165
  res.locals['requestMissingEnabled'] = services.missingReportService.enabled
166
- res.locals['saveDefaultsEnabled'] = isBooleanFlagEnabled('saveDefaultsEnabled', res.app)
166
+ res.locals['saveDefaultsEnabled'] = isBooleanFlagEnabledOrMissing('saveDefaultsEnabled', res.app)
167
167
 
168
168
  if (res.locals['bookmarkingEnabled']) {
169
169
  const bookmarks = await services.bookmarkService.getAllBookmarks(dprUser.id)
@@ -37,6 +37,7 @@ var import_json_2_csv = require("json-2-csv");
37
37
  var import_UserReports = require("../../../types/UserReports");
38
38
  var import_localsHelper = __toESM(require("../../../utils/localsHelper"));
39
39
  var import_ReportQuery = __toESM(require("../../../types/ReportQuery"));
40
+ var import_featureFlagService = require("../../../services/featureFlagService");
40
41
  const convertToCsv = (reportData, options) => {
41
42
  const csvData = (0, import_json_2_csv.json2csv)(reportData, options);
42
43
  return csvData;
@@ -89,6 +90,13 @@ const removeHtmlTags = (reportData, reportDefinition) => {
89
90
  }
90
91
  return reportData;
91
92
  };
93
+ const streamDownloadAsyncData = async (args) => {
94
+ const { token, services, tableId, reportId, id, queryParams, res } = args;
95
+ const query = {
96
+ ...queryParams
97
+ };
98
+ return services.reportingService.downloadAsyncReport(token, reportId, id, tableId, query, res);
99
+ };
92
100
  const dowloadAsyncData = async (args) => {
93
101
  const { token, services, tableId, reportId, id, queryParams } = args;
94
102
  const pageSize = await services.reportingService.getAsyncCount(token, tableId);
@@ -146,6 +154,7 @@ const downloadReport = async ({
146
154
  } = req.body;
147
155
  const { downloadPermissionService } = services;
148
156
  const canDownloadReport = await downloadPermissionService.downloadEnabledForReport(dprUser.id, reportId, id);
157
+ const streamingEnabled = (0, import_featureFlagService.isBooleanFlagExplicitlyEnabled)("streamingDownloadEnabled", res.app);
149
158
  if (!canDownloadReport) {
150
159
  res.redirect(redirect);
151
160
  } else {
@@ -164,6 +173,24 @@ const downloadReport = async ({
164
173
  queryParams
165
174
  });
166
175
  } else {
176
+ if (streamingEnabled) {
177
+ const streamDownloadQueryParams = {
178
+ dataProductDefinitionsPath,
179
+ ...columns && { columns: JSON.parse(columns) },
180
+ ...sortedAsc && { sortedAsc },
181
+ ...sortColumn && { sortColumn }
182
+ };
183
+ await streamDownloadAsyncData({
184
+ services,
185
+ token,
186
+ reportId,
187
+ id,
188
+ tableId,
189
+ queryParams: streamDownloadQueryParams,
190
+ res
191
+ });
192
+ return;
193
+ }
167
194
  reportData = await dowloadAsyncData({
168
195
  services,
169
196
  token,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../dpr/routes/journeys/download-report/utils.ts"],
4
- "sourcesContent": ["import { Response, Request } from 'express'\nimport { json2csv, Json2CsvOptions } from 'json-2-csv'\nimport { KeysList } from 'json-2-csv/lib/types'\nimport { Services } from '../../../types/Services'\nimport Dict = NodeJS.Dict\nimport { LoadType } from '../../../types/UserReports'\nimport { components } from '../../../types/api'\nimport LocalsHelper from '../../../utils/localsHelper'\nimport { Template } from '../../../types/Templates'\nimport ReportQuery from '../../../types/ReportQuery'\n\nconst convertToCsv = (reportData: Dict<string>[], options: Json2CsvOptions) => {\n const csvData = json2csv(reportData, options)\n return csvData\n}\n\nexport const getKeys = (reportData: Dict<string>[], fields: components['schemas']['FieldDefinition'][]): KeysList => {\n const keys: KeysList = []\n const keyNames: string[] = []\n reportData.forEach((row) => {\n Object.keys(row).forEach((key) => {\n const field = fields.find((f) => f.name === key)\n if (field && !keyNames.includes(key)) {\n keyNames.push(key)\n keys.push({\n field: key,\n title: field.display,\n })\n }\n })\n })\n return keys\n}\n\nconst applyColumnsAndSort = (data: Dict<string>[], columns: string[]) => {\n return data.map((row) => {\n return Object.keys(row)\n .filter((key) => columns.includes(key))\n .reduce((obj: Dict<string>, key) => {\n // eslint-disable-next-line no-param-reassign\n obj[key] = row[key]\n return obj\n }, {})\n })\n}\n\nconst removeHtmlTags = (\n reportData: Dict<string>[],\n reportDefinition: components['schemas']['SingleVariantReportDefinition'],\n) => {\n // Find HMTL field + name\n const { specification } = reportDefinition.variant\n if (specification) {\n const { fields } = specification\n const htmlFields = fields.filter((field) => {\n return field.type === 'HTML'\n })\n\n if (htmlFields.length) {\n reportData.map((d) => {\n htmlFields.forEach((field) => {\n const { name } = field\n const colValue = d[name]\n if (colValue) {\n const innerText = /target=\"_blank\">(.*?)<\\/a>/g.exec(colValue)\n // eslint-disable-next-line prefer-destructuring, no-param-reassign\n d[name] = innerText ? innerText[1] : colValue\n }\n })\n return d\n })\n }\n }\n return reportData\n}\n\nconst dowloadAsyncData = async (args: {\n services: Services\n token: string\n tableId: string\n reportId: string\n id: string\n queryParams: {\n dataProductDefinitionsPath: string\n sortedAsc?: string\n sortColumn?: string\n }\n}) => {\n const { token, services, tableId, reportId, id, queryParams } = args\n const pageSize = await services.reportingService.getAsyncCount(token, tableId)\n const query: Record<string, string | string[]> = {\n ...queryParams,\n pageSize: pageSize.toString(),\n }\n return services.reportingService.getAsyncReport(token, reportId, id, tableId, query)\n}\n\nconst downloadSyncData = async (args: {\n definition: components['schemas']['SingleVariantReportDefinition']\n services: Services\n token: string\n queryParams: {\n dataProductDefinitionsPath: string\n sortedAsc?: string\n sortColumn?: string\n }\n}) => {\n const { token, services, queryParams, definition } = args\n const { variant } = definition\n const { resourceName, specification } = variant\n let data: Dict<string>[] = []\n\n if (specification) {\n const countReportQuery = new ReportQuery({\n fields: specification.fields,\n template: specification.template as Template,\n queryParams,\n definitionsPath: <string>queryParams.dataProductDefinitionsPath,\n })\n const count = await services.reportingService.getCount(resourceName, token, countReportQuery)\n\n const dataReportQuery = new ReportQuery({\n fields: specification.fields,\n template: specification.template as Template,\n queryParams: {\n ...queryParams,\n pageSize: count.toString(),\n },\n definitionsPath: <string>queryParams.dataProductDefinitionsPath,\n })\n const reportData = await services.reportingService.getListWithWarnings(resourceName, token, dataReportQuery)\n data = reportData.data\n }\n\n return data\n}\n\nexport const downloadReport = async ({\n req,\n services,\n res,\n redirect,\n loadType,\n}: {\n req: Request\n services: Services\n res: Response\n redirect: string\n loadType?: LoadType\n}) => {\n const { dprUser, token } = LocalsHelper.getValues(res)\n const {\n reportId,\n id,\n tableId,\n dataProductDefinitionsPath,\n reportName,\n name,\n cols: columns,\n sortedAsc,\n sortColumn,\n } = req.body\n const { downloadPermissionService } = services\n const canDownloadReport = await downloadPermissionService.downloadEnabledForReport(dprUser.id, reportId, id)\n if (!canDownloadReport) {\n res.redirect(redirect)\n } else {\n const definition = await services.reportingService.getDefinition(token, reportId, id, dataProductDefinitionsPath)\n const queryParams = {\n dataProductDefinitionsPath,\n ...(sortedAsc && { sortedAsc }),\n ...(sortColumn && { sortColumn }),\n }\n\n let reportData\n if (loadType === LoadType.SYNC) {\n reportData = await downloadSyncData({\n definition,\n services,\n token,\n queryParams,\n })\n } else {\n reportData = await dowloadAsyncData({\n services,\n token,\n reportId,\n id,\n tableId,\n queryParams,\n })\n }\n if (columns) {\n reportData = applyColumnsAndSort(reportData, JSON.parse(columns))\n }\n reportData = removeHtmlTags(reportData, definition)\n const fields = definition.variant.specification?.fields || []\n const keys: KeysList = getKeys(reportData, fields)\n const csvData = convertToCsv(reportData, { keys, emptyFieldValue: '' })\n\n res.setHeader('Content-Type', 'application/json')\n res.setHeader('Content-disposition', `attachment; filename=${reportName}-${name}-${new Date().toISOString()}.csv`)\n res.end(csvData)\n }\n}\n\nexport default {\n downloadReport,\n getKeys,\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Response, Request } from 'express'\nimport { json2csv, Json2CsvOptions } from 'json-2-csv'\nimport { KeysList } from 'json-2-csv/lib/types'\nimport { Services } from '../../../types/Services'\nimport Dict = NodeJS.Dict\nimport { LoadType } from '../../../types/UserReports'\nimport { components } from '../../../types/api'\nimport LocalsHelper from '../../../utils/localsHelper'\nimport { Template } from '../../../types/Templates'\nimport ReportQuery from '../../../types/ReportQuery'\nimport { isBooleanFlagExplicitlyEnabled } from '../../../services/featureFlagService'\n\nconst convertToCsv = (reportData: Dict<string>[], options: Json2CsvOptions) => {\n const csvData = json2csv(reportData, options)\n return csvData\n}\n\nexport const getKeys = (reportData: Dict<string>[], fields: components['schemas']['FieldDefinition'][]): KeysList => {\n const keys: KeysList = []\n const keyNames: string[] = []\n reportData.forEach((row) => {\n Object.keys(row).forEach((key) => {\n const field = fields.find((f) => f.name === key)\n if (field && !keyNames.includes(key)) {\n keyNames.push(key)\n keys.push({\n field: key,\n title: field.display,\n })\n }\n })\n })\n return keys\n}\n\nconst applyColumnsAndSort = (data: Dict<string>[], columns: string[]) => {\n return data.map((row) => {\n return Object.keys(row)\n .filter((key) => columns.includes(key))\n .reduce((obj: Dict<string>, key) => {\n // eslint-disable-next-line no-param-reassign\n obj[key] = row[key]\n return obj\n }, {})\n })\n}\n\nconst removeHtmlTags = (\n reportData: Dict<string>[],\n reportDefinition: components['schemas']['SingleVariantReportDefinition'],\n) => {\n // Find HMTL field + name\n const { specification } = reportDefinition.variant\n if (specification) {\n const { fields } = specification\n const htmlFields = fields.filter((field) => {\n return field.type === 'HTML'\n })\n\n if (htmlFields.length) {\n reportData.map((d) => {\n htmlFields.forEach((field) => {\n const { name } = field\n const colValue = d[name]\n if (colValue) {\n const innerText = /target=\"_blank\">(.*?)<\\/a>/g.exec(colValue)\n // eslint-disable-next-line prefer-destructuring, no-param-reassign\n d[name] = innerText ? innerText[1] : colValue\n }\n })\n return d\n })\n }\n }\n return reportData\n}\n\nconst streamDownloadAsyncData = async (args: {\n services: Services\n token: string\n tableId: string\n reportId: string\n id: string\n queryParams: {\n dataProductDefinitionsPath: string\n columns: string[]\n sortedAsc?: string\n sortColumn?: string\n }\n res: Response\n}) => {\n const { token, services, tableId, reportId, id, queryParams, res } = args\n const query: Record<string, string | string[]> = {\n ...queryParams,\n }\n return services.reportingService.downloadAsyncReport(token, reportId, id, tableId, query, res)\n}\n\nconst dowloadAsyncData = async (args: {\n services: Services\n token: string\n tableId: string\n reportId: string\n id: string\n queryParams: {\n dataProductDefinitionsPath: string\n sortedAsc?: string\n sortColumn?: string\n }\n}) => {\n const { token, services, tableId, reportId, id, queryParams } = args\n const pageSize = await services.reportingService.getAsyncCount(token, tableId)\n const query: Record<string, string | string[]> = {\n ...queryParams,\n pageSize: pageSize.toString(),\n }\n return services.reportingService.getAsyncReport(token, reportId, id, tableId, query)\n}\n\nconst downloadSyncData = async (args: {\n definition: components['schemas']['SingleVariantReportDefinition']\n services: Services\n token: string\n queryParams: {\n dataProductDefinitionsPath: string\n sortedAsc?: string\n sortColumn?: string\n }\n}) => {\n const { token, services, queryParams, definition } = args\n const { variant } = definition\n const { resourceName, specification } = variant\n let data: Dict<string>[] = []\n\n if (specification) {\n const countReportQuery = new ReportQuery({\n fields: specification.fields,\n template: specification.template as Template,\n queryParams,\n definitionsPath: <string>queryParams.dataProductDefinitionsPath,\n })\n const count = await services.reportingService.getCount(resourceName, token, countReportQuery)\n\n const dataReportQuery = new ReportQuery({\n fields: specification.fields,\n template: specification.template as Template,\n queryParams: {\n ...queryParams,\n pageSize: count.toString(),\n },\n definitionsPath: <string>queryParams.dataProductDefinitionsPath,\n })\n const reportData = await services.reportingService.getListWithWarnings(resourceName, token, dataReportQuery)\n data = reportData.data\n }\n\n return data\n}\n\nexport const downloadReport = async ({\n req,\n services,\n res,\n redirect,\n loadType,\n}: {\n req: Request\n services: Services\n res: Response\n redirect: string\n loadType?: LoadType\n}) => {\n const { dprUser, token } = LocalsHelper.getValues(res)\n const {\n reportId,\n id,\n tableId,\n dataProductDefinitionsPath,\n reportName,\n name,\n cols: columns,\n sortedAsc,\n sortColumn,\n } = req.body\n const { downloadPermissionService } = services\n const canDownloadReport = await downloadPermissionService.downloadEnabledForReport(dprUser.id, reportId, id)\n const streamingEnabled = isBooleanFlagExplicitlyEnabled('streamingDownloadEnabled', res.app)\n\n if (!canDownloadReport) {\n res.redirect(redirect)\n } else {\n const definition = await services.reportingService.getDefinition(token, reportId, id, dataProductDefinitionsPath)\n const queryParams = {\n dataProductDefinitionsPath,\n ...(sortedAsc && { sortedAsc }),\n ...(sortColumn && { sortColumn }),\n }\n\n let reportData\n if (loadType === LoadType.SYNC) {\n reportData = await downloadSyncData({\n definition,\n services,\n token,\n queryParams,\n })\n } else {\n if (streamingEnabled) {\n const streamDownloadQueryParams = {\n dataProductDefinitionsPath,\n ...(columns && { columns: JSON.parse(columns) }),\n ...(sortedAsc && { sortedAsc }),\n ...(sortColumn && { sortColumn }),\n }\n await streamDownloadAsyncData({\n services,\n token,\n reportId,\n id,\n tableId,\n queryParams: streamDownloadQueryParams,\n res,\n })\n return\n }\n\n reportData = await dowloadAsyncData({\n services,\n token,\n reportId,\n id,\n tableId,\n queryParams,\n })\n }\n if (columns) {\n reportData = applyColumnsAndSort(reportData, JSON.parse(columns))\n }\n reportData = removeHtmlTags(reportData, definition)\n const fields = definition.variant.specification?.fields || []\n const keys: KeysList = getKeys(reportData, fields)\n const csvData = convertToCsv(reportData, { keys, emptyFieldValue: '' })\n\n res.setHeader('Content-Type', 'application/json')\n res.setHeader('Content-disposition', `attachment; filename=${reportName}-${name}-${new Date().toISOString()}.csv`)\n res.end(csvData)\n }\n}\n\nexport default {\n downloadReport,\n getKeys,\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["ReportQuery", "LocalsHelper"]
7
7
  }
@@ -8,6 +8,7 @@ import { components } from '../../../types/api'
8
8
  import LocalsHelper from '../../../utils/localsHelper'
9
9
  import { Template } from '../../../types/Templates'
10
10
  import ReportQuery from '../../../types/ReportQuery'
11
+ import { isBooleanFlagExplicitlyEnabled } from '../../../services/featureFlagService'
11
12
 
12
13
  const convertToCsv = (reportData: Dict<string>[], options: Json2CsvOptions) => {
13
14
  const csvData = json2csv(reportData, options)
@@ -74,6 +75,27 @@ const removeHtmlTags = (
74
75
  return reportData
75
76
  }
76
77
 
78
+ const streamDownloadAsyncData = async (args: {
79
+ services: Services
80
+ token: string
81
+ tableId: string
82
+ reportId: string
83
+ id: string
84
+ queryParams: {
85
+ dataProductDefinitionsPath: string
86
+ columns: string[]
87
+ sortedAsc?: string
88
+ sortColumn?: string
89
+ }
90
+ res: Response
91
+ }) => {
92
+ const { token, services, tableId, reportId, id, queryParams, res } = args
93
+ const query: Record<string, string | string[]> = {
94
+ ...queryParams,
95
+ }
96
+ return services.reportingService.downloadAsyncReport(token, reportId, id, tableId, query, res)
97
+ }
98
+
77
99
  const dowloadAsyncData = async (args: {
78
100
  services: Services
79
101
  token: string
@@ -162,6 +184,8 @@ export const downloadReport = async ({
162
184
  } = req.body
163
185
  const { downloadPermissionService } = services
164
186
  const canDownloadReport = await downloadPermissionService.downloadEnabledForReport(dprUser.id, reportId, id)
187
+ const streamingEnabled = isBooleanFlagExplicitlyEnabled('streamingDownloadEnabled', res.app)
188
+
165
189
  if (!canDownloadReport) {
166
190
  res.redirect(redirect)
167
191
  } else {
@@ -181,6 +205,25 @@ export const downloadReport = async ({
181
205
  queryParams,
182
206
  })
183
207
  } else {
208
+ if (streamingEnabled) {
209
+ const streamDownloadQueryParams = {
210
+ dataProductDefinitionsPath,
211
+ ...(columns && { columns: JSON.parse(columns) }),
212
+ ...(sortedAsc && { sortedAsc }),
213
+ ...(sortColumn && { sortColumn }),
214
+ }
215
+ await streamDownloadAsyncData({
216
+ services,
217
+ token,
218
+ reportId,
219
+ id,
220
+ tableId,
221
+ queryParams: streamDownloadQueryParams,
222
+ res,
223
+ })
224
+ return
225
+ }
226
+
184
227
  reportData = await dowloadAsyncData({
185
228
  services,
186
229
  token,
@@ -96,8 +96,8 @@ const initReportQuery = async (definition, columns, res, req, services, requestD
96
96
  res,
97
97
  services
98
98
  });
99
- const sortColumn = req.query?.["sortColumn"] || requestData?.query?.data?.["sortColumn"];
100
- const sortedAsc = req.query?.["sortedAsc"] || requestData?.query?.data?.["sortedAsc"];
99
+ const sortColumn = req.query?.["sortColumn"] || requestData?.sortBy?.data?.["sortColumn"];
100
+ const sortedAsc = req.query?.["sortedAsc"] || requestData?.sortBy?.data?.["sortedAsc"];
101
101
  const selectedPage = req.query?.["selectedPage"];
102
102
  const pageSize = req.query?.["pageSize"];
103
103
  const filtersQuery = import_utils3.default.setRequestQueryFromFilterValues(filtersData.filters);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../dpr/routes/journeys/view-report/async/report/utils.ts"],
4
- "sourcesContent": ["import parseUrl from 'parseurl'\nimport { Url } from 'url'\nimport { Request, Response } from 'express'\n\n// Types\nimport type { Columns } from '../../../../../components/_reports/report-columns-form/types'\nimport type { AsyncReportUtilsParams } from '../../../../../types/AsyncReportUtils'\nimport type { DataTable } from '../../../../../utils/DataTableBuilder/types'\nimport type { components } from '../../../../../types/api'\nimport type { AsyncSummary, RequestedReport } from '../../../../../types/UserReports'\nimport { LoadType, ReportType } from '../../../../../types/UserReports'\nimport ReportQuery from '../../../../../types/ReportQuery'\nimport type { ChildData } from '../../../../../utils/ParentChildDataTableBuilder/types'\nimport type { ExtractedDefinitionData, ExtractedRequestData, ReportUrls } from './types'\nimport type { DownloadActionParams } from '../../../../../components/_reports/report-actions/types'\nimport { FiltersType } from '../../../../../components/_filters/filtersTypeEnum'\nimport type { Services } from '../../../../../types/Services'\n\n// Utils\nimport definitionUtils from '../../../../../utils/definitionUtils'\nimport PaginationUtils from '../../../../../components/_reports/report-pagination/utils'\nimport TotalsUtils from '../../../../../components/_reports/report-totals/utils'\nimport ReportFiltersUtils from '../../../../../components/_filters/utils'\nimport ColumnUtils from '../../../../../components/_reports/report-columns-form/utils'\nimport ReportActionsUtils from '../../../../../components/_reports/report-actions/utils'\nimport UserReportsUtils from '../../../../../components/user-reports/utils'\nimport LocalsHelper from '../../../../../utils/localsHelper'\nimport DataTableUtils from '../../../../../components/_reports/report-data-table/utils'\nimport RequestedReportService from '../../../my-reports/requested-reports/service'\n\nimport CollatedSummaryBuilder from '../../../../../utils/CollatedSummaryBuilder/CollatedSummaryBuilder'\n\nexport const getData = async ({\n res,\n req,\n services,\n token,\n userId,\n}: AsyncReportUtilsParams & { token: string; userId: string }) => {\n const { definitionsPath: definitionPath } = LocalsHelper.getValues(res)\n const { reportId, variantId, id, tableId } = req.params\n const reportVariantId = variantId || id\n\n // Get the request data\n const requestedReportService = <RequestedReportService>services.requestedReportService\n const requestData: RequestedReport | undefined = await requestedReportService.getReportByTableId(tableId, userId)\n const queryData = requestData?.query?.data\n\n // Get the definition\n const definition: components['schemas']['SingleVariantReportDefinition'] =\n await services.reportingService.getDefinition(token, reportId, reportVariantId, definitionPath, queryData)\n const { variant } = definition\n const { specification } = variant\n\n if (!specification) {\n throw new Error('No specification found in variant definition')\n }\n\n // Get the columns\n const columns = ColumnUtils.getColumns(specification, req)\n\n // initialise report query\n const reportQuery = await initReportQuery(definition, columns, res, req, services, requestData)\n\n // Get the reportData\n const reportData = await getReportData({ definition, services, token, req, res, reportQuery })\n\n // Get the summary data, if applicable\n const { summaries } = definition.variant\n const summariesData = !summaries ? [] : await getSummariesData(summaries, services, token, req, res)\n\n // Get the child data, if applicable\n const { childVariants } = definition.variant\n const childData: ChildData[] = !childVariants\n ? []\n : await getChildData(childVariants, services, token, req, res, requestData)\n\n return {\n definition,\n requestData,\n reportData,\n summariesData,\n childData,\n reportQuery,\n columns,\n }\n}\n\nconst initReportQuery = async (\n definition: components['schemas']['SingleVariantReportDefinition'],\n columns: Columns,\n res: Response,\n req: Request,\n services: Services,\n requestData?: RequestedReport,\n) => {\n const { definitionsPath } = LocalsHelper.getValues(res)\n const fields = definitionUtils.getFields(definition)\n const template = definitionUtils.getTemplate(definition)\n\n const filtersData = await ReportFiltersUtils.getFilters({\n fields,\n req,\n filtersType: FiltersType.INTERACTIVE,\n res,\n services,\n })\n\n // Sort\n const sortColumn = req.query?.['sortColumn'] || requestData?.query?.data?.['sortColumn']\n const sortedAsc = req.query?.['sortedAsc'] || requestData?.query?.data?.['sortedAsc']\n\n // Pagination\n const selectedPage = req.query?.['selectedPage']\n const pageSize = req.query?.['pageSize']\n\n // Filters\n const filtersQuery = ReportFiltersUtils.setRequestQueryFromFilterValues(filtersData.filters)\n\n const queryParams = {\n ...(sortColumn && { sortColumn }),\n ...(sortedAsc && { sortedAsc }),\n ...filtersQuery,\n ...(pageSize && { pageSize }),\n ...(selectedPage && { selectedPage }),\n ...(columns && { columns: columns.value }),\n }\n\n return new ReportQuery({\n fields,\n template,\n queryParams,\n definitionsPath,\n })\n}\n\nconst getReportData = async (args: {\n definition: components['schemas']['SingleVariantReportDefinition']\n services: Services\n token: string\n req: Request\n res: Response\n reportQuery: ReportQuery\n}) => {\n const { services, token, req, reportQuery } = args\n const { reportId, variantId, id, tableId } = req.params\n const reportVariantId = variantId || id\n\n return services.reportingService.getAsyncReport(\n token,\n reportId,\n reportVariantId,\n tableId,\n reportQuery.toRecordWithFilterPrefix(true),\n )\n}\n\nexport const getSummariesData = async (\n summaries: components['schemas']['ReportSummary'][],\n services: Services,\n token: string,\n req: Request,\n res: Response,\n): Promise<AsyncSummary[]> => {\n const { reportId, variantId, id, tableId } = req.params\n const { definitionsPath: dataProductDefinitionsPath } = LocalsHelper.getValues(res)\n const reportVariantId = variantId || id\n\n return Promise.all(\n summaries.map(async (summary) => {\n const summaryReport = await services.reportingService.getAsyncSummaryReport(\n token,\n reportId,\n reportVariantId,\n tableId,\n summary.id,\n {\n dataProductDefinitionsPath,\n },\n )\n\n return {\n ...summary,\n data: summaryReport,\n }\n }),\n )\n}\n\nexport const getChildData = async (\n childVariants: components['schemas']['ChildVariantDefinition'][],\n services: Services,\n token: string,\n req: Request,\n res: Response,\n requestData?: RequestedReport,\n): Promise<ChildData[]> => {\n const { definitionsPath: dataProductDefinitionsPath } = LocalsHelper.getValues(res)\n const { reportId } = req.params\n const childExecutionData = requestData?.childExecutionData\n if (!childExecutionData) {\n throw new Error('getChildData: No execution data found for child variants')\n }\n return Promise.all(\n childVariants.map(async (childVariant) => {\n const { specification } = childVariant\n if (!specification) {\n throw new Error('getChildData: No specification found in child variant definition')\n }\n\n const query = new ReportQuery({\n fields: specification?.fields || [],\n template: 'parent-child',\n queryParams: req.query,\n definitionsPath: dataProductDefinitionsPath,\n }).toRecordWithFilterPrefix(true)\n\n const childData = childExecutionData.find((e) => e.variantId === childVariant.id)\n if (!childData || !childData.tableId) {\n throw new Error('getChildData: No matching child execution data found')\n }\n const { tableId: childTableId } = childData\n\n const childReport = await services.reportingService.getAsyncReport(\n token,\n reportId,\n childVariant.id,\n childTableId,\n query,\n )\n\n return {\n id: childVariant.id,\n data: childReport,\n }\n }),\n )\n}\n\n/**\n * Entry point function to render the report\n *\n * @param {AsyncReportUtilsParams} { req, res, services }\n * @return {*}\n */\nexport const renderReport = async ({ req, res, services }: AsyncReportUtilsParams) => {\n const { token, dprUser } = LocalsHelper.getValues(res)\n\n // Get the report data\n const { definition, requestData, reportData, childData, summariesData, reportQuery, columns } = await getData({\n req,\n res,\n services,\n token,\n userId: dprUser.id,\n })\n\n // Get the data table\n const dataTable: DataTable[] = DataTableUtils.createDataTable(\n definition,\n columns,\n reportData,\n childData,\n summariesData,\n reportQuery,\n )\n\n // Get the template data\n const templateData = await getTemplateData(\n req,\n res,\n services,\n definition,\n summariesData,\n dataTable,\n columns,\n reportQuery,\n requestData,\n )\n\n const renderData = {\n ...templateData,\n dataTable,\n }\n\n if (requestData && Object.keys(requestData).length) {\n UserReportsUtils.updateLastViewed({\n req,\n services,\n reportStateData: requestData,\n userId: dprUser.id,\n filters: templateData.filterData.filters,\n })\n }\n\n return { renderData }\n}\n\nconst getTemplateData = async (\n req: Request,\n res: Response,\n services: Services,\n definition: components['schemas']['SingleVariantReportDefinition'],\n summariesData: AsyncSummary[],\n dataTable: DataTable[],\n columns: Columns,\n reportQuery: ReportQuery,\n requestData?: RequestedReport,\n) => {\n const { nestedBaseUrl } = LocalsHelper.getValues(res)\n\n // get url data\n const url = parseUrl(req)\n if (!url) {\n throw new Error('Unable to set url data from request')\n }\n\n const urls = url ? setUrls(url, req) : undefined\n\n // get from definition\n const definitionData = extractDataFromDefinition(definition)\n const { fields, specification } = definitionData\n\n // get from requestedData\n const requestedData = requestData ? extractDataFromRequest(requestData) : undefined\n\n // Get the count\n const count = await getCount(definition, services, res, req, reportQuery)\n\n // Get the filters\n const filterData = await ReportFiltersUtils.getFilters({\n fields,\n req,\n res,\n services,\n filtersType: FiltersType.INTERACTIVE,\n })\n\n // Set the features\n const features = await setFeatures(services, res, req, columns, definitionData, requestedData, urls)\n\n // Set the extra meta data\n const meta = setMetaData(res, req)\n\n let reportSummaries\n if (summariesData.length) {\n const collatedSummaryBuilder = new CollatedSummaryBuilder(specification, summariesData)\n reportSummaries = collatedSummaryBuilder.collatePageSummaries()\n }\n\n let pagination\n let totals\n if (definitionData.template === 'list') {\n pagination = PaginationUtils.getPaginationData(url, count, req)\n const { pageSize, currentPage, totalRows } = pagination\n totals = TotalsUtils.getTotals(pageSize, currentPage, totalRows, dataTable[0].rowCount)\n }\n\n return {\n ...(showColumns(specification) && { columns }),\n filterData,\n count,\n nestedBaseUrl,\n ...meta,\n ...features,\n ...definitionData,\n ...requestedData,\n ...urls,\n ...(pagination && { pagination }),\n ...(totals && { totals }),\n ...(reportSummaries && { reportSummaries }),\n }\n}\n\nconst showColumns = (specification: components['schemas']['Specification']) => {\n const { template } = specification\n\n return !['row-section', 'row-section-child', 'summary', 'summary-section'].includes(template)\n}\n\nconst setMetaData = (res: Response, req: Request) => {\n const { csrfToken } = LocalsHelper.getValues(res)\n const { tableId, reportId, id } = req.params\n\n return {\n csrfToken,\n loadType: LoadType.ASYNC,\n type: ReportType.REPORT,\n tableId,\n reportId,\n id,\n }\n}\n\nconst setUrls = (url: Url, req: Request): ReportUrls => {\n const { search } = url\n const encodedSearch = search ? encodeURIComponent(search) : undefined\n const pathname = search ? req.originalUrl.split(search)[0] : req.originalUrl\n const reportUrl = pathname.replace('/download-disabled', '').replace('/download-disabled?', '')\n\n return {\n reportUrl,\n reportSearch: search || undefined,\n encodedSearch,\n pathname,\n }\n}\n\nconst setFeatures = async (\n services: Services,\n res: Response,\n req: Request,\n columns: Columns,\n definitionData: ExtractedDefinitionData,\n requestData?: ExtractedRequestData,\n urls?: ReportUrls,\n) => {\n const { csrfToken, dprUser, bookmarkingEnabled, downloadingEnabled } = LocalsHelper.getValues(res)\n const { reportId, id } = req.params\n const { downloadPermissionService, bookmarkService } = services\n\n let canDownload = false\n if (downloadingEnabled) {\n canDownload = await downloadPermissionService.downloadEnabledForReport(dprUser.id, reportId, id)\n }\n\n let bookmarked\n if (bookmarkingEnabled) {\n bookmarked = await bookmarkService.isBookmarked(id, reportId, dprUser.id)\n }\n\n const actions = setActions(csrfToken, columns, canDownload, res, req, definitionData, requestData, urls)\n\n return {\n actions,\n canDownload,\n bookmarked,\n }\n}\n\nconst getCount = async (\n definition: components['schemas']['SingleVariantReportDefinition'],\n services: Services,\n res: Response,\n req: Request,\n reportQuery: ReportQuery,\n) => {\n const { token } = LocalsHelper.getValues(res)\n const { tableId, reportId, id } = req.params\n\n return !definition.variant.interactive\n ? services.reportingService.getAsyncCount(token, tableId)\n : services.reportingService.getAsyncInteractiveCount(token, tableId, reportId, id, reportQuery)\n}\n\nconst extractDataFromDefinition = (\n definition: components['schemas']['SingleVariantReportDefinition'],\n): ExtractedDefinitionData => {\n const { variant, name: reportName, description: reportDescription } = definition\n const { classification, printable, specification, name, description } = variant\n if (!specification) {\n throw new Error('No specification found in variant definition')\n }\n const { template, fields } = specification\n\n return {\n reportName,\n name,\n description: description || reportDescription,\n classification,\n printable: Boolean(printable),\n specification,\n template,\n fields,\n }\n}\n\nconst extractDataFromRequest = (requestData: RequestedReport): ExtractedRequestData => {\n const { query, url, timestamp } = requestData\n\n return {\n executionId: requestData.executionId,\n requestedTimestamp: timestamp.requested ? new Date(timestamp.requested).toLocaleString() : undefined,\n querySummary: query?.summary || [],\n queryData: query?.data,\n requestUrl: url?.request,\n defaultQuery: url?.report?.default,\n dataProductDefinitionsPath: requestData.dataProductDefinitionsPath,\n }\n}\n\nconst setActions = (\n csrfToken: string,\n columns: Columns,\n canDownload: boolean,\n res: Response,\n req: Request,\n definitionData: ExtractedDefinitionData,\n requestData?: ExtractedRequestData,\n urls?: ReportUrls,\n) => {\n const { reportName, name, printable } = definitionData\n const { tableId, id, reportId } = req.params\n const { nestedBaseUrl, definitionsPath, downloadingEnabled } = LocalsHelper.getValues(res)\n\n // DownloadActionParams\n let downloadConfig: DownloadActionParams | undefined\n if (urls && downloadingEnabled) {\n downloadConfig = {\n enabled: downloadingEnabled,\n name,\n reportName,\n csrfToken,\n reportId,\n id,\n tableId,\n columns: columns.value,\n definitionPath: definitionsPath,\n loadType: LoadType.ASYNC,\n nestedBaseUrl,\n canDownload,\n currentUrl: urls.pathname,\n currentQueryParams: urls.reportSearch,\n ...(requestData?.queryData && {\n sortColumn: <string>requestData.queryData['sortColumn'],\n sortedAsc: <string>requestData.queryData['sortedAsc'],\n }),\n }\n }\n\n let shareConfig\n let copyConfig\n if (requestData?.requestUrl?.fullUrl) {\n shareConfig = {\n reportName,\n name,\n url: requestData.requestUrl.fullUrl,\n }\n copyConfig = {\n url: requestData.requestUrl.fullUrl,\n }\n }\n\n let refreshConfig\n if (requestData?.executionId && requestData?.requestUrl?.fullUrl) {\n refreshConfig = {\n url: requestData.requestUrl.fullUrl,\n executionId: requestData.executionId,\n }\n }\n\n return ReportActionsUtils.getActions({\n ...(downloadConfig && { download: downloadConfig }),\n ...(shareConfig && { share: shareConfig }),\n ...(refreshConfig && { refresh: refreshConfig }),\n ...(copyConfig && { copy: copyConfig }),\n print: { enabled: printable },\n })\n}\n\nexport default {\n renderReport,\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import parseUrl from 'parseurl'\nimport { Url } from 'url'\nimport { Request, Response } from 'express'\n\n// Types\nimport type { Columns } from '../../../../../components/_reports/report-columns-form/types'\nimport type { AsyncReportUtilsParams } from '../../../../../types/AsyncReportUtils'\nimport type { DataTable } from '../../../../../utils/DataTableBuilder/types'\nimport type { components } from '../../../../../types/api'\nimport type { AsyncSummary, RequestedReport } from '../../../../../types/UserReports'\nimport { LoadType, ReportType } from '../../../../../types/UserReports'\nimport ReportQuery from '../../../../../types/ReportQuery'\nimport type { ChildData } from '../../../../../utils/ParentChildDataTableBuilder/types'\nimport type { ExtractedDefinitionData, ExtractedRequestData, ReportUrls } from './types'\nimport type { DownloadActionParams } from '../../../../../components/_reports/report-actions/types'\nimport { FiltersType } from '../../../../../components/_filters/filtersTypeEnum'\nimport type { Services } from '../../../../../types/Services'\n\n// Utils\nimport definitionUtils from '../../../../../utils/definitionUtils'\nimport PaginationUtils from '../../../../../components/_reports/report-pagination/utils'\nimport TotalsUtils from '../../../../../components/_reports/report-totals/utils'\nimport ReportFiltersUtils from '../../../../../components/_filters/utils'\nimport ColumnUtils from '../../../../../components/_reports/report-columns-form/utils'\nimport ReportActionsUtils from '../../../../../components/_reports/report-actions/utils'\nimport UserReportsUtils from '../../../../../components/user-reports/utils'\nimport LocalsHelper from '../../../../../utils/localsHelper'\nimport DataTableUtils from '../../../../../components/_reports/report-data-table/utils'\nimport RequestedReportService from '../../../my-reports/requested-reports/service'\n\nimport CollatedSummaryBuilder from '../../../../../utils/CollatedSummaryBuilder/CollatedSummaryBuilder'\n\nexport const getData = async ({\n res,\n req,\n services,\n token,\n userId,\n}: AsyncReportUtilsParams & { token: string; userId: string }) => {\n const { definitionsPath: definitionPath } = LocalsHelper.getValues(res)\n const { reportId, variantId, id, tableId } = req.params\n const reportVariantId = variantId || id\n\n // Get the request data\n const requestedReportService = <RequestedReportService>services.requestedReportService\n const requestData: RequestedReport | undefined = await requestedReportService.getReportByTableId(tableId, userId)\n const queryData = requestData?.query?.data\n\n // Get the definition\n const definition: components['schemas']['SingleVariantReportDefinition'] =\n await services.reportingService.getDefinition(token, reportId, reportVariantId, definitionPath, queryData)\n const { variant } = definition\n const { specification } = variant\n\n if (!specification) {\n throw new Error('No specification found in variant definition')\n }\n\n // Get the columns\n const columns = ColumnUtils.getColumns(specification, req)\n\n // initialise report query\n const reportQuery = await initReportQuery(definition, columns, res, req, services, requestData)\n\n // Get the reportData\n const reportData = await getReportData({ definition, services, token, req, res, reportQuery })\n\n // Get the summary data, if applicable\n const { summaries } = definition.variant\n const summariesData = !summaries ? [] : await getSummariesData(summaries, services, token, req, res)\n\n // Get the child data, if applicable\n const { childVariants } = definition.variant\n const childData: ChildData[] = !childVariants\n ? []\n : await getChildData(childVariants, services, token, req, res, requestData)\n\n return {\n definition,\n requestData,\n reportData,\n summariesData,\n childData,\n reportQuery,\n columns,\n }\n}\n\nconst initReportQuery = async (\n definition: components['schemas']['SingleVariantReportDefinition'],\n columns: Columns,\n res: Response,\n req: Request,\n services: Services,\n requestData?: RequestedReport,\n) => {\n const { definitionsPath } = LocalsHelper.getValues(res)\n const fields = definitionUtils.getFields(definition)\n const template = definitionUtils.getTemplate(definition)\n\n const filtersData = await ReportFiltersUtils.getFilters({\n fields,\n req,\n filtersType: FiltersType.INTERACTIVE,\n res,\n services,\n })\n\n // Sort\n const sortColumn = req.query?.['sortColumn'] || requestData?.sortBy?.data?.['sortColumn']\n const sortedAsc = req.query?.['sortedAsc'] || requestData?.sortBy?.data?.['sortedAsc']\n\n // Pagination\n const selectedPage = req.query?.['selectedPage']\n const pageSize = req.query?.['pageSize']\n\n // Filters\n const filtersQuery = ReportFiltersUtils.setRequestQueryFromFilterValues(filtersData.filters)\n\n const queryParams = {\n ...(sortColumn && { sortColumn }),\n ...(sortedAsc && { sortedAsc }),\n ...filtersQuery,\n ...(pageSize && { pageSize }),\n ...(selectedPage && { selectedPage }),\n ...(columns && { columns: columns.value }),\n }\n\n return new ReportQuery({\n fields,\n template,\n queryParams,\n definitionsPath,\n })\n}\n\nconst getReportData = async (args: {\n definition: components['schemas']['SingleVariantReportDefinition']\n services: Services\n token: string\n req: Request\n res: Response\n reportQuery: ReportQuery\n}) => {\n const { services, token, req, reportQuery } = args\n const { reportId, variantId, id, tableId } = req.params\n const reportVariantId = variantId || id\n\n return services.reportingService.getAsyncReport(\n token,\n reportId,\n reportVariantId,\n tableId,\n reportQuery.toRecordWithFilterPrefix(true),\n )\n}\n\nexport const getSummariesData = async (\n summaries: components['schemas']['ReportSummary'][],\n services: Services,\n token: string,\n req: Request,\n res: Response,\n): Promise<AsyncSummary[]> => {\n const { reportId, variantId, id, tableId } = req.params\n const { definitionsPath: dataProductDefinitionsPath } = LocalsHelper.getValues(res)\n const reportVariantId = variantId || id\n\n return Promise.all(\n summaries.map(async (summary) => {\n const summaryReport = await services.reportingService.getAsyncSummaryReport(\n token,\n reportId,\n reportVariantId,\n tableId,\n summary.id,\n {\n dataProductDefinitionsPath,\n },\n )\n\n return {\n ...summary,\n data: summaryReport,\n }\n }),\n )\n}\n\nexport const getChildData = async (\n childVariants: components['schemas']['ChildVariantDefinition'][],\n services: Services,\n token: string,\n req: Request,\n res: Response,\n requestData?: RequestedReport,\n): Promise<ChildData[]> => {\n const { definitionsPath: dataProductDefinitionsPath } = LocalsHelper.getValues(res)\n const { reportId } = req.params\n const childExecutionData = requestData?.childExecutionData\n if (!childExecutionData) {\n throw new Error('getChildData: No execution data found for child variants')\n }\n return Promise.all(\n childVariants.map(async (childVariant) => {\n const { specification } = childVariant\n if (!specification) {\n throw new Error('getChildData: No specification found in child variant definition')\n }\n\n const query = new ReportQuery({\n fields: specification?.fields || [],\n template: 'parent-child',\n queryParams: req.query,\n definitionsPath: dataProductDefinitionsPath,\n }).toRecordWithFilterPrefix(true)\n\n const childData = childExecutionData.find((e) => e.variantId === childVariant.id)\n if (!childData || !childData.tableId) {\n throw new Error('getChildData: No matching child execution data found')\n }\n const { tableId: childTableId } = childData\n\n const childReport = await services.reportingService.getAsyncReport(\n token,\n reportId,\n childVariant.id,\n childTableId,\n query,\n )\n\n return {\n id: childVariant.id,\n data: childReport,\n }\n }),\n )\n}\n\n/**\n * Entry point function to render the report\n *\n * @param {AsyncReportUtilsParams} { req, res, services }\n * @return {*}\n */\nexport const renderReport = async ({ req, res, services }: AsyncReportUtilsParams) => {\n const { token, dprUser } = LocalsHelper.getValues(res)\n\n // Get the report data\n const { definition, requestData, reportData, childData, summariesData, reportQuery, columns } = await getData({\n req,\n res,\n services,\n token,\n userId: dprUser.id,\n })\n\n // Get the data table\n const dataTable: DataTable[] = DataTableUtils.createDataTable(\n definition,\n columns,\n reportData,\n childData,\n summariesData,\n reportQuery,\n )\n\n // Get the template data\n const templateData = await getTemplateData(\n req,\n res,\n services,\n definition,\n summariesData,\n dataTable,\n columns,\n reportQuery,\n requestData,\n )\n\n const renderData = {\n ...templateData,\n dataTable,\n }\n\n if (requestData && Object.keys(requestData).length) {\n UserReportsUtils.updateLastViewed({\n req,\n services,\n reportStateData: requestData,\n userId: dprUser.id,\n filters: templateData.filterData.filters,\n })\n }\n\n return { renderData }\n}\n\nconst getTemplateData = async (\n req: Request,\n res: Response,\n services: Services,\n definition: components['schemas']['SingleVariantReportDefinition'],\n summariesData: AsyncSummary[],\n dataTable: DataTable[],\n columns: Columns,\n reportQuery: ReportQuery,\n requestData?: RequestedReport,\n) => {\n const { nestedBaseUrl } = LocalsHelper.getValues(res)\n\n // get url data\n const url = parseUrl(req)\n if (!url) {\n throw new Error('Unable to set url data from request')\n }\n\n const urls = url ? setUrls(url, req) : undefined\n\n // get from definition\n const definitionData = extractDataFromDefinition(definition)\n const { fields, specification } = definitionData\n\n // get from requestedData\n const requestedData = requestData ? extractDataFromRequest(requestData) : undefined\n\n // Get the count\n const count = await getCount(definition, services, res, req, reportQuery)\n\n // Get the filters\n const filterData = await ReportFiltersUtils.getFilters({\n fields,\n req,\n res,\n services,\n filtersType: FiltersType.INTERACTIVE,\n })\n\n // Set the features\n const features = await setFeatures(services, res, req, columns, definitionData, requestedData, urls)\n\n // Set the extra meta data\n const meta = setMetaData(res, req)\n\n let reportSummaries\n if (summariesData.length) {\n const collatedSummaryBuilder = new CollatedSummaryBuilder(specification, summariesData)\n reportSummaries = collatedSummaryBuilder.collatePageSummaries()\n }\n\n let pagination\n let totals\n if (definitionData.template === 'list') {\n pagination = PaginationUtils.getPaginationData(url, count, req)\n const { pageSize, currentPage, totalRows } = pagination\n totals = TotalsUtils.getTotals(pageSize, currentPage, totalRows, dataTable[0].rowCount)\n }\n\n return {\n ...(showColumns(specification) && { columns }),\n filterData,\n count,\n nestedBaseUrl,\n ...meta,\n ...features,\n ...definitionData,\n ...requestedData,\n ...urls,\n ...(pagination && { pagination }),\n ...(totals && { totals }),\n ...(reportSummaries && { reportSummaries }),\n }\n}\n\nconst showColumns = (specification: components['schemas']['Specification']) => {\n const { template } = specification\n\n return !['row-section', 'row-section-child', 'summary', 'summary-section'].includes(template)\n}\n\nconst setMetaData = (res: Response, req: Request) => {\n const { csrfToken } = LocalsHelper.getValues(res)\n const { tableId, reportId, id } = req.params\n\n return {\n csrfToken,\n loadType: LoadType.ASYNC,\n type: ReportType.REPORT,\n tableId,\n reportId,\n id,\n }\n}\n\nconst setUrls = (url: Url, req: Request): ReportUrls => {\n const { search } = url\n const encodedSearch = search ? encodeURIComponent(search) : undefined\n const pathname = search ? req.originalUrl.split(search)[0] : req.originalUrl\n const reportUrl = pathname.replace('/download-disabled', '').replace('/download-disabled?', '')\n\n return {\n reportUrl,\n reportSearch: search || undefined,\n encodedSearch,\n pathname,\n }\n}\n\nconst setFeatures = async (\n services: Services,\n res: Response,\n req: Request,\n columns: Columns,\n definitionData: ExtractedDefinitionData,\n requestData?: ExtractedRequestData,\n urls?: ReportUrls,\n) => {\n const { csrfToken, dprUser, bookmarkingEnabled, downloadingEnabled } = LocalsHelper.getValues(res)\n const { reportId, id } = req.params\n const { downloadPermissionService, bookmarkService } = services\n\n let canDownload = false\n if (downloadingEnabled) {\n canDownload = await downloadPermissionService.downloadEnabledForReport(dprUser.id, reportId, id)\n }\n\n let bookmarked\n if (bookmarkingEnabled) {\n bookmarked = await bookmarkService.isBookmarked(id, reportId, dprUser.id)\n }\n\n const actions = setActions(csrfToken, columns, canDownload, res, req, definitionData, requestData, urls)\n\n return {\n actions,\n canDownload,\n bookmarked,\n }\n}\n\nconst getCount = async (\n definition: components['schemas']['SingleVariantReportDefinition'],\n services: Services,\n res: Response,\n req: Request,\n reportQuery: ReportQuery,\n) => {\n const { token } = LocalsHelper.getValues(res)\n const { tableId, reportId, id } = req.params\n\n return !definition.variant.interactive\n ? services.reportingService.getAsyncCount(token, tableId)\n : services.reportingService.getAsyncInteractiveCount(token, tableId, reportId, id, reportQuery)\n}\n\nconst extractDataFromDefinition = (\n definition: components['schemas']['SingleVariantReportDefinition'],\n): ExtractedDefinitionData => {\n const { variant, name: reportName, description: reportDescription } = definition\n const { classification, printable, specification, name, description } = variant\n if (!specification) {\n throw new Error('No specification found in variant definition')\n }\n const { template, fields } = specification\n\n return {\n reportName,\n name,\n description: description || reportDescription,\n classification,\n printable: Boolean(printable),\n specification,\n template,\n fields,\n }\n}\n\nconst extractDataFromRequest = (requestData: RequestedReport): ExtractedRequestData => {\n const { query, url, timestamp } = requestData\n\n return {\n executionId: requestData.executionId,\n requestedTimestamp: timestamp.requested ? new Date(timestamp.requested).toLocaleString() : undefined,\n querySummary: query?.summary || [],\n queryData: query?.data,\n requestUrl: url?.request,\n defaultQuery: url?.report?.default,\n dataProductDefinitionsPath: requestData.dataProductDefinitionsPath,\n }\n}\n\nconst setActions = (\n csrfToken: string,\n columns: Columns,\n canDownload: boolean,\n res: Response,\n req: Request,\n definitionData: ExtractedDefinitionData,\n requestData?: ExtractedRequestData,\n urls?: ReportUrls,\n) => {\n const { reportName, name, printable } = definitionData\n const { tableId, id, reportId } = req.params\n const { nestedBaseUrl, definitionsPath, downloadingEnabled } = LocalsHelper.getValues(res)\n\n // DownloadActionParams\n let downloadConfig: DownloadActionParams | undefined\n if (urls && downloadingEnabled) {\n downloadConfig = {\n enabled: downloadingEnabled,\n name,\n reportName,\n csrfToken,\n reportId,\n id,\n tableId,\n columns: columns.value,\n definitionPath: definitionsPath,\n loadType: LoadType.ASYNC,\n nestedBaseUrl,\n canDownload,\n currentUrl: urls.pathname,\n currentQueryParams: urls.reportSearch,\n ...(requestData?.queryData && {\n sortColumn: <string>requestData.queryData['sortColumn'],\n sortedAsc: <string>requestData.queryData['sortedAsc'],\n }),\n }\n }\n\n let shareConfig\n let copyConfig\n if (requestData?.requestUrl?.fullUrl) {\n shareConfig = {\n reportName,\n name,\n url: requestData.requestUrl.fullUrl,\n }\n copyConfig = {\n url: requestData.requestUrl.fullUrl,\n }\n }\n\n let refreshConfig\n if (requestData?.executionId && requestData?.requestUrl?.fullUrl) {\n refreshConfig = {\n url: requestData.requestUrl.fullUrl,\n executionId: requestData.executionId,\n }\n }\n\n return ReportActionsUtils.getActions({\n ...(downloadConfig && { download: downloadConfig }),\n ...(shareConfig && { share: shareConfig }),\n ...(refreshConfig && { refresh: refreshConfig }),\n ...(copyConfig && { copy: copyConfig }),\n print: { enabled: printable },\n })\n}\n\nexport default {\n renderReport,\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAqB;AAUrB,yBAAqC;AACrC,yBAAwB;AAIxB,6BAA4B;AAI5B,6BAA4B;AAC5B,mBAA4B;AAC5B,IAAAA,gBAAwB;AACxB,IAAAA,gBAA+B;AAC/B,IAAAA,gBAAwB;AACxB,IAAAA,gBAA+B;AAC/B,IAAAA,gBAA6B;AAC7B,0BAAyB;AACzB,IAAAA,gBAA2B;AAG3B,oCAAmC;AAE5B,MAAM,UAAU,OAAO;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAkE;AAChE,QAAM,EAAE,iBAAiB,eAAe,IAAI,oBAAAC,QAAa,UAAU,GAAG;AACtE,QAAM,EAAE,UAAU,WAAW,IAAI,QAAQ,IAAI,IAAI;AACjD,QAAM,kBAAkB,aAAa;AAGrC,QAAM,yBAAiD,SAAS;AAChE,QAAM,cAA2C,MAAM,uBAAuB,mBAAmB,SAAS,MAAM;AAChH,QAAM,YAAY,aAAa,OAAO;AAGtC,QAAM,aACJ,MAAM,SAAS,iBAAiB,cAAc,OAAO,UAAU,iBAAiB,gBAAgB,SAAS;AAC3G,QAAM,EAAE,QAAQ,IAAI;AACpB,QAAM,EAAE,cAAc,IAAI;AAE1B,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAGA,QAAM,UAAU,cAAAC,QAAY,WAAW,eAAe,GAAG;AAGzD,QAAM,cAAc,MAAM,gBAAgB,YAAY,SAAS,KAAK,KAAK,UAAU,WAAW;AAG9F,QAAM,aAAa,MAAM,cAAc,EAAE,YAAY,UAAU,OAAO,KAAK,KAAK,YAAY,CAAC;AAG7F,QAAM,EAAE,UAAU,IAAI,WAAW;AACjC,QAAM,gBAAgB,CAAC,YAAY,CAAC,IAAI,MAAM,iBAAiB,WAAW,UAAU,OAAO,KAAK,GAAG;AAGnG,QAAM,EAAE,cAAc,IAAI,WAAW;AACrC,QAAM,YAAyB,CAAC,gBAC5B,CAAC,IACD,MAAM,aAAa,eAAe,UAAU,OAAO,KAAK,KAAK,WAAW;AAE5E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,MAAM,kBAAkB,OACtB,YACA,SACA,KACA,KACA,UACA,gBACG;AACH,QAAM,EAAE,gBAAgB,IAAI,oBAAAD,QAAa,UAAU,GAAG;AACtD,QAAM,SAAS,uBAAAE,QAAgB,UAAU,UAAU;AACnD,QAAM,WAAW,uBAAAA,QAAgB,YAAY,UAAU;AAEvD,QAAM,cAAc,MAAM,cAAAC,QAAmB,WAAW;AAAA,IACtD;AAAA,IACA;AAAA,IACA,aAAa,mCAAY;AAAA,IACzB;AAAA,IACA;AAAA,EACF,CAAC;AAGD,QAAM,aAAa,IAAI,QAAQ,YAAY,KAAK,aAAa,QAAQ,OAAO,YAAY;AACxF,QAAM,YAAY,IAAI,QAAQ,WAAW,KAAK,aAAa,QAAQ,OAAO,WAAW;AAGrF,QAAM,eAAe,IAAI,QAAQ,cAAc;AAC/C,QAAM,WAAW,IAAI,QAAQ,UAAU;AAGvC,QAAM,eAAe,cAAAA,QAAmB,gCAAgC,YAAY,OAAO;AAE3F,QAAM,cAAc;AAAA,IAClB,GAAI,cAAc,EAAE,WAAW;AAAA,IAC/B,GAAI,aAAa,EAAE,UAAU;AAAA,IAC7B,GAAG;AAAA,IACH,GAAI,YAAY,EAAE,SAAS;AAAA,IAC3B,GAAI,gBAAgB,EAAE,aAAa;AAAA,IACnC,GAAI,WAAW,EAAE,SAAS,QAAQ,MAAM;AAAA,EAC1C;AAEA,SAAO,IAAI,mBAAAC,QAAY;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,MAAM,gBAAgB,OAAO,SAOvB;AACJ,QAAM,EAAE,UAAU,OAAO,KAAK,YAAY,IAAI;AAC9C,QAAM,EAAE,UAAU,WAAW,IAAI,QAAQ,IAAI,IAAI;AACjD,QAAM,kBAAkB,aAAa;AAErC,SAAO,SAAS,iBAAiB;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,yBAAyB,IAAI;AAAA,EAC3C;AACF;AAEO,MAAM,mBAAmB,OAC9B,WACA,UACA,OACA,KACA,QAC4B;AAC5B,QAAM,EAAE,UAAU,WAAW,IAAI,QAAQ,IAAI,IAAI;AACjD,QAAM,EAAE,iBAAiB,2BAA2B,IAAI,oBAAAJ,QAAa,UAAU,GAAG;AAClF,QAAM,kBAAkB,aAAa;AAErC,SAAO,QAAQ;AAAA,IACb,UAAU,IAAI,OAAO,YAAY;AAC/B,YAAM,gBAAgB,MAAM,SAAS,iBAAiB;AAAA,QACpD;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,UACE;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,MAAM,eAAe,OAC1B,eACA,UACA,OACA,KACA,KACA,gBACyB;AACzB,QAAM,EAAE,iBAAiB,2BAA2B,IAAI,oBAAAA,QAAa,UAAU,GAAG;AAClF,QAAM,EAAE,SAAS,IAAI,IAAI;AACzB,QAAM,qBAAqB,aAAa;AACxC,MAAI,CAAC,oBAAoB;AACvB,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,SAAO,QAAQ;AAAA,IACb,cAAc,IAAI,OAAO,iBAAiB;AACxC,YAAM,EAAE,cAAc,IAAI;AAC1B,UAAI,CAAC,eAAe;AAClB,cAAM,IAAI,MAAM,kEAAkE;AAAA,MACpF;AAEA,YAAM,QAAQ,IAAI,mBAAAI,QAAY;AAAA,QAC5B,QAAQ,eAAe,UAAU,CAAC;AAAA,QAClC,UAAU;AAAA,QACV,aAAa,IAAI;AAAA,QACjB,iBAAiB;AAAA,MACnB,CAAC,EAAE,yBAAyB,IAAI;AAEhC,YAAM,YAAY,mBAAmB,KAAK,CAAC,MAAM,EAAE,cAAc,aAAa,EAAE;AAChF,UAAI,CAAC,aAAa,CAAC,UAAU,SAAS;AACpC,cAAM,IAAI,MAAM,sDAAsD;AAAA,MACxE;AACA,YAAM,EAAE,SAAS,aAAa,IAAI;AAElC,YAAM,cAAc,MAAM,SAAS,iBAAiB;AAAA,QAClD;AAAA,QACA;AAAA,QACA,aAAa;AAAA,QACb;AAAA,QACA;AAAA,MACF;AAEA,aAAO;AAAA,QACL,IAAI,aAAa;AAAA,QACjB,MAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAQO,MAAM,eAAe,OAAO,EAAE,KAAK,KAAK,SAAS,MAA8B;AACpF,QAAM,EAAE,OAAO,QAAQ,IAAI,oBAAAJ,QAAa,UAAU,GAAG;AAGrD,QAAM,EAAE,YAAY,aAAa,YAAY,WAAW,eAAe,aAAa,QAAQ,IAAI,MAAM,QAAQ;AAAA,IAC5G;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAGD,QAAM,YAAyB,cAAAK,QAAe;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,eAAe,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,aAAa;AAAA,IACjB,GAAG;AAAA,IACH;AAAA,EACF;AAEA,MAAI,eAAe,OAAO,KAAK,WAAW,EAAE,QAAQ;AAClD,kBAAAC,QAAiB,iBAAiB;AAAA,MAChC;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,QAAQ,QAAQ;AAAA,MAChB,SAAS,aAAa,WAAW;AAAA,IACnC,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,WAAW;AACtB;AAEA,MAAM,kBAAkB,OACtB,KACA,KACA,UACA,YACA,eACA,WACA,SACA,aACA,gBACG;AACH,QAAM,EAAE,cAAc,IAAI,oBAAAN,QAAa,UAAU,GAAG;AAGpD,QAAM,UAAM,gBAAAO,SAAS,GAAG;AACxB,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD;AAEA,QAAM,OAAO,MAAM,QAAQ,KAAK,GAAG,IAAI;AAGvC,QAAM,iBAAiB,0BAA0B,UAAU;AAC3D,QAAM,EAAE,QAAQ,cAAc,IAAI;AAGlC,QAAM,gBAAgB,cAAc,uBAAuB,WAAW,IAAI;AAG1E,QAAM,QAAQ,MAAM,SAAS,YAAY,UAAU,KAAK,KAAK,WAAW;AAGxE,QAAM,aAAa,MAAM,cAAAJ,QAAmB,WAAW;AAAA,IACrD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,mCAAY;AAAA,EAC3B,CAAC;AAGD,QAAM,WAAW,MAAM,YAAY,UAAU,KAAK,KAAK,SAAS,gBAAgB,eAAe,IAAI;AAGnG,QAAM,OAAO,YAAY,KAAK,GAAG;AAEjC,MAAI;AACJ,MAAI,cAAc,QAAQ;AACxB,UAAM,yBAAyB,IAAI,8BAAAK,QAAuB,eAAe,aAAa;AACtF,sBAAkB,uBAAuB,qBAAqB;AAAA,EAChE;AAEA,MAAI;AACJ,MAAI;AACJ,MAAI,eAAe,aAAa,QAAQ;AACtC,iBAAa,aAAAC,QAAgB,kBAAkB,KAAK,OAAO,GAAG;AAC9D,UAAM,EAAE,UAAU,aAAa,UAAU,IAAI;AAC7C,aAAS,cAAAC,QAAY,UAAU,UAAU,aAAa,WAAW,UAAU,CAAC,EAAE,QAAQ;AAAA,EACxF;AAEA,SAAO;AAAA,IACL,GAAI,YAAY,aAAa,KAAK,EAAE,QAAQ;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAI,cAAc,EAAE,WAAW;AAAA,IAC/B,GAAI,UAAU,EAAE,OAAO;AAAA,IACvB,GAAI,mBAAmB,EAAE,gBAAgB;AAAA,EAC3C;AACF;AAEA,MAAM,cAAc,CAAC,kBAA0D;AAC7E,QAAM,EAAE,SAAS,IAAI;AAErB,SAAO,CAAC,CAAC,eAAe,qBAAqB,WAAW,iBAAiB,EAAE,SAAS,QAAQ;AAC9F;AAEA,MAAM,cAAc,CAAC,KAAe,QAAiB;AACnD,QAAM,EAAE,UAAU,IAAI,oBAAAV,QAAa,UAAU,GAAG;AAChD,QAAM,EAAE,SAAS,UAAU,GAAG,IAAI,IAAI;AAEtC,SAAO;AAAA,IACL;AAAA,IACA,UAAU,4BAAS;AAAA,IACnB,MAAM,8BAAW;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,MAAM,UAAU,CAAC,KAAU,QAA6B;AACtD,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,gBAAgB,SAAS,mBAAmB,MAAM,IAAI;AAC5D,QAAM,WAAW,SAAS,IAAI,YAAY,MAAM,MAAM,EAAE,CAAC,IAAI,IAAI;AACjE,QAAM,YAAY,SAAS,QAAQ,sBAAsB,EAAE,EAAE,QAAQ,uBAAuB,EAAE;AAE9F,SAAO;AAAA,IACL;AAAA,IACA,cAAc,UAAU;AAAA,IACxB;AAAA,IACA;AAAA,EACF;AACF;AAEA,MAAM,cAAc,OAClB,UACA,KACA,KACA,SACA,gBACA,aACA,SACG;AACH,QAAM,EAAE,WAAW,SAAS,oBAAoB,mBAAmB,IAAI,oBAAAA,QAAa,UAAU,GAAG;AACjG,QAAM,EAAE,UAAU,GAAG,IAAI,IAAI;AAC7B,QAAM,EAAE,2BAA2B,gBAAgB,IAAI;AAEvD,MAAI,cAAc;AAClB,MAAI,oBAAoB;AACtB,kBAAc,MAAM,0BAA0B,yBAAyB,QAAQ,IAAI,UAAU,EAAE;AAAA,EACjG;AAEA,MAAI;AACJ,MAAI,oBAAoB;AACtB,iBAAa,MAAM,gBAAgB,aAAa,IAAI,UAAU,QAAQ,EAAE;AAAA,EAC1E;AAEA,QAAM,UAAU,WAAW,WAAW,SAAS,aAAa,KAAK,KAAK,gBAAgB,aAAa,IAAI;AAEvG,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,MAAM,WAAW,OACf,YACA,UACA,KACA,KACA,gBACG;AACH,QAAM,EAAE,MAAM,IAAI,oBAAAA,QAAa,UAAU,GAAG;AAC5C,QAAM,EAAE,SAAS,UAAU,GAAG,IAAI,IAAI;AAEtC,SAAO,CAAC,WAAW,QAAQ,cACvB,SAAS,iBAAiB,cAAc,OAAO,OAAO,IACtD,SAAS,iBAAiB,yBAAyB,OAAO,SAAS,UAAU,IAAI,WAAW;AAClG;AAEA,MAAM,4BAA4B,CAChC,eAC4B;AAC5B,QAAM,EAAE,SAAS,MAAM,YAAY,aAAa,kBAAkB,IAAI;AACtE,QAAM,EAAE,gBAAgB,WAAW,eAAe,MAAM,YAAY,IAAI;AACxE,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,QAAM,EAAE,UAAU,OAAO,IAAI;AAE7B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,eAAe;AAAA,IAC5B;AAAA,IACA,WAAW,QAAQ,SAAS;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,MAAM,yBAAyB,CAAC,gBAAuD;AACrF,QAAM,EAAE,OAAO,KAAK,UAAU,IAAI;AAElC,SAAO;AAAA,IACL,aAAa,YAAY;AAAA,IACzB,oBAAoB,UAAU,YAAY,IAAI,KAAK,UAAU,SAAS,EAAE,eAAe,IAAI;AAAA,IAC3F,cAAc,OAAO,WAAW,CAAC;AAAA,IACjC,WAAW,OAAO;AAAA,IAClB,YAAY,KAAK;AAAA,IACjB,cAAc,KAAK,QAAQ;AAAA,IAC3B,4BAA4B,YAAY;AAAA,EAC1C;AACF;AAEA,MAAM,aAAa,CACjB,WACA,SACA,aACA,KACA,KACA,gBACA,aACA,SACG;AACH,QAAM,EAAE,YAAY,MAAM,UAAU,IAAI;AACxC,QAAM,EAAE,SAAS,IAAI,SAAS,IAAI,IAAI;AACtC,QAAM,EAAE,eAAe,iBAAiB,mBAAmB,IAAI,oBAAAA,QAAa,UAAU,GAAG;AAGzF,MAAI;AACJ,MAAI,QAAQ,oBAAoB;AAC9B,qBAAiB;AAAA,MACf,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,gBAAgB;AAAA,MAChB,UAAU,4BAAS;AAAA,MACnB;AAAA,MACA;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,oBAAoB,KAAK;AAAA,MACzB,GAAI,aAAa,aAAa;AAAA,QAC5B,YAAoB,YAAY,UAAU,YAAY;AAAA,QACtD,WAAmB,YAAY,UAAU,WAAW;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACJ,MAAI,aAAa,YAAY,SAAS;AACpC,kBAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA,KAAK,YAAY,WAAW;AAAA,IAC9B;AACA,iBAAa;AAAA,MACX,KAAK,YAAY,WAAW;AAAA,IAC9B;AAAA,EACF;AAEA,MAAI;AACJ,MAAI,aAAa,eAAe,aAAa,YAAY,SAAS;AAChE,oBAAgB;AAAA,MACd,KAAK,YAAY,WAAW;AAAA,MAC5B,aAAa,YAAY;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO,cAAAW,QAAmB,WAAW;AAAA,IACnC,GAAI,kBAAkB,EAAE,UAAU,eAAe;AAAA,IACjD,GAAI,eAAe,EAAE,OAAO,YAAY;AAAA,IACxC,GAAI,iBAAiB,EAAE,SAAS,cAAc;AAAA,IAC9C,GAAI,cAAc,EAAE,MAAM,WAAW;AAAA,IACrC,OAAO,EAAE,SAAS,UAAU;AAAA,EAC9B,CAAC;AACH;AAEA,IAAO,gBAAQ;AAAA,EACb;AACF;",
6
6
  "names": ["import_utils", "LocalsHelper", "ColumnUtils", "definitionUtils", "ReportFiltersUtils", "ReportQuery", "DataTableUtils", "UserReportsUtils", "parseUrl", "CollatedSummaryBuilder", "PaginationUtils", "TotalsUtils", "ReportActionsUtils"]
7
7
  }
@@ -107,8 +107,8 @@ const initReportQuery = async (
107
107
  })
108
108
 
109
109
  // Sort
110
- const sortColumn = req.query?.['sortColumn'] || requestData?.query?.data?.['sortColumn']
111
- const sortedAsc = req.query?.['sortedAsc'] || requestData?.query?.data?.['sortedAsc']
110
+ const sortColumn = req.query?.['sortColumn'] || requestData?.sortBy?.data?.['sortColumn']
111
+ const sortedAsc = req.query?.['sortedAsc'] || requestData?.sortBy?.data?.['sortedAsc']
112
112
 
113
113
  // Pagination
114
114
  const selectedPage = req.query?.['selectedPage']
@@ -19,7 +19,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var featureFlagService_exports = {};
20
20
  __export(featureFlagService_exports, {
21
21
  FeatureFlagService: () => FeatureFlagService,
22
- isBooleanFlagEnabled: () => isBooleanFlagEnabled
22
+ isBooleanFlagEnabledOrMissing: () => isBooleanFlagEnabledOrMissing,
23
+ isBooleanFlagExplicitlyEnabled: () => isBooleanFlagExplicitlyEnabled
23
24
  });
24
25
  module.exports = __toCommonJS(featureFlagService_exports);
25
26
  var import_flipt = require("@flipt-io/flipt");
@@ -51,16 +52,24 @@ class FeatureFlagService {
51
52
  return this.restClient.flags.listFlags(this.namespace);
52
53
  }
53
54
  }
54
- const isBooleanFlagEnabled = (flagName, app) => {
55
+ const resolveFlag = (app, flagName) => {
55
56
  const flag = app.locals.featureFlags?.flags?.[flagName];
56
57
  if (flag && flag.type !== "BOOLEAN_FLAG_TYPE") {
57
58
  throw Error("Tried to validate whether a non-boolean flag was enabled");
58
59
  }
60
+ return flag;
61
+ };
62
+ const isBooleanFlagEnabledOrMissing = (flagName, app) => {
63
+ const flag = resolveFlag(app, flagName);
59
64
  return !flag || flag.enabled;
60
65
  };
66
+ const isBooleanFlagExplicitlyEnabled = (flagName, app) => {
67
+ return resolveFlag(app, flagName)?.enabled === true;
68
+ };
61
69
  // Annotate the CommonJS export names for ESM import in node:
62
70
  0 && (module.exports = {
63
71
  FeatureFlagService,
64
- isBooleanFlagEnabled
72
+ isBooleanFlagEnabledOrMissing,
73
+ isBooleanFlagExplicitlyEnabled
65
74
  });
66
75
  //# sourceMappingURL=featureFlagService.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../dpr/services/featureFlagService.ts"],
4
- "sourcesContent": ["import { FliptClient, ListFlagsResponse } from '@flipt-io/flipt'\nimport { Application } from 'express'\nimport { FeatureFlagConfig } from '../data/types'\n\nexport class FeatureFlagService {\n restClient: FliptClient | undefined\n\n namespace: string | undefined\n\n constructor(config: FeatureFlagConfig | Record<string, unknown> = {}) {\n const { namespace, token, url } = config && (config as FeatureFlagConfig)\n if (Object.keys(config).length !== 3 || !namespace || !token || !url) {\n return\n }\n this.restClient = new FliptClient({\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n url,\n })\n this.namespace = namespace\n }\n\n async getFlags(): Promise<ListFlagsResponse> {\n if (!this.restClient || !this.namespace) {\n return {\n flags: [],\n nextPageToken: '',\n totalCount: 0,\n }\n }\n return this.restClient.flags.listFlags(this.namespace)\n }\n}\n\nexport const isBooleanFlagEnabled = (flagName: string, app: Application): boolean => {\n const flag = app.locals.featureFlags?.flags?.[flagName]\n if (flag && flag.type !== 'BOOLEAN_FLAG_TYPE') {\n throw Error('Tried to validate whether a non-boolean flag was enabled')\n }\n return !flag || flag.enabled\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+C;AAIxC,MAAM,mBAAmB;AAAA,EAC9B;AAAA,EAEA;AAAA,EAEA,YAAY,SAAsD,CAAC,GAAG;AACpE,UAAM,EAAE,WAAW,OAAO,IAAI,IAAI,UAAW;AAC7C,QAAI,OAAO,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK;AACpE;AAAA,IACF;AACA,SAAK,aAAa,IAAI,yBAAY;AAAA,MAChC,SAAS;AAAA,QACP,eAAe,UAAU,KAAK;AAAA,QAC9B,gBAAgB;AAAA,MAClB;AAAA,MACA;AAAA,IACF,CAAC;AACD,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,WAAuC;AAC3C,QAAI,CAAC,KAAK,cAAc,CAAC,KAAK,WAAW;AACvC,aAAO;AAAA,QACL,OAAO,CAAC;AAAA,QACR,eAAe;AAAA,QACf,YAAY;AAAA,MACd;AAAA,IACF;AACA,WAAO,KAAK,WAAW,MAAM,UAAU,KAAK,SAAS;AAAA,EACvD;AACF;AAEO,MAAM,uBAAuB,CAAC,UAAkB,QAA8B;AACnF,QAAM,OAAO,IAAI,OAAO,cAAc,QAAQ,QAAQ;AACtD,MAAI,QAAQ,KAAK,SAAS,qBAAqB;AAC7C,UAAM,MAAM,0DAA0D;AAAA,EACxE;AACA,SAAO,CAAC,QAAQ,KAAK;AACvB;",
4
+ "sourcesContent": ["import { FliptClient, ListFlagsResponse } from '@flipt-io/flipt'\nimport { Application } from 'express'\nimport { FeatureFlagConfig } from '../data/types'\n\nexport class FeatureFlagService {\n restClient: FliptClient | undefined\n\n namespace: string | undefined\n\n constructor(config: FeatureFlagConfig | Record<string, unknown> = {}) {\n const { namespace, token, url } = config && (config as FeatureFlagConfig)\n if (Object.keys(config).length !== 3 || !namespace || !token || !url) {\n return\n }\n this.restClient = new FliptClient({\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n url,\n })\n this.namespace = namespace\n }\n\n async getFlags(): Promise<ListFlagsResponse> {\n if (!this.restClient || !this.namespace) {\n return {\n flags: [],\n nextPageToken: '',\n totalCount: 0,\n }\n }\n return this.restClient.flags.listFlags(this.namespace)\n }\n}\n\nconst resolveFlag = (app: Application, flagName: string) => {\n const flag = app.locals.featureFlags?.flags?.[flagName]\n if (flag && flag.type !== 'BOOLEAN_FLAG_TYPE') {\n throw Error('Tried to validate whether a non-boolean flag was enabled')\n }\n return flag\n}\n\nexport const isBooleanFlagEnabledOrMissing = (flagName: string, app: Application): boolean => {\n const flag = resolveFlag(app, flagName)\n return !flag || flag.enabled\n}\n\nexport const isBooleanFlagExplicitlyEnabled = (flagName: string, app: Application): boolean => {\n return resolveFlag(app, flagName)?.enabled === true\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+C;AAIxC,MAAM,mBAAmB;AAAA,EAC9B;AAAA,EAEA;AAAA,EAEA,YAAY,SAAsD,CAAC,GAAG;AACpE,UAAM,EAAE,WAAW,OAAO,IAAI,IAAI,UAAW;AAC7C,QAAI,OAAO,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK;AACpE;AAAA,IACF;AACA,SAAK,aAAa,IAAI,yBAAY;AAAA,MAChC,SAAS;AAAA,QACP,eAAe,UAAU,KAAK;AAAA,QAC9B,gBAAgB;AAAA,MAClB;AAAA,MACA;AAAA,IACF,CAAC;AACD,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,WAAuC;AAC3C,QAAI,CAAC,KAAK,cAAc,CAAC,KAAK,WAAW;AACvC,aAAO;AAAA,QACL,OAAO,CAAC;AAAA,QACR,eAAe;AAAA,QACf,YAAY;AAAA,MACd;AAAA,IACF;AACA,WAAO,KAAK,WAAW,MAAM,UAAU,KAAK,SAAS;AAAA,EACvD;AACF;AAEA,MAAM,cAAc,CAAC,KAAkB,aAAqB;AAC1D,QAAM,OAAO,IAAI,OAAO,cAAc,QAAQ,QAAQ;AACtD,MAAI,QAAQ,KAAK,SAAS,qBAAqB;AAC7C,UAAM,MAAM,0DAA0D;AAAA,EACxE;AACA,SAAO;AACT;AAEO,MAAM,gCAAgC,CAAC,UAAkB,QAA8B;AAC5F,QAAM,OAAO,YAAY,KAAK,QAAQ;AACtC,SAAO,CAAC,QAAQ,KAAK;AACvB;AAEO,MAAM,iCAAiC,CAAC,UAAkB,QAA8B;AAC7F,SAAO,YAAY,KAAK,QAAQ,GAAG,YAAY;AACjD;",
6
6
  "names": []
7
7
  }
@@ -34,10 +34,19 @@ export class FeatureFlagService {
34
34
  }
35
35
  }
36
36
 
37
- export const isBooleanFlagEnabled = (flagName: string, app: Application): boolean => {
37
+ const resolveFlag = (app: Application, flagName: string) => {
38
38
  const flag = app.locals.featureFlags?.flags?.[flagName]
39
39
  if (flag && flag.type !== 'BOOLEAN_FLAG_TYPE') {
40
40
  throw Error('Tried to validate whether a non-boolean flag was enabled')
41
41
  }
42
+ return flag
43
+ }
44
+
45
+ export const isBooleanFlagEnabledOrMissing = (flagName: string, app: Application): boolean => {
46
+ const flag = resolveFlag(app, flagName)
42
47
  return !flag || flag.enabled
43
48
  }
49
+
50
+ export const isBooleanFlagExplicitlyEnabled = (flagName: string, app: Application): boolean => {
51
+ return resolveFlag(app, flagName)?.enabled === true
52
+ }
@@ -51,6 +51,9 @@ class ReportingService {
51
51
  async cancelAsyncRequest(token, reportId, variantId, executionId, dataProductDefinitionsPath) {
52
52
  return this.reportingClient.cancelAsyncRequest(token, reportId, variantId, executionId, dataProductDefinitionsPath);
53
53
  }
54
+ async downloadAsyncReport(token, reportId, variantId, tableId, query, res) {
55
+ return this.reportingClient.downloadAsyncReport(token, reportId, variantId, tableId, query, res);
56
+ }
54
57
  async getAsyncReport(token, reportId, variantId, tableId, query) {
55
58
  return this.reportingClient.getAsyncReport(token, reportId, variantId, tableId, query);
56
59
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../dpr/services/reportingService.ts"],
4
- "sourcesContent": ["import { components } from '../types/api'\nimport type ReportingClient from '../data/reportingClient'\nimport ReportQuery from '../types/ReportQuery'\nimport Dict = NodeJS.Dict\nimport { ListWithWarnings } from '../data/types'\n\nclass ReportingService {\n constructor(private readonly reportingClient: ReportingClient) {\n this.reportingClient = reportingClient\n }\n\n async getCount(resourceName: string, token: string, listRequest: ReportQuery): Promise<number> {\n return this.reportingClient.getCount(resourceName, token, listRequest)\n }\n\n async getList(resourceName: string, token: string, listRequest: ReportQuery): Promise<Array<NodeJS.Dict<string>>> {\n return this.reportingClient.getList(resourceName, token, listRequest)\n }\n\n async getListWithWarnings(resourceName: string, token: string, listRequest: ReportQuery): Promise<ListWithWarnings> {\n return this.reportingClient.getListWithWarnings(resourceName, token, listRequest)\n }\n\n async getDefinitionSummary(\n token: string,\n reportId: string,\n dataProductDefinitionsPath?: string,\n ): Promise<components['schemas']['ReportDefinitionSummary']> {\n return this.reportingClient.getDefinitionSummary(token, reportId, dataProductDefinitionsPath)\n }\n\n async getDefinitions(\n token: string,\n dataProductDefinitionsPath?: string,\n ): Promise<Array<components['schemas']['ReportDefinitionSummary']>> {\n return this.reportingClient.getDefinitions(token, dataProductDefinitionsPath)\n }\n\n async getDefinition(\n token: string,\n reportId: string,\n variantId: string,\n dataProductDefinitionsPath?: string,\n query?: Dict<string | string[]>,\n ): Promise<components['schemas']['SingleVariantReportDefinition']> {\n return this.reportingClient.getDefinition(token, reportId, variantId, dataProductDefinitionsPath, query)\n }\n\n async requestAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n query: Record<string, string | boolean | number>,\n ): Promise<Dict<string>> {\n return this.reportingClient.requestAsyncReport(token, reportId, variantId, query)\n }\n\n async cancelAsyncRequest(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath?: string,\n ): Promise<Dict<string>> {\n return this.reportingClient.cancelAsyncRequest(token, reportId, variantId, executionId, dataProductDefinitionsPath)\n }\n\n async getAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n query: Record<string, string | string[]>,\n ): Promise<Array<Dict<string>>> {\n return this.reportingClient.getAsyncReport(token, reportId, variantId, tableId, query)\n }\n\n async getAsyncSummaryReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n summaryId: string,\n query: Dict<string | number>,\n ): Promise<Array<Dict<string>>> {\n return this.reportingClient.getAsyncSummaryReport(token, reportId, variantId, tableId, summaryId, query)\n }\n\n async getAsyncReportStatus(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath: string,\n tableId: string,\n ): Promise<components['schemas']['StatementExecutionStatus']> {\n return this.reportingClient.getAsyncReportStatus(\n token,\n reportId,\n variantId,\n executionId,\n dataProductDefinitionsPath,\n tableId,\n )\n }\n\n async getAsyncCount(token: string, tableId: string, dataProductDefinitionsPath?: string): Promise<number> {\n return this.reportingClient.getAsyncCount(token, tableId, dataProductDefinitionsPath)\n }\n\n async getAsyncInteractiveCount(\n token: string,\n tableId: string,\n reportId: string,\n id: string,\n filters: ReportQuery,\n ): Promise<number> {\n return this.reportingClient.getAsyncInteractiveCount(token, tableId, reportId, id, filters)\n }\n}\n\nexport { ReportingService }\nexport default ReportingService\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,MAAM,iBAAiB;AAAA,EACrB,YAA6B,iBAAkC;AAAlC;AAC3B,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,MAAM,SAAS,cAAsB,OAAe,aAA2C;AAC7F,WAAO,KAAK,gBAAgB,SAAS,cAAc,OAAO,WAAW;AAAA,EACvE;AAAA,EAEA,MAAM,QAAQ,cAAsB,OAAe,aAA+D;AAChH,WAAO,KAAK,gBAAgB,QAAQ,cAAc,OAAO,WAAW;AAAA,EACtE;AAAA,EAEA,MAAM,oBAAoB,cAAsB,OAAe,aAAqD;AAClH,WAAO,KAAK,gBAAgB,oBAAoB,cAAc,OAAO,WAAW;AAAA,EAClF;AAAA,EAEA,MAAM,qBACJ,OACA,UACA,4BAC2D;AAC3D,WAAO,KAAK,gBAAgB,qBAAqB,OAAO,UAAU,0BAA0B;AAAA,EAC9F;AAAA,EAEA,MAAM,eACJ,OACA,4BACkE;AAClE,WAAO,KAAK,gBAAgB,eAAe,OAAO,0BAA0B;AAAA,EAC9E;AAAA,EAEA,MAAM,cACJ,OACA,UACA,WACA,4BACA,OACiE;AACjE,WAAO,KAAK,gBAAgB,cAAc,OAAO,UAAU,WAAW,4BAA4B,KAAK;AAAA,EACzG;AAAA,EAEA,MAAM,mBACJ,OACA,UACA,WACA,OACuB;AACvB,WAAO,KAAK,gBAAgB,mBAAmB,OAAO,UAAU,WAAW,KAAK;AAAA,EAClF;AAAA,EAEA,MAAM,mBACJ,OACA,UACA,WACA,aACA,4BACuB;AACvB,WAAO,KAAK,gBAAgB,mBAAmB,OAAO,UAAU,WAAW,aAAa,0BAA0B;AAAA,EACpH;AAAA,EAEA,MAAM,eACJ,OACA,UACA,WACA,SACA,OAC8B;AAC9B,WAAO,KAAK,gBAAgB,eAAe,OAAO,UAAU,WAAW,SAAS,KAAK;AAAA,EACvF;AAAA,EAEA,MAAM,sBACJ,OACA,UACA,WACA,SACA,WACA,OAC8B;AAC9B,WAAO,KAAK,gBAAgB,sBAAsB,OAAO,UAAU,WAAW,SAAS,WAAW,KAAK;AAAA,EACzG;AAAA,EAEA,MAAM,qBACJ,OACA,UACA,WACA,aACA,4BACA,SAC4D;AAC5D,WAAO,KAAK,gBAAgB;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,OAAe,SAAiB,4BAAsD;AACxG,WAAO,KAAK,gBAAgB,cAAc,OAAO,SAAS,0BAA0B;AAAA,EACtF;AAAA,EAEA,MAAM,yBACJ,OACA,SACA,UACA,IACA,SACiB;AACjB,WAAO,KAAK,gBAAgB,yBAAyB,OAAO,SAAS,UAAU,IAAI,OAAO;AAAA,EAC5F;AACF;AAGA,IAAO,2BAAQ;",
4
+ "sourcesContent": ["import { Response } from 'express'\nimport { components } from '../types/api'\nimport type ReportingClient from '../data/reportingClient'\nimport ReportQuery from '../types/ReportQuery'\nimport Dict = NodeJS.Dict\nimport { ListWithWarnings } from '../data/types'\n\nclass ReportingService {\n constructor(private readonly reportingClient: ReportingClient) {\n this.reportingClient = reportingClient\n }\n\n async getCount(resourceName: string, token: string, listRequest: ReportQuery): Promise<number> {\n return this.reportingClient.getCount(resourceName, token, listRequest)\n }\n\n async getList(resourceName: string, token: string, listRequest: ReportQuery): Promise<Array<NodeJS.Dict<string>>> {\n return this.reportingClient.getList(resourceName, token, listRequest)\n }\n\n async getListWithWarnings(resourceName: string, token: string, listRequest: ReportQuery): Promise<ListWithWarnings> {\n return this.reportingClient.getListWithWarnings(resourceName, token, listRequest)\n }\n\n async getDefinitionSummary(\n token: string,\n reportId: string,\n dataProductDefinitionsPath?: string,\n ): Promise<components['schemas']['ReportDefinitionSummary']> {\n return this.reportingClient.getDefinitionSummary(token, reportId, dataProductDefinitionsPath)\n }\n\n async getDefinitions(\n token: string,\n dataProductDefinitionsPath?: string,\n ): Promise<Array<components['schemas']['ReportDefinitionSummary']>> {\n return this.reportingClient.getDefinitions(token, dataProductDefinitionsPath)\n }\n\n async getDefinition(\n token: string,\n reportId: string,\n variantId: string,\n dataProductDefinitionsPath?: string,\n query?: Dict<string | string[]>,\n ): Promise<components['schemas']['SingleVariantReportDefinition']> {\n return this.reportingClient.getDefinition(token, reportId, variantId, dataProductDefinitionsPath, query)\n }\n\n async requestAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n query: Record<string, string | boolean | number>,\n ): Promise<Dict<string>> {\n return this.reportingClient.requestAsyncReport(token, reportId, variantId, query)\n }\n\n async cancelAsyncRequest(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath?: string,\n ): Promise<Dict<string>> {\n return this.reportingClient.cancelAsyncRequest(token, reportId, variantId, executionId, dataProductDefinitionsPath)\n }\n\n async downloadAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n query: Record<string, string | string[]>,\n res: Response,\n ): Promise<void> {\n return this.reportingClient.downloadAsyncReport(token, reportId, variantId, tableId, query, res)\n }\n\n async getAsyncReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n query: Record<string, string | string[]>,\n ): Promise<Array<Dict<string>>> {\n return this.reportingClient.getAsyncReport(token, reportId, variantId, tableId, query)\n }\n\n async getAsyncSummaryReport(\n token: string,\n reportId: string,\n variantId: string,\n tableId: string,\n summaryId: string,\n query: Dict<string | number>,\n ): Promise<Array<Dict<string>>> {\n return this.reportingClient.getAsyncSummaryReport(token, reportId, variantId, tableId, summaryId, query)\n }\n\n async getAsyncReportStatus(\n token: string,\n reportId: string,\n variantId: string,\n executionId: string,\n dataProductDefinitionsPath: string,\n tableId: string,\n ): Promise<components['schemas']['StatementExecutionStatus']> {\n return this.reportingClient.getAsyncReportStatus(\n token,\n reportId,\n variantId,\n executionId,\n dataProductDefinitionsPath,\n tableId,\n )\n }\n\n async getAsyncCount(token: string, tableId: string, dataProductDefinitionsPath?: string): Promise<number> {\n return this.reportingClient.getAsyncCount(token, tableId, dataProductDefinitionsPath)\n }\n\n async getAsyncInteractiveCount(\n token: string,\n tableId: string,\n reportId: string,\n id: string,\n filters: ReportQuery,\n ): Promise<number> {\n return this.reportingClient.getAsyncInteractiveCount(token, tableId, reportId, id, filters)\n }\n}\n\nexport { ReportingService }\nexport default ReportingService\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,MAAM,iBAAiB;AAAA,EACrB,YAA6B,iBAAkC;AAAlC;AAC3B,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,MAAM,SAAS,cAAsB,OAAe,aAA2C;AAC7F,WAAO,KAAK,gBAAgB,SAAS,cAAc,OAAO,WAAW;AAAA,EACvE;AAAA,EAEA,MAAM,QAAQ,cAAsB,OAAe,aAA+D;AAChH,WAAO,KAAK,gBAAgB,QAAQ,cAAc,OAAO,WAAW;AAAA,EACtE;AAAA,EAEA,MAAM,oBAAoB,cAAsB,OAAe,aAAqD;AAClH,WAAO,KAAK,gBAAgB,oBAAoB,cAAc,OAAO,WAAW;AAAA,EAClF;AAAA,EAEA,MAAM,qBACJ,OACA,UACA,4BAC2D;AAC3D,WAAO,KAAK,gBAAgB,qBAAqB,OAAO,UAAU,0BAA0B;AAAA,EAC9F;AAAA,EAEA,MAAM,eACJ,OACA,4BACkE;AAClE,WAAO,KAAK,gBAAgB,eAAe,OAAO,0BAA0B;AAAA,EAC9E;AAAA,EAEA,MAAM,cACJ,OACA,UACA,WACA,4BACA,OACiE;AACjE,WAAO,KAAK,gBAAgB,cAAc,OAAO,UAAU,WAAW,4BAA4B,KAAK;AAAA,EACzG;AAAA,EAEA,MAAM,mBACJ,OACA,UACA,WACA,OACuB;AACvB,WAAO,KAAK,gBAAgB,mBAAmB,OAAO,UAAU,WAAW,KAAK;AAAA,EAClF;AAAA,EAEA,MAAM,mBACJ,OACA,UACA,WACA,aACA,4BACuB;AACvB,WAAO,KAAK,gBAAgB,mBAAmB,OAAO,UAAU,WAAW,aAAa,0BAA0B;AAAA,EACpH;AAAA,EAEA,MAAM,oBACJ,OACA,UACA,WACA,SACA,OACA,KACe;AACf,WAAO,KAAK,gBAAgB,oBAAoB,OAAO,UAAU,WAAW,SAAS,OAAO,GAAG;AAAA,EACjG;AAAA,EAEA,MAAM,eACJ,OACA,UACA,WACA,SACA,OAC8B;AAC9B,WAAO,KAAK,gBAAgB,eAAe,OAAO,UAAU,WAAW,SAAS,KAAK;AAAA,EACvF;AAAA,EAEA,MAAM,sBACJ,OACA,UACA,WACA,SACA,WACA,OAC8B;AAC9B,WAAO,KAAK,gBAAgB,sBAAsB,OAAO,UAAU,WAAW,SAAS,WAAW,KAAK;AAAA,EACzG;AAAA,EAEA,MAAM,qBACJ,OACA,UACA,WACA,aACA,4BACA,SAC4D;AAC5D,WAAO,KAAK,gBAAgB;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,OAAe,SAAiB,4BAAsD;AACxG,WAAO,KAAK,gBAAgB,cAAc,OAAO,SAAS,0BAA0B;AAAA,EACtF;AAAA,EAEA,MAAM,yBACJ,OACA,SACA,UACA,IACA,SACiB;AACjB,WAAO,KAAK,gBAAgB,yBAAyB,OAAO,SAAS,UAAU,IAAI,OAAO;AAAA,EAC5F;AACF;AAGA,IAAO,2BAAQ;",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { Response } from 'express'
1
2
  import { components } from '../types/api'
2
3
  import type ReportingClient from '../data/reportingClient'
3
4
  import ReportQuery from '../types/ReportQuery'
@@ -65,6 +66,17 @@ class ReportingService {
65
66
  return this.reportingClient.cancelAsyncRequest(token, reportId, variantId, executionId, dataProductDefinitionsPath)
66
67
  }
67
68
 
69
+ async downloadAsyncReport(
70
+ token: string,
71
+ reportId: string,
72
+ variantId: string,
73
+ tableId: string,
74
+ query: Record<string, string | string[]>,
75
+ res: Response,
76
+ ): Promise<void> {
77
+ return this.reportingClient.downloadAsyncReport(token, reportId, variantId, tableId, query, res)
78
+ }
79
+
68
80
  async getAsyncReport(
69
81
  token: string,
70
82
  reportId: string,
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": "4.28.1",
4
+ "version": "4.28.3",
5
5
  "main": "dpr/all",
6
6
  "sass": "dpr/all.scss",
7
7
  "engines": {
@@ -186,7 +186,7 @@
186
186
  "@types/express": "4.17.21",
187
187
  "@types/express-session": "^1.18.2",
188
188
  "@types/jest": "^30.0.0",
189
- "@types/node": "24.10.4",
189
+ "@types/node": "24.10.9",
190
190
  "@types/nunjucks": "^3.2.3",
191
191
  "@types/nunjucks-date": "^0.0.10",
192
192
  "@types/parseurl": "^1.3.3",
@@ -197,7 +197,6 @@
197
197
  "audit-ci": "^6.6.1",
198
198
  "autoprefixer": "^10.4.15",
199
199
  "axe-core": "^4.9.0",
200
- "cssnano": "^6.0.1",
201
200
  "cypress": "^14.5.4",
202
201
  "cypress-axe": "^1.6.0",
203
202
  "cypress-multi-reporters": "^2.0.5",
@@ -249,4 +248,4 @@
249
248
  "peerDependencies": {
250
249
  "jquery": "^3.7.1"
251
250
  }
252
- }
251
+ }