@quillsql/react 2.11.12 → 2.11.14

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 (81) hide show
  1. package/dist/cjs/ChartBuilder.d.ts.map +1 -1
  2. package/dist/cjs/ChartBuilder.js +1 -1
  3. package/dist/cjs/Dashboard.js +1 -1
  4. package/dist/cjs/ReportBuilder.d.ts.map +1 -1
  5. package/dist/cjs/ReportBuilder.js +354 -197
  6. package/dist/cjs/SQLEditor.d.ts.map +1 -1
  7. package/dist/cjs/SQLEditor.js +1 -0
  8. package/dist/cjs/components/Chart/ChartTooltipFrame.d.ts.map +1 -1
  9. package/dist/cjs/components/Chart/ChartTooltipFrame.js +1 -0
  10. package/dist/cjs/components/Chart/LineChart.d.ts.map +1 -1
  11. package/dist/cjs/components/Chart/LineChart.js +3 -0
  12. package/dist/cjs/components/Dashboard/MetricComponent.js +2 -2
  13. package/dist/cjs/components/QuillCard.d.ts.map +1 -1
  14. package/dist/cjs/components/QuillCard.js +2 -4
  15. package/dist/cjs/components/QuillSelect.d.ts.map +1 -1
  16. package/dist/cjs/components/QuillSelect.js +7 -1
  17. package/dist/cjs/components/QuillTable.d.ts.map +1 -1
  18. package/dist/cjs/components/QuillTable.js +2 -2
  19. package/dist/cjs/components/ReportBuilder/AddColumnPopover.js +3 -3
  20. package/dist/cjs/components/ReportBuilder/AddLimitPopover.d.ts +3 -0
  21. package/dist/cjs/components/ReportBuilder/AddLimitPopover.d.ts.map +1 -0
  22. package/dist/cjs/components/ReportBuilder/AddLimitPopover.js +43 -0
  23. package/dist/cjs/components/ReportBuilder/AddSortPopover.d.ts.map +1 -1
  24. package/dist/cjs/components/ReportBuilder/AddSortPopover.js +10 -4
  25. package/dist/cjs/components/ReportBuilder/bigDateMap.d.ts.map +1 -1
  26. package/dist/cjs/components/ReportBuilder/bigDateMap.js +2 -1
  27. package/dist/cjs/components/ReportBuilder/convert.d.ts.map +1 -1
  28. package/dist/cjs/components/ReportBuilder/convert.js +38 -12
  29. package/dist/cjs/components/ReportBuilder/ui.d.ts.map +1 -1
  30. package/dist/cjs/components/ReportBuilder/ui.js +4 -3
  31. package/dist/cjs/components/ReportBuilder/util.d.ts.map +1 -1
  32. package/dist/cjs/components/ReportBuilder/util.js +7 -5
  33. package/dist/cjs/components/UiComponents.js +2 -2
  34. package/dist/cjs/internals/ReportBuilder/PivotList.d.ts.map +1 -1
  35. package/dist/cjs/internals/ReportBuilder/PivotList.js +28 -2
  36. package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts +2 -1
  37. package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
  38. package/dist/cjs/internals/ReportBuilder/PivotModal.js +49 -32
  39. package/dist/cjs/utils/getDomain.d.ts.map +1 -1
  40. package/dist/cjs/utils/getDomain.js +3 -0
  41. package/dist/esm/ChartBuilder.d.ts.map +1 -1
  42. package/dist/esm/ChartBuilder.js +1 -1
  43. package/dist/esm/Dashboard.js +1 -1
  44. package/dist/esm/ReportBuilder.d.ts.map +1 -1
  45. package/dist/esm/ReportBuilder.js +354 -197
  46. package/dist/esm/SQLEditor.d.ts.map +1 -1
  47. package/dist/esm/SQLEditor.js +1 -0
  48. package/dist/esm/components/Chart/ChartTooltipFrame.d.ts.map +1 -1
  49. package/dist/esm/components/Chart/ChartTooltipFrame.js +1 -0
  50. package/dist/esm/components/Chart/LineChart.d.ts.map +1 -1
  51. package/dist/esm/components/Chart/LineChart.js +3 -0
  52. package/dist/esm/components/Dashboard/MetricComponent.js +2 -2
  53. package/dist/esm/components/QuillCard.d.ts.map +1 -1
  54. package/dist/esm/components/QuillCard.js +2 -4
  55. package/dist/esm/components/QuillSelect.d.ts.map +1 -1
  56. package/dist/esm/components/QuillSelect.js +7 -1
  57. package/dist/esm/components/QuillTable.d.ts.map +1 -1
  58. package/dist/esm/components/QuillTable.js +2 -2
  59. package/dist/esm/components/ReportBuilder/AddColumnPopover.js +3 -3
  60. package/dist/esm/components/ReportBuilder/AddLimitPopover.d.ts +3 -0
  61. package/dist/esm/components/ReportBuilder/AddLimitPopover.d.ts.map +1 -0
  62. package/dist/esm/components/ReportBuilder/AddLimitPopover.js +38 -0
  63. package/dist/esm/components/ReportBuilder/AddSortPopover.d.ts.map +1 -1
  64. package/dist/esm/components/ReportBuilder/AddSortPopover.js +10 -4
  65. package/dist/esm/components/ReportBuilder/bigDateMap.d.ts.map +1 -1
  66. package/dist/esm/components/ReportBuilder/bigDateMap.js +2 -1
  67. package/dist/esm/components/ReportBuilder/convert.d.ts.map +1 -1
  68. package/dist/esm/components/ReportBuilder/convert.js +38 -12
  69. package/dist/esm/components/ReportBuilder/ui.d.ts.map +1 -1
  70. package/dist/esm/components/ReportBuilder/ui.js +4 -3
  71. package/dist/esm/components/ReportBuilder/util.d.ts.map +1 -1
  72. package/dist/esm/components/ReportBuilder/util.js +7 -5
  73. package/dist/esm/components/UiComponents.js +2 -2
  74. package/dist/esm/internals/ReportBuilder/PivotList.d.ts.map +1 -1
  75. package/dist/esm/internals/ReportBuilder/PivotList.js +28 -2
  76. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts +2 -1
  77. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
  78. package/dist/esm/internals/ReportBuilder/PivotModal.js +49 -32
  79. package/dist/esm/utils/getDomain.d.ts.map +1 -1
  80. package/dist/esm/utils/getDomain.js +3 -0
  81. package/package.json +2 -2
@@ -21,6 +21,8 @@ import { PivotModal, generatePivotTable, } from './internals/ReportBuilder/Pivot
21
21
  import { PivotCard } from './internals/ReportBuilder/PivotList';
22
22
  import QuillTable from './components/QuillTable';
23
23
  import { QuillSelectComponent } from './components/QuillSelect';
24
+ import { snakeCaseToTitleCase } from './utils/textProcessing';
25
+ import { AddLimitPopover, LimitSentence, } from './components/ReportBuilder/AddLimitPopover';
24
26
  /**
25
27
  * Quill Report Builder
26
28
  *
@@ -58,6 +60,8 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
58
60
  const [showPivotPopover, setShowPivotPopover] = useState(false);
59
61
  const [isEdittingPivot, setIsEdittingPivot] = useState(false);
60
62
  const [selectedPivotIndex, setSelectedPivotIndex] = useState(-1);
63
+ const [initialLoad, setInitialLoad] = useState(true);
64
+ const [currentTable, setCurrentTable] = useState(initialTableName || '');
61
65
  const parentRef = useRef(null);
62
66
  const [theme] = useContext(ThemeContext);
63
67
  const [pivotRowField, setPivotRowField] = useState(undefined);
@@ -85,7 +89,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
85
89
  return columns.map((col) => ({
86
90
  label: col,
87
91
  name: col,
88
- displayName: col,
92
+ displayName: snakeCaseToTitleCase(col),
89
93
  field: col,
90
94
  format: getPostgresBasicType(fields.find((f) => f.name === col))?.replace('number', 'whole_number') || 'string',
91
95
  fieldType: schemaTables
@@ -117,6 +121,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
117
121
  // setUniqueValues({});
118
122
  setPivot(null);
119
123
  setPivotData(null);
124
+ setRecommendedPivots([]);
120
125
  }, 0);
121
126
  };
122
127
  useEffect(() => {
@@ -177,7 +182,9 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
177
182
  }
178
183
  setUniqueValues(newValues);
179
184
  };
180
- const fetchSqlQuery = async () => {
185
+ const fetchSqlQuery = async (ast, formData) => {
186
+ setLoading(true);
187
+ setErrorMessage('');
181
188
  try {
182
189
  const response = await fetch(`https://quill-344421.uc.r.appspot.com/sqlify`, {
183
190
  method: 'POST',
@@ -185,32 +192,19 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
185
192
  'Content-Type': 'application/json',
186
193
  },
187
194
  body: JSON.stringify({
188
- ast: { ...baseAst, where: formData },
195
+ ast: { ...ast, where: formData },
189
196
  publicKey: client.publicKey,
190
197
  }),
191
198
  });
192
199
  const data = await response.json();
193
200
  setActiveQuery(data.query);
194
- fetchUponChange();
201
+ fetchUponChange(ast, formData);
195
202
  }
196
203
  catch (error) {
204
+ setLoading(false);
197
205
  console.error(error);
198
206
  }
199
207
  };
200
- useEffect(() => {
201
- setErrorMessage('');
202
- if (baseAst || formData) {
203
- fetchSqlQuery();
204
- }
205
- }, [baseAst]);
206
- // Returns an array of all the column names in the pivot config
207
- // if there are any, otherwise returns [].
208
- const getColumnsInPivot = () => {
209
- if (!pivot)
210
- return [];
211
- const { valueField, rowField, columnField } = pivot;
212
- return [valueField, rowField, columnField].filter(Boolean);
213
- };
214
208
  // It's just like getColumnsInPivot but we expand the columnField
215
209
  // if there is one to include all the variants just like it would
216
210
  // show up in the table. (eg. category -> ...[Fuel, Food, Other])
@@ -229,81 +223,78 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
229
223
  result.push(valueField, rowField);
230
224
  return result.filter(Boolean);
231
225
  };
232
- useEffect(() => {
233
- if (errorMessage) {
234
- console.error(errorMessage);
226
+ const fetchDistinctHelper = async (column, table) => {
227
+ try {
228
+ const query = `SELECT DISTINCT ${column} FROM ${table};`;
229
+ const response = await fetch(`https://quill-344421.uc.r.appspot.com/dashquery`, {
230
+ method: 'POST',
231
+ headers: {
232
+ 'Content-Type': 'application/json',
233
+ },
234
+ body: JSON.stringify({
235
+ orgId: client.customerId,
236
+ publicKey: client.publicKey,
237
+ query: query,
238
+ }),
239
+ });
240
+ const data = await response.json();
241
+ if (data.errorMessage) {
242
+ // console.error(data.errorMessage);
243
+ return null;
244
+ }
245
+ const options = data.rows.map((r) => r[column]);
246
+ const newCheckboxValues = options.reduce((obj, col) => {
247
+ obj[col] = false;
248
+ return obj;
249
+ }, {});
250
+ return { table, column, values: newCheckboxValues };
251
+ }
252
+ catch (e) {
253
+ console.error(e);
254
+ return null;
235
255
  }
236
- }, [errorMessage]);
256
+ };
237
257
  useEffect(() => {
238
- const fetchDistinctHelper = async (column, table) => {
258
+ const fetchSchema = async () => {
239
259
  try {
240
- const query = `SELECT DISTINCT ${column} FROM ${table};`;
241
- const response = await fetch(`https://quill-344421.uc.r.appspot.com/dashquery`, {
260
+ const response = await fetch(`${client.queryEndpoint}`, {
242
261
  method: 'POST',
243
262
  headers: {
263
+ ...client.queryHeaders,
244
264
  'Content-Type': 'application/json',
245
265
  },
246
266
  body: JSON.stringify({
247
- orgId: client.customerId,
248
- publicKey: client.publicKey,
249
- query: query,
267
+ metadata: {
268
+ clientId: client.publicKey,
269
+ publicKey: client.publicKey,
270
+ task: 'schema',
271
+ removeCustomerField: true,
272
+ },
250
273
  }),
251
274
  });
252
- const data = await response.json();
253
- if (data.errorMessage) {
254
- // console.error(data.errorMessage);
255
- return null;
256
- }
257
- const options = data.rows.map((r) => r[column]);
258
- const newCheckboxValues = options.reduce((obj, col) => {
259
- obj[col] = false;
260
- return obj;
261
- }, {});
262
- return { table, column, values: newCheckboxValues };
263
- }
264
- catch (e) {
265
- console.error(e);
266
- return null;
267
- }
268
- };
269
- const fetchSchema = async () => {
270
- try {
271
- const response = await fetch(`https://quill-344421.uc.r.appspot.com/schema2/${client.publicKey}`).then((res) => res.json());
275
+ const results = await response.json();
272
276
  // Filter out hidden columns on tables back from schema2.
273
- const tables = response?.tables;
274
- for (const table of tables) {
275
- table.columns = table.columns.filter((column) =>
276
- // Quick and dirty fix for removing org ids from response.
277
- // TODO: Fix this on the backend or something.
278
- column.isVisible && column.displayName !== 'pm_company_id');
279
- }
277
+ const tables = results.data.tables || results.data.data.tables;
280
278
  setSchemaTables(tables ?? []);
281
- setOrderedColumnNames((tables ?? [])
282
- // .filter((t: any) => t.displayName === initialTableName)
283
- .flatMap((table) => table.columns.map((c) => `${table.displayName}.${c.displayName}`)));
284
- // Fetch all the unique values in parallel
285
- const pendingFetches = [];
286
- for (let table of tables ?? []) {
287
- for (let column of table.columns) {
288
- if (!isTextColumnType(column.fieldType))
289
- continue;
290
- const fetchPromise = fetchDistinctHelper(column.name, table.displayName);
291
- pendingFetches.push(fetchPromise);
292
- }
293
- }
294
- const newUniqueValues = {};
295
- const resolvedPromises = await Promise.all(pendingFetches);
296
- for (const resolvedData of resolvedPromises) {
297
- if (resolvedData) {
298
- const { table, column, values } = resolvedData;
299
- if (!newUniqueValues[table]) {
300
- newUniqueValues[table] = {};
301
- }
302
- newUniqueValues[table][column] = values;
303
- }
304
- }
305
- if (hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
306
- setUniqueValues(newUniqueValues);
279
+ setOrderedColumnNames((tables ?? []).flatMap((table) => table.columns
280
+ .map((c) => `${table.name}.${c.name}`)
281
+ .sort((a, b) => {
282
+ const aIsId = a.endsWith('.id') || a.endsWith('_id');
283
+ const bIsId = b.endsWith('.id') || b.endsWith('_id');
284
+ if (aIsId && !bIsId)
285
+ return 1;
286
+ if (bIsId && !aIsId)
287
+ return -1;
288
+ return 0;
289
+ })));
290
+ if (initialTableName && initialLoad) {
291
+ setInitialLoad(false);
292
+ setLoading(true);
293
+ await getDistinctValues(initialTableName, tables);
294
+ const columnsForTable = tables
295
+ .find((t) => t.name === initialTableName)
296
+ ?.columns.map((c) => c.name);
297
+ await handleAsk(`get ${columnsForTable} from ${initialTableName}`);
307
298
  }
308
299
  }
309
300
  catch (error) {
@@ -327,7 +318,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
327
318
  const paths = globalPath.split('.').filter((p) => p);
328
319
  if (paths.length === 0 && !isInsertion && !isReplaceSubtree) {
329
320
  setFormData(null);
330
- setBaseAst(deepCopy({
321
+ const newAst = deepCopy({
331
322
  ...defaultAST,
332
323
  ...baseAst,
333
324
  ...(!baseAst?.columns && {
@@ -341,12 +332,13 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
341
332
  from: [{ ...defaultTable, table: initialTableName }],
342
333
  }),
343
334
  where: null,
344
- }));
335
+ });
336
+ setBaseAst(newAst);
337
+ fetchSqlQuery(newAst, null);
345
338
  return;
346
339
  }
347
340
  if (!formData && isInsertion) {
348
- setFormData(value);
349
- setBaseAst(deepCopy({
341
+ const newAst = deepCopy({
350
342
  ...defaultAST,
351
343
  ...baseAst,
352
344
  ...(!baseAst?.columns && {
@@ -360,7 +352,10 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
360
352
  from: [{ ...defaultTable, table: initialTableName }],
361
353
  }),
362
354
  where: value,
363
- }));
355
+ });
356
+ setFormData(value);
357
+ setBaseAst(newAst);
358
+ fetchSqlQuery(newAst, value);
364
359
  return;
365
360
  }
366
361
  let newState = deepCopy(formData);
@@ -444,7 +439,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
444
439
  }
445
440
  }
446
441
  setFormData(newState);
447
- setBaseAst({
442
+ const newAst = {
448
443
  ...defaultAST,
449
444
  ...baseAst,
450
445
  ...(!baseAst?.columns && {
@@ -458,7 +453,9 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
458
453
  from: [{ ...defaultTable, table: initialTableName }],
459
454
  }),
460
455
  where: { ...newState },
461
- });
456
+ };
457
+ setBaseAst(newAst);
458
+ fetchSqlQuery(newAst, newState);
462
459
  });
463
460
  };
464
461
  // TODO: Merge this function with the updateFormData function
@@ -607,6 +604,9 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
607
604
  };
608
605
  // Function to handle operator changes
609
606
  const handleOperatorChange = (value, node, keyPrefix, column = null) => {
607
+ if (!keyPrefix) {
608
+ setTopLevelBinaryOperator(value);
609
+ }
610
610
  if (isPending) {
611
611
  updateActiveItem([{ path: keyPrefix + 'operator', value }], { column });
612
612
  }
@@ -675,6 +675,23 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
675
675
  .find((c) => c.name === columnName);
676
676
  return column?.fieldType;
677
677
  };
678
+ const emptyPivotColumns = () => {
679
+ if (pivot && pivot.rowField && pivot.columnField && pivot.valueField) {
680
+ return [
681
+ { label: snakeCaseToTitleCase(pivot.rowField) },
682
+ { label: snakeCaseToTitleCase(pivot.columnField) },
683
+ ];
684
+ }
685
+ else if (pivot && pivot.rowField && pivot.valueField) {
686
+ return [
687
+ { label: snakeCaseToTitleCase(pivot.rowField) },
688
+ { label: snakeCaseToTitleCase(pivot.valueField) },
689
+ ];
690
+ }
691
+ else {
692
+ return [{ label: snakeCaseToTitleCase(pivot.valueField) }];
693
+ }
694
+ };
678
695
  /**
679
696
  * Render form fields based on the type of the node
680
697
  * @param node the AST or subtree to render recursively
@@ -721,7 +738,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
721
738
  handleReplaceSubtree(keyPrefix, newSubtree);
722
739
  }
723
740
  }, options: getAllPossibleColumns().map((column) => ({
724
- label: column.displayName,
741
+ label: snakeCaseToTitleCase(column.displayName),
725
742
  value: column.name,
726
743
  })) }), _jsx(Select, { theme: theme, value: dateFilterType, onChange: (value) => {
727
744
  if (value === dateFilterType)
@@ -815,7 +832,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
815
832
  else if (isInTheLastInterval(node, client.databaseType)) {
816
833
  const { dateColumn, dateFilterType, intervalCount, intervalType } = getDateFilterInfo(node);
817
834
  const options = getAllPossibleColumns().map((column) => ({
818
- label: column.displayName,
835
+ label: snakeCaseToTitleCase(column.displayName),
819
836
  value: column.name,
820
837
  }));
821
838
  const plural = node.right.args.value[1].expr.value > 1 ? 's' : '';
@@ -866,7 +883,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
866
883
  else if (isTheCurrentInterval(node, client.databaseType)) {
867
884
  const { dateFilterType } = getDateFilterInfo(node);
868
885
  const options = getAllPossibleColumns().map((column) => ({
869
- label: column.displayName,
886
+ label: snakeCaseToTitleCase(column.displayName),
870
887
  value: column.name,
871
888
  }));
872
889
  return (_jsxs("div", { style: {
@@ -911,7 +928,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
911
928
  }
912
929
  else if (isThePreviousInterval(node, client.databaseType)) {
913
930
  const options = getAllPossibleColumns().map((column) => ({
914
- label: column.displayName,
931
+ label: snakeCaseToTitleCase(column.displayName),
915
932
  value: column.name,
916
933
  }));
917
934
  return (_jsxs("div", { style: {
@@ -972,7 +989,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
972
989
  }
973
990
  else if (isColumnComparison(node)) {
974
991
  const options = getAllPossibleColumns().map((column) => ({
975
- label: column.displayName,
992
+ label: snakeCaseToTitleCase(column.displayName),
976
993
  value: column.name,
977
994
  }));
978
995
  // grab the value of the left child of the column comparison
@@ -1026,6 +1043,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1026
1043
  gap: 12,
1027
1044
  flexDirection: 'column',
1028
1045
  width: '100%',
1046
+ padding: '6px 0px',
1029
1047
  }, children: [_jsxs("div", { style: {
1030
1048
  display: 'flex',
1031
1049
  gap: 20,
@@ -1067,7 +1085,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1067
1085
  else {
1068
1086
  handleDeleteVariant(keyPrefix + 'right.' + 'value', key);
1069
1087
  }
1070
- } }), _jsx("span", { children: key })] }, key))) }, keyPrefix + 'right.'))] }));
1088
+ } }), _jsx("span", { style: { fontFamily: theme.fontFamily }, children: key })] }, key))) }, keyPrefix + 'right.'))] }));
1071
1089
  }
1072
1090
  else {
1073
1091
  const columnName = node.left.column;
@@ -1121,7 +1139,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1121
1139
  }
1122
1140
  case 'column_ref': {
1123
1141
  const options = getAllPossibleColumns().map((column) => ({
1124
- label: column.displayName,
1142
+ label: snakeCaseToTitleCase(column.displayName),
1125
1143
  value: column.name,
1126
1144
  }));
1127
1145
  return (_jsx(Select, { theme: theme, style: { width: '120px' }, value: node.column ?? options[0]?.value, onChange: (value) => {
@@ -1248,10 +1266,10 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1248
1266
  isInTheCurrentIntervalSentence ??
1249
1267
  isInTheLastIntervalSentence ??
1250
1268
  isInThePreviousIntervalSentence ?? (_jsxs(_Fragment, { children: [node.left &&
1251
- renderSentence(formData, node.left, keyPrefix + 'left.', false, false, isRow), isRow ? (' ' + OPS[node.operator] + ' ') : topLevelBinaryOperator === 'OR' ? (_jsx(TopLevelBooleanSwitch, { node: node, keyPrefix: keyPrefix, handleOperatorChange: handleOperatorChange, Select: Select })) : null, node.right &&
1269
+ renderSentence(formData, node.left, keyPrefix + 'left.', false, false, isRow), isRow ? (' ' + OPS[node.operator] + ' ') : isTopLevel || topLevelBinaryOperator === 'OR' ? (_jsx(TopLevelBooleanSwitch, { node: node, keyPrefix: keyPrefix, handleOperatorChange: handleOperatorChange, Select: Select })) : null, node.right &&
1252
1270
  renderSentence(formData, node.right, keyPrefix + 'right.', false, false, isRow)] })) }));
1253
1271
  case 'column_ref':
1254
- return node.column;
1272
+ return snakeCaseToTitleCase(node.column);
1255
1273
  case 'expr_list':
1256
1274
  if (node.value.length === 1) {
1257
1275
  const subQuery = renderSentence(formData, node.value[0]);
@@ -1283,10 +1301,10 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1283
1301
  if (node.args.value.length < 1)
1284
1302
  return null;
1285
1303
  if (node.args.value[0].value) {
1286
- return node.args.value[0].value.replaceAll('%', '');
1304
+ return snakeCaseToTitleCase(node.args.value[0].value.replaceAll('%', ''));
1287
1305
  }
1288
1306
  if (node.args.value[0].column)
1289
- return node.args.value[0].column.replaceAll('%', '');
1307
+ return snakeCaseToTitleCase(node.args.value[0].column.replaceAll('%', ''));
1290
1308
  return null;
1291
1309
  }
1292
1310
  if (node.name.toLowerCase() === 'current_date' ||
@@ -1323,37 +1341,22 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1323
1341
  const tableNamesInQuery = baseAst.from.map((tbl) => tbl.table);
1324
1342
  return schemaTables
1325
1343
  .filter((t) => tableNamesInQuery.includes(t.displayName))
1326
- .flatMap((table) => table.columns.map((c) => ({
1344
+ .flatMap((table) => table.columns
1345
+ .map((c) => ({
1327
1346
  ...c,
1328
1347
  table: table.displayName,
1329
- })));
1330
- };
1331
- const getDateColumns = () => {
1332
- const allColumns = getAllPossibleColumns();
1333
- return allColumns.filter((c) => isDateishColumnType(c.fieldType));
1334
- };
1335
- const getNumericColumns = () => {
1336
- const allColumns = getAllPossibleColumns();
1337
- const selectedColumnNames = selectedColumns.map((col) => col.split('.')[1]);
1338
- return allColumns
1339
- .filter((column) => {
1340
- return selectedColumnNames.includes(column.name);
1341
- })
1342
- .filter((c) => isNumericColumnType(c.fieldType));
1343
- };
1344
- const getNonNumericColumns = () => {
1345
- const allColumns = getAllPossibleColumns();
1346
- const selectedColumnNames = selectedColumns.map((col) => col.split('.')[1]);
1347
- return allColumns
1348
- .filter((column) => selectedColumnNames.includes(column.name))
1349
- .filter((c) => !isNumericColumnType(c.fieldType));
1350
- };
1351
- const getStringColumns = () => {
1352
- const allColumns = getAllPossibleColumns();
1353
- const selectedColumnNames = selectedColumns.map((col) => col.split('.')[1]);
1354
- return allColumns
1355
- .filter((column) => selectedColumnNames.includes(column.name))
1356
- .filter((c) => isTextColumnType(c.fieldType));
1348
+ }))
1349
+ .sort((a, b) => {
1350
+ const aIsId = a.name.toLowerCase() === 'id' ||
1351
+ a.name.toLowerCase().endsWith('_id');
1352
+ const bIsId = b.name.toLowerCase() === 'id' ||
1353
+ b.name.toLowerCase().endsWith('_id');
1354
+ if (aIsId && !bIsId)
1355
+ return 1;
1356
+ if (bIsId && !aIsId)
1357
+ return -1;
1358
+ return 0;
1359
+ }));
1357
1360
  };
1358
1361
  /**
1359
1362
  * Return whether all columns have been selected (used to hide select all
@@ -1377,26 +1380,6 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1377
1380
  },
1378
1381
  as: null,
1379
1382
  });
1380
- const SortableItem = ({ id, label, setSelectedColumns, selectedColumns, }) => {
1381
- const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: id });
1382
- const style = {
1383
- transform: DND_CSS.Transform.toString(transform),
1384
- transition,
1385
- };
1386
- const handleSelect = () => {
1387
- setSelectedColumns((selectedColumns) => {
1388
- if (selectedColumns.includes(id)) {
1389
- return selectedColumns.filter((column) => column !== id);
1390
- }
1391
- else {
1392
- return [...selectedColumns, id];
1393
- }
1394
- });
1395
- };
1396
- return (_jsx("div", { style: { userSelect: 'none', ...style }, ref: setNodeRef, children: _jsx(SelectColumn, { selected: selectedColumns?.includes(id), setSelected: handleSelect, label: label, children: _jsx("div", { style: {
1397
- cursor: 'grab',
1398
- }, ...attributes, ...listeners, children: _jsx(HandleButton, {}) }) }) }));
1399
- };
1400
1383
  const AddConditionPopover = ({ onSave }) => {
1401
1384
  return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx("h1", { style: {
1402
1385
  fontWeight: '600',
@@ -1410,8 +1393,10 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1410
1393
  justifyContent: 'end',
1411
1394
  }, children: _jsx(Button, { onClick: onSave, label: 'Add condition' }) })] }));
1412
1395
  };
1413
- const fetchUponChange = async () => {
1414
- if ((formData || baseAst) && !loading) {
1396
+ const fetchUponChange = async (baseAst, newFormData) => {
1397
+ // if newFormData is null still use it
1398
+ const curFormData = newFormData !== undefined ? newFormData : formData;
1399
+ if ((curFormData || baseAst) && !loading) {
1415
1400
  try {
1416
1401
  setLoading(true);
1417
1402
  const res2 = await fetch('https://quill-344421.uc.r.appspot.com/patterns', {
@@ -1420,7 +1405,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1420
1405
  'Content-Type': 'application/json',
1421
1406
  },
1422
1407
  body: JSON.stringify({
1423
- ast: { ...baseAst, where: formData },
1408
+ ast: { ...baseAst, where: curFormData },
1424
1409
  publicKey: client.publicKey,
1425
1410
  orgId: client.customerId,
1426
1411
  }),
@@ -1429,6 +1414,21 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1429
1414
  if (data2.rows && data2.rows.length) {
1430
1415
  const tables = getTableNames(baseAst);
1431
1416
  const table = tables.length >= 1 ? tables[0] : initialTableName;
1417
+ if (table !== currentTable) {
1418
+ getDistinctValues(table);
1419
+ setCurrentTable(table);
1420
+ }
1421
+ const sortedFields = data2.fields.sort((a, b) => {
1422
+ const aIsId = a.name.toLowerCase() === 'id' ||
1423
+ a.name.toLowerCase().endsWith('_id');
1424
+ const bIsId = b.name.toLowerCase() === 'id' ||
1425
+ b.name.toLowerCase().endsWith('_id');
1426
+ if (aIsId && !bIsId)
1427
+ return 1;
1428
+ if (bIsId && !aIsId)
1429
+ return -1;
1430
+ return 0;
1431
+ });
1432
1432
  if (pivot) {
1433
1433
  // Do all of this to make sure we have the right unique columns when applying a pivot
1434
1434
  let uniqueFormatted = {};
@@ -1439,7 +1439,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1439
1439
  uniqueFormatted[pivot.columnField] = uniqueRecords;
1440
1440
  const pivotedData = generatePivotTable(pivot, data2.rows, [null, null, null], false);
1441
1441
  console.info(`%c[Pivot]: ${JSON.stringify(pivot)}`, 'color: dimgray');
1442
- setPivotData(pivotedData);
1442
+ setPivotData(pivotedData || []);
1443
1443
  setRows(data2.rows);
1444
1444
  setFields(data2.fields);
1445
1445
  }
@@ -1562,8 +1562,35 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1562
1562
  }
1563
1563
  return false;
1564
1564
  };
1565
- const handleAsk = async () => {
1566
- if (!aiPrompt) {
1565
+ const getDistinctValues = async (table, overrideSchema) => {
1566
+ const schemaInfo = overrideSchema || schemaTables;
1567
+ const tableInfo = schemaInfo.find((tableInfo) => tableInfo.name === table);
1568
+ if (tableInfo) {
1569
+ const pendingFetches = [];
1570
+ for (let column of tableInfo.columns) {
1571
+ if (!isTextColumnType(column.fieldType))
1572
+ continue;
1573
+ const fetchPromise = fetchDistinctHelper(column.name, tableInfo.displayName);
1574
+ pendingFetches.push(fetchPromise);
1575
+ }
1576
+ const newUniqueValues = {};
1577
+ const resolvedPromises = await Promise.all(pendingFetches);
1578
+ for (const resolvedData of resolvedPromises) {
1579
+ if (resolvedData) {
1580
+ const { table, column, values } = resolvedData;
1581
+ if (!newUniqueValues[table]) {
1582
+ newUniqueValues[table] = {};
1583
+ }
1584
+ newUniqueValues[table][column] = values;
1585
+ }
1586
+ }
1587
+ if (hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
1588
+ setUniqueValues(newUniqueValues);
1589
+ }
1590
+ }
1591
+ };
1592
+ const handleAsk = async (overridePrompt = '') => {
1593
+ if (!aiPrompt && !overridePrompt) {
1567
1594
  return;
1568
1595
  }
1569
1596
  try {
@@ -1582,7 +1609,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1582
1609
  method: 'POST',
1583
1610
  headers: { 'Content-Type': 'application/json' },
1584
1611
  body: JSON.stringify({
1585
- initialQuestion: aiPrompt,
1612
+ initialQuestion: aiPrompt || overridePrompt,
1586
1613
  publicKey: client.publicKey,
1587
1614
  }),
1588
1615
  });
@@ -1630,11 +1657,14 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1630
1657
  newAst = removeNonSelectedTableReferences(newAst, tableAlias ?? table);
1631
1658
  // newAst = convertDateComparison(newAst); // TODO
1632
1659
  ast = newAst; // so we fetch data for newAst later.
1660
+ if (table !== currentTable) {
1661
+ getDistinctValues(table);
1662
+ setCurrentTable(table);
1663
+ }
1633
1664
  setPivotRowField(groupByPivot?.rowField);
1634
1665
  setPivotColumnField(groupByPivot?.columnField);
1635
1666
  setPivotValueField(groupByPivot?.valueField);
1636
1667
  setPivotAggregation(groupByPivot?.aggregationType);
1637
- setPivot(groupByPivot);
1638
1668
  setSelectedColumns(deepCopy(newAst).columns?.map((column) => {
1639
1669
  if (column.expr.type === 'column_ref') {
1640
1670
  return `${table}.${column.expr.column}`;
@@ -1645,7 +1675,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1645
1675
  return `${table}.${column.expr.value}`;
1646
1676
  }));
1647
1677
  if (groupByPivot) {
1648
- setBaseAst(deepCopy({ ...newAst, orderby: null }));
1678
+ setBaseAst(deepCopy({ ...newAst, orderby: null, limit: null }));
1649
1679
  }
1650
1680
  else {
1651
1681
  setBaseAst(deepCopy({ ...newAst }));
@@ -1654,8 +1684,6 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1654
1684
  setTopLevelBinaryOperator(
1655
1685
  // @ts-ignore
1656
1686
  newAst?.where ? newAst?.where?.operator : 'AND');
1657
- if (groupByPivot)
1658
- return; // the useEffect will handle the rest
1659
1687
  }
1660
1688
  const res2 = await fetch('https://quill-344421.uc.r.appspot.com/patterns', {
1661
1689
  method: 'POST',
@@ -1671,11 +1699,13 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1671
1699
  const data2 = await res2.json();
1672
1700
  if (data2.rows && data2.rows.length) {
1673
1701
  const tables = getTableNames(newAst);
1674
- const table = tables.length >= 1 ? tables[0] : initialTableName;
1675
1702
  if (groupByPivot) {
1676
- const pivotedData = generatePivotTable(pivot, data2.rows, [null, null, null], false);
1703
+ const pivotedData = generatePivotTable(
1704
+ // @ts-ignore
1705
+ groupByPivot, data2.rows, [null, null, null], false);
1677
1706
  console.info(`%c[Pivot]: ${JSON.stringify(groupByPivot)}`, 'color: dimgray');
1678
1707
  setPivotData(pivotedData);
1708
+ setPivot(groupByPivot);
1679
1709
  setRows(data2.rows);
1680
1710
  setFields(data2.fields);
1681
1711
  }
@@ -1685,6 +1715,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1685
1715
  }
1686
1716
  }
1687
1717
  else {
1718
+ setPivotData([]);
1688
1719
  setRows([]);
1689
1720
  setFields([]);
1690
1721
  }
@@ -1703,7 +1734,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1703
1734
  }
1704
1735
  catch (e) {
1705
1736
  console.error(e);
1706
- setErrorMessage(`${e.name}: ${e.message}`);
1737
+ setErrorMessage(`Error: Couldn't process your request, please re-word your prompt.`);
1707
1738
  }
1708
1739
  finally {
1709
1740
  setLoading(false);
@@ -1729,11 +1760,17 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1729
1760
  clearAllState();
1730
1761
  return;
1731
1762
  }
1732
- const newAst = { ...baseAst, columns };
1733
- setBaseAst(deepCopy(newAst));
1763
+ const newAst = deepCopy({ ...baseAst, columns });
1764
+ setBaseAst(newAst);
1765
+ fetchSqlQuery(newAst);
1734
1766
  };
1735
1767
  function TopLevelBooleanSwitch({ node, keyPrefix, handleOperatorChange, }) {
1736
- return (_jsx("div", { style: { width: 'fit-content' }, children: _jsx(Tabs, { defaultValue: node.operator, options: DEFAULT_TAB_OPTIONS, onValueChange: (value) => handleOperatorChange(value, node, keyPrefix) }) }));
1768
+ return (_jsx("div", { style: { width: 'fit-content' }, children: _jsx(Tabs, { defaultValue: node.operator, options: DEFAULT_TAB_OPTIONS, onValueChange: (value) => {
1769
+ if (loading) {
1770
+ return;
1771
+ }
1772
+ handleOperatorChange(value, node, keyPrefix);
1773
+ } }) }));
1737
1774
  }
1738
1775
  const DraggableItem = ({ id, label, onDelete }) => {
1739
1776
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: id });
@@ -1741,7 +1778,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1741
1778
  transform: DND_CSS.Transform.toString(transform),
1742
1779
  transition,
1743
1780
  };
1744
- return (_jsx("div", { style: { ...style }, ref: setNodeRef, children: _jsx(DraggableColumn, { label: label, onDelete: onDelete, children: _jsx("div", { style: {
1781
+ return (_jsx("div", { style: { ...style }, ref: setNodeRef, children: _jsx(DraggableColumn, { label: snakeCaseToTitleCase(label), onDelete: onDelete, children: _jsx("div", { style: {
1745
1782
  cursor: 'grab',
1746
1783
  }, ...attributes, ...listeners, children: _jsx(HandleButton, {}) }) }) }));
1747
1784
  };
@@ -1779,6 +1816,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1779
1816
  };
1780
1817
  const newAst = baseAst ? newBaseAst : fallbackAST;
1781
1818
  setBaseAst(newAst);
1819
+ fetchSqlQuery(newAst);
1782
1820
  }
1783
1821
  }
1784
1822
  const columnNamesInAst = baseAst?.columns.map((col) => {
@@ -1802,18 +1840,6 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1802
1840
  gap: 8,
1803
1841
  }, children: [columnNamesInAst.map((name) => (_jsx(DraggableItem, { id: name, label: name, onDelete: () => handleDeleteColumn(name) }, name))), columnNamesInAst?.length > 0 && _jsx("div", { style: { height: 6 } })] }) }) }));
1804
1842
  }
1805
- const allNumericColumns = getNumericColumns().map((column) => ({
1806
- label: column.displayName,
1807
- value: column.name,
1808
- }));
1809
- const allNonNumericColumns = getNonNumericColumns().map((column) => ({
1810
- label: column.displayName,
1811
- value: column.name,
1812
- }));
1813
- const allStringColumns = getStringColumns().map((column) => ({
1814
- label: column.displayName,
1815
- value: column.name,
1816
- }));
1817
1843
  if (loading) {
1818
1844
  return (_jsxs("div", { style: {
1819
1845
  display: 'flex',
@@ -1824,7 +1850,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1824
1850
  if (!openPopover) {
1825
1851
  setOpenPopover('AddColumnPopover');
1826
1852
  }
1827
- }, label: 'Select columns' }), title: "Select columns", onClose: () => {
1853
+ }, label: 'Select columns' }), label: "Select columns", onClose: () => {
1828
1854
  setIsPending(false);
1829
1855
  setActiveEditItem(null);
1830
1856
  setActivePath(null);
@@ -1833,7 +1859,10 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1833
1859
  setActiveEditItem(null);
1834
1860
  setActivePath(null);
1835
1861
  setOpenPopover(null);
1836
- }, orderedColumnNames: orderedColumnNames, setOrderedColumnNames: setOrderedColumnNames, selectedColumns: selectedColumns, setSelectedColumns: setSelectedColumns, isSelectedAllColumns: isSelectedAllColumns, clearAllState: clearAllState, nameToColumn: nameToColumn, baseAst: baseAst, setBaseAst: setBaseAst, pivot: pivot, initialTableName: initialTableName, defaultAST: defaultAST, defaultTable: defaultTable, setPivot: setPivot, TextInput: TextInput, SelectColumn: SelectColumn, SecondaryButton: SecondaryButton, Button: Button, HandleButton: HandleButton }) }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Filters" }), _jsx("div", { style: { height: 4, width: '100%' } }), formData && (_jsx("div", { style: {
1862
+ }, orderedColumnNames: orderedColumnNames, setOrderedColumnNames: setOrderedColumnNames, selectedColumns: selectedColumns, setSelectedColumns: setSelectedColumns, isSelectedAllColumns: isSelectedAllColumns, clearAllState: clearAllState, nameToColumn: nameToColumn, baseAst: baseAst, setBaseAst: (newAst) => {
1863
+ setBaseAst(newAst);
1864
+ fetchSqlQuery(newAst);
1865
+ }, pivot: pivot, initialTableName: initialTableName, defaultAST: defaultAST, defaultTable: defaultTable, setPivot: setPivot, TextInput: TextInput, SelectColumn: SelectColumn, SecondaryButton: SecondaryButton, Button: Button, HandleButton: HandleButton }) }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Filters" }), _jsx("div", { style: { height: 4, width: '100%' } }), formData && (_jsx("div", { style: {
1837
1866
  display: 'flex',
1838
1867
  flexDirection: 'column',
1839
1868
  gap: 8,
@@ -1844,6 +1873,9 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1844
1873
  gap: 2.5,
1845
1874
  alignItems: 'flex-start',
1846
1875
  }, children: [_jsx(Popover, { isOpen: openPopover === 'AddFilterPopover', title: 'Add filter', trigger: _jsx(SecondaryButton, { onClick: () => {
1876
+ if (!selectedColumns || selectedColumns.length === 0) {
1877
+ return;
1878
+ }
1847
1879
  if (!openPopover) {
1848
1880
  const value = orderedColumnNames[0];
1849
1881
  const [_table, column] = value.split('.');
@@ -1930,14 +1962,18 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1930
1962
  } }) }))] }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Pivot" }), _jsx("div", { style: { height: 4, width: '100%' } }), _jsx(PivotModal, { pivotRowField: pivotRowField, setPivotRowField: setPivotRowField, pivotColumnField: pivotColumnField, setPivotColumnField: setPivotColumnField, pivotValueField: pivotValueField, setPivotValueField: setPivotValueField, pivotAggregation: pivotAggregation, setPivotAggregation: setPivotAggregation, createdPivots: createdPivots, setCreatedPivots: setCreatedPivots, recommendedPivots: recommendedPivots, setRecommendedPivots: setRecommendedPivots, popUpTitle: pivotPopUpTitle, setPopUpTitle: setPivotPopUpTitle, selectedTable: initialTableName, SelectComponent: Select, ButtonComponent: Button, PopoverComponent: PivotPopover, TextComponent: Text, isOpen: showPivotPopover, setIsOpen: setShowPivotPopover, showUpdatePivot: isEdittingPivot, setShowUpdatePivot: setIsEdittingPivot, parentRef: parentRef, data: rows, columns: processColumnsForChartBuilder(Object.keys(rows[0] ?? {})), triggerButtonText: 'Add pivot', selectedPivotIndex: selectedPivotIndex, setSelectedPivotIndex: setSelectedPivotIndex, removePivot: () => {
1931
1963
  setPivot(null);
1932
1964
  setPivotData(null);
1933
- }, selectPivot: (pivot) => {
1965
+ },
1966
+ // TODOs
1967
+ selectPivot: (pivot) => {
1934
1968
  if (!pivot)
1935
1969
  return;
1936
1970
  const newAst = { ...baseAst };
1937
1971
  newAst.orderby = null;
1938
1972
  setBaseAst(newAst); // trigger refetch
1939
1973
  setPivot(pivot);
1940
- }, selectPivotOnEdit: true, showTrigger: !pivot || !pivotData, theme: theme, LabelComponent: Label, HeaderComponent: Header, dateRange: [null, null, null], recommendPivotCount: 3 }), pivot && pivotData && (_jsx(PivotCard, { pivotTable: {
1974
+ const pivotedData = generatePivotTable(pivot, rows, [null, null, null], false);
1975
+ setPivotData(pivotedData || []);
1976
+ }, selectPivotOnEdit: true, showTrigger: !pivot, theme: theme, LabelComponent: Label, HeaderComponent: Header, dateRange: [null, null, null], recommendPivotCount: 3, SecondaryButtonComponent: SecondaryButton }), pivot && (_jsx(PivotCard, { pivotTable: {
1941
1977
  pivot: pivot,
1942
1978
  rows: pivotData?.rows || [],
1943
1979
  columns: pivotData?.columns || [],
@@ -1964,10 +2000,16 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1964
2000
  }, columns: selectedColumns, setIsPending: setIsPending, setEditPopoverKey: setEditPopoverKey, setActiveEditItem: setActiveEditItem, setOpenPopover: setOpenPopover, SortPopover: SortPopover, EditPopover: AddSortPopover, handleDelete: () => {
1965
2001
  setPivot({ ...pivot, sort: false });
1966
2002
  setBaseAst(deepCopy(baseAst));
2003
+ if (!pivot) {
2004
+ fetchSqlQuery(baseAst);
2005
+ }
1967
2006
  }, onSave: (column, direction) => {
1968
2007
  setPivot({ ...pivot, sort: true, sortDirection: direction });
1969
2008
  setOpenPopover(null);
1970
2009
  setBaseAst(deepCopy(baseAst));
2010
+ if (!pivot) {
2011
+ fetchSqlQuery(baseAst);
2012
+ }
1971
2013
  } }, `sort-sentence-pivot`) })), baseAst && baseAst.orderby && (_jsx("div", { style: {
1972
2014
  display: 'flex',
1973
2015
  flexDirection: 'column',
@@ -1992,11 +2034,17 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
1992
2034
  setActivePath(null);
1993
2035
  setOpenPopover(null);
1994
2036
  setBaseAst(deepCopy(newAst));
2037
+ if (!pivot) {
2038
+ fetchSqlQuery(newAst);
2039
+ }
1995
2040
  }, setIsPending: setIsPending, setEditPopoverKey: setEditPopoverKey, setActiveEditItem: setActiveEditItem, setOpenPopover: setOpenPopover, SortPopover: SortPopover, EditPopover: AddSortPopover, handleDelete: () => {
1996
2041
  const newAst = { ...baseAst };
1997
2042
  newAst.orderby.splice(id, 1);
1998
2043
  setBaseAst(deepCopy(newAst));
1999
- } }, `sort-sentence-${id}`))) })), _jsx(Popover, { isOpen: openPopover === 'AddSortPopover', trigger: _jsx(SecondaryButton, { onClick: () => {
2044
+ if (!pivot) {
2045
+ fetchSqlQuery(newAst);
2046
+ }
2047
+ } }, `sort-sentence-${id}`))) })), _jsx(Popover, { isOpen: openPopover === 'AddSortPopover', setIsOpen: () => { }, trigger: _jsx(SecondaryButton, { onClick: () => {
2000
2048
  if (!openPopover) {
2001
2049
  setOpenPopover('AddSortPopover');
2002
2050
  }
@@ -2005,18 +2053,51 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2005
2053
  setActiveEditItem(null);
2006
2054
  setActivePath(null);
2007
2055
  setOpenPopover(null);
2008
- }, children: _jsx(AddSortPopover, { columns: selectedColumns, Select: Select, Button: Button, onSave: () => { } }) })] }), _jsxs(Container, { children: [!hideAi && (_jsxs("form", { onSubmit: (event) => {
2056
+ }, children: _jsx(AddSortPopover, { columns: selectedColumns, Select: Select, Button: Button, onSave: () => { } }) }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Limit" }), _jsx("div", { style: { height: 4, width: '100%' } }), baseAst && baseAst.limit ? (_jsx("div", { style: {
2057
+ display: 'flex',
2058
+ flexDirection: 'column',
2059
+ gap: 8,
2060
+ marginBottom: 12,
2061
+ }, children: _jsx(LimitSentence, { limit: baseAst.limit, setOpenPopover: setOpenPopover, LimitPopover: SortPopover, EditPopover: AddLimitPopover, handleDelete: () => {
2062
+ const newAst = { ...baseAst };
2063
+ newAst.limit = null;
2064
+ setBaseAst(deepCopy(newAst));
2065
+ fetchSqlQuery(newAst);
2066
+ }, onSave: (limit) => {
2067
+ const newAst = { ...baseAst };
2068
+ newAst.limit = {
2069
+ seperator: '',
2070
+ value: [
2071
+ {
2072
+ type: 'number',
2073
+ value: limit,
2074
+ },
2075
+ ],
2076
+ };
2077
+ setOpenPopover(null);
2078
+ setBaseAst(deepCopy(newAst));
2079
+ fetchSqlQuery(newAst);
2080
+ } }) })) : (_jsx(Popover, { isOpen: openPopover === 'AddLimitPopover', setIsOpen: () => { }, trigger: _jsx(SecondaryButton, { onClick: () => {
2081
+ if (!openPopover) {
2082
+ setOpenPopover('AddLimitPopover');
2083
+ }
2084
+ }, label: 'Add limit' }), title: "Limit", onClose: () => {
2085
+ setIsPending(false);
2086
+ setActiveEditItem(null);
2087
+ setActivePath(null);
2088
+ setOpenPopover(null);
2089
+ }, children: _jsx(TextInput, { value: 0, type: "number", style: { width: 120, minHeight: 32 }, onChange: (e) => { } }) }))] }), _jsxs(Container, { children: [!hideAi && (_jsxs("form", { onSubmit: (event) => {
2009
2090
  event.preventDefault();
2010
2091
  }, style: {
2011
2092
  display: 'flex',
2012
2093
  flexDirection: 'row',
2013
2094
  gap: 12,
2014
2095
  padding: 1,
2015
- }, children: [_jsx(TextInput, { placeholder: "Ask a question...", type: "text", style: { width: '100%', fontSize: 14 }, value: aiPrompt }), _jsx(Button, { onClick: () => { }, label: 'Ask AI' }), baseAst && (_jsx(SecondaryButton, { onClick: clearAllState, label: "New report" }))] })), baseAst && (_jsxs(_Fragment, { children: [_jsx(TableLoadingState, {}), _jsxs("div", { style: {
2096
+ }, children: [_jsx(TextInput, { placeholder: baseAst ? 'Ask a follow-up question...' : 'Ask a question...', type: "text", style: { width: '100%', fontSize: 14 }, value: aiPrompt }), _jsx(Button, { onClick: () => { }, label: 'Ask AI' }), baseAst && (_jsx(SecondaryButton, { onClick: clearAllState, label: "New report" }))] })), _jsxs(_Fragment, { children: [_jsx(TableLoadingState, {}), _jsxs("div", { style: {
2016
2097
  display: 'flex',
2017
2098
  flexDirection: 'row',
2018
2099
  gap: '12px',
2019
- }, children: [_jsx("div", { style: { width: '100%' } }), _jsx(SecondaryButton, { onClick: () => copyToClipboard(activeQuery), label: isCopying ? '✅ Copied' : 'Copy SQL' }), _jsx(Button, { label: 'Add to dashboard', onClick: () => { } })] })] }))] }), _jsx("style", { children: `body{margin:0;}` })] }));
2100
+ }, children: [_jsx("div", { style: { width: '100%' } }), _jsx(SecondaryButton, { onClick: () => copyToClipboard(activeQuery), label: isCopying ? '✅ Copied' : 'Copy SQL' }), _jsx(Button, { label: 'Add to dashboard', onClick: () => { } })] })] })] }), _jsx("style", { children: `body{margin:0;}` })] }));
2020
2101
  }
2021
2102
  return (_jsxs("div", { ref: parentRef, style: {
2022
2103
  display: 'flex',
@@ -2041,7 +2122,10 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2041
2122
  setActiveEditItem(null);
2042
2123
  setActivePath(null);
2043
2124
  setOpenPopover(null);
2044
- }, orderedColumnNames: orderedColumnNames, setOrderedColumnNames: setOrderedColumnNames, selectedColumns: selectedColumns, setSelectedColumns: setSelectedColumns, isSelectedAllColumns: isSelectedAllColumns, clearAllState: clearAllState, nameToColumn: nameToColumn, baseAst: baseAst, setBaseAst: setBaseAst, pivot: pivot, initialTableName: initialTableName, defaultAST: defaultAST, defaultTable: defaultTable, setPivot: setPivot, TextInput: TextInput, SelectColumn: SelectColumn, SecondaryButton: SecondaryButton, Button: Button, HandleButton: HandleButton }) }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Filters" }), _jsx("div", { style: { height: 4, width: '100%' } }), formData && (_jsx("div", { style: {
2125
+ }, orderedColumnNames: orderedColumnNames, setOrderedColumnNames: setOrderedColumnNames, selectedColumns: selectedColumns, setSelectedColumns: setSelectedColumns, isSelectedAllColumns: isSelectedAllColumns, clearAllState: clearAllState, nameToColumn: nameToColumn, baseAst: baseAst, setBaseAst: (ast) => {
2126
+ setBaseAst(ast);
2127
+ fetchSqlQuery(ast);
2128
+ }, pivot: pivot, initialTableName: initialTableName, defaultAST: defaultAST, defaultTable: defaultTable, setPivot: setPivot, TextInput: TextInput, SelectColumn: SelectColumn, SecondaryButton: SecondaryButton, Button: Button, HandleButton: HandleButton }) }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Filters" }), _jsx("div", { style: { height: 4, width: '100%' } }), formData && (_jsx("div", { style: {
2045
2129
  display: 'flex',
2046
2130
  flexDirection: 'column',
2047
2131
  gap: 8,
@@ -2052,6 +2136,9 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2052
2136
  gap: 2.5,
2053
2137
  alignItems: 'flex-start',
2054
2138
  }, children: [_jsx(Popover, { title: 'Add filter', isOpen: openPopover === 'AddFilterPopover', trigger: _jsx(SecondaryButton, { onClick: () => {
2139
+ if (!selectedColumns || selectedColumns.length === 0) {
2140
+ return;
2141
+ }
2055
2142
  if (!openPopover) {
2056
2143
  const value = orderedColumnNames[0];
2057
2144
  const [_table, column] = value.split('.');
@@ -2137,7 +2224,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2137
2224
  setOpenPopover(null);
2138
2225
  clearCheckboxes();
2139
2226
  }
2140
- } }) }))] }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Pivot" }), _jsx("div", { style: { height: 4, width: '100%' } }), _jsx(PivotModal, { pivotRowField: pivotRowField, setPivotRowField: setPivotRowField, pivotColumnField: pivotColumnField, setPivotColumnField: setPivotColumnField, pivotValueField: pivotValueField, setPivotValueField: setPivotValueField, pivotAggregation: pivotAggregation, setPivotAggregation: setPivotAggregation, createdPivots: createdPivots, setCreatedPivots: setCreatedPivots, recommendedPivots: recommendedPivots, setRecommendedPivots: setRecommendedPivots, popUpTitle: pivotPopUpTitle, setPopUpTitle: setPivotPopUpTitle, selectedTable: initialTableName, SelectComponent: Select, ButtonComponent: Button, PopoverComponent: PivotPopover, TextComponent: Text, isOpen: showPivotPopover, setIsOpen: setShowPivotPopover, showUpdatePivot: isEdittingPivot, setShowUpdatePivot: setIsEdittingPivot, parentRef: parentRef, data: rows, columns: processColumnsForChartBuilder(Object.keys(rows[0] ?? {})), triggerButtonText: 'Add pivot', selectedPivotIndex: selectedPivotIndex, setSelectedPivotIndex: setSelectedPivotIndex, removePivot: () => {
2227
+ } }) }))] }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Pivot" }), _jsx("div", { style: { height: 4, width: '100%' } }), _jsx(PivotModal, { pivotRowField: pivotRowField, setPivotRowField: setPivotRowField, pivotColumnField: pivotColumnField, setPivotColumnField: setPivotColumnField, pivotValueField: pivotValueField, setPivotValueField: setPivotValueField, pivotAggregation: pivotAggregation, setPivotAggregation: setPivotAggregation, createdPivots: createdPivots, setCreatedPivots: setCreatedPivots, recommendedPivots: recommendedPivots, setRecommendedPivots: setRecommendedPivots, popUpTitle: pivotPopUpTitle, setPopUpTitle: setPivotPopUpTitle, selectedTable: initialTableName, SelectComponent: Select, ButtonComponent: Button, SecondaryButtonComponent: SecondaryButton, PopoverComponent: PivotPopover, TextComponent: Text, isOpen: showPivotPopover, setIsOpen: setShowPivotPopover, showUpdatePivot: isEdittingPivot, setShowUpdatePivot: setIsEdittingPivot, parentRef: parentRef, data: rows, columns: processColumnsForChartBuilder(Object.keys(rows[0] ?? {})), triggerButtonText: 'Add pivot', selectedPivotIndex: selectedPivotIndex, setSelectedPivotIndex: setSelectedPivotIndex, removePivot: () => {
2141
2228
  setPivot(null);
2142
2229
  setPivotData(null);
2143
2230
  }, selectPivot: (pivot) => {
@@ -2151,7 +2238,9 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2151
2238
  }
2152
2239
  setBaseAst(newAst); // trigger refetch
2153
2240
  setPivot(pivot);
2154
- }, selectPivotOnEdit: true, showTrigger: !pivot || !pivotData, theme: theme, LabelComponent: Label, HeaderComponent: Header, dateRange: [null, null, null], recommendPivotCount: 3 }), pivot && pivotData && (_jsx(PivotCard, { pivotTable: {
2241
+ const pivotedData = generatePivotTable(pivot, rows, [null, null, null], false);
2242
+ setPivotData(pivotedData || []);
2243
+ }, selectPivotOnEdit: true, showTrigger: !pivot, theme: theme, LabelComponent: Label, HeaderComponent: Header, dateRange: [null, null, null], recommendPivotCount: 3 }), pivot && (_jsx(PivotCard, { pivotTable: {
2155
2244
  pivot: pivot,
2156
2245
  rows: pivotData?.rows || [],
2157
2246
  columns: pivotData?.columns || [],
@@ -2166,7 +2255,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2166
2255
  }, selectedPivotIndex: -1, onEditPivot: () => { }, ButtonComponent: Button, HeaderComponent: Header, showEdit: false, onClose: () => {
2167
2256
  setPivot(null);
2168
2257
  setPivotData(null);
2169
- setBaseAst(deepCopy(baseAst)); // trigger refetch
2258
+ setBaseAst(deepCopy(baseAst));
2170
2259
  }, minHeight: 180, LabelComponent: Label, TextComponent: Text })), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Sort" }), _jsx("div", { style: { height: 4, width: '100%' } }), pivot && pivot.sort && (_jsx("div", { style: {
2171
2260
  display: 'flex',
2172
2261
  flexDirection: 'column',
@@ -2175,13 +2264,25 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2175
2264
  }, children: _jsx(SortSentence, { sortData: {
2176
2265
  type: pivot.sortDirection,
2177
2266
  expr: { type: 'column_ref', column: pivot.rowField },
2178
- }, columns: selectedColumns, setIsPending: setIsPending, setEditPopoverKey: setEditPopoverKey, setActiveEditItem: setActiveEditItem, setOpenPopover: setOpenPopover, SortPopover: SortPopover, EditPopover: AddSortPopover, handleDelete: () => {
2179
- setPivot({ ...pivot, sort: false });
2267
+ }, columns: pivot ? [`.${pivot.rowField}`] : selectedColumns, setIsPending: setIsPending, setEditPopoverKey: setEditPopoverKey, setActiveEditItem: setActiveEditItem, setOpenPopover: setOpenPopover, SortPopover: SortPopover, EditPopover: AddSortPopover, handleDelete: () => {
2268
+ if (pivot) {
2269
+ setPivot({ ...pivot, sort: false });
2270
+ const pivotedData = generatePivotTable({ ...pivot, sort: false }, rows, [null, null, null], false);
2271
+ setPivotData(pivotedData || []);
2272
+ return;
2273
+ }
2180
2274
  setBaseAst(deepCopy(baseAst));
2275
+ fetchSqlQuery(deepCopy(baseAst));
2181
2276
  }, onSave: (column, direction) => {
2182
- setPivot({ ...pivot, sort: true, sortDirection: direction });
2277
+ if (pivot) {
2278
+ setPivot({ ...pivot, sort: true, sortDirection: direction });
2279
+ const pivotedData = generatePivotTable({ ...pivot, sort: true, sortDirection: direction }, rows, [null, null, null], false);
2280
+ setPivotData(pivotedData || []);
2281
+ return;
2282
+ }
2183
2283
  setOpenPopover(null);
2184
2284
  setBaseAst(deepCopy(baseAst));
2285
+ fetchSqlQuery(deepCopy(baseAst));
2185
2286
  } }, `sort-sentence-pivot`) })), baseAst && baseAst.orderby && (_jsx("div", { style: {
2186
2287
  display: 'flex',
2187
2288
  flexDirection: 'column',
@@ -2195,6 +2296,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2195
2296
  const newAst = { ...baseAst };
2196
2297
  newAst.orderby.splice(id, 1);
2197
2298
  setBaseAst(deepCopy(newAst));
2299
+ fetchSqlQuery(deepCopy(newAst));
2198
2300
  }, onSave: (column, direction) => {
2199
2301
  if (pivot) {
2200
2302
  setPivot({
@@ -2222,6 +2324,7 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2222
2324
  setActivePath(null);
2223
2325
  setOpenPopover(null);
2224
2326
  setBaseAst(deepCopy(newAst));
2327
+ fetchSqlQuery(deepCopy(newAst));
2225
2328
  } }, `sort-sentence-${id}`))) })), _jsx(Popover, { isOpen: openPopover === 'AddSortPopover', trigger: _jsx(SecondaryButton, { onClick: () => {
2226
2329
  if (!openPopover) {
2227
2330
  setOpenPopover('AddSortPopover');
@@ -2236,6 +2339,8 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2236
2339
  return;
2237
2340
  if (pivot) {
2238
2341
  setPivot({ ...pivot, sort: true, sortDirection: direction });
2342
+ const pivotedData = generatePivotTable({ ...pivot, sort: true, sortDirection: direction }, rows, [null, null, null], false);
2343
+ setPivotData(pivotedData || []);
2239
2344
  setActivePath(null);
2240
2345
  setOpenPopover(null);
2241
2346
  setBaseAst(deepCopy(baseAst));
@@ -2252,7 +2357,58 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2252
2357
  setActivePath(null);
2253
2358
  setOpenPopover(null);
2254
2359
  setBaseAst(deepCopy(newAst));
2255
- } }) })] }), _jsxs(Container, { children: [!hideAi && (_jsxs("form", { onSubmit: (event) => {
2360
+ fetchSqlQuery(deepCopy(newAst));
2361
+ } }) }), _jsx("div", { style: { height: 28, width: '100%' } }), _jsx(SidebarHeading, { label: "Limit" }), _jsx("div", { style: { height: 4, width: '100%' } }), baseAst && baseAst.limit ? (_jsx("div", { style: {
2362
+ display: 'flex',
2363
+ flexDirection: 'column',
2364
+ gap: 8,
2365
+ marginBottom: 12,
2366
+ }, children: _jsx(LimitSentence, { limit: baseAst.limit, setOpenPopover: setOpenPopover, LimitPopover: SortPopover, EditPopover: AddLimitPopover, handleDelete: () => {
2367
+ const newAst = { ...baseAst };
2368
+ newAst.limit = null;
2369
+ setBaseAst(deepCopy(newAst));
2370
+ fetchSqlQuery(deepCopy(newAst));
2371
+ }, onSave: (limit) => {
2372
+ const newAst = { ...baseAst };
2373
+ newAst.limit = {
2374
+ seperator: '',
2375
+ value: [
2376
+ {
2377
+ type: 'number',
2378
+ value: limit,
2379
+ },
2380
+ ],
2381
+ };
2382
+ setOpenPopover(null);
2383
+ setBaseAst(deepCopy(newAst));
2384
+ fetchSqlQuery(deepCopy(newAst));
2385
+ } }) })) : (_jsx(Popover, { isOpen: openPopover === 'AddLimitPopover', setIsOpen: () => { }, trigger: _jsx(SecondaryButton, { onClick: () => {
2386
+ if (!baseAst) {
2387
+ return;
2388
+ }
2389
+ if (!openPopover) {
2390
+ setOpenPopover('AddLimitPopover');
2391
+ }
2392
+ }, label: 'Add limit' }), title: "Limit", onClose: () => {
2393
+ setIsPending(false);
2394
+ setActiveEditItem(null);
2395
+ setActivePath(null);
2396
+ setOpenPopover(null);
2397
+ }, children: _jsx(AddLimitPopover, { TextInput: TextInput, onSave: (limit) => {
2398
+ const newAst = { ...baseAst };
2399
+ newAst.limit = {
2400
+ seperator: '',
2401
+ value: [
2402
+ {
2403
+ type: 'number',
2404
+ value: Number(limit),
2405
+ },
2406
+ ],
2407
+ };
2408
+ setOpenPopover(null);
2409
+ setBaseAst(deepCopy(newAst));
2410
+ fetchSqlQuery(deepCopy(newAst));
2411
+ } }) }))] }), _jsxs(Container, { children: [!hideAi && (_jsxs("form", { onSubmit: (event) => {
2256
2412
  event.preventDefault();
2257
2413
  handleAsk();
2258
2414
  }, style: {
@@ -2263,9 +2419,10 @@ export default function ReportBuilder({ initialTableName = '', onAddToDashboardC
2263
2419
  }, children: [_jsx(TextInput, { type: "text", value: aiPrompt, style: { width: '100%', fontSize: 14 }, onChange: (e) => setAiPrompt(e.target.value), placeholder: baseAst ? 'Ask a follow-up question...' : 'Ask a question...' }), _jsx(Button, { onClick: handleAsk, label: 'Ask AI' }), baseAst && (_jsx(SecondaryButton, { label: 'New report', onClick: clearAllState }))] })), baseAst && (_jsx(_Fragment, { children: loading && errorMessage.length === 0 ? (_jsx(TableLoadingState, {})) : (_jsx(Table, { rows: applyFormatting({
2264
2420
  rows: pivotData?.rows || rows,
2265
2421
  fields: pivotData?.fields || fields,
2266
- }, baseAst?.columns ?? []), columns: pivotData?.columns ||
2267
- enforceOrderOnColumns(Object.keys(rows[0] ?? {})).map((c) => {
2268
- return { label: c, field: c };
2422
+ }, baseAst?.columns ?? []), columns: pivot
2423
+ ? pivotData?.columns || emptyPivotColumns()
2424
+ : enforceOrderOnColumns(Object.keys(rows[0] ?? {})).map((c) => {
2425
+ return { label: snakeCaseToTitleCase(c), field: c };
2269
2426
  }), error: errorMessage, rowsPerPage: 20 })) })), _jsxs("div", { style: {
2270
2427
  display: 'flex',
2271
2428
  flexDirection: 'row',