@quillsql/react 1.5.3 → 1.5.5

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.
@@ -0,0 +1,841 @@
1
+ import React, { useState, useContext, useMemo, useEffect } from 'react';
2
+ import MonacoEditor from '@monaco-editor/react';
3
+ // import './nightOwlLight.css';
4
+ import axios from 'axios';
5
+ import { TailSpin } from 'react-loader-spinner';
6
+ import { ClientContext, SchemaContext, ThemeContext } from './Context';
7
+ import {
8
+ ChevronDownIcon,
9
+ ChevronRightIcon,
10
+ SparklesIcon,
11
+ MagnifyingGlassIcon,
12
+ } from '@heroicons/react/20/solid';
13
+
14
+ export function convertPostgresColumn(column) {
15
+ let format;
16
+
17
+ switch (column.dataTypeID) {
18
+ case 20: // int8
19
+ case 21: // int2
20
+ case 23: // int4
21
+ format = 'whole_number';
22
+ break;
23
+ case 700: // float4
24
+ case 701: // float8
25
+ case 1700: // numeric
26
+ format = 'two_decimal_places';
27
+ break;
28
+ case 1082: // date
29
+ case 1083: // time
30
+ case 1184: // timestamptz
31
+ case 1114: // timestamp
32
+ format = 'MMM_dd_yyyy';
33
+ break;
34
+ case 1043: // varchar
35
+ default:
36
+ format = 'string';
37
+ }
38
+
39
+ return {
40
+ label: column.name,
41
+ field: column.name,
42
+ format: format,
43
+ };
44
+ }
45
+
46
+ function defineEditorTheme(monaco, theme) {
47
+ monaco.editor.defineTheme('onedark', {
48
+ base: theme.darkMode ? 'vs-dark' : 'vs',
49
+ inherit: true,
50
+ rules: [
51
+ {
52
+ token: 'comment',
53
+ foreground: '#5d7988',
54
+ fontStyle: 'italic',
55
+ },
56
+ { token: 'constant', foreground: '#e06c75' },
57
+ ],
58
+ colors: {
59
+ 'editor.background': '#F9F9F9',
60
+ },
61
+ });
62
+ }
63
+ function setEditorTheme(editor, monaco) {
64
+ try {
65
+ monaco.editor.setTheme('onedark');
66
+ } catch (e) {
67
+ console.log('ERROR: ', e);
68
+ }
69
+ }
70
+
71
+ interface SQLEditorProps {
72
+ containerStyle: React.CSSProperties;
73
+ }
74
+
75
+ export default function QueryEditor({
76
+ containerStyle = { height: '100vh' },
77
+ }: SQLEditorProps) {
78
+ const [sqlPrompt, setSqlPrompt] = useState('');
79
+
80
+ const [isOpen, setIsOpen] = useState(false);
81
+
82
+ const [client] = useContext(ClientContext);
83
+ const [theme] = useContext(ThemeContext);
84
+ const [query, setQuery] = useState('');
85
+ const [rows, setRows] = useState([]);
86
+ const [columns, setColumns] = useState([]);
87
+ const [fields, setFields] = useState([]);
88
+ const [schema, setSchema] = useContext(SchemaContext);
89
+ const [errorMessage, setErrorMessage] = useState('');
90
+ const [sqlResponseLoading, setSqlResponseLoading] = useState(false);
91
+
92
+ useEffect(() => {
93
+ let isSubscribed = true;
94
+ async function getSchema() {
95
+ const { publicKey, environment } = client;
96
+ const response3 = await axios.get(
97
+ `https://quill-344421.uc.r.appspot.com/schema2/${publicKey}/`,
98
+ {
99
+ headers: {
100
+ Authorization: `Bearer `,
101
+ environment: environment || undefined,
102
+ },
103
+ }
104
+ );
105
+ if (isSubscribed) {
106
+ setSchema(response3.data.tables);
107
+ }
108
+ }
109
+ if (isSubscribed) {
110
+ getSchema();
111
+ }
112
+ return () => {
113
+ isSubscribed = false;
114
+ };
115
+ }, []);
116
+
117
+ const handleRunSqlPrompt = async () => {
118
+ const { publicKey, environment } = client;
119
+ setSqlResponseLoading(true);
120
+ const response = await axios.post(
121
+ `https://quill-344421.uc.r.appspot.com/quillai`,
122
+ {
123
+ initialQuestion: sqlPrompt,
124
+ publicKey: publicKey,
125
+ },
126
+ {
127
+ headers: {
128
+ Authorization: `Bearer `,
129
+ environment: environment || undefined,
130
+ },
131
+ }
132
+ );
133
+ setQuery(response.data.message);
134
+ setSqlResponseLoading(false);
135
+ };
136
+
137
+ const handleRunQuery = async () => {
138
+ const { publicKey, customerId, environment } = client;
139
+ try {
140
+ const response = await axios.post(
141
+ `https://quill-344421.uc.r.appspot.com/dashquery`,
142
+ {
143
+ query,
144
+ },
145
+ {
146
+ params: {
147
+ orgId: customerId,
148
+ publicKey: publicKey,
149
+ },
150
+ headers: {
151
+ Authorization: `Bearer `,
152
+ environment: environment || undefined,
153
+ },
154
+ }
155
+ );
156
+ if (response && response.data && response.data.errorMessage) {
157
+ setErrorMessage(
158
+ 'Failed to run SQL query: ' + response.data.errorMessage
159
+ );
160
+ setRows([]);
161
+ setColumns([]);
162
+ setFields([]);
163
+ return;
164
+ }
165
+ setErrorMessage('');
166
+ setRows(response.data.rows);
167
+ setColumns(response.data.fields.map(elem => convertPostgresColumn(elem)));
168
+ setFields(response.data.fields);
169
+ } catch (e) {
170
+ console.log('ERROR: ', e);
171
+ return;
172
+ }
173
+ };
174
+
175
+ const handleAddToDashboard = () => {
176
+ setIsOpen(true);
177
+ };
178
+
179
+ const newRows = useMemo(() => {
180
+ return JSON.parse(JSON.stringify(rows));
181
+ }, [rows]);
182
+
183
+ /* all your useState and useContext calls and your useEffect hooks */
184
+
185
+ const downloadCSV = () => {
186
+ // report.rows
187
+ if (!rows.length) {
188
+ return;
189
+ }
190
+ const json = rows; // JSON data passed as a prop
191
+ const fields = Object.keys(json[0]); // Assumes all objects have same keys
192
+ const csvRows = [];
193
+
194
+ // Header row
195
+ csvRows.push(fields.join(','));
196
+
197
+ // Data rows
198
+ for (const row of json) {
199
+ const values = fields.map(field => JSON.stringify(row[field] || ''));
200
+ csvRows.push(values.join(','));
201
+ }
202
+
203
+ // Create CSV string and create a 'blob' with it
204
+ const csvString = csvRows.join('\r\n');
205
+ const csvBlob = new Blob([csvString], { type: 'text/csv' });
206
+
207
+ // Create a download link and click it
208
+ const downloadLink = document.createElement('a');
209
+ downloadLink.download = `${query}.csv`;
210
+ downloadLink.href = URL.createObjectURL(csvBlob);
211
+ downloadLink.style.display = 'none';
212
+
213
+ document.body.appendChild(downloadLink);
214
+ downloadLink.click();
215
+ document.body.removeChild(downloadLink);
216
+ };
217
+
218
+ /* rest of your methods */
219
+
220
+ return (
221
+ <div style={containerStyle}>
222
+ <div
223
+ style={{
224
+ height: 'calc(100%)',
225
+ display: 'flex',
226
+ flexDirection: 'column',
227
+ padding: 0,
228
+ }}
229
+ >
230
+ <div
231
+ style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
232
+ >
233
+ <div
234
+ style={{
235
+ width: '100%',
236
+ display: 'flex',
237
+ height: '100%',
238
+ flexDirection: 'row',
239
+ }}
240
+ >
241
+ <SchemaListComponent schema={schema} theme={theme} />
242
+
243
+ <div
244
+ style={{
245
+ display: 'flex',
246
+ flexDirection: 'column',
247
+ width: 'calc(100% - 250px)',
248
+ }}
249
+ >
250
+ <div
251
+ style={{
252
+ // TODO: change color
253
+ height: 80,
254
+ background: 'white',
255
+ display: 'flex',
256
+ flexDirection: 'row',
257
+ alignItems: 'center',
258
+ }}
259
+ >
260
+ <div
261
+ style={{
262
+ display: 'flex',
263
+ flexDirection: 'row',
264
+ alignItems: 'center',
265
+ paddingLeft: '12px',
266
+ paddingRight: '12px',
267
+ height: 38,
268
+ boxShadow: 'rgba(0, 0, 0, 0.1) 0px 1px 5px 0px',
269
+ width: '445px',
270
+ // TODO: change color
271
+ borderColor: theme.borderColor,
272
+ color: theme.primaryTextColor,
273
+ borderWidth: '1px',
274
+ // TODO: change color
275
+ backgroundColor: 'white',
276
+ borderRadius: 6,
277
+ borderStyle: 'solid',
278
+ outline: 'none',
279
+ }}
280
+ >
281
+ <MagnifyingGlassIcon
282
+ style={{
283
+ height: 16,
284
+ width: 16,
285
+ color: theme.secondaryTextColor,
286
+ }}
287
+ aria-hidden="true"
288
+ />
289
+ <input
290
+ value={sqlPrompt}
291
+ onChange={e => setSqlPrompt(e.target.value)}
292
+ style={{
293
+ outline: 'none',
294
+ marginLeft: 8,
295
+ width: '100%',
296
+ border: 'none',
297
+ outline: 'none',
298
+ }}
299
+ />
300
+ </div>
301
+ <button
302
+ onClick={handleRunSqlPrompt}
303
+ style={{
304
+ // TODO: change color
305
+ background: theme.primaryButtonColor,
306
+ // TODO: change color
307
+ color: theme.backgroundColor,
308
+ height: 38,
309
+ paddingLeft: 10,
310
+ paddingRight: 12,
311
+ width: 87,
312
+ minWidth: 87,
313
+ maxWidth: 87,
314
+ marginLeft: 12,
315
+ fontWeight: '400',
316
+ borderRadius: '0.375rem',
317
+ border: 'none',
318
+ outline: 'none',
319
+ cursor: 'pointer',
320
+ }}
321
+ >
322
+ {sqlResponseLoading ? (
323
+ <div
324
+ style={{
325
+ display: 'flex',
326
+ flexDirection: 'row',
327
+ alignItems: 'center',
328
+ width: '100%',
329
+ height: '100%',
330
+ justifyContent: 'center',
331
+ }}
332
+ >
333
+ <TailSpin
334
+ height="20"
335
+ width="20"
336
+ // TODO: change color
337
+ color={theme.backgroundColor}
338
+ ariaLabel="loading-indicator"
339
+ />
340
+ </div>
341
+ ) : (
342
+ <div
343
+ style={{
344
+ display: 'flex',
345
+ flexDirection: 'row',
346
+ alignItems: 'center',
347
+ }}
348
+ >
349
+ <SparklesIcon
350
+ style={{
351
+ height: 12,
352
+ width: 12,
353
+ marginRight: 4,
354
+ // TODO: change color
355
+ color: theme.backgroundColor,
356
+ }}
357
+ aria-hidden="true"
358
+ />
359
+ <div style={{ fontSize: 14, fontWeight: 600 }}>
360
+ Ask AI
361
+ </div>
362
+ </div>
363
+ )}
364
+ </button>
365
+ </div>
366
+ <div style={{ height: 'calc(50% - 40px)' }}>
367
+ <SQLEditorComponent
368
+ query={query}
369
+ setQuery={setQuery}
370
+ handleRunQuery={handleRunQuery}
371
+ theme={theme}
372
+ defineEditorTheme={defineEditorTheme}
373
+ setEditorTheme={setEditorTheme}
374
+ />
375
+ </div>
376
+ <div
377
+ style={{
378
+ height: 'calc(50% - 40px)',
379
+ display: 'flex',
380
+ flexDirection: 'column',
381
+ padding: 0,
382
+ margin: 0,
383
+ border: 'none',
384
+ outline: 'none',
385
+ }}
386
+ >
387
+ {errorMessage && (
388
+ <div
389
+ style={{
390
+ fontFamily: theme.fontFamily,
391
+ color: theme.primaryTextColor,
392
+ fontSize: 15,
393
+ fontWeight: '400',
394
+ }}
395
+ >
396
+ <div
397
+ style={{
398
+ padding: 30,
399
+ // TODO: change color
400
+ background: 'rgba(0,0,0,0.02)',
401
+ display: 'inline-block',
402
+ flex: 0,
403
+ borderRadius: 6,
404
+ }}
405
+ >
406
+ {errorMessage}
407
+ </div>
408
+ </div>
409
+ )}
410
+ <div
411
+ style={{
412
+ height: 'calc(100% - 60px)',
413
+ overflow: 'scroll',
414
+ padding: 0,
415
+ margin: 0,
416
+ border: 'none',
417
+ outline: 'none',
418
+ }}
419
+ >
420
+ <table
421
+ style={{
422
+ padding: 0,
423
+ margin: 0,
424
+ border: 'none',
425
+ outline: 'none',
426
+ borderSpacing: 0,
427
+ }}
428
+ >
429
+ <thead
430
+ style={{
431
+ position: 'sticky',
432
+ // TODO: change color
433
+ background: theme.backgroundColor,
434
+ top: 0,
435
+ height: 37,
436
+ minHeight: 37,
437
+ maxHeight: 37,
438
+ }}
439
+ >
440
+ <tr
441
+ style={{
442
+ outline: 'none',
443
+ border: 'none',
444
+ padding: 0,
445
+ margin: 0,
446
+ }}
447
+ >
448
+ {columns.map((column, index) => (
449
+ <th
450
+ key={index}
451
+ scope="col"
452
+ style={{
453
+ textAlign: 'left',
454
+ fontSize: 13,
455
+ height: 37,
456
+ minHeight: 37,
457
+ maxHeight: 37,
458
+ paddingLeft: 12,
459
+ paddingRight: 12,
460
+ paddingTop: 0,
461
+ paddingBottom: 0,
462
+ margin: 0,
463
+ fontWeight: '500',
464
+ // TODO: change color
465
+ boxShadow: `inset 0 -1px 0 ${theme.borderColor}`,
466
+ // TODO: change color
467
+ color: theme.primaryTextColor,
468
+ outline: 'none',
469
+ border: 'none',
470
+ }}
471
+ >
472
+ {column.label}
473
+ </th>
474
+ ))}
475
+ </tr>
476
+ </thead>
477
+ <tbody
478
+ style={{
479
+ // TODO: change color
480
+ backgroundColor: theme.backgroundColor,
481
+ }}
482
+ >
483
+ {newRows.map((row, rowIndex) => (
484
+ <tr key={rowIndex}>
485
+ {columns.map((column, columnIndex) => (
486
+ <td
487
+ key={columnIndex}
488
+ style={{
489
+ padding: 12,
490
+ whiteSpace: 'nowrap',
491
+ fontSize: 13,
492
+ color: theme.secondaryTextColor,
493
+ // TODO: change color
494
+ borderBottom: `1px solid ${theme.borderColor} !important`,
495
+ outline: 'none',
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
+ </td>
509
+ ))}
510
+ </tr>
511
+ ))}
512
+ </tbody>
513
+ </table>
514
+ </div>
515
+ <div
516
+ style={{
517
+ height: 60,
518
+ // TODO: change color
519
+ background: theme.backgroundColor,
520
+ }}
521
+ >
522
+ {rows.length ? (
523
+ <div
524
+ style={{
525
+ display: 'flex',
526
+ flexDirection: 'column',
527
+ height: 60,
528
+ border: 'none',
529
+ }}
530
+ >
531
+ <div
532
+ style={{
533
+ height: 1,
534
+ // TODO: change color
535
+ background: theme.borderColor,
536
+ }}
537
+ />
538
+ <div style={{ marginLeft: 0 }}>
539
+ <button
540
+ type="button"
541
+ onClick={downloadCSV}
542
+ style={{
543
+ borderRadius: 6,
544
+ // TODO: change color
545
+ backgroundColor: theme.primaryButtonColor,
546
+ paddingLeft: '1rem',
547
+ paddingRight: '1rem',
548
+ paddingTop: '0.5rem',
549
+ paddingBottom: '0.5rem',
550
+ fontSize: '0.875rem',
551
+ fontWeight: '600',
552
+ // TODO: change color
553
+ color: theme.backgroundColor,
554
+ outline: 'none',
555
+ border: 'none',
556
+ cursor: 'pointer',
557
+ marginTop: 14,
558
+ }}
559
+ >
560
+ Download CSV
561
+ </button>
562
+ <div />
563
+ </div>
564
+ </div>
565
+ ) : null}
566
+ </div>
567
+ </div>
568
+ </div>
569
+ </div>
570
+ </div>
571
+ </div>
572
+ </div>
573
+ );
574
+ }
575
+
576
+ const SQLEditorComponent = ({
577
+ query,
578
+ setQuery,
579
+ handleRunQuery,
580
+ theme,
581
+ defineEditorTheme,
582
+ setEditorTheme,
583
+ }) => {
584
+ return (
585
+ <div
586
+ style={{
587
+ background: theme.backgroundColor,
588
+ // maxHeight: 700,
589
+ width: '100%',
590
+ height: '100%',
591
+ // minWidth: 450,
592
+ // overflowY: "scroll",
593
+ // padding: "20px 30px 20px 20px",
594
+ // marginLeft: 20,
595
+ borderTopLeftRadius: 6,
596
+ borderBottomLeftRadius: 6,
597
+ borderTopRightRadius: 0,
598
+ borderBottomRightRadius: 0,
599
+ overflow: 'hidden',
600
+ }}
601
+ >
602
+ <MonacoEditor
603
+ height="calc(100% - 50px)"
604
+ width="100%"
605
+ defaultLanguage="pgsql"
606
+ defaultValue=""
607
+ value={query}
608
+ loading={<div />}
609
+ options={{
610
+ wordWrap: 'on',
611
+ minimap: {
612
+ enabled: false,
613
+ },
614
+ padding: { top: 16 },
615
+ }}
616
+ onChange={query => setQuery(query)}
617
+ beforeMount={monaco => defineEditorTheme(monaco, theme)}
618
+ onMount={setEditorTheme}
619
+ />
620
+ <div
621
+ style={{
622
+ display: 'flex',
623
+ flexDirection: 'row',
624
+ alignItems: 'center',
625
+ height: 50,
626
+ }}
627
+ >
628
+ {/* <button
629
+ type="button"
630
+ onClick={handleRunQuery}
631
+ style={{
632
+ borderRadius: 8,
633
+ width: '100px',
634
+ // backgroundColor: "#212121",
635
+ height: '32px',
636
+ fontSize: 14,
637
+ fontWeight: '600',
638
+ backgroundColor: 'transparent',
639
+ color: '#384151',
640
+ border: 'none',
641
+ outline: 'none',
642
+ cursor: 'pointer',
643
+ }}
644
+ >
645
+ Run query
646
+ </button> */}
647
+ <button
648
+ type="button"
649
+ onClick={handleRunQuery}
650
+ style={{
651
+ borderRadius: 6,
652
+ backgroundColor: theme.primaryButtonColor,
653
+ height: 32,
654
+ width: 100,
655
+ marginLeft: 0,
656
+ // paddingLeft: '1rem',
657
+ // paddingRight: '1rem',
658
+ // paddingTop: '0.5rem',
659
+ // paddingBottom: '0.5rem',
660
+ fontSize: '0.875rem',
661
+ fontWeight: '600',
662
+ color: theme.backgroundColor,
663
+ outline: 'none',
664
+ border: 'none',
665
+ cursor: 'pointer',
666
+ }}
667
+ >
668
+ Run query
669
+ </button>
670
+ </div>
671
+ </div>
672
+ );
673
+ };
674
+
675
+ const SchemaListComponent = ({ schema, theme }) => {
676
+ return (
677
+ <div
678
+ style={{
679
+ background: theme.backgroundColor,
680
+ // maxHeight: 700,
681
+ width: 250,
682
+ minWidth: 250,
683
+ overflowY: 'scroll',
684
+ height: '100%',
685
+ // maxHeight: "100%",
686
+ paddingLeft: 20,
687
+ paddingRight: 30,
688
+ }}
689
+ >
690
+ {schema.map((elem, index) => (
691
+ <SchemaItem
692
+ key={elem.displayName + index}
693
+ elem={elem}
694
+ theme={theme}
695
+ index={index}
696
+ />
697
+ ))}
698
+ </div>
699
+ );
700
+ };
701
+
702
+ function SchemaItem({ elem, theme, index }) {
703
+ const [isOpen, setIsOpen] = useState(index === 0);
704
+
705
+ const schemaContainerStyle = {
706
+ display: 'flex',
707
+ flexDirection: 'column',
708
+ // WebkitTouchCallout: "none",
709
+ // WebkitUserSelect: "none",
710
+ // KhtmlUserSelect: "none",
711
+ // MozUserSelect: "none",
712
+ // msUserSelect: "none",
713
+ // userSelect: "none",
714
+ };
715
+
716
+ const schemaRowStyle = {
717
+ display: 'flex',
718
+ flexDirection: 'row',
719
+ alignItems: 'center',
720
+ width: '100%',
721
+ justifyContent: 'space-between',
722
+ cursor: 'pointer',
723
+ };
724
+
725
+ const schemaRowHoverStyle = {
726
+ background: theme.selectUnderlayColor,
727
+ };
728
+
729
+ return (
730
+ <div style={schemaContainerStyle}>
731
+ <div
732
+ style={{ ...schemaRowStyle, ...(isOpen && schemaRowHoverStyle) }}
733
+ onClick={() => setIsOpen(!isOpen)}
734
+ >
735
+ <p
736
+ style={{
737
+ marginLeft: theme.padding,
738
+ fontSize: 13,
739
+ color: '#384151',
740
+ fontWeight: '500',
741
+ whiteSpace: 'nowrap',
742
+ padding: 0,
743
+ margin: 0,
744
+ textOverflow: 'ellipsis',
745
+ overflow: 'hidden',
746
+ }}
747
+ title={elem.displayName}
748
+ >
749
+ {elem.displayName}
750
+ </p>
751
+ <div
752
+ style={{
753
+ display: 'flex',
754
+ alignItems: 'center',
755
+ justifyContent: 'center',
756
+ // paddingRight: 25,
757
+ paddingTop: 12,
758
+ paddingBottom: 12,
759
+ paddingLeft: 0,
760
+ cursor: 'pointer',
761
+ }}
762
+ >
763
+ {/* <Arrow
764
+ fill={theme.fontColor}
765
+ style={{
766
+ transform: isOpen ? "scale(0.8) rotate(90deg)" : "scale(0.8)",
767
+ }}
768
+ /> */}
769
+ {isOpen ? (
770
+ <ChevronDownIcon
771
+ style={{ height: 13, width: 13, color: theme.secondaryTextColor }}
772
+ aria-hidden="true"
773
+ />
774
+ ) : (
775
+ <ChevronRightIcon
776
+ style={{ height: 13, width: 13, color: theme.secondaryTextColor }}
777
+ aria-hidden="true"
778
+ />
779
+ )}
780
+ </div>
781
+ </div>
782
+ {isOpen ? (
783
+ <div
784
+ style={{
785
+ paddingBottom: theme.padding,
786
+ display: 'flex',
787
+ flexDirection: 'column',
788
+ paddingLeft: theme.padding,
789
+ paddingRight: theme.padding,
790
+ }}
791
+ >
792
+ {elem.columns.map((elem, index) => (
793
+ <div
794
+ key={elem.displayName + elem.index}
795
+ style={{
796
+ paddingTop: theme.padding,
797
+ display: 'flex',
798
+ flexDirection: 'row',
799
+ alignItems: 'center',
800
+ justifyContent: 'space-between',
801
+ }}
802
+ >
803
+ <div
804
+ title={elem.displayName}
805
+ // className="text-gray-500"
806
+ style={{
807
+ fontSize: 12,
808
+ // color: theme.secondaryFontColor,
809
+ whiteSpace: 'nowrap',
810
+ color: theme.secondaryTextColor,
811
+ // color: "#6C727F",
812
+ padding: 0,
813
+ margin: 0,
814
+ textOverflow: 'ellipsis',
815
+ overflow: 'hidden',
816
+ width: 200,
817
+ maxWidth: 200,
818
+ }}
819
+ >
820
+ {elem.displayName}
821
+ </div>
822
+ <div
823
+ // className="text-gray-500"
824
+ title={elem.displayName}
825
+ style={{
826
+ fontSize: 12,
827
+ // color: '#6C727F',
828
+ color: theme.secondaryTextColor,
829
+ padding: 0,
830
+ margin: 0,
831
+ }}
832
+ >
833
+ {elem.fieldType}
834
+ </div>
835
+ </div>
836
+ ))}
837
+ </div>
838
+ ) : null}
839
+ </div>
840
+ );
841
+ }