@quillsql/react 1.6.5 → 1.6.7

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/src/Table.tsx CHANGED
@@ -10,16 +10,35 @@ import {
10
10
  } from './Context';
11
11
  import Skeleton from 'react-loading-skeleton';
12
12
  import { valueFormatter } from './Chart';
13
- import { SpecialTable } from './SQLEditor';
13
+ // import { SpecialTable } from './SQLEditor';
14
14
  import { QuillTheme } from './QuillProvider';
15
+ import { TailSpin } from 'react-loader-spinner';
16
+
17
+ interface TableColumn {
18
+ label: string;
19
+ field: string;
20
+ }
21
+
22
+ interface ChartIdTableProps {
23
+ chartId: string;
24
+ containerStyle?: React.CSSProperties;
25
+ csvFilename?: string;
26
+ }
27
+
28
+ interface DataTableProps {
29
+ columns: TableColumn[];
30
+ rows: object[];
31
+ containerStyle?: React.CSSProperties;
32
+ csvFilename?: string;
33
+ }
15
34
 
16
35
  const Table = ({
17
36
  chartId,
37
+ columns,
38
+ rows,
18
39
  containerStyle,
19
- }: {
20
- chartId: string;
21
- containerStyle?: React.CSSProperties;
22
- }) => {
40
+ csvFilename,
41
+ }: ChartIdTableProps | DataTableProps) => {
23
42
  const { dispatch, dashboard } = useContext(DashboardContext);
24
43
  const [client, _] = useContext(ClientContext);
25
44
  const [theme] =
@@ -57,18 +76,631 @@ const Table = ({
57
76
  downloadLink.click();
58
77
  document.body.removeChild(downloadLink);
59
78
  };
79
+
80
+ return null;
81
+
82
+ // if (!chartId && rows && columns) {
83
+ // return (
84
+ // <SpecialTable
85
+ // showDownloadCsvButton
86
+ // csvFilename={csvFilename || 'table'}
87
+ // columns={columns}
88
+ // rows={rows}
89
+ // height={containerStyle?.height || '100%'}
90
+ // theme={theme}
91
+ // />
92
+ // );
93
+ // }
94
+
95
+ // return (
96
+ // <ChartUpdater
97
+ // dispatch={dispatch}
98
+ // dashboard={dashboard}
99
+ // chartId={chartId}
100
+ // containerStyle={containerStyle}
101
+ // client={client}
102
+ // theme={theme}
103
+ // downloadCSV={downloadCSV}
104
+ // csvFilename={csvFilename}
105
+ // />
106
+ // );
107
+ };
108
+
109
+ interface TableButtonComponentProps {
110
+ onClick: () => void;
111
+ }
112
+
113
+ export function SpecialTable({
114
+ columns,
115
+ rows,
116
+ height,
117
+ containerStyle,
118
+ loading,
119
+ LoadingComponent,
120
+ theme,
121
+ showDownloadCsvButton,
122
+ csvFilename,
123
+ DownloadCSVButtonComponent,
124
+ AddToDashboardButtonComponent,
125
+ }: {
126
+ columns: any[];
127
+ rows: any[];
128
+ height: string;
129
+ containerStyle?: React.CSSProperties;
130
+ loading?: boolean;
131
+ LoadingComponent?: () => JSX.Element;
132
+ theme?: any;
133
+ showDownloadCsvButton?: boolean;
134
+ csvFilename?: string;
135
+ DownloadCSVButtonComponent?: (
136
+ props: TableButtonComponentProps
137
+ ) => JSX.Element;
138
+ AddToDashboardButtonComponent?: (
139
+ props: TableButtonComponentProps
140
+ ) => JSX.Element;
141
+ }) {
142
+ const downloadCSV = () => {
143
+ // report.rows
144
+ if (!rows.length) {
145
+ return;
146
+ }
147
+ const json = rows; // JSON data passed as a prop
148
+ const fields = Object.keys(json[0]); // Assumes all objects have same keys
149
+ const csvRows = [];
150
+
151
+ // Header row
152
+ csvRows.push(fields.join(','));
153
+
154
+ // Data rows
155
+ for (const row of json) {
156
+ const values = fields.map(field => JSON.stringify(row[field] || ''));
157
+ csvRows.push(values.join(','));
158
+ }
159
+
160
+ // Create CSV string and create a 'blob' with it
161
+ const csvString = csvRows.join('\r\n');
162
+ const csvBlob = new Blob([csvString], { type: 'text/csv' });
163
+
164
+ // Create a download link and click it
165
+ const downloadLink = document.createElement('a');
166
+ downloadLink.download = `${csvFilename}.csv`;
167
+ downloadLink.href = URL.createObjectURL(csvBlob);
168
+ downloadLink.style.display = 'none';
169
+
170
+ document.body.appendChild(downloadLink);
171
+ downloadLink.click();
172
+ document.body.removeChild(downloadLink);
173
+ };
174
+ if (loading) {
175
+ return (
176
+ <div
177
+ style={{
178
+ ...containerStyle,
179
+ // paddingLeft: 25,
180
+ // paddingRight: 25,
181
+ // borderRadius: 8,
182
+ // marginTop: 25,
183
+ // overflow: 'visible',
184
+ width: '100%',
185
+ height: height,
186
+ // overflow: 'hidden',
187
+ // @ts-ignore
188
+ // boxShadow: 'rgba(231, 231, 231, 0.5) 0px 1px 2px 0px',
189
+ }}
190
+ >
191
+ <div
192
+ style={{
193
+ height: '100%',
194
+ overflow: 'scroll',
195
+ borderRadius: 6,
196
+ border: '1px solid rgb(229, 231, 235)',
197
+ padding: 0,
198
+ margin: 0,
199
+ // border: 'none',
200
+ boxSizing: 'border-box',
201
+ outline: 'none',
202
+ display: 'flex',
203
+ flexDirection: 'column',
204
+ justifyContent: 'center',
205
+ alignItems: 'center',
206
+ // maxHeight: 600,
207
+ }}
208
+ >
209
+ {LoadingComponent && <LoadingComponent />}
210
+ {!LoadingComponent && (
211
+ <TailSpin height={36} width={36} color="#364153" />
212
+ )}
213
+ </div>
214
+ </div>
215
+ );
216
+ }
217
+ if (!columns || !columns.length || !rows) {
218
+ return null;
219
+ }
220
+
221
+ if (showDownloadCsvButton) {
222
+ return (
223
+ <div
224
+ style={{
225
+ ...containerStyle,
226
+ // paddingLeft: 25,
227
+ // paddingRight: 25,
228
+ // borderRadius: 8,
229
+ // marginTop: 25,
230
+ overflow: 'visible',
231
+ height: height,
232
+ // overflow: 'hidden',
233
+ // @ts-ignore
234
+ // boxShadow: 'rgba(231, 231, 231, 0.5) 0px 1px 2px 0px',
235
+ }}
236
+ >
237
+ <div style={{ height: 50, background: 'white' }} className="thead">
238
+ <div
239
+ role="row"
240
+ className="tr"
241
+ style={{
242
+ display: 'flex',
243
+ flex: '1 0 auto',
244
+ minWidth: '100px',
245
+ boxSizing: 'border-box',
246
+ alignItems: 'center',
247
+ height: 50,
248
+ // position: 'absolute',
249
+ // bottom: 0,
250
+ }}
251
+ >
252
+ {DownloadCSVButtonComponent && (
253
+ <DownloadCSVButtonComponent onClick={downloadCSV} />
254
+ )}
255
+ {!DownloadCSVButtonComponent && (
256
+ <div
257
+ onClick={downloadCSV}
258
+ style={{
259
+ height: 40,
260
+ minHeight: 40,
261
+ color: theme?.primaryTextColor,
262
+ boxSizing: 'content-box',
263
+ fontFamily: theme?.chartLabelFontFamily || theme?.fontFamily,
264
+ fontSize: theme?.fontSizeSmall || '14px',
265
+ fontWeight: theme?.fontWeightMedium || '500',
266
+ // marginTop: 8,
267
+ marginLeft: 20,
268
+ alignItems: 'center',
269
+ display: 'flex',
270
+ cursor: 'pointer',
271
+ }}
272
+ >
273
+ Download CSV
274
+ </div>
275
+ )}
276
+ </div>
277
+ </div>
278
+ <div
279
+ style={{
280
+ height: 'calc(100% - 50px)',
281
+ overflow: 'scroll',
282
+ borderRadius: 6,
283
+ border: '1px solid rgb(229, 231, 235)',
284
+ padding: 0,
285
+ margin: 0,
286
+ // border: 'none',
287
+ boxSizing: 'border-box',
288
+ outline: 'none',
289
+ // maxHeight: 600,
290
+ }}
291
+ >
292
+ <div role="table" className="table" style={{ minWidth: '0px' }}>
293
+ <div className="thead">
294
+ <div
295
+ role="row"
296
+ className="tr"
297
+ style={{
298
+ display: 'flex',
299
+ flex: '1 0 auto',
300
+ minWidth: '100px',
301
+ boxSizing: 'border-box',
302
+ }}
303
+ >
304
+ {/* @ts-ignore */}
305
+ {columns.map((column, index) => (
306
+ <div
307
+ key={'sqlcol' + index}
308
+ // @ts-ignore
309
+ style={{
310
+ boxSizing: 'border-box',
311
+ flex: '150 0 auto',
312
+ minWidth: '50px',
313
+ width: '150px',
314
+ position: 'relative',
315
+ cursor: 'pointer',
316
+ background: 'rgb(249, 250, 251)',
317
+ borderRight: '1px solid rgb(229, 231, 235)',
318
+ whiteSpace: 'nowrap',
319
+ display: 'flex',
320
+ alignItems: 'center',
321
+ overflowX: 'visible',
322
+ margin: '0px',
323
+ textOverflow: 'ellipsis',
324
+ minHeight: '36px',
325
+ }}
326
+ >
327
+ <div style={{ width: 16 }} />
328
+ <div
329
+ aria-haspopup="dialog"
330
+ aria-expanded="false"
331
+ aria-controls="mantine-r6-dropdown"
332
+ // @ts-ignore
333
+ style={{
334
+ // fontFamily:
335
+ // 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
336
+ WebkitTapHighlightColor: 'transparent',
337
+ fontFamily: theme?.fontFamily,
338
+ // color: 'rgb(55, 65, 81)',
339
+ color: theme?.primaryTextColor,
340
+ textDecoration: 'none',
341
+ fontSize: theme?.fontSizeSmall || '14px',
342
+ fontWeight: theme?.fontWeightMedium || '500',
343
+ lineHeight: '20px', // 1.25rem * 16px = 20px
344
+ textOverflow: 'ellipsis',
345
+ whiteSpace: 'nowrap',
346
+ overflow: 'hidden',
347
+ }}
348
+ >
349
+ {column.label}
350
+ </div>
351
+ </div>
352
+ ))}
353
+ </div>
354
+ </div>
355
+ <div role="rowgroup" className="tbody">
356
+ {/* @ts-ignore */}
357
+ {!rows.length ? (
358
+ <div
359
+ key={'sqlrow0'}
360
+ role="row"
361
+ className="tr"
362
+ style={{
363
+ display: 'flex',
364
+ flex: '1 0 auto',
365
+ minWidth: '100px',
366
+ boxSizing: 'border-box',
367
+ }}
368
+ >
369
+ <div
370
+ key={'sqlcell0'}
371
+ role="cell"
372
+ className="td airplane-1h7muk6"
373
+ style={{
374
+ boxSizing: 'border-box',
375
+ flex: '150 0 auto',
376
+ minWidth: '50px',
377
+ width: '150px',
378
+ display: 'flex',
379
+ margin: '0px',
380
+ textOverflow: 'ellipsis',
381
+ minHeight: '36px',
382
+ borderRight: '1px solid rgb(229, 231, 235)',
383
+ overflow: 'hidden',
384
+ borderTop: '1px solid rgb(229, 231, 235)',
385
+ }}
386
+ >
387
+ <div
388
+ style={{
389
+ lineHeight: '24px',
390
+ width: '100%',
391
+ display: 'flex',
392
+ cursor: 'default',
393
+ position: 'relative',
394
+ }}
395
+ className="airplane-gowkln"
396
+ data-testid="static-cell"
397
+ >
398
+ <div
399
+ className="airplane-Text-root airplane-mzqt6k"
400
+ aria-haspopup="dialog"
401
+ aria-expanded="false"
402
+ aria-controls="mantine-r8-dropdown"
403
+ id="mantine-r8-target"
404
+ style={{
405
+ fontFamily:
406
+ theme?.fontFamily ||
407
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
408
+ WebkitTapHighlightColor: 'transparent',
409
+ // color: 'rgb(55, 65, 81)',
410
+ color: theme?.secondaryTextColor || 'rgb(55, 65, 81)',
411
+ textDecoration: 'none',
412
+ fontWeight: 400,
413
+ fontSize: theme?.fontSizeSmall || '14px',
414
+ lineHeight: '20px',
415
+ textOverflow: 'ellipsis',
416
+ whiteSpace: 'nowrap',
417
+ overflow: 'hidden',
418
+ padding: '8px 16px',
419
+ }}
420
+ >
421
+ No rows returned
422
+ </div>
423
+ </div>
424
+ </div>
425
+ </div>
426
+ ) : (
427
+ rows.map((row, rowIndex) => (
428
+ <div
429
+ key={'sqlrow' + rowIndex}
430
+ role="row"
431
+ className="tr"
432
+ style={{
433
+ display: 'flex',
434
+ flex: '1 0 auto',
435
+ minWidth: '100px',
436
+ boxSizing: 'border-box',
437
+ }}
438
+ >
439
+ {/* @ts-ignore */}
440
+ {columns.map((column, columnIndex) => (
441
+ <div
442
+ key={'sqlcell' + columnIndex}
443
+ role="cell"
444
+ className="td airplane-1h7muk6"
445
+ style={{
446
+ boxSizing: 'border-box',
447
+ flex: '150 0 auto',
448
+ minWidth: '50px',
449
+ width: '150px',
450
+ display: 'flex',
451
+ margin: '0px',
452
+ textOverflow: 'ellipsis',
453
+ minHeight: '36px',
454
+ borderRight: '1px solid rgb(229, 231, 235)',
455
+ overflow: 'hidden',
456
+ borderTop: '1px solid rgb(229, 231, 235)',
457
+ borderBottom:
458
+ rowIndex === rows.length - 1
459
+ ? '1px solid rgb(229, 231, 235)'
460
+ : undefined,
461
+ }}
462
+ >
463
+ <div
464
+ style={{
465
+ lineHeight: '24px',
466
+ width: '100%',
467
+ display: 'flex',
468
+ cursor: 'default',
469
+ position: 'relative',
470
+ }}
471
+ className="airplane-gowkln"
472
+ data-testid="static-cell"
473
+ >
474
+ <div
475
+ className="airplane-Text-root airplane-mzqt6k"
476
+ aria-haspopup="dialog"
477
+ aria-expanded="false"
478
+ aria-controls="mantine-r8-dropdown"
479
+ id="mantine-r8-target"
480
+ style={{
481
+ fontFamily:
482
+ theme?.fontFamily ||
483
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
484
+ WebkitTapHighlightColor: 'transparent',
485
+ // color: 'rgb(55, 65, 81)',
486
+ color:
487
+ theme?.secondaryTextColor || 'rgb(55, 65, 81)',
488
+ textDecoration: 'none',
489
+ fontWeight: 400,
490
+ fontSize: theme?.fontSizeSmall || '14px',
491
+ lineHeight: '20px',
492
+ textOverflow: 'ellipsis',
493
+ whiteSpace: 'nowrap',
494
+ overflow: 'hidden',
495
+ padding: '8px 16px',
496
+ }}
497
+ >
498
+ {typeof row[column.field] === 'object'
499
+ ? JSON.stringify(row[column.field]).length > 55
500
+ ? JSON.stringify(row[column.field]).substring(
501
+ 0,
502
+ 52
503
+ ) + '...'
504
+ : JSON.stringify(row[column.field])
505
+ : row[column.field].length > 55
506
+ ? row[column.field].substring(0, 52) + '...'
507
+ : row[column.field]}
508
+ </div>
509
+ </div>
510
+ </div>
511
+ ))}
512
+ </div>
513
+ ))
514
+ )}
515
+ </div>
516
+ </div>
517
+ </div>
518
+ </div>
519
+ );
520
+ }
521
+
60
522
  return (
61
- <ChartUpdater
62
- dispatch={dispatch}
63
- dashboard={dashboard}
64
- chartId={chartId}
65
- containerStyle={containerStyle}
66
- client={client}
67
- theme={theme}
68
- downloadCSV={downloadCSV}
69
- />
523
+ <div
524
+ style={{
525
+ ...containerStyle,
526
+ // paddingLeft: 25,
527
+ // paddingRight: 25,
528
+ // borderRadius: 8,
529
+ // marginTop: 25,
530
+ overflow: 'visible',
531
+ height: height,
532
+ // overflow: 'hidden',
533
+ // @ts-ignore
534
+ // boxShadow: 'rgba(231, 231, 231, 0.5) 0px 1px 2px 0px',
535
+ }}
536
+ >
537
+ <div
538
+ style={{
539
+ height: '100%',
540
+ overflow: 'scroll',
541
+ borderRadius: 6,
542
+ border: '1px solid rgb(229, 231, 235)',
543
+ padding: 0,
544
+ margin: 0,
545
+ // border: 'none',
546
+ boxSizing: 'border-box',
547
+ outline: 'none',
548
+ // maxHeight: 600,
549
+ }}
550
+ >
551
+ <div role="table" className="table" style={{ minWidth: '0px' }}>
552
+ <div className="thead">
553
+ <div
554
+ role="row"
555
+ className="tr"
556
+ style={{
557
+ display: 'flex',
558
+ flex: '1 0 auto',
559
+ minWidth: '100px',
560
+ boxSizing: 'border-box',
561
+ }}
562
+ >
563
+ {/* @ts-ignore */}
564
+ {columns.map((column, index) => (
565
+ <div
566
+ key={'sqlcol' + index}
567
+ // @ts-ignore
568
+ style={{
569
+ boxSizing: 'border-box',
570
+ flex: '150 0 auto',
571
+ minWidth: '50px',
572
+ width: '150px',
573
+ position: 'relative',
574
+ cursor: 'pointer',
575
+ background: 'rgb(249, 250, 251)',
576
+ borderRight: '1px solid rgb(229, 231, 235)',
577
+ whiteSpace: 'nowrap',
578
+ display: 'flex',
579
+ alignItems: 'center',
580
+ overflowX: 'visible',
581
+ margin: '0px',
582
+ textOverflow: 'ellipsis',
583
+ minHeight: '36px',
584
+ }}
585
+ >
586
+ <div style={{ width: 16 }} />
587
+ <div
588
+ aria-haspopup="dialog"
589
+ aria-expanded="false"
590
+ aria-controls="mantine-r6-dropdown"
591
+ // @ts-ignore
592
+ style={{
593
+ // fontFamily:
594
+ // 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
595
+ WebkitTapHighlightColor: 'transparent',
596
+ fontFamily: theme?.fontFamily,
597
+ // color: 'rgb(55, 65, 81)',
598
+ color: theme?.primaryTextColor,
599
+ textDecoration: 'none',
600
+ fontSize: theme?.fontSizeSmall || '14px',
601
+ fontWeight: theme?.fontWeightMedium || '500',
602
+ lineHeight: '20px', // 1.25rem * 16px = 20px
603
+ textOverflow: 'ellipsis',
604
+ whiteSpace: 'nowrap',
605
+ overflow: 'hidden',
606
+ }}
607
+ >
608
+ {column.label}
609
+ </div>
610
+ </div>
611
+ ))}
612
+ </div>
613
+ </div>
614
+ <div role="rowgroup" className="tbody">
615
+ {/* @ts-ignore */}
616
+ {rows.map((row, rowIndex) => (
617
+ <div
618
+ key={'sqlrow' + rowIndex}
619
+ role="row"
620
+ className="tr"
621
+ style={{
622
+ display: 'flex',
623
+ flex: '1 0 auto',
624
+ minWidth: '100px',
625
+ boxSizing: 'border-box',
626
+ }}
627
+ >
628
+ {/* @ts-ignore */}
629
+ {columns.map((column, columnIndex) => (
630
+ <div
631
+ key={'sqlcell' + columnIndex}
632
+ role="cell"
633
+ className="td airplane-1h7muk6"
634
+ style={{
635
+ boxSizing: 'border-box',
636
+ flex: '150 0 auto',
637
+ minWidth: '50px',
638
+ width: '150px',
639
+ display: 'flex',
640
+ margin: '0px',
641
+ textOverflow: 'ellipsis',
642
+ minHeight: '36px',
643
+ borderRight: '1px solid rgb(229, 231, 235)',
644
+ overflow: 'hidden',
645
+ borderTop: '1px solid rgb(229, 231, 235)',
646
+ }}
647
+ >
648
+ <div
649
+ style={{
650
+ lineHeight: '24px',
651
+ width: '100%',
652
+ display: 'flex',
653
+ cursor: 'default',
654
+ position: 'relative',
655
+ }}
656
+ className="airplane-gowkln"
657
+ data-testid="static-cell"
658
+ >
659
+ <div
660
+ className="airplane-Text-root airplane-mzqt6k"
661
+ aria-haspopup="dialog"
662
+ aria-expanded="false"
663
+ aria-controls="mantine-r8-dropdown"
664
+ id="mantine-r8-target"
665
+ style={{
666
+ fontFamily:
667
+ theme?.fontFamily ||
668
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
669
+ WebkitTapHighlightColor: 'transparent',
670
+ // color: 'rgb(55, 65, 81)',
671
+ color: theme?.secondaryTextColor || 'rgb(55, 65, 81)',
672
+ textDecoration: 'none',
673
+ fontWeight: 400,
674
+ fontSize: theme?.fontSizeSmall || '14px',
675
+ lineHeight: '20px',
676
+ textOverflow: 'ellipsis',
677
+ whiteSpace: 'nowrap',
678
+ overflow: 'hidden',
679
+ padding: '8px 16px',
680
+ }}
681
+ >
682
+ {typeof row[column.field] === 'object'
683
+ ? JSON.stringify(row[column.field]).length > 55
684
+ ? JSON.stringify(row[column.field]).substring(
685
+ 0,
686
+ 52
687
+ ) + '...'
688
+ : JSON.stringify(row[column.field])
689
+ : row[column.field].length > 55
690
+ ? row[column.field].substring(0, 52) + '...'
691
+ : row[column.field]}
692
+ </div>
693
+ </div>
694
+ </div>
695
+ ))}
696
+ </div>
697
+ ))}
698
+ </div>
699
+ </div>
700
+ </div>
701
+ </div>
70
702
  );
71
- };
703
+ }
72
704
 
73
705
  const ChartUpdater = ({
74
706
  chartId,
@@ -78,6 +710,7 @@ const ChartUpdater = ({
78
710
  client,
79
711
  theme,
80
712
  downloadCSV,
713
+ csvFilename,
81
714
  }: {
82
715
  dispatch: any;
83
716
  dashboard: object;
@@ -86,6 +719,7 @@ const ChartUpdater = ({
86
719
  client: any;
87
720
  theme: object;
88
721
  downloadCSV: (rows: object[], name: string) => void;
722
+ csvFilename?: string;
89
723
  }) => {
90
724
  const [chartConfig, setChartConfig] = useState<any>(null);
91
725
  const [loading, setLoading] = useState(true);
@@ -228,7 +862,7 @@ const ChartUpdater = ({
228
862
  return (
229
863
  <SpecialTable
230
864
  showDownloadCsvButton
231
- csvFilename={chartConfig.name}
865
+ csvFilename={csvFilename || chartConfig.name}
232
866
  columns={chartConfig.columns}
233
867
  rows={memoizedData}
234
868
  height={containerStyle?.height || '100%'}