ui-soxo-bootstrap-core 2.6.44 → 2.6.46-dev.1

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.
@@ -85,7 +85,7 @@ function GlobalHeaderContent({ loading, appSettings, children, isConnected, hist
85
85
  className={`global-header ${process.env.REACT_APP_THEME} ${isConnected && !kiosk ? 'connected' : ''}`}
86
86
  style={{
87
87
  // background: state.theme.colors.bodyBackground,
88
- height: auto,
88
+ height: 'auto',
89
89
  }}
90
90
  >
91
91
  {/* <MenuOutlined style={{left:'1%',top:'1%', fontSize:18, position:'absolute', zIndex:999}} onClick={showSidebar}/> */}
@@ -6,24 +6,62 @@
6
6
  * @param {Array<{ label: string, key: string }>} [headers] - Optional column headers and field mappings.
7
7
  * @param {string} [fileName='Report.xlsx'] - Optional name for the downloaded Excel file.
8
8
  */
9
-
10
- import React from 'react';
9
+
10
+ import React, { useState } from 'react';
11
11
  // Import XLSX library to handle Excel file creation
12
12
  import * as XLSX from 'xlsx';
13
+ import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
13
14
  // import * as XLSX from 'xlsx-js-style';
14
15
  // import * as XLSX from 'xlsx-js-style';
15
16
  // Import saveAs from file-saver to trigger file download in browser
16
17
  import { saveAs } from 'file-saver';
17
- import { Button } from 'antd';
18
+ import { Button, Dropdown, Form, Input, Menu, Modal, Radio, message } from 'antd';
19
+ import { DownOutlined, FileExcelFilled, FilePdfFilled, MailFilled, DownloadOutlined } from '@ant-design/icons';
18
20
  import { Trans } from 'react-i18next';
21
+ import { CoreScripts } from '../../../../models';
22
+ import './generic-list.scss';
23
+
24
+ const normalizeScriptId = (value) => {
25
+ if (value === undefined || value === null || value === '') return value;
26
+
27
+ const numberValue = Number(value);
28
+ return Number.isNaN(numberValue) ? value : numberValue;
29
+ };
30
+
31
+ const getRecipients = (value) => {
32
+ if (Array.isArray(value)) return value.filter(Boolean);
33
+
34
+ return String(value || '')
35
+ .split(/[\n,;]+/)
36
+ .map((email) => email.trim())
37
+ .filter(Boolean);
38
+ };
39
+
40
+
41
+ export const ExportReactCSV = ({
42
+ csvData,
43
+ headers,
44
+ fileName,
45
+ pdfFileName,
46
+ title,
47
+ format = 'excel',
48
+ buttonText,
49
+ dropdown = false,
50
+ onSendReportToMail,
51
+ scriptId,
52
+ inputParameters,
53
+ }) => {
54
+ const [mailModalVisible, setMailModalVisible] = useState(false);
55
+ const [sendingMail, setSendingMail] = useState(false);
56
+ const [selectedFormat, setSelectedFormat] = useState('excel');
57
+ const [mailForm] = Form.useForm();
19
58
 
20
- export const ExportReactCSV = ({ csvData, headers, fileName,title }) => {
21
59
  /**
22
60
  * exportToExcel function
23
61
  * Triggered on button click, generates and downloads an Excel file
24
62
  */
25
63
 
26
- const exportToExcel = () => {
64
+ const exportToExcel = (downloadFileName) => {
27
65
  // if (!csvData?.length) return;
28
66
 
29
67
  let worksheet;
@@ -75,14 +113,361 @@ export const ExportReactCSV = ({ csvData, headers, fileName,title }) => {
75
113
  const blob = new Blob([excelBuffer], {
76
114
  type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
77
115
  });
78
- const flName = fileName || 'Report.xlsx';
116
+ const flName = downloadFileName || fileName || 'Report.xlsx';
79
117
  // Trigger download using file-saver
80
118
  saveAs(blob, flName);
81
119
  };
120
+
121
+ const exportToPdf = async (downloadFileName) => {
122
+ const pdfDoc = await PDFDocument.create();
123
+ const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
124
+ const boldFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
125
+ const headersToUse = headers?.length
126
+ ? headers
127
+ : Object.keys(csvData?.[0] || {}).map((key) => ({ label: key, key }));
128
+ const pageSize = headersToUse.length > 12 ? [1190, 842] : [842, 595];
129
+ const margin = 30;
130
+ const minRowHeight = 20;
131
+ const titleHeight = 38;
132
+ const fontSize = headersToUse.length > 12 ? 7 : 8;
133
+ const headerFontSize = headersToUse.length > 12 ? 7 : 8;
134
+ const lineHeight = fontSize + 2;
135
+ const headerLineHeight = headerFontSize + 2;
136
+ const cellPaddingX = 4;
137
+ const cellPaddingY = 5;
138
+ const availableWidth = pageSize[0] - margin * 2;
139
+ let page;
140
+ let y;
141
+
142
+ const sanitizeValue = (value) => {
143
+ if (value === undefined || value === null) return '';
144
+ if (typeof value === 'object') return JSON.stringify(value);
145
+ return String(value);
146
+ };
147
+
148
+ const getTextWidth = (text, textFont, size) => textFont.widthOfTextAtSize(sanitizeValue(text), size);
149
+
150
+ const splitLongWord = (word, maxWidth, textFont, size) => {
151
+ const characters = Array.from(word);
152
+ const chunks = [];
153
+ let chunk = '';
154
+
155
+ characters.forEach((character) => {
156
+ const nextChunk = `${chunk}${character}`;
157
+
158
+ if (chunk && getTextWidth(nextChunk, textFont, size) > maxWidth) {
159
+ chunks.push(chunk);
160
+ chunk = character;
161
+ } else {
162
+ chunk = nextChunk;
163
+ }
164
+ });
165
+
166
+ if (chunk) chunks.push(chunk);
167
+ return chunks;
168
+ };
169
+
170
+ const wrapText = (value, maxWidth, textFont, size) => {
171
+ const text = sanitizeValue(value);
172
+ const usableWidth = Math.max(maxWidth, 1);
173
+ const paragraphs = text.split(/\r?\n/);
174
+
175
+ return paragraphs.flatMap((paragraph) => {
176
+ const words = paragraph.split(/\s+/).filter(Boolean);
177
+ const lines = [];
178
+ let line = '';
179
+
180
+ if (!words.length) return [''];
181
+
182
+ words.forEach((word) => {
183
+ if (getTextWidth(word, textFont, size) > usableWidth) {
184
+ if (line) {
185
+ lines.push(line);
186
+ line = '';
187
+ }
188
+
189
+ const chunks = splitLongWord(word, usableWidth, textFont, size);
190
+ chunks.forEach((chunk, chunkIndex) => {
191
+ if (chunkIndex === chunks.length - 1) {
192
+ line = chunk;
193
+ } else {
194
+ lines.push(chunk);
195
+ }
196
+ });
197
+
198
+ return;
199
+ }
200
+
201
+ const nextLine = line ? `${line} ${word}` : word;
202
+ if (getTextWidth(nextLine, textFont, size) <= usableWidth) {
203
+ line = nextLine;
204
+ } else {
205
+ if (line) lines.push(line);
206
+ line = word;
207
+ }
208
+ });
209
+
210
+ if (line) lines.push(line);
211
+ return lines;
212
+ });
213
+ };
214
+
215
+ const getColumnWidths = () => {
216
+ if (!headersToUse.length) return [availableWidth];
217
+
218
+ const sampleRows = (csvData || []).slice(0, 100);
219
+ const minWidths = [];
220
+ const preferredWidths = headersToUse.map((header, index) => {
221
+ const label = sanitizeValue(header.label);
222
+ const compactColumn = label === '#' || ['slno', 'sl no'].includes(label.toLowerCase());
223
+ const minWidth = compactColumn ? 28 : 36;
224
+ const values = [label, ...sampleRows.map((row) => sanitizeValue(row[header.key]))];
225
+ const longestValueWidth = values.reduce((maxWidth, value) => Math.max(maxWidth, getTextWidth(value, font, fontSize)), 0);
226
+ const longestWordWidth = values.reduce((maxWidth, value) => {
227
+ const words = value.split(/\s+/).filter(Boolean);
228
+ return words.reduce((wordMaxWidth, word) => Math.max(wordMaxWidth, getTextWidth(word, font, fontSize)), maxWidth);
229
+ }, 0);
230
+ const headerWidth = getTextWidth(label, boldFont, headerFontSize);
231
+ const preferredWidth = Math.max(
232
+ minWidth,
233
+ Math.min(longestValueWidth + cellPaddingX * 2, compactColumn ? 48 : 130),
234
+ Math.min(longestWordWidth + cellPaddingX * 2, compactColumn ? 48 : 95),
235
+ headerWidth + cellPaddingX * 2
236
+ );
237
+
238
+ minWidths[index] = minWidth;
239
+ return preferredWidth;
240
+ });
241
+
242
+ const minTotal = minWidths.reduce((total, width) => total + width, 0);
243
+ const preferredTotal = preferredWidths.reduce((total, width) => total + width, 0);
244
+
245
+ if (preferredTotal <= availableWidth) {
246
+ const extraWidth = availableWidth - preferredTotal;
247
+ return preferredWidths.map((width) => width + (extraWidth * width) / preferredTotal);
248
+ }
249
+
250
+ if (minTotal >= availableWidth) {
251
+ return minWidths.map((width) => (width * availableWidth) / minTotal);
252
+ }
253
+
254
+ const flexibleTotal = preferredWidths.reduce((total, width, index) => total + (width - minWidths[index]), 0);
255
+ const extraWidth = availableWidth - minTotal;
256
+
257
+ return preferredWidths.map((width, index) => {
258
+ const flexibleWidth = width - minWidths[index];
259
+ return minWidths[index] + (extraWidth * flexibleWidth) / flexibleTotal;
260
+ });
261
+ };
262
+
263
+ const columnWidths = getColumnWidths();
264
+
265
+ const getMaxLineCount = (cellLines) => Math.max(1, ...cellLines.map((lines) => lines.length));
266
+
267
+ const getRowHeight = (cellLines, rowLineHeight) =>
268
+ Math.max(minRowHeight, getMaxLineCount(cellLines) * rowLineHeight + cellPaddingY * 2);
269
+
270
+ const drawTableRow = (cellLines, rowHeight, options) => {
271
+ let x = margin;
272
+
273
+ cellLines.forEach((lines, index) => {
274
+ const width = columnWidths[index] || availableWidth;
275
+ page.drawRectangle({
276
+ x,
277
+ y: y - rowHeight,
278
+ width,
279
+ height: rowHeight,
280
+ color: options.backgroundColor,
281
+ borderColor: options.borderColor,
282
+ borderWidth: 0.5,
283
+ });
284
+
285
+ lines.forEach((line, lineIndex) => {
286
+ page.drawText(line, {
287
+ x: x + cellPaddingX,
288
+ y: y - cellPaddingY - options.fontSize - lineIndex * options.lineHeight,
289
+ size: options.fontSize,
290
+ font: options.font,
291
+ color: options.textColor,
292
+ });
293
+ });
294
+
295
+ x += width;
296
+ });
297
+
298
+ y -= rowHeight;
299
+ };
300
+
301
+ const headerCellLines = headersToUse.map((header, index) =>
302
+ wrapText(header.label, columnWidths[index] - cellPaddingX * 2, boldFont, headerFontSize)
303
+ );
304
+ const headerRowHeight = getRowHeight(headerCellLines, headerLineHeight);
305
+
306
+ const drawHeader = () => {
307
+ drawTableRow(headerCellLines, headerRowHeight, {
308
+ backgroundColor: rgb(0.92, 0.94, 0.96),
309
+ borderColor: rgb(0.72, 0.75, 0.78),
310
+ font: boldFont,
311
+ fontSize: headerFontSize,
312
+ lineHeight: headerLineHeight,
313
+ textColor: rgb(0.1, 0.1, 0.1),
314
+ });
315
+ };
316
+
317
+ const addPage = () => {
318
+ page = pdfDoc.addPage(pageSize);
319
+ y = pageSize[1] - margin;
320
+
321
+ page.drawText(title || 'Report', {
322
+ x: margin,
323
+ y,
324
+ size: 14,
325
+ font: boldFont,
326
+ color: rgb(0.1, 0.1, 0.1),
327
+ });
328
+
329
+ y -= titleHeight;
330
+ drawHeader();
331
+ };
332
+
333
+ const drawDataRow = (row) => {
334
+ const rowFont = row.isSummaryRow ? boldFont : font;
335
+ const cellLines = headersToUse.map((header, index) =>
336
+ wrapText(row[header.key], columnWidths[index] - cellPaddingX * 2, rowFont, fontSize)
337
+ );
338
+ let remainingCellLines = cellLines.map((lines) => (lines.length ? lines : ['']));
339
+ const fullPageDataHeight = pageSize[1] - margin * 2 - titleHeight - headerRowHeight;
340
+
341
+ while (remainingCellLines.some((lines) => lines.length)) {
342
+ const rowHeight = getRowHeight(remainingCellLines, lineHeight);
343
+ const availableHeight = y - margin;
344
+
345
+ if (rowHeight > availableHeight && rowHeight <= fullPageDataHeight) {
346
+ addPage();
347
+ continue;
348
+ }
349
+
350
+ const maxLinesOnPage =
351
+ rowHeight > availableHeight
352
+ ? Math.max(1, Math.floor((availableHeight - cellPaddingY * 2) / lineHeight))
353
+ : getMaxLineCount(remainingCellLines);
354
+ const segmentCellLines = remainingCellLines.map((lines) => lines.slice(0, maxLinesOnPage));
355
+ const segmentHeight = getRowHeight(segmentCellLines, lineHeight);
356
+
357
+ if (segmentHeight > availableHeight && availableHeight < fullPageDataHeight) {
358
+ addPage();
359
+ continue;
360
+ }
361
+
362
+ drawTableRow(segmentCellLines, segmentHeight, {
363
+ backgroundColor: row.isSummaryRow ? rgb(0.97, 0.97, 0.97) : rgb(1, 1, 1),
364
+ borderColor: rgb(0.82, 0.84, 0.86),
365
+ font: rowFont,
366
+ fontSize,
367
+ lineHeight,
368
+ textColor: rgb(0.12, 0.12, 0.12),
369
+ });
370
+
371
+ remainingCellLines = remainingCellLines.map((lines) => lines.slice(maxLinesOnPage));
372
+ if (remainingCellLines.some((lines) => lines.length)) addPage();
373
+ }
374
+ };
375
+
376
+ addPage();
377
+
378
+ (csvData || []).forEach((row) => {
379
+ drawDataRow(row);
380
+ });
381
+
382
+ if (!csvData?.length) {
383
+ page.drawText('No records found', {
384
+ x: margin,
385
+ y: y + 1,
386
+ size: fontSize,
387
+ font,
388
+ color: rgb(0.12, 0.12, 0.12),
389
+ });
390
+ }
391
+
392
+ const pdfBytes = await pdfDoc.save();
393
+ const blob = new Blob([pdfBytes], { type: 'application/pdf' });
394
+ const flName = downloadFileName || pdfFileName || fileName || 'Report.pdf';
395
+ saveAs(blob, flName);
396
+ };
397
+
398
+ const handleDownloadMenuClick = ({ key }) => {
399
+ if (key === 'excel') {
400
+ exportToExcel(fileName);
401
+ return;
402
+ }
403
+
404
+ if (key === 'pdf') {
405
+ exportToPdf(pdfFileName);
406
+ return;
407
+ }
408
+
409
+ if (key === 'mail') {
410
+ setMailModalVisible(true);
411
+ }
412
+ };
413
+
414
+ const handleMailModalClose = () => {
415
+ setMailModalVisible(false);
416
+ mailForm.resetFields();
417
+ setSelectedFormat('excel');
418
+ };
419
+
420
+ const handleFormatToggle = (value) => {
421
+ const nextValue = selectedFormat === value ? null : value;
422
+ setSelectedFormat(nextValue);
423
+ mailForm.setFieldsValue({ format: nextValue });
424
+ };
425
+
426
+
427
+ const downloadMenu = (
428
+ <Menu className="export-download-menu" onClick={handleDownloadMenuClick}>
429
+ <Menu.Item
430
+ key="excel"
431
+ icon={<FileExcelFilled className="export-download-menu__icon export-download-menu__icon--excel" />}
432
+ >
433
+ Download Excel Sheet
434
+ </Menu.Item>
435
+ <Menu.Item
436
+ key="pdf"
437
+ icon={<FilePdfFilled className="export-download-menu__icon export-download-menu__icon--pdf" />}
438
+ >
439
+ Download PDF
440
+ </Menu.Item>
441
+ </Menu>
442
+ );
443
+
444
+ const isPdf = format === 'pdf';
445
+ const handleExportButtonClick = () => {
446
+ if (isPdf) {
447
+ exportToPdf();
448
+ return;
449
+ }
450
+
451
+ exportToExcel();
452
+ };
453
+
454
+ if (dropdown) {
455
+ return (
456
+ <>
457
+ <Dropdown overlay={downloadMenu} trigger={['click']} placement="bottomRight">
458
+ <Button type="primary" size="small" className="export-download-button">
459
+ <Trans i18nKey={buttonText || 'Download'} /> <DownloadOutlined className="export-download-button__icon" />
460
+ </Button>
461
+ </Dropdown>
462
+ </>
463
+
464
+ );
465
+ }
466
+
82
467
  // Render an Ant Design Button that triggers the Excel export
83
468
  return (
84
- <Button type="secondary" size="small" onClick={exportToExcel}>
85
- <Trans i18nKey="Download" />
469
+ <Button type="secondary" size="small" onClick={handleExportButtonClick} className="export-download-button">
470
+ <Trans i18nKey={buttonText || (isPdf ? 'PDF Download' : 'Download')} /> <DownloadOutlined className="export-download-button__icon" />
86
471
  </Button>
87
472
  );
88
473
  };
@@ -32,3 +32,37 @@
32
32
  }
33
33
  }
34
34
  }
35
+
36
+ .export-download-button {
37
+ &.ant-btn-primary {
38
+ background: #2f80ed;
39
+ border-color: #2f80ed;
40
+ color: #fff;
41
+
42
+ &:hover,
43
+ &:focus {
44
+ background: #1c7ed6;
45
+ border-color: #1c7ed6;
46
+ color: #fff;
47
+ }
48
+ }
49
+ }
50
+
51
+ .export-download-menu {
52
+ &__icon {
53
+ font-size: 16px;
54
+ vertical-align: -0.15em;
55
+
56
+ &--excel {
57
+ color: #18a058;
58
+ }
59
+
60
+ &--pdf {
61
+ color: #e03131;
62
+ }
63
+
64
+ &--mail {
65
+ color: #1c7ed6;
66
+ }
67
+ }
68
+ }
@@ -80,6 +80,14 @@ class CoreScript extends Base {
80
80
  });
81
81
  };
82
82
 
83
+ // sentToReportMail = (formBody) => {
84
+ // return ApiUtils.post({
85
+ // baseUrl: 'http://localhost:8002/dev/',
86
+ // url: `core-scripts/send-to-report-mail`,
87
+ // formBody,
88
+ // });
89
+ // };
90
+
83
91
  /**
84
92
  *Updating user details
85
93
  * @returns
@@ -70,6 +70,10 @@ export default function ReportingDashboard({
70
70
 
71
71
  const [formContents, setformContents] = useState({});
72
72
  const [liveFormContents, setLiveFormContents] = useState({});
73
+ const [reportMailRequest, setReportMailRequest] = useState({
74
+ scriptId: null,
75
+ inputParameters: {},
76
+ });
73
77
 
74
78
  const scriptId = useRef(null);
75
79
 
@@ -300,6 +304,11 @@ export default function ReportingDashboard({
300
304
  formBody = { body: { ...scope, ...paginationData } };
301
305
  }
302
306
 
307
+ setReportMailRequest({
308
+ scriptId: coreScriptId,
309
+ inputParameters: formBody,
310
+ });
311
+
303
312
  // Fetch result
304
313
  const result = await CoreScripts.getReportingLisitng(coreScriptId, formBody, dbPtr);
305
314
 
@@ -668,6 +677,8 @@ export default function ReportingDashboard({
668
677
  selectedSearchFields={selectedSearchFields}
669
678
  handleRemoveSearchField={handleRemoveSearchField}
670
679
  fetchReportData={(paginationUpdate) => fetchReportData(id, formContents, dbPtr, paginationUpdate || pagination)}
680
+ reportScriptId={reportMailRequest.scriptId}
681
+ reportInputParameters={reportMailRequest.inputParameters}
671
682
  />
672
683
  {/** GuestList component end*/}
673
684
  </>
@@ -676,6 +687,29 @@ export default function ReportingDashboard({
676
687
  );
677
688
  }
678
689
 
690
+ /**
691
+ * Filters report records using the same search text that drives the table.
692
+ *
693
+ * @param {Array<Object>} records - Report rows.
694
+ * @param {string} searchText - Current table search text.
695
+ * @returns {Array<Object>} Rows matching the search text.
696
+ */
697
+ function filterReportRecords(records, searchText) {
698
+ if (!Array.isArray(records)) return [];
699
+
700
+ const query = String(searchText || '').trim().toLowerCase();
701
+
702
+ if (!query) return records;
703
+
704
+ return records.filter((record) =>
705
+ Object.values(record).some((value) => {
706
+ if (value === undefined || value === null || typeof value === 'object') return false;
707
+
708
+ return String(value).toLowerCase().indexOf(query) !== -1;
709
+ })
710
+ );
711
+ }
712
+
679
713
  /**
680
714
  *
681
715
  * @param root0
@@ -703,6 +737,8 @@ function GuestList({
703
737
  selectedSearchFields,
704
738
  handleRemoveSearchField,
705
739
  fetchReportData,
740
+ reportScriptId,
741
+ reportInputParameters,
706
742
  }) {
707
743
  /**
708
744
  * @param {*} propValues
@@ -791,13 +827,13 @@ function GuestList({
791
827
  return col;
792
828
  });
793
829
  const summaryCols = columns.filter((col) => col.enable_summary);
794
- let dataToExport = [...patients];
830
+ let dataToExport = [...filterReportRecords(patients, query)];
795
831
 
796
832
  if (summaryCols.length > 0) {
797
833
  // Build one synthetic row for CSV export that mirrors the table layout:
798
834
  // numeric summary cells are populated from `calculateSummaryValues`, while
799
835
  // non-summary columns stay blank unless a configured caption should be shown.
800
- const summaryValues = calculateSummaryValues(summaryCols, patients);
836
+ const summaryValues = calculateSummaryValues(summaryCols, dataToExport);
801
837
  const summaryRow = { isSummaryRow: true };
802
838
 
803
839
  cols.forEach((col, index) => {
@@ -824,37 +860,15 @@ function GuestList({
824
860
  }
825
861
  let exportDatas = getExportData(dataToExport, exportCols);
826
862
 
827
- if (exportDatas.exportDataColumns.length && exportDatas.exportDataHeaders.length) {
863
+ if (exportDatas.exportDataHeaders.length) {
828
864
  setExportData({ exportDatas });
865
+ } else {
866
+ setExportData({});
829
867
  }
830
868
  }
831
- }, [patients, columns]);
832
-
833
- let filtered;
834
-
835
- if (patients) {
836
- filtered = patients.filter((record) => {
837
- if (query) {
838
- // Keys
839
- let keys = Object.keys(record);
840
-
841
- let flag = false;
869
+ }, [patients, columns, query]);
842
870
 
843
- keys.forEach((key) => {
844
- let ele = record[key];
845
-
846
- if (ele && typeof ele === 'string' && ele.toLowerCase().indexOf(query.toLowerCase()) !== -1) {
847
- flag = true;
848
- }
849
- });
850
-
851
- /**Will return flag */
852
- return flag;
853
- } else {
854
- return true;
855
- }
856
- });
857
- }
871
+ let filtered = filterReportRecords(patients, query);
858
872
 
859
873
  /**
860
874
  * Checks for a match in the filtered patient list based on a scanned code,
@@ -977,11 +991,18 @@ function GuestList({
977
991
  <Search className="table-search-input" placeholder="Enter Search Value" allowClear onChange={onSearch} />
978
992
  <div className="table-export-button">
979
993
  {exportData.exportDatas && (
980
- <ExportReactCSV
981
- title={config.caption}
982
- headers={exportData.exportDatas.exportDataHeaders}
983
- csvData={exportData.exportDatas.exportDataColumns}
984
- />
994
+ <>
995
+ <ExportReactCSV
996
+ title={config.caption}
997
+ headers={exportData.exportDatas.exportDataHeaders}
998
+ csvData={exportData.exportDatas.exportDataColumns}
999
+ fileName={`${config.caption || 'Report'}.xlsx`}
1000
+ pdfFileName={`${config.caption || 'Report'}.pdf`}
1001
+ scriptId={reportScriptId}
1002
+ inputParameters={reportInputParameters}
1003
+ dropdown
1004
+ />
1005
+ </>
985
1006
  )}
986
1007
  </div>
987
1008
 
@@ -1036,7 +1057,7 @@ function GuestList({
1036
1057
  dataSource={filtered ? filtered : patients} // In case if there is no filtered values we can use patient data
1037
1058
  columns={cols}
1038
1059
  sticky
1039
- pagination={false}
1060
+ pagination={true}
1040
1061
  summary={(pageData) => {
1041
1062
  const summaryCols = columns.filter((col) => col.enable_summary);
1042
1063
  if (!summaryCols.length) return null;
@@ -52,6 +52,7 @@
52
52
  display: flex;
53
53
  align-items: center;
54
54
  flex-shrink: 0;
55
+ gap: 4px;
55
56
  }
56
57
 
57
58
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui-soxo-bootstrap-core",
3
- "version": "2.6.44",
3
+ "version": "2.6.46-dev.1",
4
4
  "description": "All the Core Components for you to start",
5
5
  "keywords": [
6
6
  "all in one"