@openmrs/esm-reports-app 4.2.2-pre.402 → 4.2.2-pre.414
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +12 -12
- package/dist/1650.js +1 -1
- package/dist/1650.js.map +1 -1
- package/dist/2136.js +2 -0
- package/dist/2136.js.map +1 -0
- package/dist/289.js +1 -1
- package/dist/289.js.map +1 -1
- package/dist/3715.js +1 -1
- package/dist/3715.js.map +1 -1
- package/dist/3854.js +2 -0
- package/dist/3854.js.map +1 -0
- package/dist/3877.js +1 -1
- package/dist/3877.js.map +1 -1
- package/dist/4300.js +1 -1
- package/dist/439.js +1 -1
- package/dist/439.js.map +1 -1
- package/dist/4584.js +1 -1
- package/dist/4584.js.map +1 -1
- package/dist/6173.js +1 -0
- package/dist/6173.js.map +1 -0
- package/dist/826.js +1 -1
- package/dist/826.js.map +1 -1
- package/dist/8390.js +1 -1
- package/dist/8390.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-reports-app.js +1 -1
- package/dist/openmrs-esm-reports-app.js.buildmanifest.json +83 -83
- package/dist/openmrs-esm-reports-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/components/overview.component.test.tsx +156 -0
- package/src/components/overview.component.tsx +77 -5
- package/src/components/report-overview-button.component.tsx +1 -1
- package/src/components/reports-data-overview.component.tsx +2 -2
- package/src/components/reports.scss +9 -2
- package/src/components/run-report/run-report-form.component.tsx +22 -6
- package/src/config-schema.ts +14 -0
- package/src/index.ts +3 -1
- package/src/types/report-definition.ts +1 -0
- package/translations/en.json +5 -0
- package/tsconfig.json +1 -1
- package/dist/1917.js +0 -2
- package/dist/1917.js.map +0 -1
- package/dist/2252.js +0 -2
- package/dist/2252.js.map +0 -1
- package/dist/9090.js +0 -1
- package/dist/9090.js.map +0 -1
- /package/dist/{2252.js.LICENSE.txt → 2136.js.LICENSE.txt} +0 -0
- /package/dist/{1917.js.LICENSE.txt → 3854.js.LICENSE.txt} +0 -0
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
TableHeader,
|
|
15
15
|
TableRow,
|
|
16
16
|
} from '@carbon/react';
|
|
17
|
-
import { Calendar, Download, Play, Save, TrashCan } from '@carbon/react/icons';
|
|
17
|
+
import { Calendar, Download, Play, Save, TrashCan, View } from '@carbon/react/icons';
|
|
18
18
|
import { downloadMultipleReports, downloadReport, preserveReport, useReports } from './reports.resource';
|
|
19
19
|
import {
|
|
20
20
|
ExtensionSlot,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
navigate,
|
|
23
23
|
showModal,
|
|
24
24
|
showSnackbar,
|
|
25
|
+
useConfig,
|
|
25
26
|
useLayoutType,
|
|
26
27
|
userHasAccess,
|
|
27
28
|
useSession,
|
|
@@ -35,10 +36,12 @@ import { COMPLETED, RAN_REPORT_STATUSES, SAVED } from './report-statuses-constan
|
|
|
35
36
|
import { DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZES } from './pagination-constants';
|
|
36
37
|
import { PRIVILEGE_SYSTEM_DEVELOPER } from '../constants';
|
|
37
38
|
import styles from './reports.scss';
|
|
39
|
+
import { type ConfigObject } from '../config-schema';
|
|
38
40
|
|
|
39
41
|
const OverviewComponent: React.FC = () => {
|
|
40
42
|
const { t } = useTranslation();
|
|
41
43
|
const currentSession = useSession();
|
|
44
|
+
const { webPreviewViewReportUrl } = useConfig<ConfigObject>();
|
|
42
45
|
|
|
43
46
|
let [checkedReportUuidsArray, setCheckedReportUuidsArray] = useState([]);
|
|
44
47
|
const [downloadReportButtonVisible, setDownloadReportButtonVisible] = useState(false);
|
|
@@ -75,6 +78,30 @@ const OverviewComponent: React.FC = () => {
|
|
|
75
78
|
return row?.cells.find((cell) => cell.info?.header === 'status')?.value;
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
function getReportOutputFormat(row) {
|
|
82
|
+
return row?.cells.find((cell) => cell.info?.header === 'outputFormat')?.value;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function shouldShowDownloadButton(row) {
|
|
86
|
+
const outputFormat = getReportOutputFormat(row);
|
|
87
|
+
const status = getReportStatus(row);
|
|
88
|
+
const isWebPreviewWithUrl = outputFormat === 'Web Preview' && webPreviewViewReportUrl;
|
|
89
|
+
|
|
90
|
+
// Don't show download button for web preview when we have a view URL
|
|
91
|
+
if (isWebPreviewWithUrl) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return status === COMPLETED || status === SAVED;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function shouldShowViewButton(row) {
|
|
99
|
+
const outputFormat = getReportOutputFormat(row);
|
|
100
|
+
const status = getReportStatus(row);
|
|
101
|
+
|
|
102
|
+
return outputFormat === 'Web Preview' && webPreviewViewReportUrl && (status === COMPLETED || status === SAVED);
|
|
103
|
+
}
|
|
104
|
+
|
|
78
105
|
function isCurrentUserTheSameAsReportRequestedByUser(reportRequestUuid: string) {
|
|
79
106
|
const report = reports.find((tableRow) => tableRow.id === reportRequestUuid);
|
|
80
107
|
const requestedByUserUuid = report?.requestedByUserUuid;
|
|
@@ -162,6 +189,44 @@ const OverviewComponent: React.FC = () => {
|
|
|
162
189
|
});
|
|
163
190
|
};
|
|
164
191
|
|
|
192
|
+
const handleViewReport = useCallback(
|
|
193
|
+
(reportRequestUuid: string) => {
|
|
194
|
+
if (!webPreviewViewReportUrl) {
|
|
195
|
+
showSnackbar({
|
|
196
|
+
title: t('error', 'Error'),
|
|
197
|
+
subtitle: t('noWebPreviewUrlConfigured', 'No web preview URL configured.'),
|
|
198
|
+
kind: 'error',
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
// Basic URL validation
|
|
205
|
+
new URL(webPreviewViewReportUrl.replace('{reportRequestUuid}', 'placeholder'));
|
|
206
|
+
} catch {
|
|
207
|
+
showSnackbar({
|
|
208
|
+
title: t('error', 'Error'),
|
|
209
|
+
subtitle: t('invalidWebPreviewUrl', 'Configured web preview URL is invalid.'),
|
|
210
|
+
kind: 'error',
|
|
211
|
+
});
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!webPreviewViewReportUrl.includes('{reportRequestUuid}')) {
|
|
216
|
+
showSnackbar({
|
|
217
|
+
title: t('error', 'Error'),
|
|
218
|
+
subtitle: t('missingPlaceholder', 'Configured web preview URL must include {reportRequestUuid} placeholder.'),
|
|
219
|
+
kind: 'error',
|
|
220
|
+
});
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const viewUrl = webPreviewViewReportUrl.replace('{reportRequestUuid}', reportRequestUuid);
|
|
225
|
+
window.open(viewUrl, '_blank', 'noopener,noreferrer');
|
|
226
|
+
},
|
|
227
|
+
[webPreviewViewReportUrl, t],
|
|
228
|
+
);
|
|
229
|
+
|
|
165
230
|
const handleDownloadReport = useCallback(
|
|
166
231
|
async (reportRequestUuid: string) => {
|
|
167
232
|
try {
|
|
@@ -293,13 +358,13 @@ const OverviewComponent: React.FC = () => {
|
|
|
293
358
|
<TableRow>
|
|
294
359
|
<th></th>
|
|
295
360
|
{headers.map((header) => (
|
|
296
|
-
<TableHeader>{header.header}</TableHeader>
|
|
361
|
+
<TableHeader key={header.key}>{header.header}</TableHeader>
|
|
297
362
|
))}
|
|
298
363
|
</TableRow>
|
|
299
364
|
</TableHead>
|
|
300
365
|
<TableBody>
|
|
301
366
|
{rows.map((row, index) => (
|
|
302
|
-
<TableRow className={styles.tableRow}>
|
|
367
|
+
<TableRow className={styles.tableRow} key={index}>
|
|
303
368
|
{renderRowCheckbox(row, index)}
|
|
304
369
|
{row.cells.map((cell) => (
|
|
305
370
|
<TableCell
|
|
@@ -310,13 +375,20 @@ const OverviewComponent: React.FC = () => {
|
|
|
310
375
|
})}
|
|
311
376
|
>
|
|
312
377
|
{cell.info.header === 'actions' ? (
|
|
313
|
-
<div>
|
|
378
|
+
<div className={styles.actionsContainer}>
|
|
379
|
+
<ReportOverviewButton
|
|
380
|
+
icon={() => <View size={16} className={styles.actionButtonIcon} />}
|
|
381
|
+
label={t('view', 'View')}
|
|
382
|
+
onClick={() => handleViewReport(row.id)}
|
|
383
|
+
reportRequestUuid={row.id}
|
|
384
|
+
shouldBeDisplayed={shouldShowViewButton(row)}
|
|
385
|
+
/>
|
|
314
386
|
<ReportOverviewButton
|
|
315
387
|
icon={() => <Download size={16} className={styles.actionButtonIcon} />}
|
|
316
388
|
label={t('download', 'Download')}
|
|
317
389
|
onClick={() => handleDownloadReport(row.id)}
|
|
318
390
|
reportRequestUuid={row.id}
|
|
319
|
-
shouldBeDisplayed={
|
|
391
|
+
shouldBeDisplayed={shouldShowDownloadButton(row)}
|
|
320
392
|
/>
|
|
321
393
|
<ReportOverviewButton
|
|
322
394
|
icon={() => <Save size={16} className={styles.actionButtonIcon} />}
|
|
@@ -2,7 +2,7 @@ import React, { useState, useMemo, useEffect } from 'react';
|
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Select, SelectItem, Button } from '@carbon/react';
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
|
-
import { ExtensionSlot, showSnackbar, getCoreTranslation } from '@openmrs/esm-framework';
|
|
5
|
+
import { ExtensionSlot, showSnackbar, getCoreTranslation, useConfig } from '@openmrs/esm-framework';
|
|
6
6
|
import Overlay from './overlay.component';
|
|
7
7
|
import ReportDataViewer from './report-data-viewer.component';
|
|
8
8
|
import ReportParameter from './report-parameter.component';
|
|
@@ -67,7 +67,7 @@ const ReportsDataOverviewComponent: React.FC = () => {
|
|
|
67
67
|
if (hasParameters) {
|
|
68
68
|
// Check if all parameters have values
|
|
69
69
|
const missingParameters = selectedReportDefinition?.parameters
|
|
70
|
-
?.filter((param) => !reportParameters[param.name])
|
|
70
|
+
?.filter((param) => !reportParameters[param.name] && param.required)
|
|
71
71
|
.map((param) => param.label);
|
|
72
72
|
|
|
73
73
|
if (missingParameters?.length > 0) {
|
|
@@ -42,9 +42,16 @@
|
|
|
42
42
|
width: 100px;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
.actionsContainer {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-wrap: wrap;
|
|
48
|
+
gap: 0.5rem;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: flex-start;
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
.actionButtonsWrapperDiv {
|
|
46
|
-
|
|
47
|
-
display: inline-block;
|
|
54
|
+
flex-shrink: 0;
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
.mainActionButtonsDiv {
|
|
@@ -26,7 +26,14 @@ const RunReportForm: React.FC<RunReportForm> = ({ closePanel }) => {
|
|
|
26
26
|
const { reportDesigns, mutateReportDesigns } = useReportDesigns(reportUuid);
|
|
27
27
|
|
|
28
28
|
const supportedParameterTypes = useMemo(
|
|
29
|
-
() => [
|
|
29
|
+
() => [
|
|
30
|
+
'java.util.Date',
|
|
31
|
+
'java.lang.String',
|
|
32
|
+
'java.lang.Integer',
|
|
33
|
+
'org.openmrs.Location',
|
|
34
|
+
'org.openmrs.Concept',
|
|
35
|
+
'org.openmrs.EncounterType',
|
|
36
|
+
],
|
|
30
37
|
[],
|
|
31
38
|
);
|
|
32
39
|
|
|
@@ -36,12 +43,21 @@ const RunReportForm: React.FC<RunReportForm> = ({ closePanel }) => {
|
|
|
36
43
|
|
|
37
44
|
useEffect(() => {
|
|
38
45
|
const paramTypes = currentReport?.parameters.map((param) => param.type);
|
|
39
|
-
const isAnyNotSupportedType = !paramTypes?.every((paramType) => supportedParameterTypes.includes(paramType));
|
|
40
|
-
const allParametersNotEmpty = currentReport?.parameters.every(
|
|
41
|
-
(parameter) => !!reportParameters[parameter.name] && reportParameters[parameter.name] !== 'Invalid Date',
|
|
42
|
-
);
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
const isAnyNotSupportedType =
|
|
48
|
+
paramTypes?.some((paramType) => !supportedParameterTypes.includes(paramType)) ?? false;
|
|
49
|
+
const allRequiredParametersValid =
|
|
50
|
+
currentReport?.parameters?.every((parameter) => {
|
|
51
|
+
if (!parameter.required) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const paramValue = reportParameters[parameter.name];
|
|
56
|
+
const isValid = !!paramValue && paramValue !== 'Invalid Date' && paramValue !== '';
|
|
57
|
+
return isValid;
|
|
58
|
+
}) ?? true;
|
|
59
|
+
|
|
60
|
+
if (!isAnyNotSupportedType && allRequiredParametersValid && reportUuid !== '' && renderModeUuid !== '') {
|
|
45
61
|
setIsFormValid(true);
|
|
46
62
|
} else {
|
|
47
63
|
setIsFormValid(false);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Type } from '@openmrs/esm-framework';
|
|
2
|
+
|
|
3
|
+
export const configSchema = {
|
|
4
|
+
webPreviewViewReportUrl: {
|
|
5
|
+
_type: Type.String,
|
|
6
|
+
_description:
|
|
7
|
+
'The custom URL that the "View Report" button should open when output format is Web Preview. Use {reportRequestUuid} as placeholder.',
|
|
8
|
+
_default: '',
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export interface ConfigObject {
|
|
13
|
+
webPreviewViewReportUrl: string;
|
|
14
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { getAsyncLifecycle, registerBreadcrumbs } from '@openmrs/esm-framework';
|
|
1
|
+
import { defineConfigSchema, getAsyncLifecycle, registerBreadcrumbs } from '@openmrs/esm-framework';
|
|
2
2
|
import { getFixedT } from 'i18next';
|
|
3
3
|
import { basePath, moduleName } from './constants';
|
|
4
|
+
import { configSchema } from './config-schema';
|
|
4
5
|
|
|
5
6
|
const options = {
|
|
6
7
|
featureName: 'reports',
|
|
@@ -38,6 +39,7 @@ export function startupApp() {
|
|
|
38
39
|
parent: `${window.getOpenmrsSpaBase()}reports`,
|
|
39
40
|
},
|
|
40
41
|
]);
|
|
42
|
+
defineConfigSchema(moduleName, configSchema);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
export const root = getAsyncLifecycle(() => import('./reports.component'), options);
|
package/translations/en.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"downloadReports": "Download reports",
|
|
22
22
|
"edit": "Edit",
|
|
23
23
|
"editScheduledReport": "Edit scheduled report",
|
|
24
|
+
"error": "Error",
|
|
24
25
|
"errorDownloadingReport": "Error downloading report",
|
|
25
26
|
"errorDownloadingReports": "Error downloading reports",
|
|
26
27
|
"errorFetchingReport": "Error fetching report",
|
|
@@ -29,13 +30,16 @@
|
|
|
29
30
|
"exportCSV": "Export CSV",
|
|
30
31
|
"failed": "Failed",
|
|
31
32
|
"fetchReport": "Fetch Report",
|
|
33
|
+
"invalidWebPreviewUrl": "Configured web preview URL is invalid.",
|
|
32
34
|
"missingParameters": "Please provide the following parameters: {parameters}",
|
|
35
|
+
"missingPlaceholder": "Configured web preview URL must include {reportRequestUuid} placeholder.",
|
|
33
36
|
"nextPage": "Next page",
|
|
34
37
|
"nextRun": "Next run",
|
|
35
38
|
"no": "No",
|
|
36
39
|
"noDataAvailable": "No data available",
|
|
37
40
|
"notATimeText": "hh:mm 24-hr pattern required",
|
|
38
41
|
"notScheduled": "Not scheduled",
|
|
42
|
+
"noWebPreviewUrlConfigured": "No web preview URL configured.",
|
|
39
43
|
"on": "on",
|
|
40
44
|
"outputFormat": "Output format",
|
|
41
45
|
"parameters": "Parameters",
|
|
@@ -82,6 +86,7 @@
|
|
|
82
86
|
"selectReportLabel": "Report",
|
|
83
87
|
"status": "Status",
|
|
84
88
|
"unknownParameterType": "Unknown parameter type: {type} for parameter: {label}",
|
|
89
|
+
"view": "View",
|
|
85
90
|
"viewReports": "Reports Webview",
|
|
86
91
|
"yes": "Yes"
|
|
87
92
|
}
|
package/tsconfig.json
CHANGED