@quillsql/react 1.6.1 → 1.6.4

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.
Files changed (71) hide show
  1. package/lib/AddToDashboardButton.d.ts +1 -0
  2. package/lib/AddToDashboardButton.js +2 -0
  3. package/lib/AddToDashboardButton.js.map +1 -0
  4. package/lib/AddToDashboardModal.d.ts +22 -0
  5. package/lib/AddToDashboardModal.js +638 -0
  6. package/lib/AddToDashboardModal.js.map +1 -0
  7. package/lib/BarList.js +28 -28
  8. package/lib/BarList.js.map +1 -1
  9. package/lib/Chart.js +30 -114
  10. package/lib/Chart.js.map +1 -1
  11. package/lib/Context.d.ts +3 -3
  12. package/lib/Context.js +3 -3
  13. package/lib/Context.js.map +1 -1
  14. package/lib/Dashboard.js +31 -16
  15. package/lib/Dashboard.js.map +1 -1
  16. package/lib/Dialog.d.ts +68 -0
  17. package/lib/Dialog.js +407 -0
  18. package/lib/Dialog.js.map +1 -0
  19. package/lib/Portal.d.ts +32 -0
  20. package/lib/Portal.js +171 -0
  21. package/lib/Portal.js.map +1 -0
  22. package/lib/Props.d.ts +0 -0
  23. package/lib/Props.js +2 -0
  24. package/lib/Props.js.map +1 -0
  25. package/lib/QuillProvider.d.ts +32 -14
  26. package/lib/QuillProvider.js +15 -2
  27. package/lib/QuillProvider.js.map +1 -1
  28. package/lib/ReportBuilder.d.ts +26 -2
  29. package/lib/ReportBuilder.js +210 -486
  30. package/lib/ReportBuilder.js.map +1 -1
  31. package/lib/SQLEditor.d.ts +38 -1
  32. package/lib/SQLEditor.js +385 -210
  33. package/lib/SQLEditor.js.map +1 -1
  34. package/lib/Table.js +12 -14
  35. package/lib/Table.js.map +1 -1
  36. package/lib/components/BigModal/BigModal.d.ts +14 -0
  37. package/lib/components/BigModal/BigModal.js +85 -0
  38. package/lib/components/BigModal/BigModal.js.map +1 -0
  39. package/lib/components/BigModal/Modal.d.ts +14 -0
  40. package/lib/components/BigModal/Modal.js +109 -0
  41. package/lib/components/BigModal/Modal.js.map +1 -0
  42. package/lib/components/Modal/Modal.d.ts +1 -1
  43. package/lib/hooks/useQuill.js +14 -24
  44. package/lib/hooks/useQuill.js.map +1 -1
  45. package/lib/hooks/useSyncRefs.d.ts +5 -0
  46. package/lib/hooks/useSyncRefs.js +38 -0
  47. package/lib/hooks/useSyncRefs.js.map +1 -0
  48. package/lib/index.d.ts +1 -0
  49. package/lib/index.js +1 -0
  50. package/lib/index.js.map +1 -1
  51. package/lib/types/Props.d.ts +0 -0
  52. package/lib/types/Props.js +2 -0
  53. package/lib/types/Props.js.map +1 -0
  54. package/lib/types.d.ts +27 -0
  55. package/lib/types.js +6 -0
  56. package/lib/types.js.map +1 -0
  57. package/package.json +2 -1
  58. package/src/AddToDashboardModal.tsx +1213 -0
  59. package/src/BarList.tsx +28 -28
  60. package/src/Chart.tsx +31 -107
  61. package/src/Context.tsx +8 -5
  62. package/src/Dashboard.tsx +29 -2
  63. package/src/QuillProvider.tsx +52 -10
  64. package/src/ReportBuilder.tsx +420 -649
  65. package/src/SQLEditor.tsx +805 -235
  66. package/src/Table.tsx +20 -26
  67. package/src/components/BigModal/BigModal.tsx +108 -0
  68. package/src/components/Modal/Modal.tsx +1 -1
  69. package/src/continue_logs.txt +75 -0
  70. package/src/hooks/useQuill.ts +2 -16
  71. package/src/index.ts +1 -0
package/src/SQLEditor.tsx CHANGED
@@ -1,3 +1,5 @@
1
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
+ // @ts-ignore
1
3
  import React, { useState, useContext, useMemo, useEffect } from 'react';
2
4
  import MonacoEditor from '@monaco-editor/react';
3
5
  // import './nightOwlLight.css';
@@ -10,6 +12,7 @@ import {
10
12
  SparklesIcon,
11
13
  MagnifyingGlassIcon,
12
14
  } from '@heroicons/react/20/solid';
15
+ import { QuillTheme } from './QuillProvider';
13
16
 
14
17
  export function convertPostgresColumn(column) {
15
18
  let format;
@@ -68,19 +71,131 @@ function setEditorTheme(editor, monaco) {
68
71
  }
69
72
  }
70
73
 
74
+ interface ButtonComponentProps {
75
+ onClick: () => void;
76
+ label: string;
77
+ }
78
+
71
79
  interface SQLEditorProps {
72
80
  containerStyle: React.CSSProperties;
81
+ ButtonComponent?: (props: ButtonComponentProps) => JSX.Element;
82
+ SecondaryButtonComponent?: (props: ButtonComponentProps) => JSX.Element;
83
+ TextInputComponent?: (props: TextInputComponentProps) => JSX.Element;
84
+ TableComponent?: (props: TableComponentProps) => JSX.Element;
85
+ AddToDashboardButton?: (props: AddToDashboardButtonProps) => JSX.Element;
86
+ LoadingComponent?: () => JSX.Element;
87
+ }
88
+
89
+ interface AddToDashboardButtonProps {
90
+ rows: any[];
91
+ columns: any[];
92
+ query: string;
93
+ }
94
+
95
+ interface TableComponentProps {
96
+ rows: any[];
97
+ columns: any[];
98
+ height: string;
99
+ }
100
+
101
+ interface TextInputComponentProps {
102
+ onChange: (e: any) => void;
103
+ value: string;
104
+ id: string;
105
+ placeholder?: string;
73
106
  }
74
107
 
108
+ const QuillButton = ({
109
+ onClick,
110
+ label,
111
+ theme,
112
+ secondary,
113
+ }: {
114
+ onClick: () => void;
115
+ label: string;
116
+ theme?: any;
117
+ secondary?: boolean;
118
+ }) => (
119
+ <button
120
+ style={{
121
+ borderRadius: '6px',
122
+ backgroundColor: secondary
123
+ ? theme?.secondaryButtonColor || '#FFFFFF'
124
+ : theme?.primaryButtonColor,
125
+ opacity: 1,
126
+ paddingLeft: '16px',
127
+ paddingRight: '16px',
128
+ paddingTop: '10px',
129
+ paddingBottom: '10px',
130
+ fontSize: '14px',
131
+ fontWeight: 600,
132
+ color: secondary ? theme?.primaryTextColor : '#FFFFFF',
133
+ cursor: 'pointer',
134
+ outline: 'none',
135
+ border: 'none',
136
+ fontFamily: theme?.fontFamily,
137
+ }}
138
+ onClick={onClick}
139
+ >
140
+ {label}
141
+ </button>
142
+ );
143
+
144
+ const QuillTextInput = ({
145
+ onChange,
146
+ value,
147
+ id,
148
+ placeholder,
149
+ theme,
150
+ }: {
151
+ onChange: (e: any) => void;
152
+ value: string;
153
+ id: string;
154
+ placeholder?: string;
155
+ theme?: any;
156
+ }) => {
157
+ return (
158
+ <input
159
+ style={{
160
+ display: 'flex',
161
+ flexDirection: 'row',
162
+ alignItems: 'center',
163
+ paddingLeft: '12px',
164
+ paddingRight: '12px',
165
+ fontWeight: 'medium',
166
+ height: 36,
167
+ boxShadow: 'rgba(0, 0, 0, 0.1) 0px 1px 5px 0px',
168
+ width: '445px',
169
+ backgroundColor: theme?.backgroundColor || 'white',
170
+ color: theme?.primaryTextColor,
171
+ borderWidth: '1px',
172
+ borderColor: theme?.borderColor || '#E7E7E7',
173
+ borderRadius: '6px',
174
+ }}
175
+ id={id}
176
+ onChange={onChange}
177
+ value={value}
178
+ placeholder={placeholder}
179
+ />
180
+ );
181
+ };
182
+
75
183
  export default function QueryEditor({
76
184
  containerStyle = { height: '100vh' },
185
+ ButtonComponent,
186
+ SecondaryButtonComponent,
187
+ TextInputComponent,
188
+ TableComponent,
189
+ AddToDashboardButton,
190
+ LoadingComponent,
77
191
  }: SQLEditorProps) {
78
192
  const [sqlPrompt, setSqlPrompt] = useState('');
79
193
 
80
194
  const [isOpen, setIsOpen] = useState(false);
81
195
 
82
196
  const [client] = useContext(ClientContext);
83
- const [theme] = useContext(ThemeContext);
197
+ const [theme] =
198
+ useContext<[QuillTheme, (theme: QuillTheme) => void]>(ThemeContext);
84
199
  const [query, setQuery] = useState('');
85
200
  const [rows, setRows] = useState([]);
86
201
  const [columns, setColumns] = useState([]);
@@ -88,11 +203,14 @@ export default function QueryEditor({
88
203
  const [schema, setSchema] = useContext(SchemaContext);
89
204
  const [errorMessage, setErrorMessage] = useState('');
90
205
  const [sqlResponseLoading, setSqlResponseLoading] = useState(false);
206
+ const [sqlQueryLoading, setSqlQueryLoading] = useState(false);
207
+ const [schemaLoading, setSchemaLoading] = useState(false);
91
208
 
92
209
  useEffect(() => {
93
210
  let isSubscribed = true;
94
211
  async function getSchema() {
95
212
  const { publicKey, environment } = client;
213
+ setSchemaLoading(true);
96
214
  const response3 = await axios.get(
97
215
  `https://quill-344421.uc.r.appspot.com/schema2/${publicKey}/`,
98
216
  {
@@ -104,6 +222,7 @@ export default function QueryEditor({
104
222
  );
105
223
  if (isSubscribed) {
106
224
  setSchema(response3.data.tables);
225
+ setSchemaLoading(false);
107
226
  }
108
227
  }
109
228
  if (isSubscribed) {
@@ -135,25 +254,37 @@ export default function QueryEditor({
135
254
  };
136
255
 
137
256
  const handleRunQuery = async () => {
138
- const { publicKey, customerId, environment } = client;
257
+ const { publicKey, customerId, environment, queryEndpoint, queryHeaders } =
258
+ client;
139
259
  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,
260
+ let response;
261
+ setSqlQueryLoading(true);
262
+ if (queryEndpoint) {
263
+ response = await axios.post(
264
+ queryEndpoint,
265
+ { metadata: { query, task: 'query' } },
266
+ { headers: queryHeaders }
267
+ );
268
+ } else {
269
+ response = await axios.post(
270
+ `https://quill-344421.uc.r.appspot.com/dashquery`,
271
+ {
272
+ query,
153
273
  },
154
- }
155
- );
274
+ {
275
+ params: {
276
+ orgId: customerId,
277
+ publicKey: publicKey,
278
+ },
279
+ headers: {
280
+ Authorization: `Bearer `,
281
+ environment: environment || undefined,
282
+ },
283
+ }
284
+ );
285
+ }
156
286
  if (response && response.data && response.data.errorMessage) {
287
+ setSqlQueryLoading(false);
157
288
  setErrorMessage(
158
289
  'Failed to run SQL query: ' + response.data.errorMessage
159
290
  );
@@ -162,8 +293,13 @@ export default function QueryEditor({
162
293
  setFields([]);
163
294
  return;
164
295
  }
296
+ setSqlQueryLoading(false);
165
297
  setErrorMessage('');
166
- setRows(response.data.rows);
298
+ setRows(
299
+ response.data.rows && response.data.rows.length
300
+ ? response.data.rows
301
+ : []
302
+ );
167
303
  setColumns(response.data.fields.map(elem => convertPostgresColumn(elem)));
168
304
  setFields(response.data.fields);
169
305
  } catch (e) {
@@ -176,10 +312,6 @@ export default function QueryEditor({
176
312
  setIsOpen(true);
177
313
  };
178
314
 
179
- const newRows = useMemo(() => {
180
- return JSON.parse(JSON.stringify(rows));
181
- }, [rows]);
182
-
183
315
  /* all your useState and useContext calls and your useEffect hooks */
184
316
 
185
317
  const downloadCSV = () => {
@@ -238,7 +370,12 @@ export default function QueryEditor({
238
370
  flexDirection: 'row',
239
371
  }}
240
372
  >
241
- <SchemaListComponent schema={schema} theme={theme} />
373
+ <SchemaListComponent
374
+ schema={schema}
375
+ theme={theme}
376
+ LoadingComponent={LoadingComponent}
377
+ loading={schemaLoading}
378
+ />
242
379
 
243
380
  <div
244
381
  style={{
@@ -257,7 +394,7 @@ export default function QueryEditor({
257
394
  alignItems: 'center',
258
395
  }}
259
396
  >
260
- <div
397
+ {/* <div
261
398
  style={{
262
399
  display: 'flex',
263
400
  flexDirection: 'row',
@@ -299,79 +436,37 @@ export default function QueryEditor({
299
436
  fontFamily: theme?.fontFamily,
300
437
  }}
301
438
  />
302
- </div>
303
- <button
304
- onClick={handleRunSqlPrompt}
305
- style={{
306
- // TODO: change color
307
- background: theme.primaryButtonColor,
308
- // TODO: change color
309
- color: theme.backgroundColor,
310
- height: 38,
311
- paddingLeft: 10,
312
- paddingRight: 12,
313
- width: 87,
314
- minWidth: 87,
315
- maxWidth: 87,
316
- marginLeft: 12,
317
- fontWeight: '400',
318
- borderRadius: '0.375rem',
319
- border: 'none',
320
- outline: 'none',
321
- cursor: 'pointer',
322
- fontFamily: theme?.fontFamily,
323
- }}
324
- >
325
- {sqlResponseLoading ? (
326
- <div
327
- style={{
328
- display: 'flex',
329
- flexDirection: 'row',
330
- alignItems: 'center',
331
- width: '100%',
332
- height: '100%',
333
- justifyContent: 'center',
334
- }}
335
- >
336
- <TailSpin
337
- height="20"
338
- width="20"
339
- // TODO: change color
340
- color={theme.backgroundColor}
341
- ariaLabel="loading-indicator"
342
- />
343
- </div>
344
- ) : (
345
- <div
346
- style={{
347
- display: 'flex',
348
- flexDirection: 'row',
349
- alignItems: 'center',
350
- }}
351
- >
352
- <SparklesIcon
353
- style={{
354
- height: 12,
355
- width: 12,
356
- marginRight: 4,
357
- // TODO: change color
358
- color: theme.backgroundColor,
359
- }}
360
- aria-hidden="true"
361
- />
362
- <div
363
- style={{
364
- fontSize: 14,
365
- fontWeight: 600,
366
- fontFamily: theme?.fontFamily,
367
- color: theme.backgroundColor,
368
- }}
369
- >
370
- Ask AI
371
- </div>
372
- </div>
439
+ </div> */}
440
+ <div style={{ minWidth: 440, marginRight: 10 }}>
441
+ {(TextInputComponent && (
442
+ <TextInputComponent
443
+ id="ai-search"
444
+ value={sqlPrompt}
445
+ onChange={e => setSqlPrompt(e.target.value)}
446
+ placeholder="Ask a question..."
447
+ />
448
+ )) || (
449
+ <QuillTextInput
450
+ id="ai-search"
451
+ value={sqlPrompt}
452
+ onChange={e => setSqlPrompt(e.target.value)}
453
+ placeholder="Ask a question..."
454
+ theme={theme}
455
+ />
373
456
  )}
374
- </button>
457
+ </div>
458
+ {(ButtonComponent && (
459
+ <ButtonComponent
460
+ onClick={handleRunSqlPrompt}
461
+ label="Ask AI"
462
+ />
463
+ )) || (
464
+ <QuillButton
465
+ theme={theme}
466
+ onClick={handleRunSqlPrompt}
467
+ label="Ask AI"
468
+ />
469
+ )}
375
470
  </div>
376
471
  <div style={{ height: 'calc(50% - 40px)' }}>
377
472
  <SQLEditorComponent
@@ -381,6 +476,9 @@ export default function QueryEditor({
381
476
  theme={theme}
382
477
  defineEditorTheme={defineEditorTheme}
383
478
  setEditorTheme={setEditorTheme}
479
+ ButtonComponent={ButtonComponent}
480
+ loading={sqlResponseLoading}
481
+ LoadingComponent={LoadingComponent}
384
482
  />
385
483
  </div>
386
484
  <div
@@ -397,8 +495,8 @@ export default function QueryEditor({
397
495
  {errorMessage && (
398
496
  <div
399
497
  style={{
400
- fontFamily: theme.fontFamily,
401
- color: theme.primaryTextColor,
498
+ fontFamily: theme?.fontFamily,
499
+ color: theme?.primaryTextColor,
402
500
  fontSize: 15,
403
501
  fontWeight: '400',
404
502
  }}
@@ -411,6 +509,7 @@ export default function QueryEditor({
411
509
  display: 'inline-block',
412
510
  flex: 0,
413
511
  borderRadius: 6,
512
+ color: theme?.primaryTextColor,
414
513
  fontFamily: theme?.fontFamily,
415
514
  }}
416
515
  >
@@ -418,119 +517,28 @@ export default function QueryEditor({
418
517
  </div>
419
518
  </div>
420
519
  )}
520
+ {errorMessage
521
+ ? null
522
+ : (TableComponent && (
523
+ <TableComponent
524
+ rows={rows}
525
+ columns={columns}
526
+ height="calc(100% - 70px)"
527
+ />
528
+ )) || (
529
+ <SpecialTable
530
+ rows={rows}
531
+ columns={columns}
532
+ height="calc(100% - 70px)"
533
+ LoadingComponent={LoadingComponent}
534
+ loading={sqlQueryLoading}
535
+ />
536
+ )}
421
537
  <div
422
538
  style={{
423
- height: 'calc(100% - 60px)',
424
- overflow: 'scroll',
425
- padding: 0,
426
- margin: 0,
427
- border: 'none',
428
- outline: 'none',
429
- }}
430
- >
431
- <table
432
- style={{
433
- padding: 0,
434
- margin: 0,
435
- border: 'none',
436
- outline: 'none',
437
- borderSpacing: 0,
438
- }}
439
- >
440
- <thead
441
- style={{
442
- position: 'sticky',
443
- // TODO: change color
444
- background: theme.backgroundColor,
445
- top: 0,
446
- height: 37,
447
- minHeight: 37,
448
- maxHeight: 37,
449
- }}
450
- >
451
- <tr
452
- style={{
453
- outline: 'none',
454
- border: 'none',
455
- padding: 0,
456
- margin: 0,
457
- }}
458
- >
459
- {columns.map((column, index) => (
460
- <th
461
- key={index}
462
- scope="col"
463
- style={{
464
- textAlign: 'left',
465
- fontFamily: theme?.fontFamily,
466
- fontSize: 13,
467
- height: 37,
468
- minHeight: 37,
469
- maxHeight: 37,
470
- paddingLeft: 12,
471
- paddingRight: 12,
472
- paddingTop: 0,
473
- paddingBottom: 0,
474
- margin: 0,
475
- fontWeight: '500',
476
- // TODO: change color
477
- boxShadow: `inset 0 -1px 0 ${theme.borderColor}`,
478
- // TODO: change color
479
- color: theme.primaryTextColor,
480
- outline: 'none',
481
- border: 'none',
482
- }}
483
- >
484
- {column.label}
485
- </th>
486
- ))}
487
- </tr>
488
- </thead>
489
- <tbody
490
- style={{
491
- // TODO: change color
492
- backgroundColor: theme.backgroundColor,
493
- }}
494
- >
495
- {newRows.map((row, rowIndex) => (
496
- <tr key={rowIndex}>
497
- {columns.map((column, columnIndex) => (
498
- <td
499
- key={columnIndex}
500
- style={{
501
- padding: 12,
502
- whiteSpace: 'nowrap',
503
- fontSize: 13,
504
- color: theme.secondaryTextColor,
505
- fontFamily: theme?.fontFamily,
506
- // TODO: change color
507
- // borderBottom: `1px solid ${theme.borderColor} !important`,
508
- boxShadow: `inset 0 -1px 0 ${theme.borderColor}`,
509
- outline: 'none',
510
- }}
511
- >
512
- {typeof row[column.field] === 'object'
513
- ? JSON.stringify(row[column.field]).length > 55
514
- ? JSON.stringify(row[column.field]).substring(
515
- 0,
516
- 52
517
- ) + '...'
518
- : JSON.stringify(row[column.field])
519
- : row[column.field].length > 55
520
- ? row[column.field].substring(0, 52) + '...'
521
- : row[column.field]}
522
- </td>
523
- ))}
524
- </tr>
525
- ))}
526
- </tbody>
527
- </table>
528
- </div>
529
- <div
530
- style={{
531
- height: 60,
539
+ height: 70,
532
540
  // TODO: change color
533
- background: theme.backgroundColor,
541
+ background: theme?.backgroundColor,
534
542
  }}
535
543
  >
536
544
  {rows.length ? (
@@ -538,19 +546,29 @@ export default function QueryEditor({
538
546
  style={{
539
547
  display: 'flex',
540
548
  flexDirection: 'column',
541
- height: 60,
549
+ height: 70,
542
550
  border: 'none',
543
551
  }}
544
552
  >
545
553
  <div
546
554
  style={{
547
555
  height: 1,
556
+ width: '100%',
548
557
  // TODO: change color
549
- background: theme.borderColor,
558
+ // background: theme.borderColor,
550
559
  }}
551
560
  />
552
- <div style={{ marginLeft: 0 }}>
553
- <button
561
+ <div
562
+ style={{
563
+ marginLeft: 0,
564
+ height: 69,
565
+ display: 'flex',
566
+ alignItems: 'center',
567
+ justifyContent: 'flex-end',
568
+ paddingRight: 20,
569
+ }}
570
+ >
571
+ {/* <button
554
572
  type="button"
555
573
  onClick={downloadCSV}
556
574
  style={{
@@ -573,7 +591,29 @@ export default function QueryEditor({
573
591
  }}
574
592
  >
575
593
  Download CSV
576
- </button>
594
+ </button> */}
595
+ {(SecondaryButtonComponent && (
596
+ <SecondaryButtonComponent
597
+ onClick={downloadCSV}
598
+ label="Download CSV"
599
+ />
600
+ )) || (
601
+ <QuillButton
602
+ theme={theme}
603
+ onClick={downloadCSV}
604
+ label="Download CSV"
605
+ secondary
606
+ />
607
+ )}
608
+ {AddToDashboardButton && <div style={{ width: 10 }} />}
609
+ {AddToDashboardButton && (
610
+ <AddToDashboardButton
611
+ // @ts-ignore
612
+ rows={rows}
613
+ columns={columns}
614
+ query={query}
615
+ />
616
+ )}
577
617
  <div />
578
618
  </div>
579
619
  </div>
@@ -595,6 +635,10 @@ const SQLEditorComponent = ({
595
635
  theme,
596
636
  defineEditorTheme,
597
637
  setEditorTheme,
638
+ ButtonComponent,
639
+ theme,
640
+ loading,
641
+ LoadingComponent,
598
642
  }) => {
599
643
  return (
600
644
  <div
@@ -614,30 +658,48 @@ const SQLEditorComponent = ({
614
658
  overflow: 'hidden',
615
659
  }}
616
660
  >
617
- <MonacoEditor
618
- height="calc(100% - 50px)"
619
- width="100%"
620
- defaultLanguage="pgsql"
621
- defaultValue=""
622
- value={query}
623
- loading={<div />}
624
- options={{
625
- wordWrap: 'on',
626
- minimap: {
627
- enabled: false,
628
- },
629
- padding: { top: 16 },
630
- }}
631
- onChange={query => setQuery(query)}
632
- beforeMount={monaco => defineEditorTheme(monaco, theme)}
633
- onMount={setEditorTheme}
634
- />
661
+ {loading ? (
662
+ <div
663
+ style={{
664
+ height: 'calc(100% - 70px)',
665
+ width: '100%',
666
+ display: 'flex',
667
+ alignItems: 'center',
668
+ justifyContent: 'center',
669
+ background: '#F9F9F9',
670
+ }}
671
+ >
672
+ {LoadingComponent && <LoadingComponent />}
673
+ {!LoadingComponent && (
674
+ <TailSpin height={36} width={36} color="#364153" />
675
+ )}
676
+ </div>
677
+ ) : (
678
+ <MonacoEditor
679
+ height="calc(100% - 70px)"
680
+ width="100%"
681
+ defaultLanguage="pgsql"
682
+ defaultValue=""
683
+ value={query}
684
+ loading={<div />}
685
+ options={{
686
+ wordWrap: 'on',
687
+ minimap: {
688
+ enabled: false,
689
+ },
690
+ padding: { top: 16 },
691
+ }}
692
+ onChange={query => setQuery(query)}
693
+ beforeMount={monaco => defineEditorTheme(monaco, theme)}
694
+ onMount={setEditorTheme}
695
+ />
696
+ )}
635
697
  <div
636
698
  style={{
637
699
  display: 'flex',
638
700
  flexDirection: 'row',
639
701
  alignItems: 'center',
640
- height: 50,
702
+ height: 70,
641
703
  }}
642
704
  >
643
705
  {/* <button
@@ -659,7 +721,7 @@ const SQLEditorComponent = ({
659
721
  >
660
722
  Run query
661
723
  </button> */}
662
- <button
724
+ {/* <button
663
725
  type="button"
664
726
  onClick={handleRunQuery}
665
727
  style={{
@@ -682,13 +744,521 @@ const SQLEditorComponent = ({
682
744
  }}
683
745
  >
684
746
  Run query
685
- </button>
747
+ </button> */}
748
+ {(ButtonComponent && (
749
+ <ButtonComponent onClick={handleRunQuery} label="Run query" />
750
+ )) || (
751
+ <QuillButton
752
+ onClick={handleRunQuery}
753
+ label="Run query"
754
+ theme={theme}
755
+ />
756
+ )}
686
757
  </div>
687
758
  </div>
688
759
  );
689
760
  };
690
761
 
691
- const SchemaListComponent = ({ schema, theme }) => {
762
+ const styles = {
763
+ columnHeader: {
764
+ boxSizing: 'border-box',
765
+ flex: '150 0 auto',
766
+ minWidth: '50px',
767
+ width: '150px',
768
+ position: 'relative',
769
+ cursor: 'pointer',
770
+ background: 'rgb(249, 250, 251)',
771
+ borderRight: '1px solid rgb(229, 231, 235)',
772
+ whiteSpace: 'nowrap',
773
+ display: 'flex',
774
+ alignItems: 'center',
775
+ overflowX: 'visible',
776
+ margin: '0px',
777
+ textOverflow: 'ellipsis',
778
+ minHeight: '36px', // 2.25rem * 16px = 36px
779
+ },
780
+ columnHeaderLabel: {
781
+ fontFamily:
782
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
783
+ WebkitTapHighlightColor: 'transparent',
784
+ color: 'rgb(55, 65, 81)',
785
+ textDecoration: 'none',
786
+ fontWeight: 500,
787
+ fontSize: '14px', // 0.875rem * 16px = 14px
788
+ lineHeight: '20px', // 1.25rem * 16px = 20px
789
+ textOverflow: 'ellipsis',
790
+ whiteSpace: 'nowrap',
791
+ overflow: 'hidden',
792
+ },
793
+ };
794
+
795
+ export function SpecialTable({
796
+ columns,
797
+ rows,
798
+ height,
799
+ containerStyle,
800
+ loading,
801
+ LoadingComponent,
802
+ theme,
803
+ showDownloadCsvButton,
804
+ csvFilename,
805
+ }: {
806
+ columns: any[];
807
+ rows: any[];
808
+ height: string;
809
+ containerStyle?: React.CSSProperties;
810
+ loading?: boolean;
811
+ LoadingComponent?: () => JSX.Element;
812
+ theme?: any;
813
+ showDownloadCsvButton?: boolean;
814
+ csvFilename?: string;
815
+ }) {
816
+ const downloadCSV = () => {
817
+ // report.rows
818
+ if (!rows.length) {
819
+ return;
820
+ }
821
+ const json = rows; // JSON data passed as a prop
822
+ const fields = Object.keys(json[0]); // Assumes all objects have same keys
823
+ const csvRows = [];
824
+
825
+ // Header row
826
+ csvRows.push(fields.join(','));
827
+
828
+ // Data rows
829
+ for (const row of json) {
830
+ const values = fields.map(field => JSON.stringify(row[field] || ''));
831
+ csvRows.push(values.join(','));
832
+ }
833
+
834
+ // Create CSV string and create a 'blob' with it
835
+ const csvString = csvRows.join('\r\n');
836
+ const csvBlob = new Blob([csvString], { type: 'text/csv' });
837
+
838
+ // Create a download link and click it
839
+ const downloadLink = document.createElement('a');
840
+ downloadLink.download = `${csvFilename}.csv`;
841
+ downloadLink.href = URL.createObjectURL(csvBlob);
842
+ downloadLink.style.display = 'none';
843
+
844
+ document.body.appendChild(downloadLink);
845
+ downloadLink.click();
846
+ document.body.removeChild(downloadLink);
847
+ };
848
+ if (loading) {
849
+ return (
850
+ <div
851
+ style={{
852
+ ...containerStyle,
853
+ // paddingLeft: 25,
854
+ // paddingRight: 25,
855
+ // borderRadius: 8,
856
+ // marginTop: 25,
857
+ // overflow: 'visible',
858
+ width: '100%',
859
+ height: height,
860
+ // overflow: 'hidden',
861
+ // @ts-ignore
862
+ // boxShadow: 'rgba(231, 231, 231, 0.5) 0px 1px 2px 0px',
863
+ }}
864
+ >
865
+ <div
866
+ style={{
867
+ height: '100%',
868
+ overflow: 'scroll',
869
+ borderRadius: 6,
870
+ border: '1px solid rgb(229, 231, 235)',
871
+ padding: 0,
872
+ margin: 0,
873
+ // border: 'none',
874
+ boxSizing: 'border-box',
875
+ outline: 'none',
876
+ display: 'flex',
877
+ flexDirection: 'column',
878
+ justifyContent: 'center',
879
+ alignItems: 'center',
880
+ // maxHeight: 600,
881
+ }}
882
+ >
883
+ {LoadingComponent && <LoadingComponent />}
884
+ {!LoadingComponent && (
885
+ <TailSpin height={36} width={36} color="#364153" />
886
+ )}
887
+ </div>
888
+ </div>
889
+ );
890
+ }
891
+ if (!columns || !columns.length || !rows) {
892
+ return null;
893
+ }
894
+
895
+ if (showDownloadCsvButton) {
896
+ return (
897
+ <div
898
+ style={{
899
+ ...containerStyle,
900
+ // paddingLeft: 25,
901
+ // paddingRight: 25,
902
+ // borderRadius: 8,
903
+ // marginTop: 25,
904
+ overflow: 'visible',
905
+ height: height,
906
+ // overflow: 'hidden',
907
+ // @ts-ignore
908
+ // boxShadow: 'rgba(231, 231, 231, 0.5) 0px 1px 2px 0px',
909
+ }}
910
+ >
911
+ <div style={{ height: 50, background: 'white' }} className="thead">
912
+ <div
913
+ role="row"
914
+ className="tr"
915
+ style={{
916
+ display: 'flex',
917
+ flex: '1 0 auto',
918
+ minWidth: '100px',
919
+ boxSizing: 'border-box',
920
+ alignItems: 'center',
921
+ height: 50,
922
+ // position: 'absolute',
923
+ // bottom: 0,
924
+ }}
925
+ >
926
+ <div
927
+ onClick={downloadCSV}
928
+ style={{
929
+ height: 40,
930
+ minHeight: 40,
931
+ color: theme?.primaryTextColor,
932
+ boxSizing: 'content-box',
933
+ fontFamily: theme?.chartLabelFontFamily || theme?.fontFamily,
934
+ fontSize: theme?.fontSizeSmall || '14px',
935
+ fontWeight: theme?.fontWeightMedium || '500',
936
+ // marginTop: 8,
937
+ marginLeft: 20,
938
+ alignItems: 'center',
939
+ display: 'flex',
940
+ cursor: 'pointer',
941
+ }}
942
+ >
943
+ Download CSV
944
+ </div>
945
+ </div>
946
+ </div>
947
+ <div
948
+ style={{
949
+ height: 'calc(100% - 50px)',
950
+ overflow: 'scroll',
951
+ borderRadius: 6,
952
+ border: '1px solid rgb(229, 231, 235)',
953
+ padding: 0,
954
+ margin: 0,
955
+ // border: 'none',
956
+ boxSizing: 'border-box',
957
+ outline: 'none',
958
+ // maxHeight: 600,
959
+ }}
960
+ >
961
+ <div role="table" className="table" style={{ minWidth: '0px' }}>
962
+ <div className="thead">
963
+ <div
964
+ role="row"
965
+ className="tr"
966
+ style={{
967
+ display: 'flex',
968
+ flex: '1 0 auto',
969
+ minWidth: '100px',
970
+ boxSizing: 'border-box',
971
+ }}
972
+ >
973
+ {/* @ts-ignore */}
974
+ {columns.map((column, index) => (
975
+ <div
976
+ key={'sqlcol' + index}
977
+ // @ts-ignore
978
+ style={styles.columnHeader}
979
+ >
980
+ <div style={{ width: 16 }} />
981
+ <div
982
+ aria-haspopup="dialog"
983
+ aria-expanded="false"
984
+ aria-controls="mantine-r6-dropdown"
985
+ // @ts-ignore
986
+ style={styles.columnHeaderLabel}
987
+ >
988
+ {column.label}
989
+ </div>
990
+ </div>
991
+ ))}
992
+ </div>
993
+ </div>
994
+ <div role="rowgroup" className="tbody">
995
+ {/* @ts-ignore */}
996
+ {rows.map((row, rowIndex) => (
997
+ <div
998
+ key={'sqlrow' + rowIndex}
999
+ role="row"
1000
+ className="tr"
1001
+ style={{
1002
+ display: 'flex',
1003
+ flex: '1 0 auto',
1004
+ minWidth: '100px',
1005
+ boxSizing: 'border-box',
1006
+ }}
1007
+ >
1008
+ {/* @ts-ignore */}
1009
+ {columns.map((column, columnIndex) => (
1010
+ <div
1011
+ key={'sqlcell' + columnIndex}
1012
+ role="cell"
1013
+ className="td airplane-1h7muk6"
1014
+ style={{
1015
+ boxSizing: 'border-box',
1016
+ flex: '150 0 auto',
1017
+ minWidth: '50px',
1018
+ width: '150px',
1019
+ display: 'flex',
1020
+ margin: '0px',
1021
+ textOverflow: 'ellipsis',
1022
+ minHeight: '36px',
1023
+ borderRight: '1px solid rgb(229, 231, 235)',
1024
+ overflow: 'hidden',
1025
+ borderTop: '1px solid rgb(229, 231, 235)',
1026
+ }}
1027
+ >
1028
+ <div
1029
+ style={{
1030
+ lineHeight: '1.5rem',
1031
+ width: '100%',
1032
+ display: 'flex',
1033
+ cursor: 'default',
1034
+ position: 'relative',
1035
+ }}
1036
+ className="airplane-gowkln"
1037
+ data-testid="static-cell"
1038
+ >
1039
+ <div
1040
+ className="airplane-Text-root airplane-mzqt6k"
1041
+ aria-haspopup="dialog"
1042
+ aria-expanded="false"
1043
+ aria-controls="mantine-r8-dropdown"
1044
+ id="mantine-r8-target"
1045
+ style={{
1046
+ fontFamily:
1047
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
1048
+ WebkitTapHighlightColor: 'transparent',
1049
+ color: 'rgb(55, 65, 81)',
1050
+ textDecoration: 'none',
1051
+ fontWeight: 400,
1052
+ fontSize: '14px',
1053
+ lineHeight: '20px',
1054
+ textOverflow: 'ellipsis',
1055
+ whiteSpace: 'nowrap',
1056
+ overflow: 'hidden',
1057
+ padding: '8px 16px',
1058
+ }}
1059
+ >
1060
+ {typeof row[column.field] === 'object'
1061
+ ? JSON.stringify(row[column.field]).length > 55
1062
+ ? JSON.stringify(row[column.field]).substring(
1063
+ 0,
1064
+ 52
1065
+ ) + '...'
1066
+ : JSON.stringify(row[column.field])
1067
+ : row[column.field].length > 55
1068
+ ? row[column.field].substring(0, 52) + '...'
1069
+ : row[column.field]}
1070
+ </div>
1071
+ </div>
1072
+ </div>
1073
+ ))}
1074
+ </div>
1075
+ ))}
1076
+ </div>
1077
+ </div>
1078
+ </div>
1079
+ </div>
1080
+ );
1081
+ }
1082
+
1083
+ return (
1084
+ <div
1085
+ style={{
1086
+ ...containerStyle,
1087
+ // paddingLeft: 25,
1088
+ // paddingRight: 25,
1089
+ // borderRadius: 8,
1090
+ // marginTop: 25,
1091
+ overflow: 'visible',
1092
+ height: height,
1093
+ // overflow: 'hidden',
1094
+ // @ts-ignore
1095
+ // boxShadow: 'rgba(231, 231, 231, 0.5) 0px 1px 2px 0px',
1096
+ }}
1097
+ >
1098
+ <div
1099
+ style={{
1100
+ height: '100%',
1101
+ overflow: 'scroll',
1102
+ borderRadius: 6,
1103
+ border: '1px solid rgb(229, 231, 235)',
1104
+ padding: 0,
1105
+ margin: 0,
1106
+ // border: 'none',
1107
+ boxSizing: 'border-box',
1108
+ outline: 'none',
1109
+ // maxHeight: 600,
1110
+ }}
1111
+ >
1112
+ <div role="table" className="table" style={{ minWidth: '0px' }}>
1113
+ <div className="thead">
1114
+ <div
1115
+ role="row"
1116
+ className="tr"
1117
+ style={{
1118
+ display: 'flex',
1119
+ flex: '1 0 auto',
1120
+ minWidth: '100px',
1121
+ boxSizing: 'border-box',
1122
+ }}
1123
+ >
1124
+ {/* @ts-ignore */}
1125
+ {columns.map((column, index) => (
1126
+ <div
1127
+ key={'sqlcol' + index}
1128
+ // @ts-ignore
1129
+ style={styles.columnHeader}
1130
+ >
1131
+ <div style={{ width: 16 }} />
1132
+ <div
1133
+ aria-haspopup="dialog"
1134
+ aria-expanded="false"
1135
+ aria-controls="mantine-r6-dropdown"
1136
+ // @ts-ignore
1137
+ style={styles.columnHeaderLabel}
1138
+ >
1139
+ {column.label}
1140
+ </div>
1141
+ </div>
1142
+ ))}
1143
+ </div>
1144
+ </div>
1145
+ <div role="rowgroup" className="tbody">
1146
+ {/* @ts-ignore */}
1147
+ {rows.map((row, rowIndex) => (
1148
+ <div
1149
+ key={'sqlrow' + rowIndex}
1150
+ role="row"
1151
+ className="tr"
1152
+ style={{
1153
+ display: 'flex',
1154
+ flex: '1 0 auto',
1155
+ minWidth: '100px',
1156
+ boxSizing: 'border-box',
1157
+ }}
1158
+ >
1159
+ {/* @ts-ignore */}
1160
+ {columns.map((column, columnIndex) => (
1161
+ <div
1162
+ key={'sqlcell' + columnIndex}
1163
+ role="cell"
1164
+ className="td airplane-1h7muk6"
1165
+ style={{
1166
+ boxSizing: 'border-box',
1167
+ flex: '150 0 auto',
1168
+ minWidth: '50px',
1169
+ width: '150px',
1170
+ display: 'flex',
1171
+ margin: '0px',
1172
+ textOverflow: 'ellipsis',
1173
+ minHeight: '36px',
1174
+ borderRight: '1px solid rgb(229, 231, 235)',
1175
+ overflow: 'hidden',
1176
+ borderTop: '1px solid rgb(229, 231, 235)',
1177
+ }}
1178
+ >
1179
+ <div
1180
+ style={{
1181
+ lineHeight: '1.5rem',
1182
+ width: '100%',
1183
+ display: 'flex',
1184
+ cursor: 'default',
1185
+ position: 'relative',
1186
+ }}
1187
+ className="airplane-gowkln"
1188
+ data-testid="static-cell"
1189
+ >
1190
+ <div
1191
+ className="airplane-Text-root airplane-mzqt6k"
1192
+ aria-haspopup="dialog"
1193
+ aria-expanded="false"
1194
+ aria-controls="mantine-r8-dropdown"
1195
+ id="mantine-r8-target"
1196
+ style={{
1197
+ fontFamily:
1198
+ 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
1199
+ WebkitTapHighlightColor: 'transparent',
1200
+ color: 'rgb(55, 65, 81)',
1201
+ textDecoration: 'none',
1202
+ fontWeight: 400,
1203
+ fontSize: '14px',
1204
+ lineHeight: '20px',
1205
+ textOverflow: 'ellipsis',
1206
+ whiteSpace: 'nowrap',
1207
+ overflow: 'hidden',
1208
+ padding: '8px 16px',
1209
+ }}
1210
+ >
1211
+ {typeof row[column.field] === 'object'
1212
+ ? JSON.stringify(row[column.field]).length > 55
1213
+ ? JSON.stringify(row[column.field]).substring(
1214
+ 0,
1215
+ 52
1216
+ ) + '...'
1217
+ : JSON.stringify(row[column.field])
1218
+ : row[column.field].length > 55
1219
+ ? row[column.field].substring(0, 52) + '...'
1220
+ : row[column.field]}
1221
+ </div>
1222
+ </div>
1223
+ </div>
1224
+ ))}
1225
+ </div>
1226
+ ))}
1227
+ </div>
1228
+ </div>
1229
+ </div>
1230
+ </div>
1231
+ );
1232
+ }
1233
+
1234
+ const SchemaListComponent = ({ schema, theme, loading, LoadingComponent }) => {
1235
+ if (loading) {
1236
+ return (
1237
+ <div
1238
+ style={{
1239
+ background: theme.backgroundColor,
1240
+ // maxHeight: 700,
1241
+ width: 250,
1242
+ minWidth: 250,
1243
+ // overflowY: 'scroll',
1244
+ height: '100%',
1245
+ // maxHeight: "100%",
1246
+ paddingLeft: 20,
1247
+ paddingRight: 30,
1248
+ paddingTop: 40,
1249
+ display: 'flex',
1250
+ // alignItems: 'center',
1251
+ justifyContent: 'center',
1252
+ }}
1253
+ >
1254
+ <div style={{ height: 100 }} />
1255
+ {LoadingComponent && <LoadingComponent />}
1256
+ {!LoadingComponent && (
1257
+ <TailSpin height={36} width={36} color="#364153" />
1258
+ )}
1259
+ </div>
1260
+ );
1261
+ }
692
1262
  return (
693
1263
  <div
694
1264
  style={{