@quillsql/react 2.13.22 → 2.13.24

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 (65) hide show
  1. package/dist/cjs/ChartBuilder.d.ts +7 -3
  2. package/dist/cjs/ChartBuilder.d.ts.map +1 -1
  3. package/dist/cjs/ChartBuilder.js +36 -19
  4. package/dist/cjs/ReportBuilder.d.ts.map +1 -1
  5. package/dist/cjs/ReportBuilder.js +183 -233
  6. package/dist/cjs/SQLEditor.js +12 -10
  7. package/dist/cjs/components/Dashboard/DataLoader.d.ts.map +1 -1
  8. package/dist/cjs/components/QuillTable.d.ts +2 -1
  9. package/dist/cjs/components/QuillTable.d.ts.map +1 -1
  10. package/dist/cjs/components/QuillTable.js +5 -2
  11. package/dist/cjs/components/ReportBuilder/AddSortPopover.d.ts +1 -2
  12. package/dist/cjs/components/ReportBuilder/AddSortPopover.d.ts.map +1 -1
  13. package/dist/cjs/components/ReportBuilder/AddSortPopover.js +1 -2
  14. package/dist/cjs/components/ReportBuilder/convert.d.ts +1 -1
  15. package/dist/cjs/components/ReportBuilder/convert.d.ts.map +1 -1
  16. package/dist/cjs/components/ReportBuilder/convert.js +31 -4
  17. package/dist/cjs/components/ReportBuilder/util.js +1 -1
  18. package/dist/cjs/components/UiComponents.d.ts +3 -2
  19. package/dist/cjs/components/UiComponents.d.ts.map +1 -1
  20. package/dist/cjs/components/UiComponents.js +6 -3
  21. package/dist/cjs/utils/astFilterProcessing.d.ts.map +1 -1
  22. package/dist/cjs/utils/astFilterProcessing.js +921 -1604
  23. package/dist/cjs/utils/astProcessing.d.ts +1 -1
  24. package/dist/cjs/utils/astProcessing.d.ts.map +1 -1
  25. package/dist/cjs/utils/astProcessing.js +4 -2
  26. package/dist/cjs/utils/constants.d.ts.map +1 -1
  27. package/dist/cjs/utils/constants.js +2 -2
  28. package/dist/cjs/utils/logging.js +1 -1
  29. package/dist/cjs/utils/pivotConstructor.js +2 -2
  30. package/dist/cjs/utils/queryConstructor.js +2 -2
  31. package/dist/cjs/utils/report.d.ts.map +1 -1
  32. package/dist/cjs/utils/report.js +1 -1
  33. package/dist/esm/ChartBuilder.d.ts +7 -3
  34. package/dist/esm/ChartBuilder.d.ts.map +1 -1
  35. package/dist/esm/ChartBuilder.js +36 -19
  36. package/dist/esm/ReportBuilder.d.ts.map +1 -1
  37. package/dist/esm/ReportBuilder.js +190 -238
  38. package/dist/esm/SQLEditor.js +12 -10
  39. package/dist/esm/components/Dashboard/DataLoader.d.ts.map +1 -1
  40. package/dist/esm/components/QuillTable.d.ts +2 -1
  41. package/dist/esm/components/QuillTable.d.ts.map +1 -1
  42. package/dist/esm/components/QuillTable.js +5 -2
  43. package/dist/esm/components/ReportBuilder/AddSortPopover.d.ts +1 -2
  44. package/dist/esm/components/ReportBuilder/AddSortPopover.d.ts.map +1 -1
  45. package/dist/esm/components/ReportBuilder/AddSortPopover.js +1 -2
  46. package/dist/esm/components/ReportBuilder/convert.d.ts +1 -1
  47. package/dist/esm/components/ReportBuilder/convert.d.ts.map +1 -1
  48. package/dist/esm/components/ReportBuilder/convert.js +31 -4
  49. package/dist/esm/components/ReportBuilder/util.js +1 -1
  50. package/dist/esm/components/UiComponents.d.ts +3 -2
  51. package/dist/esm/components/UiComponents.d.ts.map +1 -1
  52. package/dist/esm/components/UiComponents.js +6 -3
  53. package/dist/esm/utils/astFilterProcessing.d.ts.map +1 -1
  54. package/dist/esm/utils/astFilterProcessing.js +921 -1604
  55. package/dist/esm/utils/astProcessing.d.ts +1 -1
  56. package/dist/esm/utils/astProcessing.d.ts.map +1 -1
  57. package/dist/esm/utils/astProcessing.js +4 -2
  58. package/dist/esm/utils/constants.d.ts.map +1 -1
  59. package/dist/esm/utils/constants.js +2 -2
  60. package/dist/esm/utils/logging.js +1 -1
  61. package/dist/esm/utils/pivotConstructor.js +2 -2
  62. package/dist/esm/utils/queryConstructor.js +2 -2
  63. package/dist/esm/utils/report.d.ts.map +1 -1
  64. package/dist/esm/utils/report.js +1 -1
  65. package/package.json +1 -1
@@ -11,7 +11,7 @@ import { QuillTextInput } from './components/UiComponents';
11
11
  import { QuillSidebar, CustomContainer, QuillSelectColumn, QuillDraggableColumn, QuillSidebarHeading, QuillFilterPopover, QuillSortPopover, QuillLimitPopover, } from './components/ReportBuilder/ui';
12
12
  import { deepCopy } from './components/ReportBuilder/util';
13
13
  import { hashCode } from './utils/crypto';
14
- import { defaultAST, defaultColumn, defaultEntry, defaultNumericComparison, defaultTable, defaultVariant, } from './components/ReportBuilder/constants';
14
+ import { defaultAST, defaultColumn, defaultEntry, defaultNumericComparison, defaultTable, } from './components/ReportBuilder/constants';
15
15
  import AddColumnModal from './components/ReportBuilder/AddColumnModal';
16
16
  import { AddSortPopover, SortSentence, } from './components/ReportBuilder/AddSortPopover';
17
17
  import { PivotModal, generatePivotTable, } from './internals/ReportBuilder/PivotModal';
@@ -23,15 +23,17 @@ import { QuillCard } from './components/QuillCard';
23
23
  import { DATE_FORMAT_TYPES, quillFormat } from './utils/valueFormatter';
24
24
  import { getPossiblePivotFieldOptions, isValidPivot, pivotToSql, } from './utils/pivotProcessing';
25
25
  import { getUniqueValuesByColumns, getQueryDateRangeByColumns, fetchResultsByQuery, getUniqueStringValues, fetchTableByAST, } from './utils/tableProcessing';
26
- import { createBasicSelectASTFromColumns, fetchAndProcessASTFromPrompt, fetchASTFromQuillReport, getAllPossibleColumns, } from './utils/astProcessing';
26
+ import { createBasicSelectASTFromColumns, fetchAndProcessASTFromPrompt, fetchASTFromQuillReport, } from './utils/astProcessing';
27
27
  import PivotForm from './internals/ReportBuilder/PivotForm';
28
28
  import { getDateBucketFromRange, getDateFormatFromBucket } from './utils/dates';
29
29
  import FilterModal from './components/ReportBuilder/FilterModal';
30
- import { astToFilterTree, filterToAst, filterTreeToAst, } from './utils/astFilterProcessing';
30
+ import { astToFilterTree, filterTreeToAst, getFieldFromExpression, } from './utils/astFilterProcessing';
31
31
  import useAstToFilterTree from './hooks/useAstToFilterTree';
32
- import { uniqueValuesToStringMap } from './utils/filterProcessing';
32
+ import { filterStackToFilterTree, uniqueValuesToStringMap, } from './utils/filterProcessing';
33
33
  import { QuillMultiSelectComponentWithCombo } from './components/QuillMultiSelectWithCombo';
34
- import { shouldFetchMore, shouldSortInMemory, } from './utils/paginationProcessing';
34
+ import { DEFAULT_PAGINATION, shouldFetchMore,
35
+ // shouldSortInMemory,
36
+ } from './utils/paginationProcessing';
35
37
  import { EMPTY_INTERNAL_REPORT, fetchReportBuilderDataFromAST, formatRowsFromReport, } from './utils/report';
36
38
  import equal from 'fast-deep-equal';
37
39
  import FilterStack from './components/ReportBuilder/FilterStack';
@@ -91,7 +93,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
91
93
  const [selectedOrderedColumns, setSelectedOrderedColumns] = useState([]);
92
94
  const [activeQuery, setActiveQuery] = useState('');
93
95
  const [, setActiveEditItem] = useState(null);
94
- const [activePath, setActivePath] = useState(null);
95
96
  const [openPopover, setOpenPopover] = useState(null);
96
97
  const [loading, setLoading] = useState(!!initialTableName);
97
98
  const [isChartBuilderOpen, setIsChartBuilderOpen] = useState(false);
@@ -99,6 +100,8 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
99
100
  const [dataDisplayed, setDataDisplayed] = useState(false);
100
101
  const [rows, setRows] = useState([]);
101
102
  const [filteredRows, setFilteredRows] = useState([]);
103
+ const [filteredRowCount, setFilteredRowCount] = useState(0);
104
+ const [filteredTableIsLoading, setFilteredTableIsLoading] = useState(false);
102
105
  const [chartBuilderInFilteredPreview, setChartBuilderInFilteredPreview] = useState(true);
103
106
  const [formattedRows, setFormattedRows] = useState([]);
104
107
  const [columns, setColumns] = useState([]);
@@ -274,7 +277,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
274
277
  setSelectedColumns([]);
275
278
  setActiveQuery('');
276
279
  setActiveEditItem(null);
277
- setActivePath(null);
278
280
  setOpenPopover(null);
279
281
  setLoading(false);
280
282
  setDataDisplayed(false);
@@ -395,7 +397,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
395
397
  });
396
398
  const data = await response.json();
397
399
  setActiveQuery(data.query);
398
- fetchFilteredRows(data.query);
399
400
  if (fetchData) {
400
401
  fetchReportFromASTHelper(ast, formData);
401
402
  }
@@ -535,166 +536,35 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
535
536
  useEffect(() => {
536
537
  onSchemaChange();
537
538
  }, [schemaData.schema, initialTableName, reportId]);
538
- const updateFormData = (updates, { isDeletion = false, isInsertion = false, isReplaceSubtree = false, isAddVariant = false, isDeleteVariant = false, topLevelBinOp = 'OR', isCondition = undefined, }) => {
539
- // Function to immutably update or delete nodes based on their path
540
- // TODO: fix the following horible code
541
- updates.forEach(({ path, value }) => {
542
- const globalPath = [
543
- (activePath ?? isDeletion) ? path : '',
544
- isDeletion || isReplaceSubtree ? '' : path,
545
- ]
546
- .filter(Boolean)
547
- .join('.');
548
- const paths = globalPath.split('.').filter((p) => p);
549
- if (paths.length === 0 && !isInsertion && !isReplaceSubtree) {
550
- setFormData(null);
551
- const newAst = deepCopy({
552
- ...defaultAST,
553
- ...baseAst,
554
- ...(!baseAst?.columns && {
555
- columns: getAllPossibleColumns(baseAst, schemaData.schema).map((c) => {
556
- const newColumn = deepCopy(defaultColumn);
557
- newColumn.expr.column = c.field;
558
- return newColumn;
559
- }),
560
- }),
561
- ...(!baseAst?.from && {
562
- from: [{ ...defaultTable, table: initialTableName }],
563
- }),
564
- where: null,
565
- });
566
- setBaseAst(newAst);
567
- fetchSqlQuery(newAst, null);
568
- return;
569
- }
570
- if (!formData && isInsertion) {
571
- const newAst = deepCopy({
572
- ...defaultAST,
573
- ...baseAst,
574
- ...(!baseAst?.columns && {
575
- columns: getAllPossibleColumns(baseAst, schemaData.schema).map((c) => {
576
- const newColumn = deepCopy(defaultColumn);
577
- newColumn.expr.column = c.field;
578
- return newColumn;
579
- }),
580
- }),
581
- ...(!baseAst?.from && {
582
- from: [{ ...defaultTable, table: initialTableName }],
583
- }),
584
- where: value,
585
- });
586
- setFormData(value);
587
- setBaseAst(newAst);
588
- fetchSqlQuery(newAst, value);
589
- return;
590
- }
591
- let newState = deepCopy(formData);
592
- let current = newState;
593
- let parent = null;
594
- let parentKey = null;
595
- for (let i = 0; i < paths.length - 1; i++) {
596
- if (current[paths[i]]) {
597
- parent = current;
598
- parentKey = paths[i];
599
- current = current[paths[i]];
600
- }
601
- }
602
- const lastKey = paths[paths.length - 1];
603
- if (isDeletion) {
604
- if (lastKey === 'left' || lastKey === 'right') {
605
- if (parent) {
606
- if (lastKey === 'right') {
607
- parent[parentKey] = parent[parentKey].left;
608
- }
609
- else {
610
- parent[parentKey] = parent[parentKey].right;
611
- }
612
- }
613
- else {
614
- delete current[lastKey];
615
- if (newState?.left && !newState?.right) {
616
- newState = newState.left;
617
- }
618
- else if (newState?.right && !newState?.left) {
619
- newState = newState.right;
620
- }
621
- }
622
- }
623
- }
624
- else if (isInsertion) {
625
- newState = {
626
- type: 'binary_expr',
627
- operator: topLevelBinOp,
628
- isCondition: isCondition,
629
- left: newState,
630
- right: value,
631
- };
632
- }
633
- else if (isAddVariant) {
634
- const newVariant = deepCopy(defaultVariant);
635
- if (value) {
636
- newVariant.args.value[0].value = value;
637
- // if there is already a single default value there,
638
- // let's remove it so when we push we replace.
639
- if (current[lastKey].length === 1 &&
640
- current[lastKey][0].args.value[0].value === '') {
641
- current[lastKey].pop();
642
- }
643
- }
644
- current[lastKey].push(newVariant);
645
- }
646
- else if (isDeleteVariant) {
647
- if (value) {
648
- const argList = current[lastKey];
649
- argList.splice(argList.findIndex((arg) => arg.args.value[0].value === name), 1);
650
- }
651
- else {
652
- current[lastKey].pop();
653
- }
654
- }
655
- else if (isReplaceSubtree) {
656
- if (lastKey) {
657
- current[lastKey] = value;
658
- }
659
- else {
660
- newState = value;
661
- }
662
- }
663
- else {
664
- if (typeof current[lastKey] === 'object' && current[lastKey] !== null) {
665
- current[lastKey].value = value;
666
- }
667
- else {
668
- current[lastKey] = value;
669
- }
670
- }
671
- setFormData(newState);
672
- const newAst = {
673
- ...defaultAST,
674
- ...baseAst,
675
- ...(!baseAst?.columns && {
676
- columns: getAllPossibleColumns(baseAst, schemaData.schema).map((c) => {
677
- const newColumn = deepCopy(defaultColumn);
678
- newColumn.expr.column = c.field;
679
- return newColumn;
680
- }),
681
- }),
682
- ...(!baseAst?.from && {
683
- from: [{ ...defaultTable, table: initialTableName }],
684
- }),
685
- where: { ...newState },
539
+ // Function to handle the insertion of expressions
540
+ const handleInsertion = (value) => {
541
+ const newFilterStack = [...filterStack];
542
+ if (newFilterStack.length > 0) {
543
+ const tabNode = {
544
+ leaf: false,
545
+ operator: 'and',
546
+ leftNode: null,
547
+ rightNode: null,
686
548
  };
549
+ newFilterStack.push(tabNode);
550
+ }
551
+ const newItem = {
552
+ leaf: true,
553
+ operator: null,
554
+ leftNode: null,
555
+ rightNode: null,
556
+ value: value,
557
+ };
558
+ newFilterStack.push(newItem);
559
+ const tree = filterStackToFilterTree(newFilterStack);
560
+ if (tree) {
561
+ const newFormData = filterTreeToAst(tree, client.databaseType.toLowerCase());
562
+ setFormData(newFormData);
563
+ const newAst = { ...baseAst };
564
+ newAst.where = newFormData;
687
565
  setBaseAst(newAst);
688
- fetchSqlQuery(newAst, newState);
689
- });
690
- };
691
- // Function to handle the insertion of expressions
692
- const handleInsertion = (value, op = 'OR', isCondition = undefined) => {
693
- updateFormData([{ path: '', value }], {
694
- isInsertion: true,
695
- topLevelBinOp: op,
696
- isCondition,
697
- });
566
+ fetchSqlQuery(newAst, newFormData);
567
+ }
698
568
  };
699
569
  /**
700
570
  * Searches for the column by name and returns the field type.
@@ -734,36 +604,93 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
734
604
  }
735
605
  };
736
606
  const [previousPage, setPreviousPage] = useState(0);
607
+ const [filteredPreviousPage, setFilteredPreviousPage] = useState(0);
737
608
  const [currentProcessing, setCurrentProcessing] = useState({
738
609
  page: REPORT_BUILDER_PAGINATION,
739
610
  });
611
+ const [filteredProcessing, setFilteredProcessing] = useState({
612
+ page: DEFAULT_PAGINATION,
613
+ });
740
614
  const [numberOfRows, setNumberOfRows] = useState(0);
741
615
  const [rowCountIsLoading, setRowCountIsLoading] = useState(false);
742
616
  const [tableLoading, setTableLoading] = useState(false);
743
- const onPageChange = (page) => {
744
- if (currentProcessing.page &&
745
- shouldFetchMore(REPORT_BUILDER_PAGINATION, page, previousPage)) {
746
- const newPagination = { ...currentProcessing.page, page };
747
- const updatedProcessing = { ...currentProcessing, page: newPagination };
748
- setCurrentProcessing(updatedProcessing);
749
- handleRunQuery(updatedProcessing);
617
+ const onPageChange = (page, isFilteredRows, initiator = 'ReportBuilder') => {
618
+ const pagination = initiator === 'ReportBuilder'
619
+ ? REPORT_BUILDER_PAGINATION
620
+ : DEFAULT_PAGINATION;
621
+ if (isFilteredRows) {
622
+ if (filteredProcessing.page &&
623
+ shouldFetchMore(pagination, page, filteredPreviousPage)) {
624
+ const newPagination = { ...filteredProcessing.page, page };
625
+ const updatedProcessing = {
626
+ ...filteredProcessing,
627
+ page: newPagination,
628
+ };
629
+ setFilteredProcessing(updatedProcessing);
630
+ fetchFilteredRows(activeQuery, updatedProcessing, false);
631
+ }
632
+ if (page > filteredPreviousPage) {
633
+ setFilteredPreviousPage(page);
634
+ }
750
635
  }
751
- if (page > previousPage) {
752
- setPreviousPage(page);
636
+ else {
637
+ if (currentProcessing.page &&
638
+ shouldFetchMore(pagination, page, previousPage)) {
639
+ const newPagination = { ...currentProcessing.page, page };
640
+ const updatedProcessing = { ...currentProcessing, page: newPagination };
641
+ setCurrentProcessing(updatedProcessing);
642
+ handleRunQuery(updatedProcessing);
643
+ }
644
+ if (page > previousPage) {
645
+ setPreviousPage(page);
646
+ }
753
647
  }
754
648
  };
755
- const onSortChange = (sort) => {
756
- if (shouldSortInMemory(REPORT_BUILDER_PAGINATION, numberOfRows, !!pivot)) {
757
- return;
649
+ const onSortChange = (sort, isFilteredRows, persistSort = false) => {
650
+ // if (shouldSortInMemory(REPORT_BUILDER_PAGINATION, numberOfRows, !!pivot)) {
651
+ // return;
652
+ // }
653
+ if (isFilteredRows) {
654
+ const updatedProcessing = { page: DEFAULT_PAGINATION, sort };
655
+ fetchFilteredRows(activeQuery, updatedProcessing, true);
656
+ setFilteredProcessing(updatedProcessing);
657
+ setFilteredPreviousPage(0);
658
+ }
659
+ else {
660
+ const updatedProcessing = { page: REPORT_BUILDER_PAGINATION, sort };
661
+ if (persistSort) {
662
+ const newAst = { ...baseAst };
663
+ if (!newAst.orderby) {
664
+ newAst.orderby = [];
665
+ }
666
+ const existingSortIndex = newAst.orderby.findIndex((item) => getFieldFromExpression(item.expr) === sort.field);
667
+ if (existingSortIndex !== -1) {
668
+ newAst.orderby[existingSortIndex] = {
669
+ expr: { type: 'column_ref', column: sort.field },
670
+ type: sort.direction.toUpperCase(),
671
+ };
672
+ }
673
+ else {
674
+ newAst.orderby.push({
675
+ expr: { type: 'column_ref', column: sort.field },
676
+ type: sort.direction.toUpperCase(),
677
+ });
678
+ }
679
+ setBaseAst(deepCopy(newAst));
680
+ fetchReportFromASTHelper(newAst, newAst.where);
681
+ }
682
+ else {
683
+ handleRunQuery(updatedProcessing, true);
684
+ }
685
+ setCurrentProcessing(updatedProcessing);
686
+ setPreviousPage(0);
758
687
  }
759
- const updatedProcessing = { page: REPORT_BUILDER_PAGINATION, sort };
760
- handleRunQuery(updatedProcessing, true);
761
- setCurrentProcessing(updatedProcessing);
762
- setPreviousPage(0);
763
688
  };
764
689
  const onFilterPreviewChange = (preview) => {
765
690
  setChartBuilderInFilteredPreview(preview);
766
- // handleRunQuery(currentProcessing, true, preview);
691
+ if (preview) {
692
+ fetchFilteredRows(activeQuery);
693
+ }
767
694
  };
768
695
  const fetchRowCount = async (processing, includeFilters) => {
769
696
  if (!client || !activeQuery) {
@@ -796,38 +723,45 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
796
723
  }
797
724
  setRowCountIsLoading(false);
798
725
  };
799
- const fetchFilteredRows = async (query) => {
800
- const filteredTableInfo = await fetchResultsByQuery(query, client, currentProcessing, schemaData.customFields, specificDashboardFilters, tempReport.dateField, true);
726
+ const fetchFilteredRows = async (query, processing, resetRows = true) => {
727
+ setFilteredTableIsLoading(true);
728
+ const filteredTableInfo = await fetchResultsByQuery(query, client, processing ?? filteredProcessing, schemaData.customFields, specificDashboardFilters, tempReport.dateField, resetRows ? false : true);
801
729
  if (filteredTableInfo.error) {
802
730
  throw new Error(filteredTableInfo.error);
803
731
  }
804
- setFilteredRows([...filteredRows, ...filteredTableInfo.rows]);
732
+ if (resetRows) {
733
+ setFilteredRows(filteredTableInfo.rows);
734
+ }
735
+ else {
736
+ setFilteredRows((filteredRows) => [
737
+ ...filteredRows,
738
+ ...filteredTableInfo.rows,
739
+ ]);
740
+ }
741
+ if (resetRows) {
742
+ setFilteredRowCount(filteredTableInfo.rowCount ?? 0);
743
+ }
744
+ setFilteredTableIsLoading(false);
805
745
  };
806
746
  const handleRunQuery = async (processing, resetRows = false, includeFilters = false) => {
807
747
  try {
808
748
  setErrorMessage('');
809
749
  setTableLoading(true);
810
750
  const tableInfo = await fetchResultsByQuery(activeQuery, client, processing, schemaData.customFields, undefined, undefined, true);
811
- const filteredTableInfo = await fetchResultsByQuery(activeQuery, client, processing, schemaData.customFields, specificDashboardFilters, tempReport.dateField, true);
812
751
  if (tableInfo.error) {
813
752
  throw new Error(tableInfo.error);
814
753
  }
815
- else if (filteredTableInfo.error) {
816
- throw new Error(filteredTableInfo.error);
817
- }
818
754
  else if (tableInfo.rows.length === 0) {
819
755
  throw new Error('No data found');
820
756
  }
821
757
  fetchRowCount(processing, includeFilters);
822
758
  setCurrentProcessing(processing);
823
759
  let tempRows = [...rows, ...tableInfo.rows];
824
- let tempFilteredRows = [...filteredRows, ...filteredTableInfo.rows];
825
760
  if (resetRows) {
826
761
  tempRows = tableInfo.rows;
827
- tempFilteredRows = filteredTableInfo.rows;
762
+ setPreviousPage(0);
828
763
  }
829
764
  setRows(tempRows);
830
- setFilteredRows(tempFilteredRows);
831
765
  setFormattedRows(formatRowsFromReport({ rows: tempRows, columns: tableInfo.columns }));
832
766
  setTempReport((tempReport) => ({
833
767
  ...tempReport,
@@ -910,7 +844,7 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
910
844
  const prevTable = currentTable;
911
845
  const prevOrganization = currentOrganizationId;
912
846
  setRows(reportBuilderInfo.rows);
913
- setFilteredRows(reportBuilderInfo.rows);
847
+ setPreviousPage(0);
914
848
  if (!(client.databaseType.toLowerCase() === 'bigquery') ||
915
849
  (reportBuilderInfo.rows && reportBuilderInfo.rows.length > 0)) {
916
850
  setColumns(reportBuilderInfo.columns);
@@ -939,6 +873,27 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
939
873
  setLoading(false);
940
874
  }
941
875
  setReportInfo(reportBuilderInfo.report);
876
+ const schema = curSchema ?? schemaData.schema;
877
+ const tableInfo = schema.find((tableInfo) => tableInfo.name === reportBuilderInfo?.table);
878
+ let query = reportBuilderInfo.query;
879
+ if (!query && tableInfo) {
880
+ const ast = baseAst ??
881
+ createBasicSelectASTFromColumns(tableInfo.columns, reportBuilderInfo.table);
882
+ const queryResult = await fetchSqlQuery({
883
+ ...ast,
884
+ where: curFormData,
885
+ }, curFormData, false);
886
+ if (queryResult.error) {
887
+ console.error(queryResult.error);
888
+ }
889
+ else {
890
+ query = queryResult;
891
+ setActiveQuery(queryResult);
892
+ }
893
+ }
894
+ else if (query) {
895
+ setActiveQuery(query);
896
+ }
942
897
  // fetch unique values after everything else since it is the most expensive
943
898
  if (prevTable !== reportBuilderInfo.table ||
944
899
  !equal(prevFormData, curFormData) ||
@@ -948,42 +903,27 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
948
903
  if (reportBuilderInfo.pivot) {
949
904
  setUnresolvedReportMessage('Processing pivot selection options...');
950
905
  }
951
- const schema = curSchema ?? schemaData.schema;
952
- const tableInfo = schema.find((tableInfo) => tableInfo.name === reportBuilderInfo?.table);
953
- if (!reportBuilderInfo.table || !tableInfo) {
954
- throw new Error('No table found;');
955
- }
956
- let query = reportBuilderInfo.query;
957
- if (!query) {
958
- const queryResult = await fetchSqlQuery({
959
- ...createBasicSelectASTFromColumns(tableInfo.columns, reportBuilderInfo.table),
960
- where: curFormData,
961
- }, curFormData, false);
962
- if (queryResult.error) {
963
- console.error(queryResult.error);
964
- }
965
- else {
966
- query = queryResult.query;
967
- }
906
+ if (!tableInfo) {
907
+ throw new Error('Table info not found');
968
908
  }
969
909
  const uniqueStrings = await getUniqueStringValues(tableInfo.columns, reportBuilderInfo.table, client, schemaData.customFields, undefined, true, query);
970
910
  const newUnique = updateUniqueValue(uniqueStrings, reportBuilderInfo.table);
971
911
  let pivotChanged = false;
972
912
  let newPivot;
973
913
  if (reportBuilderInfo.pivot &&
974
- !isValidPivotForReport(reportBuilderInfo.pivot, newUnique)) {
914
+ !isValidPivotForReport(reportBuilderInfo.pivot, newUnique, reportBuilderInfo.table, reportBuilderInfo.columns)) {
975
915
  // try flipping row and column field
976
916
  newPivot = {
977
917
  ...reportBuilderInfo.pivot,
978
918
  rowField: reportBuilderInfo.pivot.columnField,
979
919
  columnField: reportBuilderInfo.pivot.rowField,
980
920
  };
981
- if (isValidPivotForReport(newPivot, newUnique)) {
921
+ if (isValidPivotForReport(newPivot, newUnique, reportBuilderInfo.table, reportBuilderInfo.columns)) {
982
922
  setPivot(newPivot);
983
923
  pivotChanged = true;
984
924
  setPivotHint('Flipped pivot row and column fields to maintain validity');
985
925
  }
986
- else if (isValidPivotForReport({ ...reportBuilderInfo.pivot, columnField: undefined }, newUnique)) {
926
+ else if (isValidPivotForReport({ ...reportBuilderInfo.pivot, columnField: undefined }, newUnique, reportBuilderInfo.table, reportBuilderInfo.columns)) {
987
927
  // try removing column field
988
928
  newPivot = {
989
929
  ...reportBuilderInfo.pivot,
@@ -1019,6 +959,9 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1019
959
  return { error: true, message: 'Failed to fetch', rows: [] };
1020
960
  }
1021
961
  }
962
+ else {
963
+ setLoading(false);
964
+ }
1022
965
  };
1023
966
  const fetchAstFromPromptHelper = async (overridePrompt) => {
1024
967
  let astInfo = {};
@@ -1030,7 +973,7 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1030
973
  try {
1031
974
  setLoading(true);
1032
975
  setAskAILoading(true);
1033
- astInfo = await fetchAndProcessASTFromPrompt(prompt, schemaData.schema, client, pivot, activeQuery);
976
+ astInfo = await fetchAndProcessASTFromPrompt(prompt, schemaData.schema, client, pivot, activeQuery, currentTable);
1034
977
  if (astInfo.error) {
1035
978
  throw new Error(astInfo.error);
1036
979
  }
@@ -1060,13 +1003,15 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1060
1003
  setAskAILoading(false);
1061
1004
  await fetchReportFromASTHelper(astInfo.ast, cleanAst, astInfo.pivot);
1062
1005
  };
1063
- const isValidPivotForReport = (pivot, uniqueValuesForPivot) => {
1064
- if (!isValidPivot) {
1006
+ const isValidPivotForReport = (pivot, uniqueValuesForPivot, reportTable, reportColumns) => {
1007
+ if (!isValidPivot(pivot)) {
1065
1008
  return false;
1066
1009
  }
1067
1010
  const uniqueValuesToCheck = uniqueValuesForPivot ?? uniqueValues;
1068
1011
  // check that pivot rows and columns
1069
- const possibleOptions = getPossiblePivotFieldOptions(columns, uniqueValuesToCheck[currentTable] ?? {});
1012
+ const pivotTable = reportTable ?? currentTable;
1013
+ const pivotColumns = reportColumns ?? columns;
1014
+ const possibleOptions = getPossiblePivotFieldOptions(pivotColumns, uniqueValuesToCheck[pivotTable] ?? {});
1070
1015
  if (pivot.rowField &&
1071
1016
  pivot.columnField &&
1072
1017
  pivot.rowField === pivot.columnField) {
@@ -1214,13 +1159,11 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1214
1159
  // delay onClose callback so onClick no-ops
1215
1160
  setTimeout(() => {
1216
1161
  setActiveEditItem(null);
1217
- setActivePath(null);
1218
1162
  setOpenPopover(null);
1219
1163
  }, 100);
1220
1164
  }
1221
1165
  }, title: "Select columns", children: _jsx(AddColumnModal, { onSave: () => {
1222
1166
  setActiveEditItem(null);
1223
- setActivePath(null);
1224
1167
  setOpenPopover(null);
1225
1168
  }, orderedColumnNames: orderedColumnNames, setOrderedColumnNames: setOrderedColumnNames, selectedColumns: selectedColumns, setSelectedColumns: setSelectedColumns, isSelectedAllColumns: isSelectedAllColumns, clearAllState: clearAllState, nameToColumn: nameToColumn, baseAst: baseAst, setBaseAst: (ast) => {
1226
1169
  if (baseAst &&
@@ -1269,7 +1212,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1269
1212
  setActiveEditItem(newSubtree);
1270
1213
  }
1271
1214
  setOpenPopover('AddFilterPopover');
1272
- setActivePath('');
1273
1215
  }
1274
1216
  }, label: 'Add filter' }), _jsx("div", { style: {
1275
1217
  position: 'relative',
@@ -1279,7 +1221,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1279
1221
  // delay onClose callback so onClick no-ops
1280
1222
  setOpenPopover(null);
1281
1223
  setTimeout(() => {
1282
- setActivePath(null);
1283
1224
  clearCheckboxes();
1284
1225
  setActiveEditItem(null);
1285
1226
  }, 300);
@@ -1287,8 +1228,7 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1287
1228
  }, popoverTitle: "Add filter", popoverChildren: _jsx(FilterModal, { schema: schemaData.schema.find((s) => s.name === currentTable ||
1288
1229
  s.displayName === currentTable) ?? schemaData.schema[0], fieldValuesMap: fieldValuesMap, fieldValuesMapIsLoading: uniqueValuesIsLoading, onSubmitFilter: (filter) => {
1289
1230
  setOpenPopover(null);
1290
- const item = filterToAst(filter, client.databaseType.toLowerCase());
1291
- handleInsertion(item, 'AND', false);
1231
+ handleInsertion(filter);
1292
1232
  }, onDeleteFilter: () => { }, ButtonComponent: ButtonComponent, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, MultiSelectComponent: MultiSelectComponent }) }) })] })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Pivot" }), _jsx(PivotModal, { pivotRowField: pivotRowField, setPivotRowField: setPivotRowField, pivotColumnField: pivotColumnField, setPivotColumnField: setPivotColumnField, pivotValueField: pivotValueField, pivotValueField2: pivotValueField2, setPivotValueField: setPivotValueField, setPivotValueField2: setPivotValueField2, pivotAggregation: pivotAggregation, setPivotAggregation: setPivotAggregation, createdPivots: createdPivots, setCreatedPivots: setCreatedPivots, recommendedPivots: recommendedPivots, setRecommendedPivots: setRecommendedPivots, popUpTitle: pivotPopUpTitle, setPopUpTitle: setPivotPopUpTitle, selectedTable: initialTableName, SelectComponent: SelectComponent, ButtonComponent: ButtonComponent, CardComponent: CardComponent, SecondaryButtonComponent: SecondaryButtonComponent, PopoverComponent: PopoverComponent, TextComponent: TextComponent, ErrorMessageComponent: ErrorMessageComponent, PivotRowContainer: PivotRowContainer, PivotColumnContainer: PivotColumnContainer, LoadingComponent: LoadingComponent, isOpen: showPivotPopover, setIsOpen: setShowPivotPopover, showUpdatePivot: isEditingPivot, setShowUpdatePivot: setIsEditingPivot, parentRef: parentRef, data: rows, columns: columns, triggerButtonText: 'Add pivot', selectedPivotIndex: selectedPivotIndex, setSelectedPivotIndex: setSelectedPivotIndex, removePivot: () => {
1293
1233
  setPivot(null);
1294
1234
  setPivotHint('');
@@ -1371,7 +1311,7 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1371
1311
  `.${pivot.rowField}`,
1372
1312
  `.${pivot.valueField || 'count'}`,
1373
1313
  ]
1374
- : selectedColumns, setIsPending: () => { }, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setActivePath: setActivePath, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: async () => {
1314
+ : selectedColumns, setIsPending: () => { }, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: async () => {
1375
1315
  if (!pivot) {
1376
1316
  setBaseAst(deepCopy(baseAst));
1377
1317
  fetchSqlQuery(deepCopy(baseAst));
@@ -1452,12 +1392,12 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1452
1392
  if (e instanceof Error)
1453
1393
  setPivotError(e.message);
1454
1394
  }
1455
- }, Select: SelectComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent, disabled: tableLoading || loading }, `sort-sentence-pivot`) })), baseAst && baseAst.orderby && (_jsx("div", { style: {
1395
+ }, Select: SelectComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent, disabled: tableLoading || loading }, `sort-sentence-pivot`) })), baseAst && baseAst.orderby && baseAst.orderby.length > 0 && (_jsx("div", { style: {
1456
1396
  display: 'flex',
1457
1397
  flexDirection: 'column',
1458
1398
  gap: 8,
1459
1399
  marginBottom: 12,
1460
- }, children: baseAst.orderby.map((sortData, id) => (_jsx(SortSentence, { sortData: sortData, columns: selectedColumns, setIsPending: () => { }, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setActivePath: setActivePath, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: () => {
1400
+ }, children: baseAst.orderby.map((sortData, id) => (_jsx(SortSentence, { sortData: sortData, columns: selectedColumns, setIsPending: () => { }, setEditPopoverKey: () => { }, setActiveEditItem: setActiveEditItem, setOpenPopover: setOpenPopover, SortPopover: SortPopoverComponent, EditPopover: AddSortPopover, handleDelete: () => {
1461
1401
  if (pivot) {
1462
1402
  setPivot({ ...pivot, sort: false });
1463
1403
  setPivotHint('');
@@ -1465,6 +1405,9 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1465
1405
  }
1466
1406
  const newAst = { ...baseAst };
1467
1407
  newAst.orderby.splice(id, 1);
1408
+ if (newAst.orderby.length === 0) {
1409
+ newAst.orderby = null;
1410
+ }
1468
1411
  setBaseAst(deepCopy(newAst));
1469
1412
  fetchSqlQuery(deepCopy(newAst));
1470
1413
  }, onSave: (column, direction) => {
@@ -1496,7 +1439,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1496
1439
  type: direction,
1497
1440
  };
1498
1441
  // look through the columns
1499
- setActivePath(null);
1500
1442
  setOpenPopover(null);
1501
1443
  setBaseAst(deepCopy(newAst));
1502
1444
  fetchSqlQuery(deepCopy(newAst));
@@ -1513,7 +1455,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1513
1455
  }, children: _jsx(PopoverComponent, { isOpen: openPopover === 'AddSortPopover', setIsOpen: (isOpen) => {
1514
1456
  if (!isOpen) {
1515
1457
  setActiveEditItem(null);
1516
- setActivePath(null);
1517
1458
  setOpenPopover(null);
1518
1459
  }
1519
1460
  }, popoverTitle: "Sort by", popoverChildren: _jsx(AddSortPopover, { columns: pivot
@@ -1563,7 +1504,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1563
1504
  if (e instanceof Error)
1564
1505
  setPivotError(e.message);
1565
1506
  }
1566
- setActivePath(null);
1567
1507
  setOpenPopover(null);
1568
1508
  setBaseAst(deepCopy(baseAst));
1569
1509
  return;
@@ -1571,12 +1511,20 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1571
1511
  const newAst = { ...baseAst };
1572
1512
  if (!newAst.orderby)
1573
1513
  newAst.orderby = [];
1574
- newAst.orderby.push({
1575
- expr: { type: 'column_ref', column },
1576
- type: direction,
1577
- });
1514
+ const existingSortIndex = newAst.orderby.findIndex((item) => getFieldFromExpression(item.expr) === column);
1515
+ if (existingSortIndex !== -1) {
1516
+ newAst.orderby[existingSortIndex] = {
1517
+ expr: { type: 'column_ref', column },
1518
+ type: direction,
1519
+ };
1520
+ }
1521
+ else {
1522
+ newAst.orderby.push({
1523
+ expr: { type: 'column_ref', column },
1524
+ type: direction,
1525
+ });
1526
+ }
1578
1527
  // look through the columns
1579
- setActivePath(null);
1580
1528
  setOpenPopover(null);
1581
1529
  setBaseAst(deepCopy(newAst));
1582
1530
  fetchSqlQuery(deepCopy(newAst));
@@ -1620,7 +1568,6 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1620
1568
  }, children: _jsx(PopoverComponent, { isOpen: openPopover === 'AddLimitPopover', setIsOpen: (isOpen) => {
1621
1569
  if (!isOpen) {
1622
1570
  setActiveEditItem(null);
1623
- setActivePath(null);
1624
1571
  setOpenPopover(null);
1625
1572
  }
1626
1573
  }, popoverTitle: "Add limit", popoverChildren: _jsx(AddLimitPopover, { TextInputComponent: TextInputComponent, Button: ButtonComponent, SecondaryButton: SecondaryButtonComponent, onSave: (limit) => {
@@ -1659,7 +1606,9 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1659
1606
  label: snakeAndCamelCaseToTitleCase(c),
1660
1607
  field: c,
1661
1608
  };
1662
- }), onPageChange: onPageChange, onSortChange: onSortChange, containerStyle: {
1609
+ }), onPageChange: onPageChange, onSortChange: (sort) => {
1610
+ onSortChange(sort, false, true);
1611
+ }, containerStyle: {
1663
1612
  maxHeight: Math.max(window.innerHeight - 290, 75 + Math.min(Math.max(10, rows.length), 20) * 37),
1664
1613
  } })), _jsxs("div", { style: {
1665
1614
  display: 'flex',
@@ -1678,6 +1627,7 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1678
1627
  fetchAstFromPromptHelper();
1679
1628
  }, label: 'Retry' })] })) : (_jsx("div", { style: { width: '100%' } })), baseAst && dataDisplayed && (_jsxs(_Fragment, { children: [onDiscardChanges && (_jsx(SecondaryButtonComponent, { onClick: onDiscardChanges, label: "Discard changes" })), !hideCopySQL && (_jsx(SecondaryButtonComponent, { label: isCopying ? 'Copied' : 'Copy SQL', onClick: () => copySQLToClipboard() })), _jsx(ButtonComponent, { onClick: async () => {
1680
1629
  onSaveChanges && onSaveChanges();
1630
+ fetchFilteredRows(activeQuery);
1681
1631
  setIsChartBuilderOpen(true);
1682
1632
  }, disabled: !!errorMessage ||
1683
1633
  tableLoading ||
@@ -1698,5 +1648,7 @@ SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectCol
1698
1648
  }
1699
1649
  : {
1700
1650
  ...tempReport,
1701
- }, rows: chartBuilderInFilteredPreview ? filteredRows : rows, columns: columns, pivot: pivot, query: activeQuery, showTableFormatOptions: showChartBuilderTableFormatOptions, showDateFieldOptions: isAdminEnabled, showAccessControlOptions: isAdminEnabled, isAdmin: isAdminEnabled, title: reportId ? 'Save changes' : 'Add to dashboard', isHorizontalView: true, isOpen: isChartBuilderOpen, setIsOpen: setIsChartBuilderOpen, onAddToDashboardComplete: reportId ? onSubmitEditReport : onSubmitCreateReport, destinationDashboard: destinationDashboard, organizationName: organizationName, pivotData: pivotData, initialUniqueValues: uniqueValues[currentTable], initialUniqueValuesIsLoading: uniqueValuesIsLoading, pivotRecommendationsEnabled: pivotRecommendationsEnabledState, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, ButtonComponent: ButtonComponent, SecondaryButtonComponent: SecondaryButtonComponent, HeaderComponent: HeaderComponent, SubHeaderComponent: SubHeaderComponent, LabelComponent: LabelComponent, TextComponent: TextComponent, CardComponent: CardComponent, ModalComponent: ChartBuilderModalComponent, PopoverComponent: PopoverComponent, TableComponent: TableComponent, DeleteButtonComponent: DeleteButtonComponent, LoadingComponent: LoadingComponent, ChartBuilderInputRowContainer: ChartBuilderInputRowContainer, ChartBuilderInputColumnContainer: ChartBuilderInputColumnContainer, FormContainer: ChartBuilderFormContainer, hideDateRangeFilter: true, buttonLabel: !!reportId ? 'Save changes' : 'Add to dashboard', onClickChartElement: onClickChartElement, rowCount: numberOfRows, onPageChange: onPageChange, onSortChange: onSortChange, onFilterPreviewChange: onFilterPreviewChange, isLoading: tableLoading, isEditingMode: true }))] }));
1651
+ }, rows: chartBuilderInFilteredPreview ? filteredRows : rows, columns: columns, pivot: pivot, query: activeQuery, showTableFormatOptions: showChartBuilderTableFormatOptions, showDateFieldOptions: isAdminEnabled, showAccessControlOptions: isAdminEnabled, isAdmin: isAdminEnabled, title: reportId ? 'Save changes' : 'Add to dashboard', isHorizontalView: true, isOpen: isChartBuilderOpen, setIsOpen: setIsChartBuilderOpen, onAddToDashboardComplete: reportId ? onSubmitEditReport : onSubmitCreateReport, destinationDashboard: destinationDashboard, organizationName: organizationName, pivotData: pivotData, initialUniqueValues: uniqueValues[currentTable], initialUniqueValuesIsLoading: uniqueValuesIsLoading, pivotRecommendationsEnabled: pivotRecommendationsEnabledState, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, ButtonComponent: ButtonComponent, SecondaryButtonComponent: SecondaryButtonComponent, HeaderComponent: HeaderComponent, SubHeaderComponent: SubHeaderComponent, LabelComponent: LabelComponent, TextComponent: TextComponent, CardComponent: CardComponent, ModalComponent: ChartBuilderModalComponent, PopoverComponent: PopoverComponent, TableComponent: TableComponent, DeleteButtonComponent: DeleteButtonComponent, LoadingComponent: LoadingComponent, ChartBuilderInputRowContainer: ChartBuilderInputRowContainer, ChartBuilderInputColumnContainer: ChartBuilderInputColumnContainer, FormContainer: ChartBuilderFormContainer, hideDateRangeFilter: true, buttonLabel: !!reportId ? 'Save changes' : 'Add to dashboard', onClickChartElement: onClickChartElement, rowCount: chartBuilderInFilteredPreview ? filteredRowCount : numberOfRows, onPageChange: onPageChange, onSortChange: onSortChange, onFilterPreviewChange: reportId ? onFilterPreviewChange : undefined, isLoading: chartBuilderInFilteredPreview
1652
+ ? filteredTableIsLoading
1653
+ : tableLoading, isEditingMode: true }))] }));
1702
1654
  }