@quillsql/react 1.7.4 → 1.7.6

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 (86) hide show
  1. package/lib/AddToDashboardModal.js +2 -2
  2. package/lib/AddToDashboardModal.js.map +1 -1
  3. package/lib/Chart.js +2 -2
  4. package/lib/Chart.js.map +1 -1
  5. package/lib/Context.d.ts +2 -1
  6. package/lib/Context.js +3 -1
  7. package/lib/Context.js.map +1 -1
  8. package/lib/Dashboard.js +2 -2
  9. package/lib/Dashboard.js.map +1 -1
  10. package/lib/QuillProvider.d.ts +2 -1
  11. package/lib/QuillProvider.js +2 -2
  12. package/lib/QuillProvider.js.map +1 -1
  13. package/lib/ReportBuilder.d.ts +1 -1
  14. package/lib/ReportBuilder.js +3 -2
  15. package/lib/ReportBuilder.js.map +1 -1
  16. package/lib/SQLEditor.js +5 -5
  17. package/lib/SQLEditor.js.map +1 -1
  18. package/lib/Table.js +1 -1
  19. package/lib/Table.js.map +1 -1
  20. package/lib/components/BigModal/BigModal.js +1 -0
  21. package/lib/components/BigModal/BigModal.js.map +1 -1
  22. package/lib/components/Modal/Modal.js +1 -0
  23. package/lib/components/Modal/Modal.js.map +1 -1
  24. package/lib/hooks/useQuill.js +3 -2
  25. package/lib/hooks/useQuill.js.map +1 -1
  26. package/package.json +11 -4
  27. package/.eslintrc.json +0 -19
  28. package/.prettierrc +0 -11
  29. package/.vscode/settings.json +0 -10
  30. package/src/AddToDashboardModal.tsx +0 -1213
  31. package/src/BarList.tsx +0 -580
  32. package/src/Chart.tsx +0 -1336
  33. package/src/Context.tsx +0 -249
  34. package/src/Dashboard.tsx +0 -819
  35. package/src/DateRangePicker/Calendar.tsx +0 -442
  36. package/src/DateRangePicker/DateRangePicker.tsx +0 -261
  37. package/src/DateRangePicker/DateRangePickerButton.tsx +0 -250
  38. package/src/DateRangePicker/dateRangePickerUtils.tsx +0 -480
  39. package/src/DateRangePicker/index.ts +0 -4
  40. package/src/PieChart.tsx +0 -845
  41. package/src/QuillProvider.tsx +0 -78
  42. package/src/ReportBuilder.tsx +0 -2202
  43. package/src/SQLEditor.tsx +0 -1087
  44. package/src/Table.tsx +0 -1074
  45. package/src/TableChart.tsx +0 -428
  46. package/src/assets/ArrowDownHeadIcon.tsx +0 -11
  47. package/src/assets/ArrowDownIcon.tsx +0 -14
  48. package/src/assets/ArrowDownRightIcon.tsx +0 -14
  49. package/src/assets/ArrowLeftHeadIcon.tsx +0 -11
  50. package/src/assets/ArrowRightHeadIcon.tsx +0 -11
  51. package/src/assets/ArrowRightIcon.tsx +0 -14
  52. package/src/assets/ArrowUpHeadIcon.tsx +0 -11
  53. package/src/assets/ArrowUpIcon.tsx +0 -14
  54. package/src/assets/ArrowUpRightIcon.tsx +0 -14
  55. package/src/assets/CalendarIcon.tsx +0 -14
  56. package/src/assets/DoubleArrowLeftHeadIcon.tsx +0 -18
  57. package/src/assets/DoubleArrowRightHeadIcon.tsx +0 -20
  58. package/src/assets/ExclamationFilledIcon.tsx +0 -14
  59. package/src/assets/LoadingSpinner.tsx +0 -11
  60. package/src/assets/SearchIcon.tsx +0 -14
  61. package/src/assets/XCircleIcon.tsx +0 -14
  62. package/src/assets/index.ts +0 -16
  63. package/src/components/BigModal/BigModal.tsx +0 -108
  64. package/src/components/Dropdown/Dropdown.tsx +0 -169
  65. package/src/components/Dropdown/DropdownItem.tsx +0 -68
  66. package/src/components/Dropdown/index.ts +0 -2
  67. package/src/components/Modal/Modal.tsx +0 -132
  68. package/src/components/Modal/index.ts +0 -1
  69. package/src/components/selectUtils.ts +0 -60
  70. package/src/contexts/BaseColorContext.tsx +0 -5
  71. package/src/contexts/HoveredValueContext.tsx +0 -12
  72. package/src/contexts/RootStylesContext.tsx +0 -5
  73. package/src/contexts/SelectedValueContext.tsx +0 -13
  74. package/src/contexts/index.ts +0 -4
  75. package/src/hooks/index.ts +0 -4
  76. package/src/hooks/useInternalState.tsx +0 -18
  77. package/src/hooks/useOnClickOutside.tsx +0 -23
  78. package/src/hooks/useOnWindowResize.tsx +0 -17
  79. package/src/hooks/useQuill.ts +0 -137
  80. package/src/hooks/useSelectOnKeyDown.tsx +0 -80
  81. package/src/index.ts +0 -9
  82. package/src/lib/font.ts +0 -14
  83. package/src/lib/index.ts +0 -3
  84. package/src/lib/inputTypes.ts +0 -81
  85. package/src/lib/utils.tsx +0 -46
  86. package/tsconfig.json +0 -22
@@ -1,2202 +0,0 @@
1
- import React, { useState, useContext, useCallback, useEffect } from 'react';
2
- // import './nightOwlLight.css';
3
- import axios from 'axios';
4
- import { ClientContext, SchemaContext, ThemeContext } from './Context';
5
- import {
6
- ChevronDownIcon,
7
- ChevronRightIcon,
8
- SparklesIcon,
9
- MagnifyingGlassIcon,
10
- XMarkIcon,
11
- CheckIcon,
12
- } from '@heroicons/react/20/solid';
13
- import { convertPostgresColumn } from './SQLEditor';
14
- import { format } from 'date-fns';
15
- import { QuillTheme } from './QuillProvider';
16
-
17
- interface Option {
18
- value: string;
19
- label: string;
20
- }
21
-
22
- interface SelectComponentProps {
23
- onChange: (value: string) => void;
24
- value: string;
25
- options: Option[];
26
- }
27
-
28
- interface ButtonComponentProps {
29
- onClick: () => void;
30
- label: string;
31
- }
32
-
33
- interface ModalTriggerComponentProps {
34
- onClick: () => void;
35
- label: string;
36
- }
37
-
38
- interface ModalComponentProps {
39
- children: any;
40
- isOpen: boolean;
41
- onClose: () => void;
42
- title: string;
43
- }
44
-
45
- interface TextInputComponentProps {
46
- onChange: (e: any) => void;
47
- value: string;
48
- id: string;
49
- }
50
-
51
- interface ReportBuilderProps {
52
- onChangeQuery: (query: string) => void;
53
- onChangeData: (data: object[]) => void;
54
- onChangeColumns: (columns: object[]) => void;
55
- onChangeLoading: (loading: boolean) => void;
56
- onError: (error: string) => void;
57
- SelectComponent?: (props: SelectComponentProps) => JSX.Element;
58
- ButtonComponent?: (props: ButtonComponentProps) => JSX.Element;
59
- ModalComponent?: (props: ModalComponentProps) => JSX.Element;
60
- ModalTriggerComponent?: (props: ModalTriggerComponentProps) => JSX.Element;
61
- TextInputComponent?: (props: TextInputComponentProps) => JSX.Element;
62
- tagStyle: React.CSSProperties;
63
- }
64
-
65
- function QuillModal({ children, isOpen, onClose, title, theme }) {
66
- if (!isOpen) {
67
- return null;
68
- }
69
- return (
70
- <div
71
- style={{
72
- position: 'absolute',
73
- top: 45,
74
- minWidth: 300,
75
- left: 0,
76
- backgroundColor: theme.backgroundColor || 'white',
77
- padding: '20px',
78
- zIndex: '1000',
79
- borderRadius: 8,
80
- boxShadow: '0 1px 8px 0 rgba(0,0,0,.09)',
81
- borderWidth: theme.borderWidth,
82
- borderStyle: 'solid',
83
- borderColor: theme.borderColor,
84
- }}
85
- >
86
- {children}
87
- </div>
88
- );
89
- }
90
-
91
- export default function ReportBuilder({
92
- onChangeQuery,
93
- onChangeData,
94
- onChangeColumns,
95
- onChangeLoading,
96
- onError,
97
- SelectComponent,
98
- ButtonComponent,
99
- ModalComponent,
100
- ModalTriggerComponent,
101
- TextInputComponent,
102
- tagStyle,
103
- }: ReportBuilderProps) {
104
- const [data, setData] = useState([]);
105
- const [client] = useContext(ClientContext);
106
- const [schema, setSchema] = useContext(SchemaContext);
107
- const [theme] =
108
- useContext<[QuillTheme, (theme: QuillTheme) => void]>(ThemeContext);
109
- const [columns, setColumns] = useState([]);
110
- const [fields, setFields] = useState([]);
111
-
112
- useEffect(() => {
113
- async function getData(schema) {
114
- if (schema.length && !data.length) {
115
- const { publicKey, customerId, environment } = client;
116
- const response = await axios.post(
117
- `https://quill-344421.uc.r.appspot.com/dashquery`,
118
- {
119
- query: `select * from ${schema[0].displayName} limit 10;`,
120
- },
121
- {
122
- params: {
123
- orgId: customerId,
124
- publicKey,
125
- },
126
- headers: {
127
- Authorization: `Bearer `,
128
- environment: environment || undefined,
129
- },
130
- }
131
- );
132
- setData(response.data.rows);
133
- }
134
- }
135
- getData(schema);
136
- }, [schema]);
137
-
138
- useEffect(() => {
139
- let isSubscribed = true;
140
- async function getSchema() {
141
- const { publicKey, environment } = client;
142
- const response3 = await axios.get(
143
- `https://quill-344421.uc.r.appspot.com/schema2/${publicKey}/`,
144
- {
145
- headers: {
146
- Authorization: `Bearer `,
147
- environment: environment || undefined,
148
- },
149
- }
150
- );
151
- if (isSubscribed) {
152
- setSchema(response3.data.tables);
153
- }
154
- }
155
- if (isSubscribed) {
156
- getSchema();
157
- }
158
- return () => {
159
- isSubscribed = false;
160
- };
161
- }, []);
162
-
163
- const runQuery = async query => {
164
- const { publicKey, customerId, environment, queryEndpoint, queryHeaders } =
165
- client;
166
-
167
- let response;
168
- if (queryEndpoint) {
169
- response = await axios.post(
170
- queryEndpoint,
171
- { metadata: { query, task: 'query' } },
172
- { headers: queryHeaders }
173
- );
174
- } else {
175
- response = await axios.post(
176
- `https://quill-344421.uc.r.appspot.com/dashquery`,
177
- {
178
- query,
179
- },
180
- {
181
- params: {
182
- orgId: customerId,
183
- publicKey,
184
- },
185
- headers: {
186
- Authorization: `Bearer `,
187
- environment: environment || undefined,
188
- },
189
- }
190
- );
191
- }
192
- if (response && response.data && response.data.errorMessage) {
193
- onError(response.data.errorMessage);
194
- setData([]);
195
- onChangeData([]);
196
- setColumns([]);
197
- onChangeColumns([]);
198
- setFields([]);
199
- return;
200
- }
201
- setData(response.data.rows);
202
- onChangeData(response.data.rows);
203
- setColumns(response.data.fields.map(elem => convertPostgresColumn(elem)));
204
- onChangeColumns(
205
- response.data.fields.map(elem => convertPostgresColumn(elem))
206
- );
207
- setFields(response.data.fields);
208
- };
209
-
210
- if (!schema.length) {
211
- return null;
212
- }
213
-
214
- return (
215
- <ReportingTool
216
- theme={theme}
217
- data={data}
218
- schema={schema}
219
- onChangeQuery={onChangeQuery}
220
- runQuery={runQuery}
221
- SelectComponent={
222
- SelectComponent
223
- ? SelectComponent
224
- : ({ onChange, value, options }: SelectComponentProps) => {
225
- return (
226
- <select
227
- onChange={event => onChange(event.target.value)}
228
- value={value}
229
- id={'reportbuilderdropdown'}
230
- style={{
231
- width: '100%',
232
- minWidth: 230,
233
- outline: 'none',
234
- textAlign: 'left',
235
- whiteSpace: 'nowrap',
236
- overflow: 'hidden',
237
- textOverflow: 'ellipsis',
238
- borderRadius: 6,
239
- paddingLeft: 12,
240
- paddingRight: 12,
241
- height: 38,
242
- borderWidth: theme.borderWidth,
243
- borderColor: theme.borderColor,
244
- background: theme.backgroundColor,
245
- color: theme.primaryTextColor,
246
- boxShadow: '0 1px 2px 0 rgba(0,0,0,.05)',
247
- fontFamily: theme.fontFamily,
248
- }}
249
- >
250
- {options.map((option, index) => (
251
- <option key={option.label + index} value={option.value}>
252
- {option.label}
253
- </option>
254
- ))}
255
- </select>
256
- );
257
- }
258
- }
259
- ButtonComponent={
260
- ButtonComponent
261
- ? ButtonComponent
262
- : ({ onClick, label }: ButtonComponentProps) => {
263
- return (
264
- <div
265
- style={{
266
- height: 32,
267
- background: theme.primaryButtonColor,
268
- borderWidth: theme.borderWidth,
269
- borderColor: theme.borderColor,
270
- color: theme.backgroundColor,
271
- display: 'flex',
272
- borderRadius: 6,
273
- alignItems: 'center',
274
- justifyContent: 'center',
275
- outline: 'none',
276
- cursor: 'pointer',
277
- fontFamily: theme.fontFamily,
278
- fontWeight: theme.buttonFontWeight || 600,
279
- }}
280
- onClick={onClick}
281
- >
282
- {label}
283
- </div>
284
- );
285
- }
286
- }
287
- ModalComponent={
288
- ModalComponent
289
- ? ModalComponent
290
- : ({ children, isOpen, onClose, title }: ModalComponentProps) => {
291
- return (
292
- <QuillModal
293
- isOpen={isOpen}
294
- theme={theme}
295
- onClose={onClose}
296
- title={title}
297
- >
298
- {children}
299
- </QuillModal>
300
- );
301
- }
302
- }
303
- ModalTriggerComponent={
304
- ModalTriggerComponent
305
- ? ModalTriggerComponent
306
- : ({ onClick, label }: ModalTriggerComponentProps) => {
307
- return (
308
- <div
309
- style={{
310
- height: 32,
311
- background: theme.backgroundColor,
312
- borderWidth: theme.borderWidth,
313
- borderColor: theme.borderColor,
314
- borderStyle: 'solid',
315
- outline: 'none',
316
- cursor: 'pointer',
317
- display: 'flex',
318
- borderRadius: 6,
319
- alignItems: 'center',
320
- justifyContent: 'center',
321
- boxShadow: '0 1px 2px 0 rgba(0,0,0,.05)',
322
- paddingRight: 12,
323
- paddingLeft: 12,
324
- fontSize: 14,
325
- color: theme.primaryTextColor,
326
- fontWeight: theme.buttonFontWeight || 600,
327
- fontFamily: theme.fontFamily,
328
- }}
329
- onClick={onClick}
330
- >
331
- {label}
332
- </div>
333
- );
334
- }
335
- }
336
- TextInputComponent={
337
- TextInputComponent
338
- ? TextInputComponent
339
- : ({ onChange, value, id }: TextInputComponentProps) => {
340
- return (
341
- <input
342
- style={{
343
- outline: 'none',
344
- textAlign: 'left',
345
- whiteSpace: 'nowrap',
346
- overflow: 'hidden',
347
- textOverflow: 'ellipsis',
348
- borderRadius: 6,
349
- paddingLeft: 12,
350
- paddingRight: 12,
351
- height: 38,
352
- borderWidth: theme.borderWidth,
353
- borderColor: theme.borderColor,
354
- borderStyle: 'solid',
355
- background: theme.backgroundColor,
356
- color: theme.primaryTextColor,
357
- boxShadow: '0 1px 2px 0 rgba(0,0,0,.05)',
358
- fontFamily: theme.fontFamily,
359
- }}
360
- id={id}
361
- onChange={onChange}
362
- value={value}
363
- />
364
- );
365
- }
366
- }
367
- tagStyle={tagStyle}
368
- />
369
- );
370
- }
371
-
372
- export function getPostgresBasicType(column) {
373
- let format;
374
-
375
- // first check if column.dataTypeID exists
376
- if (column.dataTypeID) {
377
- switch (column.dataTypeID) {
378
- case 20: // int8
379
- case 21: // int2
380
- case 23: // int4
381
- case 700: // float4
382
- case 701: // float8
383
- case 1700: // numeric
384
- format = 'number';
385
- break;
386
- case 1082: // date
387
- case 1083: // time
388
- case 1184: // timestamptz
389
- case 1114: // timestamp
390
- format = 'date';
391
- break;
392
- case 1043: // varchar
393
- default:
394
- format = 'string';
395
- }
396
- } else if (column.fieldType) {
397
- // if column.dataTypeID doesn't exist, check column.fieldType
398
- switch (column.fieldType) {
399
- case 'int8':
400
- case 'int2':
401
- case 'int4':
402
- case 'float4':
403
- case 'float8':
404
- case 'numeric':
405
- format = 'number';
406
- break;
407
- case 'date':
408
- case 'time':
409
- case 'timestamptz':
410
- case 'timestamp':
411
- format = 'date';
412
- break;
413
- case 'varchar':
414
- default:
415
- format = 'string';
416
- }
417
- }
418
-
419
- return format;
420
- }
421
-
422
- function ReportingTool({
423
- schema,
424
- data,
425
- runQuery,
426
- SelectComponent,
427
- ButtonComponent,
428
- onChangeQuery,
429
- theme,
430
- ModalComponent,
431
- ModalTriggerComponent,
432
- TextInputComponent,
433
- tagStyle,
434
- }) {
435
- const [selectedTable, setSelectedTable] = useState(schema[0]);
436
- const [selectedColumn, setSelectedColumn] = useState(schema[0].columns[0]);
437
- const [filters, setFilters] = useState([]);
438
- const [AST, setAST] = useState({
439
- with: null,
440
- type: 'select',
441
- options: null,
442
- distinct: { type: null },
443
- columns: '*',
444
- into: { position: null },
445
- from: [{ db: null, table: schema[0].displayName, as: null }],
446
- where: null,
447
- groupby: null,
448
- having: null,
449
- orderby: null,
450
- limit: { seperator: '', value: [] },
451
- window: null,
452
- });
453
- const [numberStart, setNumberStart] = useState(0);
454
- const [numberEnd, setNumberEnd] = useState(0);
455
- const [dateStart, setDateStart] = useState('');
456
- const [dateEnd, setDateEnd] = useState('');
457
- const [computedColumns, setComputedColumns] = useState({});
458
- const [stringFilterValues, setStringFilterValues] = useState([]);
459
- const [columnType, setColumnType] = useState(
460
- getPostgresBasicType(schema[0].columns[0])
461
- );
462
- const [sqlQuery, setSqlQuery] = useState('');
463
- // month | week | day | quarter
464
- const [dateBucket, setDateBucket] = useState('month');
465
- const [indexBeingEdited, setIndexBeingEdited] = useState(-1);
466
- const [groupBys, setGroupBys] = useState([]);
467
- const [aggregations, setAggregations] = useState([]);
468
- const [selectedGroupByColumn, setSelectedGroupByColumn] = useState(
469
- schema[0].columns[0]
470
- );
471
- const [groupByColumnType, setGroupByColumnType] = useState(
472
- getPostgresBasicType(schema[0].columns[0])
473
- );
474
- const [selectedSortByColumn, setSelectedSortByColumn] = useState(
475
- schema[0].columns[0].name
476
- );
477
- const [sortBys, setSortBys] = useState([]);
478
- const [selectedSortByDirection, setSelectedSortByDirection] =
479
- useState('ascending');
480
-
481
- const [groupByIndexBeingEdited, setGroupByIndexBeingEdited] = useState(-1);
482
-
483
- const [sortByIndexBeingEdited, setSortByIndexBeingEdited] = useState(-1);
484
- const [sortableColumns, setSortableColumns] = useState(
485
- schema[0].columns.map(col => col.name)
486
- );
487
-
488
- const addGroupBy = () => {
489
- if (selectedGroupByColumn && groupByColumnType) {
490
- if (groupByColumnType === 'string') {
491
- setGroupBys(groupBys => {
492
- return [
493
- ...groupBys,
494
- {
495
- column: selectedGroupByColumn.name,
496
- columnType: groupByColumnType,
497
- tag: selectedGroupByColumn.name,
498
- },
499
- ];
500
- });
501
- return;
502
- } else if (groupByColumnType === 'number') {
503
- // is this possible lmao
504
- return;
505
- } else if (groupByColumnType === 'date') {
506
- setGroupBys(groupBys => {
507
- return [
508
- ...groupBys,
509
- {
510
- column: selectedGroupByColumn.name,
511
- columnType: groupByColumnType,
512
- bucket: dateBucket,
513
- tag: dateBucket,
514
- },
515
- ];
516
- });
517
- return;
518
- }
519
- }
520
- };
521
-
522
- const addSortBy = () => {
523
- setSortBys(sortBys => {
524
- return [
525
- ...sortBys,
526
- {
527
- column: selectedSortByColumn,
528
- direction: selectedSortByDirection,
529
- },
530
- ];
531
- });
532
- };
533
-
534
- const removeSortBy = index => {
535
- setSortBys(oldSortBys => {
536
- const newSortBys = [...oldSortBys];
537
- newSortBys.splice(index, 1);
538
- return newSortBys;
539
- });
540
- setSortByIndexBeingEdited(-1);
541
- };
542
-
543
- const removeGroupBy = index => {
544
- const columnBeingDeleted = groupBys[index].tag;
545
- setSortBys(oldSortBys => {
546
- const newSortBys = [
547
- ...oldSortBys.filter(sortBy => sortBy.column !== columnBeingDeleted),
548
- ];
549
- return newSortBys;
550
- });
551
- setGroupBys(oldGroupBys => {
552
- const newGroupBys = [...oldGroupBys];
553
- newGroupBys.splice(index, 1);
554
- return newGroupBys;
555
- });
556
- setGroupByIndexBeingEdited(-1);
557
- };
558
-
559
- const updateSortBy = index => {
560
- if (selectedSortByColumn && selectedSortByDirection) {
561
- setSortBys(sortBys => {
562
- const newSortBys = [...sortBys];
563
- newSortBys[index] = {
564
- column: selectedSortByColumn,
565
- direction: selectedSortByDirection,
566
- };
567
- return newSortBys;
568
- });
569
- setSortByIndexBeingEdited(-1);
570
- return;
571
- }
572
- };
573
-
574
- useEffect(() => {
575
- setColumnType(getPostgresBasicType(selectedColumn));
576
- // console.log("WTF: ", selectedColumn);
577
- }, [selectedColumn]);
578
-
579
- useEffect(() => {
580
- setGroupByColumnType(getPostgresBasicType(selectedGroupByColumn));
581
- }, [selectedGroupByColumn]);
582
-
583
- const selectFilter = index => {
584
- const filter = filters[index];
585
- const matchingColumn = selectedTable.columns.find(
586
- column => column.name === filter.column
587
- );
588
- setSelectedColumn(matchingColumn);
589
- if (filter.columnType === 'string') {
590
- setStringFilterValues(filter.stringFilterValues);
591
- setIndexBeingEdited(index);
592
- } else if (filter.columnType === 'number') {
593
- setNumberStart(filter.numberStart);
594
- setNumberEnd(filter.numberEnd);
595
- setIndexBeingEdited(index);
596
- } else if (filter.columnType === 'date') {
597
- setDateStart(filter.dateStart);
598
- setDateEnd(filter.dateEnd);
599
- setIndexBeingEdited(index);
600
- }
601
- };
602
-
603
- const selectSortBy = index => {
604
- const sortBy = sortBys[index];
605
- setSelectedSortByColumn(sortBy.column);
606
- setSelectedSortByDirection(sortBy.direction);
607
- setSortByIndexBeingEdited(index);
608
- };
609
-
610
- const selectGroupBy = index => {
611
- const groupBy = groupBys[index];
612
- const matchingColumn = selectedTable.columns.find(
613
- column => column.name === groupBy.column
614
- );
615
- setSelectedGroupByColumn(matchingColumn);
616
- if (groupBy.bucket) {
617
- setDateBucket(groupBy.bucket);
618
- }
619
- setGroupByIndexBeingEdited(index);
620
- };
621
-
622
- const updateGroupBy = index => {
623
- if (selectedGroupByColumn && groupByColumnType) {
624
- // if column changed, then auto delete the sort using that column
625
- const columnBeingDeleted =
626
- selectedGroupByColumn.name !== groupBys[index].column
627
- ? groupBys[index].tag
628
- : 'nocolumnbeingdeleted';
629
- setSortBys(oldSortBys => {
630
- const newSortBys = [
631
- ...oldSortBys.filter(sortBy => sortBy.column !== columnBeingDeleted),
632
- ];
633
- return newSortBys;
634
- });
635
- if (groupByColumnType === 'date') {
636
- setGroupBys(groupBys => {
637
- const newGroupBys = [...groupBys];
638
- newGroupBys[index] = {
639
- column: selectedGroupByColumn.name,
640
- columnType: groupByColumnType,
641
- bucket: dateBucket,
642
- tag: dateBucket,
643
- };
644
- return newGroupBys;
645
- });
646
- } else {
647
- setGroupBys(groupBys => {
648
- const newGroupBys = [...groupBys];
649
- newGroupBys[index] = {
650
- column: selectedGroupByColumn.name,
651
- columnType: groupByColumnType,
652
- tag: selectedGroupByColumn.name,
653
- };
654
- return newGroupBys;
655
- });
656
- }
657
- setGroupByIndexBeingEdited(-1);
658
- return;
659
- }
660
- };
661
-
662
- const updateFilter = index => {
663
- if (selectedColumn && columnType) {
664
- if (columnType === 'string') {
665
- setFilters(filters => {
666
- const newFilters = [...filters];
667
- newFilters[index] = {
668
- column: selectedColumn.name,
669
- columnType,
670
- stringFilterValues,
671
- tag: `${selectedColumn.name} (${stringFilterValues.join(', ')})`,
672
- };
673
- return newFilters;
674
- });
675
- } else if (columnType === 'number') {
676
- setFilters(filters => {
677
- const newFilters = [...filters];
678
- newFilters[index] = {
679
- column: selectedColumn.name,
680
- columnType,
681
- numberStart,
682
- numberEnd,
683
- tag: `${numberStart} < ${selectedColumn.name} < ${numberEnd}`,
684
- };
685
- return newFilters;
686
- });
687
- } else if (columnType === 'date') {
688
- setFilters(filters => {
689
- const newFilters = [...filters];
690
- newFilters[index] = {
691
- column: selectedColumn.name,
692
- columnType,
693
- dateStart,
694
- dateEnd,
695
- tag: `${selectedColumn.name} (${format(
696
- new Date(dateStart),
697
- 'MMM dd'
698
- )} - ${format(new Date(dateEnd), 'MMM dd')})`,
699
- };
700
- return newFilters;
701
- });
702
- }
703
-
704
- setStringFilterValues([]);
705
- setNumberStart(0);
706
- setNumberEnd(0);
707
- setDateStart('');
708
- setDateEnd('');
709
- setIndexBeingEdited(-1);
710
- return;
711
- }
712
- };
713
-
714
- // ADD FILTER TO "FILTERS" ARRAY
715
- const addFilter = () => {
716
- if (selectedColumn && columnType) {
717
- // const type = getPostgresBasicType(selectedColumn);
718
- let newCondition;
719
-
720
- if (columnType === 'string') {
721
- setFilters(filters => {
722
- return [
723
- ...filters,
724
- {
725
- column: selectedColumn.name,
726
- columnType,
727
- stringFilterValues,
728
- tag: `${selectedColumn.name} (${stringFilterValues.join(', ')})`,
729
- },
730
- ];
731
- });
732
- setStringFilterValues([]);
733
- setNumberStart(0);
734
- setNumberEnd(0);
735
- setDateStart('');
736
- setDateEnd('');
737
- return;
738
- } else if (columnType === 'number') {
739
- setFilters(filters => {
740
- return [
741
- ...filters,
742
- {
743
- column: selectedColumn.name,
744
- columnType,
745
- numberStart,
746
- numberEnd,
747
- tag: `${numberStart} < ${selectedColumn.name} < ${numberEnd}`,
748
- },
749
- ];
750
- });
751
- setStringFilterValues([]);
752
- setNumberStart(0);
753
- setNumberEnd(0);
754
- setDateStart('');
755
- setDateEnd('');
756
- return;
757
- } else if (columnType === 'date') {
758
- setFilters(filters => {
759
- return [
760
- ...filters,
761
- {
762
- column: selectedColumn.name,
763
- columnType,
764
- dateStart,
765
- dateEnd,
766
- tag: `${selectedColumn.name} (${format(
767
- new Date(dateStart),
768
- 'MMM dd'
769
- )} - ${format(new Date(dateEnd), 'MMM dd')})`,
770
- },
771
- ];
772
- });
773
- setStringFilterValues([]);
774
- setNumberStart(0);
775
- setNumberEnd(0);
776
- setDateStart('');
777
- setDateEnd('');
778
- }
779
- }
780
- };
781
-
782
- const setAggregationColumn = (column, index) => {
783
- // ex
784
- setAggregations(aggregations => {
785
- const newAggregations = [...aggregations];
786
- newAggregations[index] = {
787
- ...newAggregations[index],
788
- column: column,
789
- };
790
- return newAggregations;
791
- });
792
- };
793
-
794
- const setAggregationType = (aggregationType, index) => {
795
- // ex
796
- setAggregations(aggregations => {
797
- const newAggregations = [...aggregations];
798
- newAggregations[index] = {
799
- ...newAggregations[index],
800
- aggregationType: aggregationType,
801
- };
802
- return newAggregations;
803
- });
804
- };
805
-
806
- const addAggregation = () => {
807
- // setAggregations([
808
- // {
809
- // column: selectedTable.columns.filter(
810
- // (col) => getPostgresBasicType(col) === "number"
811
- // )[0],
812
- // aggregationType: "sum",
813
- // },
814
- // ]);
815
- setAggregations(aggregations => {
816
- const newAggregations = [
817
- ...aggregations,
818
- {
819
- column: selectedTable.columns.filter(
820
- col =>
821
- getPostgresBasicType(col) === 'number' &&
822
- !aggregations.map(elem => elem.name).includes(col.name)
823
- )[0],
824
- aggregationType: 'sum',
825
- },
826
- ];
827
- return newAggregations;
828
- });
829
- };
830
-
831
- useEffect(() => {
832
- // if selected table changes, clear everything
833
- if (selectedTable.displayName !== AST.from.table) {
834
- setSelectedColumn(selectedTable.columns[0]);
835
- setSortableColumns(selectedTable.columns.map(col => col.name));
836
- setGroupBys([]);
837
- setSortBys([]);
838
- setFilters([]);
839
- // setAST((AST) => {
840
- // return {
841
- // with: null,
842
- // type: "select",
843
- // options: null,
844
- // distinct: { type: null },
845
- // columns: "*",
846
- // into: { position: null },
847
- // where: null,
848
- // groupby: null,
849
- // having: null,
850
- // orderby: null,
851
- // limit: { seperator: "", value: [] },
852
- // window: null,
853
- // from: [{ db: null, table: selectedTable.displayName, as: null }],
854
- // };
855
- // });
856
- return;
857
- }
858
- }, [selectedTable]);
859
-
860
- // USE EFFECT HOOK THAT TRANSFORMS "FILTERS ARRAY INTO AST"
861
- useEffect(() => {
862
- if (filters.length || groupBys.length || aggregations.length) {
863
- const newAST = {
864
- with: null,
865
- type: 'select',
866
- options: null,
867
- distinct: null,
868
- columns: null,
869
- into: { position: null },
870
- from: [{ db: null, table: selectedTable.displayName, as: null }],
871
- where: null,
872
- groupby: null,
873
- having: null,
874
- orderby: null,
875
- limit: null,
876
- window: null,
877
- };
878
- // FILTERS
879
- for (let i = 0; i < filters.length; i++) {
880
- const filter = filters[i];
881
- const {
882
- column,
883
- columnType,
884
- stringFilterValues,
885
- numberStart,
886
- numberEnd,
887
- dateStart,
888
- dateEnd,
889
- } = filter;
890
- let newCondition;
891
- if (columnType === 'string') {
892
- newCondition = {
893
- type: 'binary_expr',
894
- operator: 'IN',
895
- left: {
896
- type: 'column_ref',
897
- table: null,
898
- column: column,
899
- },
900
- right: {
901
- type: 'expr_list',
902
- value: stringFilterValues.map(value => ({
903
- type: 'single_quote_string',
904
- value,
905
- })),
906
- },
907
- };
908
- } else if (columnType === 'number') {
909
- newCondition = {
910
- type: 'binary_expr',
911
- operator: 'BETWEEN',
912
- left: {
913
- type: 'column_ref',
914
- table: null,
915
- column: column,
916
- },
917
- right: {
918
- type: 'expr_list',
919
- value: [
920
- { type: 'number', value: numberStart },
921
- { type: 'number', value: numberEnd },
922
- ],
923
- },
924
- };
925
- } else if (columnType === 'date') {
926
- newCondition = {
927
- type: 'binary_expr',
928
- operator: 'BETWEEN',
929
- left: {
930
- type: 'column_ref',
931
- table: null,
932
- column: column,
933
- },
934
- right: {
935
- type: 'expr_list',
936
- value: [
937
- {
938
- type: 'single_quote_string',
939
- value: format(new Date(dateStart), 'MM/dd/yyyy'),
940
- },
941
- {
942
- type: 'single_quote_string',
943
- value: format(new Date(dateEnd), 'MM/dd/yyyy'),
944
- },
945
- ],
946
- },
947
- };
948
- }
949
-
950
- if (!newAST.where) {
951
- newAST.where = newCondition;
952
- } else {
953
- newAST.where = {
954
- type: 'binary_expr',
955
- operator: 'AND',
956
- left: newAST.where,
957
- right: newCondition,
958
- };
959
- }
960
- }
961
-
962
- // GROUP BYS and AGGREGATIONS
963
- // if (groupBys.length > 0) {
964
- // newAST.groupby = groupBys.map((groupBy) => ({
965
- // type: "column_ref",
966
- // table: null,
967
- // column: groupBy.column,
968
- // }));
969
-
970
- // if (aggregations.length > 0) {
971
- // newAST.columns = [
972
- // ...groupBys.map((groupBy) => ({
973
- // expr: {
974
- // type: "column_ref",
975
- // table: null,
976
- // column: groupBy.column,
977
- // },
978
- // as: null,
979
- // })),
980
- // ...aggregations.map((aggregation) => ({
981
- // expr: {
982
- // type: "aggr_func",
983
- // name: aggregation.aggregationType.toUpperCase(),
984
- // args: {
985
- // expr: {
986
- // type: "column_ref",
987
- // table: null,
988
- // column: aggregation.column.name,
989
- // },
990
- // },
991
- // over: null,
992
- // },
993
- // as: null,
994
- // })),
995
- // ];
996
- // } else {
997
- // newAST.columns = groupBys.map((groupBy) => ({
998
- // expr: {
999
- // type: "column_ref",
1000
- // table: null,
1001
- // column: groupBy.column,
1002
- // },
1003
- // as: null,
1004
- // }));
1005
- // }
1006
- // } else {
1007
- // newAST.columns = "*";
1008
- // newAST.groupby = null;
1009
- // }
1010
-
1011
- // GROUP BYS
1012
- if (groupBys.length > 0) {
1013
- newAST.columns = [];
1014
- newAST.groupby = [];
1015
-
1016
- for (let i = 0; i < groupBys.length; i++) {
1017
- const groupBy = groupBys[i];
1018
- if (groupBy.columnType === 'date') {
1019
- newAST.columns.push({
1020
- expr: {
1021
- type: 'function',
1022
- name: 'date_trunc',
1023
- args: {
1024
- type: 'expr_list',
1025
- value: [
1026
- {
1027
- type: 'single_quote_string',
1028
- value: groupBy.bucket,
1029
- },
1030
- {
1031
- type: 'column_ref',
1032
- table: null,
1033
- column: groupBy.column,
1034
- },
1035
- ],
1036
- },
1037
- over: null,
1038
- },
1039
- as: groupBy.bucket,
1040
- });
1041
- newAST.groupby.push({
1042
- type: 'column_ref',
1043
- table: null,
1044
- column: groupBy.bucket,
1045
- });
1046
- } else {
1047
- newAST.columns.push({
1048
- expr: {
1049
- type: 'column_ref',
1050
- table: null,
1051
- column: groupBy.column,
1052
- },
1053
- as: null,
1054
- });
1055
- newAST.groupby.push({
1056
- type: 'column_ref',
1057
- table: null,
1058
- column: groupBy.column,
1059
- });
1060
- }
1061
- }
1062
-
1063
- // AGGREGATIONS
1064
- if (aggregations.length > 0) {
1065
- for (let i = 0; i < aggregations.length; i++) {
1066
- const aggregation = aggregations[i];
1067
- newAST.columns.push({
1068
- expr: {
1069
- type: 'aggr_func',
1070
- name: aggregation.aggregationType.toUpperCase(),
1071
- args: {
1072
- expr: {
1073
- type: 'column_ref',
1074
- table: null,
1075
- column: aggregation.column.name,
1076
- },
1077
- },
1078
- over: null,
1079
- },
1080
- as: null,
1081
- });
1082
- }
1083
- }
1084
- } else {
1085
- newAST.columns = '*';
1086
- newAST.groupby = null;
1087
- }
1088
-
1089
- if (sortBys.length > 0) {
1090
- newAST.orderby = [];
1091
- for (let i = 0; i < sortBys.length; i++) {
1092
- const sortBy = sortBys[i];
1093
- newAST.orderby.push({
1094
- expr: { type: 'column_ref', table: null, column: sortBy.column },
1095
- type: sortBy.direction === 'descending' ? 'DESC' : 'ASC',
1096
- });
1097
- }
1098
- // "orderby":[{"expr":{"type":"column_ref","table":null,"column":"amount"},"type":"DESC"},{"expr":{"type":"column_ref","table":null,"column":"month"},"type":"ASC"}]
1099
- }
1100
-
1101
- setAST(newAST);
1102
- }
1103
- }, [filters, groupBys, aggregations, sortBys]);
1104
-
1105
- const removeFilter = index => {
1106
- setFilters(oldFilters => {
1107
- const newFilters = [...oldFilters];
1108
- newFilters.splice(index, 1);
1109
- return newFilters;
1110
- });
1111
- setIndexBeingEdited(-1);
1112
- };
1113
-
1114
- const computeStats = useCallback(
1115
- column => {
1116
- if (!computedColumns[column.name] && data) {
1117
- const basicType = getPostgresBasicType(column);
1118
- let result;
1119
-
1120
- if (basicType === 'number') {
1121
- let min = Infinity,
1122
- max = -Infinity;
1123
- data.forEach(row => {
1124
- const value = row[column.name];
1125
- min = Math.min(min, value);
1126
- max = Math.max(max, value);
1127
- });
1128
- result = { min, max };
1129
- } else if (basicType === 'string') {
1130
- const freqMap = {};
1131
- data.forEach(row => {
1132
- const value = row[column.name];
1133
- freqMap[value] = (freqMap[value] || 0) + 1;
1134
- });
1135
- result = Object.entries(freqMap)
1136
- .sort((a, b) => b[1] - a[1])
1137
- .slice(0, 6)
1138
- .map(([key]) => key);
1139
- } else {
1140
- // Handle other column types if necessary
1141
- }
1142
-
1143
- setComputedColumns({
1144
- ...computedColumns,
1145
- [column.name]: result,
1146
- });
1147
- }
1148
- },
1149
- [data, computedColumns]
1150
- );
1151
-
1152
- // Call this function whenever the selected column changes
1153
- useEffect(() => {
1154
- computeStats(selectedColumn);
1155
- }, [selectedColumn]);
1156
-
1157
- // Use the results directly in your component
1158
- const columnStats = computedColumns[selectedColumn.name];
1159
-
1160
- // useEffect(() => {
1161
- // if (AST && AST.from[0].table) {
1162
- // const parser = new Parser();
1163
- // const sqlQuery = parser.sqlify(AST, { database: "PostgresQL" });
1164
- // if (sqlQuery) {
1165
- // runQuery(sqlQuery);
1166
- // return;
1167
- // }
1168
- // }
1169
- // }, [AST]);
1170
-
1171
- useEffect(() => {
1172
- if (!aggregations.length) {
1173
- setAggregations([
1174
- {
1175
- column: selectedTable.columns.filter(
1176
- col => getPostgresBasicType(col) === 'number'
1177
- )[0],
1178
- aggregationType: 'sum',
1179
- },
1180
- ]);
1181
- }
1182
- }, [selectedGroupByColumn]);
1183
-
1184
- useEffect(() => {
1185
- const getSqlQueryFromAST = async () => {
1186
- try {
1187
- if (AST && AST.from[0].table) {
1188
- const response = await axios.post(
1189
- 'https://quill-344421.uc.r.appspot.com/sqlify',
1190
- { ast: AST }
1191
- );
1192
- const sqlQuery = response.data.query; // assuming the response contains the SQL query
1193
- // alert(sqlQuery);
1194
- if (sqlQuery) {
1195
- onChangeQuery(sqlQuery);
1196
- runQuery(sqlQuery);
1197
- setSqlQuery(sqlQuery);
1198
- if (AST.columns === '*') {
1199
- setSortableColumns(selectedTable.columns.map(col => col.name));
1200
- } else if (AST.columns.length) {
1201
- setSortableColumns(
1202
- AST.columns.map(elem => elem.as || elem.expr.name)
1203
- );
1204
- }
1205
- }
1206
- }
1207
- } catch (err) {
1208
- console.error(err);
1209
- }
1210
- };
1211
-
1212
- getSqlQueryFromAST();
1213
- }, [AST]);
1214
-
1215
- useEffect(() => {
1216
- if (sortableColumns.length) {
1217
- setSelectedSortByColumn(sortableColumns[0]);
1218
- }
1219
- }, [sortableColumns]);
1220
-
1221
- if (!schema || !schema.length) {
1222
- return null;
1223
- }
1224
-
1225
- return (
1226
- <div style={{ marginLeft: '25px' }}>
1227
- <div style={{ maxWidth: 245 }}>
1228
- <div
1229
- style={{
1230
- fontSize: 14,
1231
- marginBottom: '6px',
1232
- fontWeight: '600',
1233
- color: theme.secondaryTextColor,
1234
- fontFamily: theme?.fontFamily,
1235
- }}
1236
- >
1237
- Table
1238
- </div>
1239
- <SelectComponent
1240
- label="Table"
1241
- value={selectedTable.displayName}
1242
- onChange={e => {
1243
- const table = schema.find(t => t.displayName === e);
1244
- setSelectedTable(table);
1245
- }}
1246
- options={
1247
- schema?.length
1248
- ? schema.map(elem => {
1249
- return { label: elem.displayName, value: elem.displayName };
1250
- })
1251
- : []
1252
- }
1253
- />
1254
- </div>
1255
- <div
1256
- style={{ display: 'flex', flexDirection: 'column', marginTop: '12px' }}
1257
- >
1258
- {/* <AddFilterModal
1259
- filters={filters}
1260
- selectedColumn={selectedColumn}
1261
- numberStart={numberStart}
1262
- numberEnd={numberEnd}
1263
- dateStart={dateStart}
1264
- setDateStart={setDateStart}
1265
- columnStats={columnStats}
1266
- stringFilterValues={stringFilterValues}
1267
- setStringFilterValues={setStringFilterValues}
1268
- addFilter={addFilter}
1269
- setSelectedColumn={setSelectedColumn}
1270
- setNumberStart={setNumberStart}
1271
- setNumberEnd={setNumberEnd}
1272
- selectedTable={selectedTable}
1273
- columnType={columnType}
1274
- dateEnd={dateEnd}
1275
- setDateEnd={setDateEnd}
1276
- removeFilter={removeFilter}
1277
- selectFilter={selectFilter}
1278
- ref={ref}
1279
- indexBeingEdited={indexBeingEdited}
1280
- updateFilter={updateFilter}
1281
- SelectComponent={SelectComponent}
1282
- /> */}
1283
-
1284
- <AddFilterModal2
1285
- filters={filters}
1286
- selectedColumn={selectedColumn}
1287
- numberStart={numberStart}
1288
- numberEnd={numberEnd}
1289
- dateStart={dateStart}
1290
- setDateStart={setDateStart}
1291
- columnStats={columnStats}
1292
- stringFilterValues={stringFilterValues}
1293
- setStringFilterValues={setStringFilterValues}
1294
- addFilter={addFilter}
1295
- setSelectedColumn={setSelectedColumn}
1296
- setNumberStart={setNumberStart}
1297
- setNumberEnd={setNumberEnd}
1298
- selectedTable={selectedTable}
1299
- columnType={columnType}
1300
- dateEnd={dateEnd}
1301
- setDateEnd={setDateEnd}
1302
- removeFilter={removeFilter}
1303
- selectFilter={selectFilter}
1304
- indexBeingEdited={indexBeingEdited}
1305
- updateFilter={updateFilter}
1306
- SelectComponent={SelectComponent}
1307
- ButtonComponent={ButtonComponent}
1308
- ModalComponent={ModalComponent}
1309
- ModalTriggerComponent={ModalTriggerComponent}
1310
- TextInputComponent={TextInputComponent}
1311
- tagStyle={tagStyle}
1312
- theme={theme}
1313
- />
1314
-
1315
- {/* <div style={{ height: 12 }} /> */}
1316
-
1317
- <GroupByModal2
1318
- selectedTable={selectedTable}
1319
- groupBys={groupBys}
1320
- selectedGroupByColumn={selectedGroupByColumn}
1321
- setSelectedGroupByColumn={setSelectedGroupByColumn}
1322
- addGroupBy={addGroupBy}
1323
- groupByColumnType={groupByColumnType}
1324
- removeGroupBy={removeGroupBy}
1325
- selectGroupBy={selectGroupBy}
1326
- groupByIndexBeingEdited={groupByIndexBeingEdited}
1327
- updateGroupBy={updateGroupBy}
1328
- aggregations={aggregations}
1329
- setAggregationColumn={setAggregationColumn}
1330
- setAggregationType={setAggregationType}
1331
- SelectComponent={SelectComponent}
1332
- ButtonComponent={ButtonComponent}
1333
- ModalComponent={ModalComponent}
1334
- ModalTriggerComponent={ModalTriggerComponent}
1335
- TextInputComponent={TextInputComponent}
1336
- tagStyle={tagStyle}
1337
- addAggregation={addAggregation}
1338
- dateBucket={dateBucket}
1339
- setDateBucket={setDateBucket}
1340
- theme={theme}
1341
- />
1342
-
1343
- <SortByModal
1344
- selectedTable={selectedTable}
1345
- sortableColumns={sortableColumns}
1346
- sortBys={sortBys}
1347
- selectedSortByColumn={selectedSortByColumn}
1348
- setSelectedSortByColumn={setSelectedSortByColumn}
1349
- selectedSortByDirection={selectedSortByDirection}
1350
- setSelectedSortByDirection={setSelectedSortByDirection}
1351
- addSortBy={addSortBy}
1352
- removeSortBy={removeSortBy}
1353
- selectSortBy={selectSortBy}
1354
- sortByIndexBeingEdited={sortByIndexBeingEdited}
1355
- updateSortBy={updateSortBy}
1356
- SelectComponent={SelectComponent}
1357
- ButtonComponent={ButtonComponent}
1358
- ModalComponent={ModalComponent}
1359
- ModalTriggerComponent={ModalTriggerComponent}
1360
- tagStyle={tagStyle}
1361
- theme={theme}
1362
- />
1363
- </div>
1364
- </div>
1365
- );
1366
- }
1367
-
1368
- function FilterTag({
1369
- id,
1370
- label,
1371
- removeFilter,
1372
- index,
1373
- setIsOpen,
1374
- selectFilter,
1375
- theme,
1376
- tagStyle,
1377
- }) {
1378
- const handleRemoveFilter = () => {
1379
- removeFilter(index);
1380
- };
1381
- const handleSelectFilter = () => {
1382
- selectFilter(index);
1383
- setIsOpen(true);
1384
- };
1385
- return (
1386
- <div
1387
- id={id}
1388
- onClick={handleSelectFilter}
1389
- style={
1390
- tagStyle || {
1391
- marginLeft: '12px',
1392
- cursor: 'pointer',
1393
- borderRadius: 8,
1394
- backgroundColor: '#EFF0FC',
1395
- paddingLeft: '12px',
1396
- paddingRight: '8px',
1397
- height: 30,
1398
- display: 'flex',
1399
- alignItems: 'center',
1400
- fontSize: 13,
1401
- fontWeight: 'medium',
1402
- color: theme?.primaryTextColor,
1403
- fontFamily: theme?.fontFamily,
1404
- outline: 'none',
1405
- }
1406
- }
1407
- >
1408
- <div
1409
- id={id}
1410
- style={{
1411
- textOverflow: 'ellipsis',
1412
- whiteSpace: 'nowrap',
1413
- overflow: 'hidden',
1414
- maxWidth: '80px',
1415
- }}
1416
- >
1417
- {label}
1418
- </div>
1419
- <div
1420
- // onClick={handleRemoveFilter}
1421
- onClick={e => {
1422
- e.stopPropagation(); // Prevents the event from bubbling up to the parent
1423
- handleRemoveFilter();
1424
- }}
1425
- style={{
1426
- display: 'flex',
1427
- flexDirection: 'row',
1428
- alignItems: 'center',
1429
- cursor: 'pointer',
1430
- paddingLeft: '6px',
1431
- }}
1432
- >
1433
- <XMarkIcon
1434
- style={{
1435
- height: '20px',
1436
- width: '20px',
1437
- color: tagStyle?.color || theme?.primaryTextColor,
1438
- }}
1439
- aria-hidden="true"
1440
- />
1441
- </div>
1442
- </div>
1443
- );
1444
- }
1445
-
1446
- const SortByModal = ({
1447
- selectedSortByColumn,
1448
- selectedSortByDirection,
1449
- setSelectedSortByColumn,
1450
- setSelectedSortByDirection,
1451
- selectedTable,
1452
- sortableColumns,
1453
- removeSortBy,
1454
- selectSortBy,
1455
- updateSortBy,
1456
- addSortBy,
1457
- sortBys,
1458
- SelectComponent,
1459
- ButtonComponent,
1460
- ModalComponent,
1461
- tagStyle,
1462
- ModalTriggerComponent,
1463
- sortByIndexBeingEdited,
1464
- theme,
1465
- }) => {
1466
- const [isOpen, setIsOpen] = useState(false);
1467
- return (
1468
- <div style={{ display: 'flex', flexDirection: 'column', marginTop: 12 }}>
1469
- <div
1470
- style={{
1471
- position: 'relative',
1472
- display: 'inline-block',
1473
- textAlign: 'left',
1474
- }}
1475
- >
1476
- <div
1477
- style={{
1478
- display: 'flex',
1479
- flexDirection: 'row',
1480
- alignItems: 'center',
1481
- }}
1482
- >
1483
- <ModalTriggerComponent
1484
- onClick={() => setIsOpen(isOpen => !isOpen)}
1485
- label="Sort"
1486
- />
1487
- <div
1488
- style={{
1489
- overflowX: 'scroll',
1490
- display: 'flex',
1491
- flexDirection: 'row',
1492
- alignItems: 'center',
1493
- }}
1494
- >
1495
- {sortBys.map((elem, index) => (
1496
- <FilterTag
1497
- id="sort-tag"
1498
- label={elem.column}
1499
- removeFilter={removeSortBy}
1500
- selectFilter={selectSortBy}
1501
- setIsOpen={setIsOpen}
1502
- index={index}
1503
- theme={theme}
1504
- tagStyle={tagStyle}
1505
- key={'sort' + index}
1506
- />
1507
- ))}
1508
- </div>
1509
- </div>
1510
-
1511
- <ModalComponent
1512
- isOpen={isOpen}
1513
- onClose={() => setIsOpen(false)}
1514
- title="Add sort"
1515
- >
1516
- <div
1517
- style={{
1518
- display: 'flex',
1519
- flexDirection: 'column',
1520
- }}
1521
- // className="transform opacity-100 scale-100"
1522
- >
1523
- {/* <div
1524
- style={{
1525
- display: 'flex',
1526
- flexDirection: 'row',
1527
- alignItems: 'center',
1528
- }}
1529
- > */}
1530
- <div style={{ display: 'flex', flexDirection: 'column' }}>
1531
- <div
1532
- style={{
1533
- fontSize: '14px',
1534
- marginBottom: '6px',
1535
- fontWeight: '600',
1536
- color: theme.secondaryTextColor,
1537
- fontFamily: theme?.fontFamily,
1538
- }}
1539
- >
1540
- Column
1541
- </div>
1542
- {/* select column */}
1543
- <SelectComponent
1544
- value={selectedSortByColumn}
1545
- onChange={e => {
1546
- setSelectedSortByColumn(e);
1547
- }}
1548
- options={sortableColumns.map(elem => {
1549
- return { label: elem, value: elem };
1550
- })}
1551
- />
1552
- </div>
1553
- {/* </div> */}
1554
- {/* Select bucket (if date) */}
1555
-
1556
- {/* Select aggregations */}
1557
- <div
1558
- style={{
1559
- fontSize: '14px',
1560
- marginBottom: '6px',
1561
- fontWeight: '600',
1562
- color: theme.secondaryTextColor,
1563
- fontFamily: theme?.fontFamily,
1564
- marginTop: 20,
1565
- }}
1566
- >
1567
- Direction
1568
- </div>
1569
-
1570
- <SelectComponent
1571
- value={selectedSortByDirection}
1572
- onChange={e => {
1573
- setSelectedSortByDirection(e);
1574
- }}
1575
- options={[
1576
- { label: 'ascending', value: 'ascending' },
1577
- { label: 'descending', value: 'descending' },
1578
- ]}
1579
- />
1580
- <div style={{ height: 20 }} />
1581
- <ButtonComponent
1582
- id="custom-button"
1583
- onClick={() => {
1584
- if (sortByIndexBeingEdited > -1) {
1585
- updateSortBy(sortByIndexBeingEdited);
1586
- setIsOpen(false);
1587
- // close();
1588
- return;
1589
- }
1590
- addSortBy();
1591
- setIsOpen(false);
1592
- // close();
1593
- }}
1594
- label={sortByIndexBeingEdited > -1 ? 'Edit sort' : 'Add sort'}
1595
- />
1596
- </div>
1597
- </ModalComponent>
1598
- </div>
1599
- </div>
1600
- );
1601
- };
1602
-
1603
- const GroupByModal2 = ({
1604
- selectedGroupByColumn,
1605
- addGroupBy,
1606
- setSelectedGroupByColumn,
1607
- selectedTable,
1608
- groupByColumnType,
1609
- groupByIndexBeingEdited,
1610
- updateGroupBy,
1611
- groupBys,
1612
- removeGroupBy,
1613
- selectGroupBy,
1614
- SelectComponent,
1615
- ButtonComponent,
1616
- aggregations,
1617
- setAggregationColumn,
1618
- setAggregationType,
1619
- addAggregation,
1620
- dateBucket,
1621
- setDateBucket,
1622
- ModalComponent,
1623
- theme,
1624
- ModalTriggerComponent,
1625
- TextInputComponent,
1626
- tagStyle,
1627
- }) => {
1628
- const [isOpen, setIsOpen] = useState(false);
1629
- return (
1630
- <div style={{ display: 'flex', flexDirection: 'column' }}>
1631
- <div
1632
- style={{
1633
- position: 'relative',
1634
- display: 'inline-block',
1635
- textAlign: 'left',
1636
- }}
1637
- >
1638
- <div
1639
- style={{
1640
- display: 'flex',
1641
- flexDirection: 'row',
1642
- alignItems: 'center',
1643
- }}
1644
- >
1645
- <ModalTriggerComponent
1646
- onClick={() => setIsOpen(isOpen => !isOpen)}
1647
- label="Group by"
1648
- />
1649
- <div
1650
- style={{
1651
- overflowX: 'scroll',
1652
- display: 'flex',
1653
- flexDirection: 'row',
1654
- alignItems: 'center',
1655
- }}
1656
- >
1657
- {groupBys.map((elem, index) => (
1658
- <FilterTag
1659
- id="group-tag"
1660
- label={elem.tag}
1661
- removeFilter={removeGroupBy}
1662
- selectFilter={selectGroupBy}
1663
- setIsOpen={setIsOpen}
1664
- index={index}
1665
- theme={theme}
1666
- tagStyle={tagStyle}
1667
- key={'groupby' + index}
1668
- />
1669
- ))}
1670
- </div>
1671
- </div>
1672
- <ModalComponent
1673
- isOpen={isOpen}
1674
- onClose={() => setIsOpen(false)}
1675
- title="Add group by"
1676
- >
1677
- <div style={{ display: 'flex', flexDirection: 'column' }}>
1678
- <div style={{ display: 'flex', flexDirection: 'column' }}>
1679
- {/* select column */}
1680
- <div
1681
- style={{
1682
- fontSize: '14px',
1683
- marginBottom: '6px',
1684
- fontWeight: '600',
1685
- fontFamily: theme?.fontFamily,
1686
- color: theme.secondaryTextColor,
1687
- }}
1688
- >
1689
- Column
1690
- </div>
1691
- <SelectComponent
1692
- label="Column"
1693
- value={selectedGroupByColumn.name}
1694
- onChange={e => {
1695
- const column = selectedTable.columns.find(c => c.name === e);
1696
- setSelectedGroupByColumn(column);
1697
- }}
1698
- options={selectedTable.columns.map(elem => {
1699
- return { label: elem.name, value: elem.name };
1700
- })}
1701
- />
1702
- </div>
1703
- {groupByColumnType === 'date' && (
1704
- <div
1705
- style={{
1706
- display: 'flex',
1707
- flexDirection: 'column',
1708
- // marginLeft: 12,
1709
- }}
1710
- >
1711
- <div
1712
- style={{
1713
- fontSize: '14px',
1714
- marginBottom: '6px',
1715
- fontWeight: '600',
1716
- color: theme.secondaryTextColor,
1717
- fontFamily: theme?.fontFamily,
1718
- marginTop: 20,
1719
- }}
1720
- >
1721
- Bucket
1722
- </div>
1723
- <SelectComponent
1724
- label="Bucket"
1725
- value={dateBucket}
1726
- onChange={e => {
1727
- setDateBucket(e);
1728
- }}
1729
- options={[
1730
- { label: 'month', value: 'month' },
1731
- { label: 'day', value: 'day' },
1732
- { label: 'week', value: 'week' },
1733
- ]}
1734
- />
1735
- </div>
1736
- )}
1737
- {/* Select bucket (if date) */}
1738
-
1739
- {/* Select aggregations */}
1740
- <div
1741
- style={{
1742
- fontSize: 14,
1743
- marginBottom: '6px',
1744
- fontWeight: '600',
1745
- marginTop: 20,
1746
- color: theme.secondaryTextColor,
1747
- fontFamily: theme?.fontFamily,
1748
- }}
1749
- >
1750
- Aggregations
1751
- </div>
1752
- {/* select column */}
1753
- {aggregations.map((aggregation, index) => (
1754
- // setAggregationType
1755
- <div
1756
- key={'agg' + index}
1757
- style={{
1758
- display: 'flex',
1759
- flexDirection: 'row',
1760
- alignItems: 'center',
1761
- }}
1762
- >
1763
- <SelectComponent
1764
- value={aggregation.column?.name}
1765
- onChange={e => {
1766
- const column = selectedTable.columns.find(
1767
- c => c.name === e
1768
- );
1769
- setAggregationColumn(column, index);
1770
- }}
1771
- options={selectedTable.columns.map(elem => {
1772
- return { label: elem.name, value: elem.name };
1773
- })}
1774
- />
1775
- <div style={{ width: 16 }} />
1776
- <SelectComponent
1777
- value={aggregation.aggregationType}
1778
- onChange={e => {
1779
- setAggregationType(e, index);
1780
- }}
1781
- options={[
1782
- { label: 'sum', value: 'sum' },
1783
- { label: 'average', value: 'average' },
1784
- { label: 'count', value: 'count' },
1785
- ]}
1786
- />
1787
- </div>
1788
- ))}
1789
- <div style={{ height: 20 }} />
1790
- <ButtonComponent
1791
- id="custom-button"
1792
- onClick={() => {
1793
- if (groupByIndexBeingEdited > -1) {
1794
- updateGroupBy(groupByIndexBeingEdited);
1795
- setIsOpen(false);
1796
- // close();
1797
- return;
1798
- }
1799
- addGroupBy();
1800
- setIsOpen(false);
1801
- // close();
1802
- }}
1803
- label={
1804
- groupByIndexBeingEdited > -1 ? 'Edit group by' : 'Add group by'
1805
- }
1806
- />
1807
- </div>
1808
- </ModalComponent>
1809
- </div>
1810
- </div>
1811
- );
1812
- };
1813
-
1814
- const AddFilterModal2 = ({
1815
- filters,
1816
- selectedColumn,
1817
- numberStart,
1818
- numberEnd,
1819
- dateStart,
1820
- setDateStart,
1821
- columnStats,
1822
- stringFilterValues,
1823
- setStringFilterValues,
1824
- addFilter,
1825
- setSelectedColumn,
1826
- setNumberStart,
1827
- setNumberEnd,
1828
- selectedTable,
1829
- columnType,
1830
- setDateEnd,
1831
- dateEnd,
1832
- removeFilter,
1833
- selectFilter,
1834
- indexBeingEdited,
1835
- updateFilter,
1836
- SelectComponent,
1837
- ButtonComponent,
1838
- ModalComponent,
1839
- theme,
1840
- ModalTriggerComponent,
1841
- TextInputComponent,
1842
- tagStyle,
1843
- }) => {
1844
- const [isOpen, setIsOpen] = useState(false);
1845
-
1846
- return (
1847
- <div style={{ display: 'flex', flexDirection: 'column' }}>
1848
- <div
1849
- style={{
1850
- position: 'relative',
1851
- display: 'inline-block',
1852
- textAlign: 'left',
1853
- }}
1854
- >
1855
- <div
1856
- style={{
1857
- display: 'flex',
1858
- flexDirection: 'row',
1859
- alignItems: 'center',
1860
- }}
1861
- >
1862
- <ModalTriggerComponent
1863
- onClick={() => setIsOpen(isOpen => !isOpen)}
1864
- label="Filter"
1865
- />
1866
- <div
1867
- style={{
1868
- overflowX: 'scroll',
1869
- display: 'flex',
1870
- flexDirection: 'row',
1871
- alignItems: 'center',
1872
- }}
1873
- >
1874
- {filters.map((elem, index) => (
1875
- <FilterTag
1876
- id="filter-tag"
1877
- label={elem.tag}
1878
- removeFilter={removeFilter}
1879
- selectFilter={selectFilter}
1880
- index={index}
1881
- theme={theme}
1882
- setIsOpen={setIsOpen}
1883
- key={'filter' + index}
1884
- tagStyle={tagStyle}
1885
- />
1886
- ))}
1887
- </div>
1888
- </div>
1889
- <ModalComponent
1890
- isOpen={isOpen}
1891
- onClose={() => setIsOpen(false)}
1892
- title="Add filter"
1893
- >
1894
- <div
1895
- style={{
1896
- backgroundColor: 'rgb(255, 255, 255)',
1897
- display: 'flex',
1898
- flexDirection: 'column',
1899
- }}
1900
- >
1901
- <div
1902
- style={{
1903
- fontSize: 14,
1904
- marginBottom: '6px',
1905
- fontWeight: '600',
1906
- color: theme.secondaryTextColor,
1907
- fontFamily: theme?.fontFamily,
1908
- }}
1909
- >
1910
- Column
1911
- </div>
1912
- <SelectComponent
1913
- id="custom-select"
1914
- value={selectedColumn.name}
1915
- onChange={e => {
1916
- const column = selectedTable.columns.find(c => c.name === e);
1917
- setSelectedColumn(column);
1918
- }}
1919
- options={selectedTable.columns.map(elem => {
1920
- return { label: elem.name, value: elem.name };
1921
- })}
1922
- />
1923
-
1924
- {columnType === 'number' && (
1925
- <div>
1926
- <div
1927
- style={{
1928
- display: 'flex',
1929
- flexDirection: 'row',
1930
- alignItems: 'center',
1931
- justifyContent: 'space-between',
1932
- }}
1933
- >
1934
- <div
1935
- style={{
1936
- display: 'flex',
1937
- flexDirection: 'column',
1938
- marginTop: '20px',
1939
- }}
1940
- >
1941
- <div
1942
- style={{
1943
- fontSize: '14px',
1944
- fontWeight: '600',
1945
- color: theme.secondaryTextColor,
1946
- fontFamily: theme?.fontFamily,
1947
- marginBottom: 6,
1948
- }}
1949
- >
1950
- Minimum
1951
- </div>
1952
- <TextInputComponent
1953
- id="min-input"
1954
- value={numberStart}
1955
- onChange={e => setNumberStart(e.target.value)}
1956
- />
1957
- </div>
1958
- <div style={{ width: 16 }} />
1959
- <div
1960
- style={{
1961
- display: 'flex',
1962
- flexDirection: 'column',
1963
- marginTop: '20px',
1964
- }}
1965
- >
1966
- <div
1967
- style={{
1968
- fontSize: '14px',
1969
- fontWeight: '600',
1970
- color: theme.secondaryTextColor,
1971
- fontFamily: theme?.fontFamily,
1972
- marginBottom: 6,
1973
- }}
1974
- >
1975
- Maximum
1976
- </div>
1977
- <TextInputComponent
1978
- id="max-input"
1979
- value={numberEnd}
1980
- onChange={e => setNumberEnd(e.target.value)}
1981
- />
1982
- </div>
1983
- </div>
1984
- </div>
1985
- )}
1986
-
1987
- {columnType === 'date' && (
1988
- <div
1989
- style={{
1990
- display: 'flex',
1991
- flexDirection: 'row',
1992
- alignItems: 'center',
1993
- justifyContent: 'space-between',
1994
- }}
1995
- >
1996
- <div
1997
- style={{
1998
- display: 'flex',
1999
- flexDirection: 'column',
2000
- marginTop: '20px',
2001
- }}
2002
- >
2003
- <div
2004
- style={{
2005
- fontSize: 14,
2006
- fontWeight: '600',
2007
- color: 'rgba(56, 65, 81, 0.7)',
2008
- fontFamily: theme?.fontFamily,
2009
- }}
2010
- >
2011
- Start date
2012
- </div>
2013
- <input
2014
- type="date"
2015
- value={dateStart}
2016
- onChange={e => setDateStart(e.target.value)}
2017
- placeholder="Start date"
2018
- // style={{
2019
- // width: '115px',
2020
- // fontSize: '0.8rem',
2021
- // color: theme?.primaryTextColor,
2022
- // borderWidth: '1px',
2023
- // marginTop: '4px',
2024
- // borderColor: '#E7E7E7',
2025
- // backgroundColor: 'white',
2026
- // borderRadius: '0.375rem',
2027
- // boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
2028
- // paddingLeft: '0.5rem',
2029
- // paddingRight: '0.5rem',
2030
- // paddingTop: '0.375rem',
2031
- // paddingBottom: '0.375rem',
2032
- // fontFamily: theme?.fontFamily,
2033
- // }}
2034
- />
2035
- </div>
2036
- <div
2037
- style={{
2038
- display: 'flex',
2039
- flexDirection: 'column',
2040
- marginTop: '20px',
2041
- }}
2042
- >
2043
- <div
2044
- style={{
2045
- fontSize: 14,
2046
- fontWeight: '600',
2047
- color: 'rgba(56, 65, 81, 0.7)',
2048
- fontFamily: theme?.fontFamily,
2049
- }}
2050
- >
2051
- End date
2052
- </div>
2053
- <input
2054
- type="date"
2055
- value={dateEnd}
2056
- onChange={e => setDateEnd(e.target.value)}
2057
- placeholder="End date"
2058
- // style={{
2059
- // width: '115px',
2060
- // fontSize: '0.8rem',
2061
- // color: theme?.primaryTextColor,
2062
- // borderWidth: '1px',
2063
- // marginTop: '4px',
2064
- // borderColor: '#E7E7E7',
2065
- // backgroundColor: 'white',
2066
- // borderRadius: '0.375rem',
2067
- // boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
2068
- // paddingLeft: '0.5rem',
2069
- // paddingRight: '0.5rem',
2070
- // paddingTop: '0.375rem',
2071
- // paddingBottom: '0.375rem',
2072
- // fontFamily: theme?.fontFamily,
2073
- // }}
2074
- />
2075
- </div>
2076
- </div>
2077
- )}
2078
-
2079
- {columnType === 'string' &&
2080
- columnStats &&
2081
- columnStats.length > 0 && (
2082
- <div
2083
- style={{
2084
- flex: 'flex',
2085
- flexDirection: 'column',
2086
- marginTop: '14px',
2087
- overflow: 'hidden',
2088
- }}
2089
- >
2090
- {columnStats.map(value => (
2091
- <div
2092
- style={{
2093
- display: 'flex',
2094
- flexDirection: 'row',
2095
- alignItems: 'center',
2096
- }}
2097
- key={value}
2098
- >
2099
- <div
2100
- style={{
2101
- display: 'flex',
2102
- flexDirection: 'row',
2103
- alignItems: 'center',
2104
- paddingTop: 6,
2105
- paddingBottom: 6,
2106
- }}
2107
- key={value}
2108
- >
2109
- <DivCheckbox
2110
- theme={theme}
2111
- checked={stringFilterValues.includes(value)}
2112
- onChange={() => {
2113
- setStringFilterValues(prev =>
2114
- prev.includes(value)
2115
- ? prev.filter(v => v !== value)
2116
- : [...prev, value]
2117
- );
2118
- }}
2119
- />
2120
- <div
2121
- style={{
2122
- marginLeft: 6,
2123
- display: 'block',
2124
- overflow: 'hidden',
2125
- textOverflow: 'ellipsis',
2126
- whiteSpace: 'nowrap',
2127
- color: theme?.primaryTextColor,
2128
- fontFamily: theme?.fontFamily,
2129
- }}
2130
- >
2131
- {value}
2132
- </div>
2133
- </div>
2134
- </div>
2135
- ))}
2136
- </div>
2137
- )}
2138
- <div style={{ height: 20 }} />
2139
- <ButtonComponent
2140
- id="custom-button"
2141
- onClick={() => {
2142
- if (indexBeingEdited > -1) {
2143
- updateFilter(indexBeingEdited);
2144
- setIsOpen(false);
2145
- return;
2146
- }
2147
- addFilter();
2148
- setIsOpen(false);
2149
- }}
2150
- label={indexBeingEdited > -1 ? 'Edit filter' : 'Add filter'}
2151
- />
2152
- </div>
2153
- </ModalComponent>
2154
- {/* )} */}
2155
- </div>
2156
- <div style={{ height: '12px' }}></div>
2157
- </div>
2158
- );
2159
- };
2160
-
2161
- const DivCheckbox = ({ onChange, checked, theme }) => {
2162
- const toggleCheckbox = () => {
2163
- if (onChange) {
2164
- onChange(!checked);
2165
- }
2166
- };
2167
-
2168
- const style = {
2169
- // display: 'inline-block',
2170
- width: '18px',
2171
- height: '18px',
2172
- background: checked ? '#384151' : '#fff',
2173
- border: checked ? '1px solid #384151' : '1px solid #E7E7E7',
2174
- borderRadius: '4px',
2175
- position: 'relative',
2176
- cursor: 'pointer',
2177
- boxShadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
2178
- fontFamily: theme?.fontFamily,
2179
- display: 'flex',
2180
- flexDirection: 'column',
2181
- alignItems: 'center',
2182
- justifyContent: 'center',
2183
- };
2184
-
2185
- return (
2186
- <div
2187
- style={style}
2188
- onClick={toggleCheckbox}
2189
- aria-checked={checked}
2190
- // className="shadow-sm"
2191
- role="checkbox"
2192
- >
2193
- {checked && (
2194
- <CheckIcon
2195
- style={{ color: theme?.backgroundColor, height: 16, width: 16 }}
2196
- className="text-white"
2197
- aria-hidden="true"
2198
- />
2199
- )}
2200
- </div>
2201
- );
2202
- };