@quillsql/react 2.12.39 → 2.12.41
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.
- package/dist/cjs/Chart.js +1 -1
- package/dist/cjs/ChartBuilder.d.ts +1 -1
- package/dist/cjs/ChartBuilder.d.ts.map +1 -1
- package/dist/cjs/ChartBuilder.js +6 -6
- package/dist/cjs/Dashboard.d.ts +35 -3
- package/dist/cjs/Dashboard.d.ts.map +1 -1
- package/dist/cjs/Dashboard.js +72 -74
- package/dist/cjs/ReportBuilder.d.ts +1 -1
- package/dist/cjs/ReportBuilder.d.ts.map +1 -1
- package/dist/cjs/ReportBuilder.js +111 -1588
- package/dist/cjs/components/Chart/BarChart.d.ts.map +1 -1
- package/dist/cjs/components/Chart/BarChart.js +0 -9
- package/dist/cjs/components/Chart/LineChart.d.ts.map +1 -1
- package/dist/cjs/components/Chart/LineChart.js +1 -11
- package/dist/cjs/components/Dashboard/ChartComponent.d.ts.map +1 -1
- package/dist/cjs/components/Dashboard/ChartComponent.js +1 -0
- package/dist/cjs/components/Dashboard/DashboardTemplate.d.ts +12 -0
- package/dist/cjs/components/Dashboard/DashboardTemplate.d.ts.map +1 -0
- package/dist/cjs/components/Dashboard/DashboardTemplate.js +69 -0
- package/dist/cjs/components/Dashboard/DataLoader.js +1 -1
- package/dist/cjs/components/Dashboard/TemplateChartComponent.d.ts +4 -0
- package/dist/cjs/components/Dashboard/TemplateChartComponent.d.ts.map +1 -0
- package/dist/cjs/components/Dashboard/TemplateChartComponent.js +23 -0
- package/dist/cjs/components/Dashboard/TemplateMetricComponent.d.ts +4 -0
- package/dist/cjs/components/Dashboard/TemplateMetricComponent.d.ts.map +1 -0
- package/dist/cjs/components/Dashboard/TemplateMetricComponent.js +23 -0
- package/dist/cjs/components/Dashboard/TemplateTableComponent.d.ts +15 -0
- package/dist/cjs/components/Dashboard/TemplateTableComponent.d.ts.map +1 -0
- package/dist/cjs/components/Dashboard/TemplateTableComponent.js +23 -0
- package/dist/cjs/components/Dashboard/util.d.ts +6 -0
- package/dist/cjs/components/Dashboard/util.d.ts.map +1 -0
- package/dist/cjs/components/Dashboard/util.js +85 -0
- package/dist/cjs/components/ReportBuilder/FilterModal.js +32 -32
- package/dist/cjs/components/ReportBuilder/convert.d.ts +5 -31
- package/dist/cjs/components/ReportBuilder/convert.d.ts.map +1 -1
- package/dist/cjs/components/ReportBuilder/convert.js +1 -1
- package/dist/cjs/components/UiComponents.d.ts +1 -23
- package/dist/cjs/components/UiComponents.d.ts.map +1 -1
- package/dist/cjs/components/UiComponents.js +67 -25
- package/dist/cjs/hooks/useAskQuill.d.ts +27 -0
- package/dist/cjs/hooks/useAskQuill.d.ts.map +1 -0
- package/dist/cjs/hooks/useAskQuill.js +177 -0
- package/dist/cjs/hooks/useDashboard.d.ts.map +1 -1
- package/dist/cjs/hooks/useDashboard.js +7 -5
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/internals/ReportBuilder/PivotForm.d.ts +3 -3
- package/dist/cjs/internals/ReportBuilder/PivotForm.d.ts.map +1 -1
- package/dist/cjs/internals/ReportBuilder/PivotForm.js +4 -2
- package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts +1 -15
- package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
- package/dist/cjs/internals/ReportBuilder/PivotModal.js +24 -24
- package/dist/cjs/models/Filter.d.ts +25 -19
- package/dist/cjs/models/Filter.d.ts.map +1 -1
- package/dist/cjs/models/Filter.js +2 -2
- package/dist/cjs/{components/ReportBuilder/pivot.d.ts → models/Pivot.d.ts} +13 -4
- package/dist/cjs/models/Pivot.d.ts.map +1 -0
- package/dist/cjs/models/Report.d.ts +5 -1
- package/dist/cjs/models/Report.d.ts.map +1 -1
- package/dist/cjs/models/Tables.d.ts +16 -0
- package/dist/cjs/models/Tables.d.ts.map +1 -1
- package/dist/cjs/utils/astFilterProcessing.js +27 -27
- package/dist/cjs/utils/astProcessing.d.ts +42 -0
- package/dist/cjs/utils/astProcessing.d.ts.map +1 -1
- package/dist/cjs/utils/astProcessing.js +210 -1
- package/dist/cjs/utils/constants.d.ts +1 -0
- package/dist/cjs/utils/constants.d.ts.map +1 -1
- package/dist/cjs/utils/constants.js +2 -1
- package/dist/cjs/utils/dashboard.d.ts.map +1 -1
- package/dist/cjs/utils/dashboard.js +2 -0
- package/dist/cjs/utils/dataFetcher.d.ts +4 -0
- package/dist/cjs/utils/dataFetcher.d.ts.map +1 -1
- package/dist/cjs/utils/dataFetcher.js +24 -1
- package/dist/cjs/utils/dates.d.ts +1 -1
- package/dist/cjs/utils/filterProcessing.d.ts +2 -2
- package/dist/cjs/utils/filterProcessing.d.ts.map +1 -1
- package/dist/cjs/utils/filterProcessing.js +6 -6
- package/dist/cjs/utils/pivotConstructor.d.ts +1 -1
- package/dist/cjs/utils/pivotConstructor.d.ts.map +1 -1
- package/dist/cjs/utils/pivotConstructor.js +7 -4
- package/dist/cjs/utils/pivotProcessing.d.ts +4 -4
- package/dist/cjs/utils/pivotProcessing.d.ts.map +1 -1
- package/dist/cjs/utils/pivotProcessing.js +21 -2
- package/dist/cjs/utils/queryConstructor.d.ts +1 -1
- package/dist/cjs/utils/queryConstructor.d.ts.map +1 -1
- package/dist/cjs/utils/queryConstructor.js +3 -3
- package/dist/cjs/utils/report.d.ts +25 -0
- package/dist/cjs/utils/report.d.ts.map +1 -1
- package/dist/cjs/utils/report.js +114 -2
- package/dist/cjs/utils/schema.d.ts.map +1 -1
- package/dist/cjs/utils/schema.js +1 -1
- package/dist/cjs/utils/tableProcessing.d.ts +18 -0
- package/dist/cjs/utils/tableProcessing.d.ts.map +1 -1
- package/dist/cjs/utils/tableProcessing.js +94 -1
- package/dist/esm/Chart.js +1 -1
- package/dist/esm/ChartBuilder.d.ts +1 -1
- package/dist/esm/ChartBuilder.d.ts.map +1 -1
- package/dist/esm/ChartBuilder.js +6 -6
- package/dist/esm/Dashboard.d.ts +35 -3
- package/dist/esm/Dashboard.d.ts.map +1 -1
- package/dist/esm/Dashboard.js +73 -75
- package/dist/esm/ReportBuilder.d.ts +1 -1
- package/dist/esm/ReportBuilder.d.ts.map +1 -1
- package/dist/esm/ReportBuilder.js +121 -1598
- package/dist/esm/components/Chart/BarChart.d.ts.map +1 -1
- package/dist/esm/components/Chart/BarChart.js +0 -9
- package/dist/esm/components/Chart/LineChart.d.ts.map +1 -1
- package/dist/esm/components/Chart/LineChart.js +1 -11
- package/dist/esm/components/Dashboard/ChartComponent.d.ts.map +1 -1
- package/dist/esm/components/Dashboard/ChartComponent.js +1 -0
- package/dist/esm/components/Dashboard/DashboardTemplate.d.ts +12 -0
- package/dist/esm/components/Dashboard/DashboardTemplate.d.ts.map +1 -0
- package/dist/esm/components/Dashboard/DashboardTemplate.js +63 -0
- package/dist/esm/components/Dashboard/DataLoader.js +1 -1
- package/dist/esm/components/Dashboard/TemplateChartComponent.d.ts +4 -0
- package/dist/esm/components/Dashboard/TemplateChartComponent.d.ts.map +1 -0
- package/dist/esm/components/Dashboard/TemplateChartComponent.js +17 -0
- package/dist/esm/components/Dashboard/TemplateMetricComponent.d.ts +4 -0
- package/dist/esm/components/Dashboard/TemplateMetricComponent.d.ts.map +1 -0
- package/dist/esm/components/Dashboard/TemplateMetricComponent.js +17 -0
- package/dist/esm/components/Dashboard/TemplateTableComponent.d.ts +15 -0
- package/dist/esm/components/Dashboard/TemplateTableComponent.d.ts.map +1 -0
- package/dist/esm/components/Dashboard/TemplateTableComponent.js +17 -0
- package/dist/esm/components/Dashboard/util.d.ts +6 -0
- package/dist/esm/components/Dashboard/util.d.ts.map +1 -0
- package/dist/esm/components/Dashboard/util.js +80 -0
- package/dist/esm/components/ReportBuilder/FilterModal.js +32 -32
- package/dist/esm/components/ReportBuilder/convert.d.ts +5 -31
- package/dist/esm/components/ReportBuilder/convert.d.ts.map +1 -1
- package/dist/esm/components/ReportBuilder/convert.js +1 -1
- package/dist/esm/components/UiComponents.d.ts +1 -23
- package/dist/esm/components/UiComponents.d.ts.map +1 -1
- package/dist/esm/components/UiComponents.js +65 -23
- package/dist/esm/hooks/useAskQuill.d.ts +27 -0
- package/dist/esm/hooks/useAskQuill.d.ts.map +1 -0
- package/dist/esm/hooks/useAskQuill.js +173 -0
- package/dist/esm/hooks/useDashboard.d.ts.map +1 -1
- package/dist/esm/hooks/useDashboard.js +7 -5
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/internals/ReportBuilder/PivotForm.d.ts +3 -3
- package/dist/esm/internals/ReportBuilder/PivotForm.d.ts.map +1 -1
- package/dist/esm/internals/ReportBuilder/PivotForm.js +4 -2
- package/dist/esm/internals/ReportBuilder/PivotModal.d.ts +1 -15
- package/dist/esm/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
- package/dist/esm/internals/ReportBuilder/PivotModal.js +24 -24
- package/dist/esm/models/Filter.d.ts +25 -19
- package/dist/esm/models/Filter.d.ts.map +1 -1
- package/dist/esm/models/Filter.js +2 -2
- package/dist/esm/{components/ReportBuilder/pivot.d.ts → models/Pivot.d.ts} +13 -4
- package/dist/esm/models/Pivot.d.ts.map +1 -0
- package/dist/esm/models/Report.d.ts +5 -1
- package/dist/esm/models/Report.d.ts.map +1 -1
- package/dist/esm/models/Tables.d.ts +16 -0
- package/dist/esm/models/Tables.d.ts.map +1 -1
- package/dist/esm/utils/astFilterProcessing.js +27 -27
- package/dist/esm/utils/astProcessing.d.ts +42 -0
- package/dist/esm/utils/astProcessing.d.ts.map +1 -1
- package/dist/esm/utils/astProcessing.js +204 -0
- package/dist/esm/utils/constants.d.ts +1 -0
- package/dist/esm/utils/constants.d.ts.map +1 -1
- package/dist/esm/utils/constants.js +1 -0
- package/dist/esm/utils/dashboard.d.ts.map +1 -1
- package/dist/esm/utils/dashboard.js +2 -0
- package/dist/esm/utils/dataFetcher.d.ts +4 -0
- package/dist/esm/utils/dataFetcher.d.ts.map +1 -1
- package/dist/esm/utils/dataFetcher.js +22 -0
- package/dist/esm/utils/dates.d.ts +1 -1
- package/dist/esm/utils/filterProcessing.d.ts +2 -2
- package/dist/esm/utils/filterProcessing.d.ts.map +1 -1
- package/dist/esm/utils/filterProcessing.js +7 -7
- package/dist/esm/utils/pivotConstructor.d.ts +1 -1
- package/dist/esm/utils/pivotConstructor.d.ts.map +1 -1
- package/dist/esm/utils/pivotConstructor.js +7 -4
- package/dist/esm/utils/pivotProcessing.d.ts +4 -4
- package/dist/esm/utils/pivotProcessing.d.ts.map +1 -1
- package/dist/esm/utils/pivotProcessing.js +19 -1
- package/dist/esm/utils/queryConstructor.d.ts +1 -1
- package/dist/esm/utils/queryConstructor.d.ts.map +1 -1
- package/dist/esm/utils/queryConstructor.js +3 -3
- package/dist/esm/utils/report.d.ts +25 -0
- package/dist/esm/utils/report.d.ts.map +1 -1
- package/dist/esm/utils/report.js +114 -3
- package/dist/esm/utils/schema.d.ts.map +1 -1
- package/dist/esm/utils/schema.js +1 -1
- package/dist/esm/utils/tableProcessing.d.ts +18 -0
- package/dist/esm/utils/tableProcessing.d.ts.map +1 -1
- package/dist/esm/utils/tableProcessing.js +91 -1
- package/package.json +1 -1
- package/dist/cjs/components/ReportBuilder/pivot.d.ts.map +0 -1
- package/dist/cjs/models/Pivots.d.ts +0 -2
- package/dist/cjs/models/Pivots.d.ts.map +0 -1
- package/dist/cjs/models/Pivots.js +0 -2
- package/dist/esm/components/ReportBuilder/pivot.d.ts.map +0 -1
- package/dist/esm/models/Pivots.d.ts +0 -2
- package/dist/esm/models/Pivots.d.ts.map +0 -1
- package/dist/esm/models/Pivots.js +0 -1
- /package/dist/cjs/{components/ReportBuilder/pivot.js → models/Pivot.js} +0 -0
- /package/dist/esm/{components/ReportBuilder/pivot.js → models/Pivot.js} +0 -0
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useContext, useEffect, useRef, useState, } from 'react';
|
|
3
|
-
import { DEFAULT_TAB_OPTIONS, MemoizedButton,
|
|
3
|
+
import { DEFAULT_TAB_OPTIONS, MemoizedButton, MemoizedDeleteButton, MemoizedHeader, MemoizedLabel, MemoizedSecondaryButton, MemoizedText, MemoizedPopover, QuillTabs, MemoizedModal, QuillChartBuilderInputRowContainer, QuillChartBuilderInputColumnContainer, MemoizedSubHeader, QuillErrorMessageComponent, QuillPivotRowContainer, QuillPivotColumnContainer, QuillColumnSearchEmptyState, QuillChartBuilderFormContainer, QuillLoadingComponent, QuillTableSQLEditorComponent, } from './components/UiComponents';
|
|
4
4
|
import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, } from '@dnd-kit/core';
|
|
5
5
|
import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable, } from '@dnd-kit/sortable';
|
|
6
6
|
import { CSS as DND_CSS } from '@dnd-kit/utilities';
|
|
7
|
-
import { ClientContext, CustomFieldContext, SchemaContext, ThemeContext, } from './Context';
|
|
8
|
-
import {
|
|
9
|
-
import { ChartBuilderWithModal
|
|
7
|
+
import { ClientContext, CustomFieldContext, DashboardContext, SchemaContext, ThemeContext, } from './Context';
|
|
8
|
+
import { getTableNames, isNumericColumnType, isTextColumnType, } from './components/ReportBuilder/ast';
|
|
9
|
+
import { ChartBuilderWithModal } from './ChartBuilder';
|
|
10
10
|
import { QuillTextInput } from './components/UiComponents';
|
|
11
11
|
import { QuillSidebar, CustomContainer, QuillSelectColumn, QuillDraggableColumn, QuillSidebarHeading, QuillFilterPopover, QuillSortPopover, QuillLimitPopover, FilterPopoverWrapper, } from './components/ReportBuilder/ui';
|
|
12
|
-
import {
|
|
13
|
-
import { convertBigQuery, convertGroupBy, convertRemoveSimpleParentheses, convertStringComparison, convertWildcardColumns, convertUnaryToBinary, } from './components/ReportBuilder/convert';
|
|
14
|
-
import { deepCopy, formatDateComparisonNode, getDateFilterInfo, isColumnComparison, isDateTruncEquals, isInTheLastInterval, isNodeEmptyCollection, isTheCurrentInterval, isThePreviousInterval, showNodeAsRow, removeNonSelectedTableReferences, isEquals, } from './components/ReportBuilder/util';
|
|
15
|
-
import { getDefaultOperatorSubtrees, OPERATOR_GROUPS, } from './components/ReportBuilder/operators';
|
|
12
|
+
import { deepCopy } from './components/ReportBuilder/util';
|
|
16
13
|
import { hashCode } from './utils/crypto';
|
|
17
|
-
import { defaultAST,
|
|
14
|
+
import { defaultAST, defaultColumn, defaultEntry, defaultNumericComparison, defaultTable, defaultVariant, } from './components/ReportBuilder/constants';
|
|
18
15
|
import AddColumnModal from './components/ReportBuilder/AddColumnModal';
|
|
19
16
|
import { AddSortPopover, SortSentence, } from './components/ReportBuilder/AddSortPopover';
|
|
20
17
|
import { PivotModal, generatePivotTable, } from './internals/ReportBuilder/PivotModal';
|
|
@@ -23,14 +20,11 @@ import { AddLimitPopover, LimitSentence, } from './components/ReportBuilder/AddL
|
|
|
23
20
|
import { updateFirstChildWidth } from './utils/width';
|
|
24
21
|
import { QuillSelectComponent } from './components/QuillSelect';
|
|
25
22
|
import { QuillCard } from './components/QuillCard';
|
|
26
|
-
import { getData } from './utils/dataFetcher';
|
|
27
23
|
import { DATE_FORMAT_TYPES, quillFormat } from './utils/valueFormatter';
|
|
28
|
-
import {
|
|
24
|
+
import { pivotToSql } from './utils/pivotProcessing';
|
|
29
25
|
import { getUniqueValuesByColumns, getDateRangeByColumns, getCountsByColumns, fetchTableByQuery, } from './utils/tableProcessing';
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import { convertColumnInfoToColumnInternal, convertPostgresColumn, } from './utils/columnProcessing';
|
|
33
|
-
import { getSelectFromAST, processApostrophe, processStarColumn, } from './utils/astProcessing';
|
|
26
|
+
import { convertColumnInfoToColumnInternal } from './utils/columnProcessing';
|
|
27
|
+
import { fetchAndProcessASTFromPrompt, fetchASTFromQuillReport, getAllPossibleColumns, } from './utils/astProcessing';
|
|
34
28
|
import PivotForm from './internals/ReportBuilder/PivotForm';
|
|
35
29
|
import { getSchemaInfoWithCustomFields } from './utils/schema';
|
|
36
30
|
import { getDateBucketFromRange } from './utils/dates';
|
|
@@ -40,8 +34,7 @@ import useAstToFilterTree from './hooks/useAstToFilterTree';
|
|
|
40
34
|
import { filterSentence } from './utils/filterProcessing';
|
|
41
35
|
import { QuillMultiSelectComponentWithCombo } from './components/QuillMultiSelectWithCombo';
|
|
42
36
|
import { shouldFetchMore, DEFAULT_PAGINATION, shouldSortInMemory, } from './utils/paginationProcessing';
|
|
43
|
-
import { EMPTY_REPORT, formatRowsFromReport } from './utils/report';
|
|
44
|
-
import { parseValueFromBigQueryDates } from './utils/dataProcessing';
|
|
37
|
+
import { EMPTY_REPORT, fetchReportBuilderDataFromAST, formatRowsFromReport, } from './utils/report';
|
|
45
38
|
export const QUILL_SERVER = (typeof process !== 'undefined' && process?.env?.QUILL_SERVER_HOST) ||
|
|
46
39
|
'https://quill-344421.uc.r.appspot.com';
|
|
47
40
|
/**
|
|
@@ -75,8 +68,12 @@ export const QUILL_SERVER = (typeof process !== 'undefined' && process?.env?.QUI
|
|
|
75
68
|
* ### Report Builder API
|
|
76
69
|
* @see https://docs.quillsql.com/components/report-builder
|
|
77
70
|
*/
|
|
78
|
-
export default function ReportBuilder({ initialTableName = '', onSubmitEditReport = () => void null, onSubmitCreateReport = () => void null, destinationDashboard = undefined, organizationName = '', ButtonComponent = MemoizedButton, SecondaryButtonComponent = MemoizedSecondaryButton, DeleteButtonComponent = MemoizedDeleteButton, ModalComponent = MemoizedModal, TextInputComponent = QuillTextInput, SelectComponent = QuillSelectComponent, MultiSelectComponent = QuillMultiSelectComponentWithCombo, TableComponent = QuillTableSQLEditorComponent, PopoverComponent = MemoizedPopover, TabsComponent = QuillTabs,
|
|
79
|
-
|
|
71
|
+
export default function ReportBuilder({ initialTableName = '', onSubmitEditReport = () => void null, onSubmitCreateReport = () => void null, destinationDashboard = undefined, organizationName = '', ButtonComponent = MemoizedButton, SecondaryButtonComponent = MemoizedSecondaryButton, DeleteButtonComponent = MemoizedDeleteButton, ModalComponent = MemoizedModal, TextInputComponent = QuillTextInput, SelectComponent = QuillSelectComponent, MultiSelectComponent = QuillMultiSelectComponentWithCombo, TableComponent = QuillTableSQLEditorComponent, PopoverComponent = MemoizedPopover, TabsComponent = QuillTabs,
|
|
72
|
+
// CheckboxComponent = MemoizedCheckbox,
|
|
73
|
+
SidebarComponent = QuillSidebar, ContainerComponent = CustomContainer, SelectColumnComponent = QuillSelectColumn, DraggableColumnComponent = QuillDraggableColumn, SidebarHeadingComponent = QuillSidebarHeading, FilterPopoverComponent = QuillFilterPopover, SortPopoverComponent = QuillSortPopover, LimitPopoverComponent = QuillLimitPopover, CardComponent = QuillCard, LabelComponent = MemoizedLabel, HeaderComponent = MemoizedHeader, SubHeaderComponent = MemoizedSubHeader, TextComponent = MemoizedText, ErrorMessageComponent = QuillErrorMessageComponent, ChartBuilderInputRowContainer = QuillChartBuilderInputRowContainer, ChartBuilderInputColumnContainer = QuillChartBuilderInputColumnContainer, PivotRowContainer = QuillPivotRowContainer, PivotColumnContainer = QuillPivotColumnContainer, LoadingComponent = QuillLoadingComponent, ColumnSearchEmptyState = QuillColumnSearchEmptyState, ChartBuilderFormContainer = QuillChartBuilderFormContainer, ChartBuilderModalComponent = MemoizedModal, isAdminEnabled = false, isAIEnabled = true, showChartBuilderTableFormatOptions = true, containerStyle, className, pivotRecommendationsEnabled = true, reportId, hideCopySQL = true, isChartBuilderHorizontalView = true, onClickChartElement, }) {
|
|
74
|
+
const [dashboard] = useContext(DashboardContext);
|
|
75
|
+
const [schema, setSchema] = useContext(SchemaContext);
|
|
76
|
+
const [reportInfo, setReportInfo] = useState(null);
|
|
80
77
|
const [aiPrompt, setAiPrompt] = useState('');
|
|
81
78
|
const [errorMessage, setErrorMessage] = useState('');
|
|
82
79
|
const [baseAst, setBaseAst] = useState(null);
|
|
@@ -84,22 +81,20 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
84
81
|
const [orderedColumnNames, setOrderedColumnNames] = useState([]);
|
|
85
82
|
const [selectedColumns, setSelectedColumns] = useState([]);
|
|
86
83
|
const [selectedOrderedColumns, setSelectedOrderedColumns] = useState([]);
|
|
87
|
-
const [schema, setSchema] = useContext(SchemaContext);
|
|
88
84
|
const [activeQuery, setActiveQuery] = useState('');
|
|
89
|
-
const [
|
|
85
|
+
const [, setActiveEditItem] = useState(null);
|
|
90
86
|
const [activePath, setActivePath] = useState(null);
|
|
91
87
|
const [openPopover, setOpenPopover] = useState(null);
|
|
92
88
|
const [loading, setLoading] = useState(!!initialTableName);
|
|
93
89
|
const [loadingSchema, setLoadingSchema] = useState(false);
|
|
94
90
|
const [isChartBuilderOpen, setIsChartBuilderOpen] = useState(false);
|
|
95
|
-
const [
|
|
91
|
+
const [, setIsPending] = useState(false);
|
|
96
92
|
const [isCopying, setIsCopying] = useState(false);
|
|
97
93
|
const [dataDisplayed, setDataDisplayed] = useState(false);
|
|
98
94
|
const [rows, setRows] = useState([]);
|
|
99
95
|
const [formattedRows, setFormattedRows] = useState([]);
|
|
100
96
|
const [columns, setColumns] = useState([]);
|
|
101
97
|
const [tempReport, setTempReport] = useState(EMPTY_REPORT);
|
|
102
|
-
const [topLevelBinaryOperator, setTopLevelBinaryOperator] = useState('AND');
|
|
103
98
|
const [uniqueValues, setUniqueValues] = useState({});
|
|
104
99
|
const [pivot, setPivot] = useState(null);
|
|
105
100
|
const [pivotData, setPivotData] = useState(null);
|
|
@@ -183,7 +178,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
183
178
|
const column = columns.find((c) => c.field === changeField);
|
|
184
179
|
if (column?.jsType === 'date') {
|
|
185
180
|
newPivot.rowFieldType = 'date';
|
|
186
|
-
newPivot.sort =
|
|
181
|
+
newPivot.sort = true;
|
|
187
182
|
newPivot.sortField = changeField;
|
|
188
183
|
newPivot.sortFieldType = column.format;
|
|
189
184
|
newPivot.sortDirection = 'ASC';
|
|
@@ -194,7 +189,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
194
189
|
}
|
|
195
190
|
}
|
|
196
191
|
let dateBucket = undefined;
|
|
197
|
-
const tempDateRange = dateRanges && dateRanges[newPivot.rowField];
|
|
192
|
+
const tempDateRange = dateRanges && dateRanges[newPivot.rowField || ''];
|
|
198
193
|
if (tempDateRange) {
|
|
199
194
|
dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
|
|
200
195
|
}
|
|
@@ -247,7 +242,6 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
247
242
|
setDataDisplayed(false);
|
|
248
243
|
setRows([]);
|
|
249
244
|
setColumns([]);
|
|
250
|
-
setTopLevelBinaryOperator('AND');
|
|
251
245
|
setErrorMessage('');
|
|
252
246
|
setFormattedRows([]);
|
|
253
247
|
// setUniqueValues({});
|
|
@@ -264,12 +258,6 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
264
258
|
clearAllState();
|
|
265
259
|
}
|
|
266
260
|
}, [client]);
|
|
267
|
-
useEffect(() => {
|
|
268
|
-
if (activePath !== null) {
|
|
269
|
-
// update the modal with the new subtree
|
|
270
|
-
setActiveEditItem(getByKey(formData, activePath));
|
|
271
|
-
}
|
|
272
|
-
}, [formData]);
|
|
273
261
|
const formatRows = (rows, columns, pivot, aggregationType) => {
|
|
274
262
|
const copiedRows = deepCopy(rows);
|
|
275
263
|
if (pivot) {
|
|
@@ -314,19 +302,6 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
314
302
|
return formattedRows;
|
|
315
303
|
}
|
|
316
304
|
};
|
|
317
|
-
const getByKey = (formData, path) => {
|
|
318
|
-
if (!path)
|
|
319
|
-
return deepCopy(formData);
|
|
320
|
-
// Function to immutably update or delete nodes based on their path
|
|
321
|
-
const paths = path.split('.');
|
|
322
|
-
let current = deepCopy(formData);
|
|
323
|
-
for (let i = 0; i < paths.length; i++) {
|
|
324
|
-
if (current[paths[i]]) {
|
|
325
|
-
current = current[paths[i]];
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
return current;
|
|
329
|
-
};
|
|
330
305
|
const copySQLToClipboard = () => {
|
|
331
306
|
let query = activeQuery;
|
|
332
307
|
if (pivot) {
|
|
@@ -371,7 +346,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
371
346
|
const data = await response.json();
|
|
372
347
|
setActiveQuery(data.query);
|
|
373
348
|
if (fetchData) {
|
|
374
|
-
|
|
349
|
+
fetchReportFromASTHelper(ast, formData);
|
|
375
350
|
}
|
|
376
351
|
return data.query;
|
|
377
352
|
}
|
|
@@ -459,7 +434,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
459
434
|
return -1;
|
|
460
435
|
return 0;
|
|
461
436
|
});
|
|
462
|
-
await
|
|
437
|
+
await fetchAstFromPromptHelper(`get ${columnsForTable} from ${initialTableName}`);
|
|
463
438
|
setInitialLoad(false);
|
|
464
439
|
};
|
|
465
440
|
const fetchSchema = async () => {
|
|
@@ -498,106 +473,27 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
498
473
|
};
|
|
499
474
|
useEffect(() => {
|
|
500
475
|
const loadChart = async () => {
|
|
501
|
-
|
|
502
|
-
// @ts-ignore THIS PROCESS SHOULD BE UPDATED TO NOT USE USEQUILL
|
|
503
|
-
if (!report || report.referencedTables.length !== 1) {
|
|
504
|
-
setInitialChartLoad(false);
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
476
|
+
let report;
|
|
507
477
|
try {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
const ast = getSelectFromAST(resp.ast);
|
|
523
|
-
let convertedAst = processStarColumn(ast, report.columns);
|
|
524
|
-
processApostrophe(convertedAst, ['type', 'value']);
|
|
525
|
-
convertedAst = convertBigQuery(convertedAst);
|
|
526
|
-
const schemaInfo = schema.length !== 0 ? schema : await fetchSchema();
|
|
527
|
-
let newAst;
|
|
528
|
-
let groupByPivot = {};
|
|
529
|
-
({ ast: newAst, pivot: groupByPivot } = convertGroupBy(convertedAst,
|
|
530
|
-
// @ts-ignore
|
|
531
|
-
report.pivot, schemaInfo));
|
|
532
|
-
if (convertedAst.where) {
|
|
533
|
-
setFormData(deepCopy(convertedAst.where));
|
|
534
|
-
}
|
|
535
|
-
// @ts-ignore THIS PROCESS SHOULD BE UPDATED TO NOT USE USEQUILL
|
|
536
|
-
setActiveQuery(report.queryString);
|
|
537
|
-
newAst = groupByPivot ? newAst : convertedAst;
|
|
538
|
-
const initialRows = await fetchUponChange(newAst, undefined);
|
|
539
|
-
if (initialRows.error) {
|
|
540
|
-
setBaseAst(null);
|
|
541
|
-
setErrorMessage(initialRows.message);
|
|
542
|
-
setInitialChartLoad(false);
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
setBaseAst(newAst);
|
|
546
|
-
const tableInfo = schemaInfo.find((table) => table.name === tableName);
|
|
547
|
-
let newUniqueValues = undefined;
|
|
548
|
-
let dateRangesTemp = undefined;
|
|
549
|
-
if (tableName) {
|
|
550
|
-
newUniqueValues = await getUniqueStringValues(tableInfo.columns, tableName);
|
|
551
|
-
setUniqueValues(newUniqueValues);
|
|
552
|
-
dateRangesTemp = await getDateRanges(tableInfo.columns, tableName);
|
|
553
|
-
setDateRanges(dateRangesTemp);
|
|
554
|
-
}
|
|
555
|
-
if (groupByPivot) {
|
|
556
|
-
// @ts-ignore
|
|
557
|
-
setPivotRowField(groupByPivot.rowField);
|
|
558
|
-
// @ts-ignore
|
|
559
|
-
setPivotAggregation(groupByPivot.aggregationType);
|
|
560
|
-
// @ts-ignore
|
|
561
|
-
setPivotColumnField(groupByPivot.columnField);
|
|
562
|
-
// @ts-ignore
|
|
563
|
-
setPivotValueField(groupByPivot.valueField);
|
|
564
|
-
setPivot(groupByPivot);
|
|
565
|
-
let dateBucket = undefined;
|
|
566
|
-
const tempDateRange = dateRangesTemp &&
|
|
567
|
-
groupByPivot.rowField &&
|
|
568
|
-
dateRangesTemp[groupByPivot.rowField];
|
|
569
|
-
if (tempDateRange) {
|
|
570
|
-
dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
|
|
571
|
-
}
|
|
572
|
-
const pivotedData = await generatePivotTable(
|
|
573
|
-
// @ts-ignore
|
|
574
|
-
groupByPivot, initialRows, tempDateRange, false, -1, undefined, dateBucket, report, client, newUniqueValues[tableName]);
|
|
575
|
-
setPivotData(pivotedData || []);
|
|
576
|
-
const formattedRows = formatRows(pivotedData.rows, report.columns, true,
|
|
577
|
-
// @ts-ignore
|
|
578
|
-
groupByPivot.aggregationType);
|
|
579
|
-
setFormattedRows(formattedRows);
|
|
580
|
-
}
|
|
581
|
-
else {
|
|
582
|
-
const formattedRows = formatRows(report.rows, report.columns);
|
|
583
|
-
setFormattedRows(formattedRows);
|
|
584
|
-
}
|
|
585
|
-
setCurrentTable(tableName);
|
|
586
|
-
}
|
|
587
|
-
catch (error) {
|
|
588
|
-
console.error(error);
|
|
589
|
-
setErrorMessage('Error loading report');
|
|
478
|
+
if (!reportId) {
|
|
479
|
+
throw new Error('Report ID is required');
|
|
480
|
+
}
|
|
481
|
+
report = dashboard[reportId];
|
|
482
|
+
if (!report || report.referencedTables?.length !== 1) {
|
|
483
|
+
throw new Error('Report not found');
|
|
484
|
+
}
|
|
485
|
+
const { ast: newAst, pivot: newPivot, schema: curSchema, } = await fetchASTFromQuillReport(report, client, schema);
|
|
486
|
+
setBaseAst({ ...newAst, where: null });
|
|
487
|
+
await fetchReportFromASTHelper({ ...newAst, where: null }, newAst.where, newPivot, curSchema, report);
|
|
488
|
+
await fetchSchema();
|
|
489
|
+
setReportInfo(report);
|
|
590
490
|
}
|
|
591
|
-
|
|
592
|
-
setTimeout(() => {
|
|
491
|
+
catch (err) {
|
|
593
492
|
setInitialChartLoad(false);
|
|
594
|
-
}
|
|
493
|
+
}
|
|
595
494
|
};
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
loadChart();
|
|
599
|
-
}
|
|
600
|
-
}, [report]);
|
|
495
|
+
loadChart();
|
|
496
|
+
}, [dashboard[reportId || '']]);
|
|
601
497
|
useEffect(() => {
|
|
602
498
|
if (schema.length === 0) {
|
|
603
499
|
fetchSchema();
|
|
@@ -620,7 +516,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
620
516
|
...defaultAST,
|
|
621
517
|
...baseAst,
|
|
622
518
|
...(!baseAst?.columns && {
|
|
623
|
-
columns: getAllPossibleColumns().map((c) => {
|
|
519
|
+
columns: getAllPossibleColumns(baseAst, schema).map((c) => {
|
|
624
520
|
const newColumn = deepCopy(defaultColumn);
|
|
625
521
|
newColumn.expr.column = c.name;
|
|
626
522
|
return newColumn;
|
|
@@ -640,7 +536,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
640
536
|
...defaultAST,
|
|
641
537
|
...baseAst,
|
|
642
538
|
...(!baseAst?.columns && {
|
|
643
|
-
columns: getAllPossibleColumns().map((c) => {
|
|
539
|
+
columns: getAllPossibleColumns(baseAst, schema).map((c) => {
|
|
644
540
|
const newColumn = deepCopy(defaultColumn);
|
|
645
541
|
newColumn.expr.column = c.name;
|
|
646
542
|
return newColumn;
|
|
@@ -741,7 +637,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
741
637
|
...defaultAST,
|
|
742
638
|
...baseAst,
|
|
743
639
|
...(!baseAst?.columns && {
|
|
744
|
-
columns: getAllPossibleColumns().map((c) => {
|
|
640
|
+
columns: getAllPossibleColumns(baseAst, schema).map((c) => {
|
|
745
641
|
const newColumn = deepCopy(defaultColumn);
|
|
746
642
|
newColumn.expr.column = c.name;
|
|
747
643
|
return newColumn;
|
|
@@ -756,169 +652,6 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
756
652
|
fetchSqlQuery(newAst, newState);
|
|
757
653
|
});
|
|
758
654
|
};
|
|
759
|
-
// TODO: Merge this function with the updateFormData function
|
|
760
|
-
const updateActiveItem = (updates, { isDeletion = false, isInsertion = false, isReplaceSubtree = false, isAddVariant = false, isDeleteVariant = false, column = undefined, }) => {
|
|
761
|
-
let newState = deepCopy(activeEditItem);
|
|
762
|
-
updates.forEach(({ path, value }) => {
|
|
763
|
-
let current = newState;
|
|
764
|
-
const globalPath = path;
|
|
765
|
-
const paths = globalPath.split('.').filter((p) => p);
|
|
766
|
-
if (paths.length === 0 && !isInsertion && !isReplaceSubtree) {
|
|
767
|
-
setActiveEditItem(null);
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
const isOperatorChange = paths[paths.length - 1] === 'operator';
|
|
771
|
-
let parent = null;
|
|
772
|
-
let parentKey = null;
|
|
773
|
-
for (let i = 0; i < paths.length - 1; i++) {
|
|
774
|
-
let currentPath = paths[i];
|
|
775
|
-
let index;
|
|
776
|
-
if (paths[i].includes('||')) {
|
|
777
|
-
const splitPath = paths[i].split('||');
|
|
778
|
-
currentPath = splitPath[0];
|
|
779
|
-
index = splitPath[1];
|
|
780
|
-
}
|
|
781
|
-
if (current[currentPath]) {
|
|
782
|
-
parent = current;
|
|
783
|
-
parentKey = currentPath;
|
|
784
|
-
current = current[currentPath];
|
|
785
|
-
}
|
|
786
|
-
if (index) {
|
|
787
|
-
current = current[parseInt(index)];
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
const lastKey = paths[paths.length - 1];
|
|
791
|
-
if (isDeletion) {
|
|
792
|
-
if (lastKey === 'left' || lastKey === 'right') {
|
|
793
|
-
if (parent) {
|
|
794
|
-
if (lastKey === 'right') {
|
|
795
|
-
parent[parentKey] = parent[parentKey].left;
|
|
796
|
-
}
|
|
797
|
-
else {
|
|
798
|
-
parent[parentKey] = parent[parentKey].right;
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
else {
|
|
802
|
-
delete current[lastKey];
|
|
803
|
-
if (newState?.left && !newState?.right) {
|
|
804
|
-
newState = newState.left;
|
|
805
|
-
}
|
|
806
|
-
else if (newState?.right && !newState?.left) {
|
|
807
|
-
newState = newState.right;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
else if (isInsertion) {
|
|
813
|
-
const columns = getAllPossibleColumns();
|
|
814
|
-
const defaultColumn = columns[0].name;
|
|
815
|
-
// TODO: I think this is a bug, take a closer look here
|
|
816
|
-
newState = {
|
|
817
|
-
type: 'binary_expr',
|
|
818
|
-
operator: 'AND',
|
|
819
|
-
left: newState,
|
|
820
|
-
right: {
|
|
821
|
-
...defaultEntry,
|
|
822
|
-
left: {
|
|
823
|
-
...defaultEntry.left,
|
|
824
|
-
column: defaultColumn,
|
|
825
|
-
},
|
|
826
|
-
},
|
|
827
|
-
};
|
|
828
|
-
}
|
|
829
|
-
else if (isAddVariant) {
|
|
830
|
-
const newVariant = deepCopy(defaultVariant);
|
|
831
|
-
if (value) {
|
|
832
|
-
newVariant.args.value[0].value = value;
|
|
833
|
-
// if there is already a single default value there,
|
|
834
|
-
// let's remove it so when we push we replace.
|
|
835
|
-
if (current[lastKey].length === 1 &&
|
|
836
|
-
current[lastKey][0].args.value[0].value === '') {
|
|
837
|
-
current[lastKey].pop();
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
current[lastKey].push(newVariant);
|
|
841
|
-
}
|
|
842
|
-
else if (isDeleteVariant) {
|
|
843
|
-
if (value) {
|
|
844
|
-
const argList = current[lastKey];
|
|
845
|
-
argList.splice(argList.findIndex((arg) => arg.args.value[0].value === value), 1);
|
|
846
|
-
}
|
|
847
|
-
else {
|
|
848
|
-
current[lastKey].pop();
|
|
849
|
-
}
|
|
850
|
-
// add back in a phantom element to prevent app from crashing
|
|
851
|
-
// when the user removes all variants and hits save.
|
|
852
|
-
if (current[lastKey].length === 0) {
|
|
853
|
-
const newVariant = deepCopy(defaultVariant);
|
|
854
|
-
newVariant.args.value[0].value = '';
|
|
855
|
-
current[lastKey].push(newVariant);
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
else if (isReplaceSubtree) {
|
|
859
|
-
if (lastKey) {
|
|
860
|
-
current[lastKey] = value;
|
|
861
|
-
}
|
|
862
|
-
else {
|
|
863
|
-
newState = value;
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
else if (isOperatorChange) {
|
|
867
|
-
const newOp = value;
|
|
868
|
-
const oldOp = current[lastKey];
|
|
869
|
-
if (OPERATOR_GROUPS[oldOp] === OPERATOR_GROUPS[newOp]) {
|
|
870
|
-
current[lastKey] = value;
|
|
871
|
-
}
|
|
872
|
-
else {
|
|
873
|
-
const group = OPERATOR_GROUPS[newOp];
|
|
874
|
-
const subtree = getDefaultOperatorSubtrees(group, newOp, column, '', client.databaseType);
|
|
875
|
-
if (parentKey) {
|
|
876
|
-
parent[parentKey] = deepCopy(subtree);
|
|
877
|
-
}
|
|
878
|
-
else {
|
|
879
|
-
newState = deepCopy(subtree);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
else {
|
|
884
|
-
if (typeof current[lastKey] === 'object' && current[lastKey] !== null) {
|
|
885
|
-
current[lastKey].value = value;
|
|
886
|
-
}
|
|
887
|
-
else {
|
|
888
|
-
current[lastKey] = value;
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
});
|
|
892
|
-
// Function to immutably update or delete nodes based on their path
|
|
893
|
-
setActiveEditItem(newState);
|
|
894
|
-
};
|
|
895
|
-
const handleChange = (updates) => {
|
|
896
|
-
const callback = isPending ? updateActiveItem : updateFormData;
|
|
897
|
-
callback(updates, {});
|
|
898
|
-
};
|
|
899
|
-
const handleChangeText = (updates) => {
|
|
900
|
-
const callback = isPending ? updateActiveItem : updateFormData;
|
|
901
|
-
callback(updates, {});
|
|
902
|
-
};
|
|
903
|
-
// Function to handle operator changes
|
|
904
|
-
const handleOperatorChange = (value, node, keyPrefix, column = null) => {
|
|
905
|
-
if (!keyPrefix) {
|
|
906
|
-
setTopLevelBinaryOperator(value);
|
|
907
|
-
}
|
|
908
|
-
if (isPending) {
|
|
909
|
-
updateActiveItem([{ path: keyPrefix + 'operator', value }], { column });
|
|
910
|
-
}
|
|
911
|
-
else {
|
|
912
|
-
updateFormData([{ path: keyPrefix + 'operator', value }], { column });
|
|
913
|
-
}
|
|
914
|
-
};
|
|
915
|
-
// Function to replace an entire subtree with a given value.
|
|
916
|
-
const handleReplaceSubtree = (keyPrefix, newValue, pending = isPending) => {
|
|
917
|
-
const callback = pending ? updateActiveItem : updateFormData;
|
|
918
|
-
callback([{ path: keyPrefix, value: newValue }], {
|
|
919
|
-
isReplaceSubtree: true,
|
|
920
|
-
});
|
|
921
|
-
};
|
|
922
655
|
// Function to handle the insertion of expressions
|
|
923
656
|
const handleInsertion = (value, op = 'OR', isCondition = undefined) => {
|
|
924
657
|
updateFormData([{ path: '', value }], {
|
|
@@ -927,23 +660,6 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
927
660
|
isCondition,
|
|
928
661
|
});
|
|
929
662
|
};
|
|
930
|
-
// Function to handle the insertion of expr_list variants
|
|
931
|
-
const handleInsertVariant = (key, name = null) => {
|
|
932
|
-
// note: if name, treat that as the name of the value to insert
|
|
933
|
-
const callback = isPending ? updateActiveItem : updateFormData;
|
|
934
|
-
callback([{ path: key, value: name }], { isAddVariant: true });
|
|
935
|
-
};
|
|
936
|
-
// Function to handle the insertion of expr_list variants
|
|
937
|
-
const handleDeleteVariant = (key, name = null) => {
|
|
938
|
-
// note: if name, treat that as the name of the valeu to delete
|
|
939
|
-
const callback = isPending ? updateActiveItem : updateFormData;
|
|
940
|
-
callback([{ path: key, value: name }], { isDeleteVariant: true });
|
|
941
|
-
};
|
|
942
|
-
const getColumnValueForColumnComparison = (node) => node.left.value ??
|
|
943
|
-
node.left.column ??
|
|
944
|
-
node.left.args?.value[0]?.value ??
|
|
945
|
-
node.left.args?.value[0]?.column ??
|
|
946
|
-
undefined;
|
|
947
663
|
/**
|
|
948
664
|
* Searches for the column by name and returns the field type.
|
|
949
665
|
*
|
|
@@ -1040,676 +756,6 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
1040
756
|
return;
|
|
1041
757
|
}
|
|
1042
758
|
};
|
|
1043
|
-
/**
|
|
1044
|
-
* Render form fields based on the type of the node
|
|
1045
|
-
* @param node the AST or subtree to render recursively
|
|
1046
|
-
* @param keyPrefix a stringified version of the path from the root
|
|
1047
|
-
*
|
|
1048
|
-
* Note: The keyPrefix should be separated by '.' characters and each item
|
|
1049
|
-
* should be a valid index into the node (eg. 'left.right.value' is a valid
|
|
1050
|
-
* keyPrefix but 'left.args[0].value' is not -- should be 'left.args.0.value')
|
|
1051
|
-
*/
|
|
1052
|
-
const renderNode = (node, keyPrefix = '') => {
|
|
1053
|
-
const dateComparisonPartialMatch = formatDateComparisonNode(node);
|
|
1054
|
-
switch (node.type) {
|
|
1055
|
-
case 'binary_expr':
|
|
1056
|
-
if (dateComparisonPartialMatch ||
|
|
1057
|
-
(isDateTruncEquals(node) && client.databaseType !== 'BigQuery')) {
|
|
1058
|
-
const { dateColumn, dateFilterType, intervalCount, intervalType, intervalPaths, } = getDateFilterInfo(node);
|
|
1059
|
-
const isPlural = intervalCount !== 1 && dateFilterType !== 'in the current'
|
|
1060
|
-
? 's'
|
|
1061
|
-
: '';
|
|
1062
|
-
// Pull off the string literal date for "equals" comparisons
|
|
1063
|
-
const rawDateStringEquals = node.right?.value ??
|
|
1064
|
-
node.right?.args?.value[1]?.column ??
|
|
1065
|
-
node.right?.args?.value[1]?.value;
|
|
1066
|
-
const rawDateStringEqualsPath = (node.right?.value && 'node.right.value') ??
|
|
1067
|
-
(node.right?.args?.value[1]?.column &&
|
|
1068
|
-
'node.right.args.value.1.column') ??
|
|
1069
|
-
(node.right?.args?.value[1]?.value &&
|
|
1070
|
-
'node.right.args.value.1.value');
|
|
1071
|
-
return (_jsxs("div", { style: { display: 'flex', gap: 20 }, children: [_jsx(SelectComponent, { value: dateColumn, onChange: (event) => {
|
|
1072
|
-
const columnType = getColumnTypeByName(event.target.value);
|
|
1073
|
-
if (isDateishColumnType(columnType)) {
|
|
1074
|
-
// handleChange(value, keyPrefix + dateColumnPath, "text");
|
|
1075
|
-
handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
|
|
1076
|
-
}
|
|
1077
|
-
else if (isNumericColumnType(columnType)) {
|
|
1078
|
-
const newSubtree = deepCopy(defaultNumericComparison);
|
|
1079
|
-
newSubtree.left.column = event.target.value;
|
|
1080
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1081
|
-
}
|
|
1082
|
-
else if (isBoolColumnType(columnType)) {
|
|
1083
|
-
const newSubtree = deepCopy(defaultBoolComparison);
|
|
1084
|
-
newSubtree.left.column = event.target.value;
|
|
1085
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1086
|
-
}
|
|
1087
|
-
else {
|
|
1088
|
-
const newSubtree = deepCopy(defaultEntry);
|
|
1089
|
-
newSubtree.left.args.value[0].column = event.target.value;
|
|
1090
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1091
|
-
}
|
|
1092
|
-
}, options: getAllPossibleColumns().map((column) => ({
|
|
1093
|
-
label: snakeAndCamelCaseToTitleCase(column.displayName),
|
|
1094
|
-
value: column.name,
|
|
1095
|
-
})), width: 200 }), _jsx(SelectComponent, { value: dateFilterType, onChange: (event) => {
|
|
1096
|
-
if (event.target.value === dateFilterType)
|
|
1097
|
-
return null;
|
|
1098
|
-
let newSubtree = {};
|
|
1099
|
-
// TODO: implement one for each database type (eg. pg, snowflake, etc.)
|
|
1100
|
-
if (event.target.value === 'in the last') {
|
|
1101
|
-
newSubtree = generateLastNPeriodsPostgres({
|
|
1102
|
-
dateField: dateColumn,
|
|
1103
|
-
intervalPeriod: `${intervalCount ?? 1} ${intervalType}`,
|
|
1104
|
-
});
|
|
1105
|
-
}
|
|
1106
|
-
else if (event.target.value === 'in the previous') {
|
|
1107
|
-
newSubtree = generatePreviousPeriodPostgres({
|
|
1108
|
-
dateField: dateColumn,
|
|
1109
|
-
intervalPeriod: `${intervalCount ?? 1} ${intervalType}`,
|
|
1110
|
-
currentPeriod: intervalType,
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1113
|
-
else if (event.target.value === 'in the current') {
|
|
1114
|
-
newSubtree = generateCurrentPeriodPostgres({
|
|
1115
|
-
dateField: dateColumn,
|
|
1116
|
-
currentPeriod: intervalType,
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
1119
|
-
else if (event.target.value === 'equals') {
|
|
1120
|
-
newSubtree = generateEqualsPostgres({
|
|
1121
|
-
dateField: dateColumn,
|
|
1122
|
-
currentPeriod: intervalType,
|
|
1123
|
-
timestamp: '2024-01-01',
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
// replace the entire subtree for this filter
|
|
1127
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1128
|
-
}, options: [
|
|
1129
|
-
{ label: 'in the last', value: 'in the last' },
|
|
1130
|
-
{ label: 'in the previous', value: 'in the previous' },
|
|
1131
|
-
{ label: 'in the current', value: 'in the current' },
|
|
1132
|
-
{ label: 'equals', value: 'equals' },
|
|
1133
|
-
], width: 200 }), !['in the current', 'equals'].includes(dateFilterType) && (_jsx(TextInputComponent, { id: "date_filter_interval_count", value: intervalCount?.toString() ?? '', width: 70, onChange: (e) => {
|
|
1134
|
-
if (Number.isNaN(parseFloat(e.target.value || '0'))) {
|
|
1135
|
-
alert('Please input a number.');
|
|
1136
|
-
return;
|
|
1137
|
-
}
|
|
1138
|
-
const isPluralNow = parseFloat(e.target.value || '0') !== 1 ? 's' : '';
|
|
1139
|
-
intervalPaths.forEach((intervalPath) => handleChangeText([
|
|
1140
|
-
{
|
|
1141
|
-
value: `${e.target.value || 0} ${intervalType}${isPluralNow}`,
|
|
1142
|
-
path: keyPrefix + intervalPath,
|
|
1143
|
-
},
|
|
1144
|
-
]));
|
|
1145
|
-
} })), _jsx(SelectComponent, { value: intervalType, onChange: (event) => {
|
|
1146
|
-
if (intervalPaths.length === 1 &&
|
|
1147
|
-
dateFilterType !== 'in the previous') {
|
|
1148
|
-
handleChangeText([
|
|
1149
|
-
{
|
|
1150
|
-
value: intervalCount !== null
|
|
1151
|
-
? `${intervalCount} ${event.target.value}${isPlural}`
|
|
1152
|
-
: event.target.value,
|
|
1153
|
-
path: keyPrefix + intervalPaths[0],
|
|
1154
|
-
},
|
|
1155
|
-
]);
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
let newSubtree;
|
|
1159
|
-
if (dateFilterType === 'in the previous') {
|
|
1160
|
-
newSubtree = generatePreviousPeriodPostgres({
|
|
1161
|
-
dateField: dateColumn,
|
|
1162
|
-
intervalPeriod: `${intervalCount ?? 1} ${event.target.value}`,
|
|
1163
|
-
currentPeriod: event.target.value,
|
|
1164
|
-
});
|
|
1165
|
-
}
|
|
1166
|
-
else if (dateFilterType === 'equals') {
|
|
1167
|
-
newSubtree = generateEqualsPostgres({
|
|
1168
|
-
dateField: dateColumn,
|
|
1169
|
-
currentPeriod: event.target.value,
|
|
1170
|
-
timestamp: rawDateStringEquals,
|
|
1171
|
-
});
|
|
1172
|
-
}
|
|
1173
|
-
else {
|
|
1174
|
-
newSubtree = generateCurrentPeriodPostgres({
|
|
1175
|
-
dateField: dateColumn,
|
|
1176
|
-
currentPeriod: event.target.value,
|
|
1177
|
-
});
|
|
1178
|
-
}
|
|
1179
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1180
|
-
}, options: dateFilterType === 'in the previous' ||
|
|
1181
|
-
dateFilterType === 'in the last'
|
|
1182
|
-
? [
|
|
1183
|
-
{ label: `year${isPlural}`, value: 'year' },
|
|
1184
|
-
{ label: `month${isPlural}`, value: 'month' },
|
|
1185
|
-
{ label: `week${isPlural}`, value: 'week' },
|
|
1186
|
-
{ label: `day${isPlural}`, value: 'day' },
|
|
1187
|
-
{ label: `hour${isPlural}`, value: 'hour' },
|
|
1188
|
-
]
|
|
1189
|
-
: [
|
|
1190
|
-
{ label: `year${isPlural}`, value: 'year' },
|
|
1191
|
-
{ label: `quarter${isPlural}`, value: 'quarter' },
|
|
1192
|
-
{ label: `month${isPlural}`, value: 'month' },
|
|
1193
|
-
{ label: `week${isPlural}`, value: 'week' },
|
|
1194
|
-
{ label: `day${isPlural}`, value: 'day' },
|
|
1195
|
-
{ label: `hour${isPlural}`, value: 'hour' },
|
|
1196
|
-
], width: 200 }), dateFilterType === 'equals' && (_jsx(TextInputComponent, { id: "date_filter_equals_raw_date", value: rawDateStringEquals, width: 120, onChange: (e) => {
|
|
1197
|
-
handleChangeText([
|
|
1198
|
-
{
|
|
1199
|
-
value: e.target.value,
|
|
1200
|
-
path: keyPrefix + rawDateStringEqualsPath,
|
|
1201
|
-
},
|
|
1202
|
-
]);
|
|
1203
|
-
} }))] }));
|
|
1204
|
-
}
|
|
1205
|
-
else if (isInTheLastInterval(node, client.databaseType)) {
|
|
1206
|
-
const { dateColumn } = getDateFilterInfo(node);
|
|
1207
|
-
const options = getAllPossibleColumns().map((column) => ({
|
|
1208
|
-
label: snakeAndCamelCaseToTitleCase(column.displayName),
|
|
1209
|
-
value: column.name,
|
|
1210
|
-
}));
|
|
1211
|
-
const plural = node.right.args.value[1].expr.value !== 1 ? 's' : '';
|
|
1212
|
-
return (_jsxs("div", { style: {
|
|
1213
|
-
display: 'flex',
|
|
1214
|
-
flexDirection: 'row',
|
|
1215
|
-
alignItems: 'center',
|
|
1216
|
-
gap: 20,
|
|
1217
|
-
}, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
|
|
1218
|
-
const columnType = getColumnTypeByName(event.target.value);
|
|
1219
|
-
if (isDateishColumnType(columnType)) {
|
|
1220
|
-
// handleChange(value, keyPrefix + dateColumnPath, "text");
|
|
1221
|
-
handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
|
|
1222
|
-
}
|
|
1223
|
-
else if (isNumericColumnType(columnType)) {
|
|
1224
|
-
const newSubtree = deepCopy(defaultNumericComparison);
|
|
1225
|
-
newSubtree.left.column = event.target.value;
|
|
1226
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1227
|
-
}
|
|
1228
|
-
else if (isBoolColumnType(columnType)) {
|
|
1229
|
-
const newSubtree = deepCopy(defaultBoolComparison);
|
|
1230
|
-
newSubtree.left.column = event.target.value;
|
|
1231
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1232
|
-
}
|
|
1233
|
-
else {
|
|
1234
|
-
const newSubtree = deepCopy(defaultEntry);
|
|
1235
|
-
newSubtree.left.args.value[0].column = event.target.value;
|
|
1236
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1237
|
-
}
|
|
1238
|
-
}, options: options, width: 200 }), _jsx(SelectComponent, { value: 'IN_THE_LAST', onChange: (event) => {
|
|
1239
|
-
handleOperatorChange(event.target.value, node, keyPrefix, dateColumn);
|
|
1240
|
-
}, options: [
|
|
1241
|
-
{ label: 'in the last', value: 'IN_THE_LAST' },
|
|
1242
|
-
{ label: 'in the previous', value: 'IN_THE_PREVIOUS' },
|
|
1243
|
-
{ label: 'in the current', value: 'IN_THE_CURRENT' },
|
|
1244
|
-
{ label: 'equals', value: 'EQUALS' },
|
|
1245
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1246
|
-
{ label: 'is null', value: 'IS' },
|
|
1247
|
-
], width: 200 }), _jsx(TextInputComponent, { id: 'date_window_interval_count', value: node.right.args.value[1].expr.value, width: 120, onChange: (e) => {
|
|
1248
|
-
handleChange([
|
|
1249
|
-
{
|
|
1250
|
-
value: e.target.value,
|
|
1251
|
-
path: keyPrefix + 'right.args.value||1.expr.value',
|
|
1252
|
-
},
|
|
1253
|
-
]);
|
|
1254
|
-
} }), _jsx("div", { children: _jsx(SelectComponent, { value: node.right.args.value[1].unit, onChange: (event) => handleChange([
|
|
1255
|
-
{
|
|
1256
|
-
value: event.target.value,
|
|
1257
|
-
path: keyPrefix + 'right.args.value||1.unit',
|
|
1258
|
-
},
|
|
1259
|
-
]), options: [
|
|
1260
|
-
{ label: `year${plural}`, value: '* 365 DAY' },
|
|
1261
|
-
{ label: `month${plural}`, value: '* 30 DAY' },
|
|
1262
|
-
{ label: `week${plural}`, value: '* 7 DAY' },
|
|
1263
|
-
{ label: `day${plural}`, value: 'DAY' },
|
|
1264
|
-
], width: 200 }) })] }));
|
|
1265
|
-
}
|
|
1266
|
-
else if (isTheCurrentInterval(node, client.databaseType)) {
|
|
1267
|
-
const options = getAllPossibleColumns().map((column) => ({
|
|
1268
|
-
label: snakeAndCamelCaseToTitleCase(column.displayName),
|
|
1269
|
-
value: column.name,
|
|
1270
|
-
}));
|
|
1271
|
-
return (_jsxs("div", { style: {
|
|
1272
|
-
display: 'flex',
|
|
1273
|
-
flexDirection: 'row',
|
|
1274
|
-
alignItems: 'center',
|
|
1275
|
-
gap: 20,
|
|
1276
|
-
}, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
|
|
1277
|
-
const columnType = getColumnTypeByName(event.target.value);
|
|
1278
|
-
if (isDateishColumnType(columnType)) {
|
|
1279
|
-
// handleChange(value, keyPrefix + dateColumnPath, "text");
|
|
1280
|
-
handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
|
|
1281
|
-
}
|
|
1282
|
-
else if (isNumericColumnType(columnType)) {
|
|
1283
|
-
const newSubtree = deepCopy(defaultNumericComparison);
|
|
1284
|
-
newSubtree.left.column = event.target.value;
|
|
1285
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1286
|
-
}
|
|
1287
|
-
else if (isBoolColumnType(columnType)) {
|
|
1288
|
-
const newSubtree = deepCopy(defaultBoolComparison);
|
|
1289
|
-
newSubtree.left.column = event.target.value;
|
|
1290
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1291
|
-
}
|
|
1292
|
-
else {
|
|
1293
|
-
const newSubtree = deepCopy(defaultEntry);
|
|
1294
|
-
newSubtree.left.args.value[0].column = event.target.value;
|
|
1295
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1296
|
-
}
|
|
1297
|
-
}, options: options, width: 200 }), _jsx(SelectComponent, { value: 'IN_THE_CURRENT', onChange: (event) => {
|
|
1298
|
-
handleOperatorChange(event.target.value, node, keyPrefix, node.left.column);
|
|
1299
|
-
}, options: [
|
|
1300
|
-
{ label: 'in the last', value: 'IN_THE_LAST' },
|
|
1301
|
-
{ label: 'in the previous', value: 'IN_THE_PREVIOUS' },
|
|
1302
|
-
{ label: 'in the current', value: 'IN_THE_CURRENT' },
|
|
1303
|
-
{ label: 'equals', value: 'EQUALS' },
|
|
1304
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1305
|
-
{ label: 'is null', value: 'IS' },
|
|
1306
|
-
// { label: 'equals', value: 'equals' },
|
|
1307
|
-
], width: 200 }), _jsx(SelectComponent, { value: node.left.args.value[1].column, onChange: (event) => {
|
|
1308
|
-
handleChange([
|
|
1309
|
-
{
|
|
1310
|
-
value: event.target.value,
|
|
1311
|
-
path: 'right.args.value||1.column',
|
|
1312
|
-
},
|
|
1313
|
-
{
|
|
1314
|
-
value: event.target.value,
|
|
1315
|
-
path: 'left.args.value||1.column',
|
|
1316
|
-
},
|
|
1317
|
-
]);
|
|
1318
|
-
}, options: [
|
|
1319
|
-
{ label: `year`, value: 'YEAR' },
|
|
1320
|
-
{ label: `quarter`, value: 'QUARTER' },
|
|
1321
|
-
{ label: `month`, value: 'MONTH' },
|
|
1322
|
-
{ label: `week`, value: 'WEEK' },
|
|
1323
|
-
], width: 200 })] }));
|
|
1324
|
-
}
|
|
1325
|
-
else if (isThePreviousInterval(node)) {
|
|
1326
|
-
const options = getAllPossibleColumns().map((column) => ({
|
|
1327
|
-
label: snakeAndCamelCaseToTitleCase(column.displayName),
|
|
1328
|
-
value: column.name,
|
|
1329
|
-
}));
|
|
1330
|
-
return (_jsxs("div", { style: {
|
|
1331
|
-
display: 'flex',
|
|
1332
|
-
flexDirection: 'row',
|
|
1333
|
-
alignItems: 'center',
|
|
1334
|
-
gap: 20,
|
|
1335
|
-
}, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
|
|
1336
|
-
const columnType = getColumnTypeByName(event.target.value);
|
|
1337
|
-
if (isDateishColumnType(columnType)) {
|
|
1338
|
-
// handleChange(value, keyPrefix + dateColumnPath, "text");
|
|
1339
|
-
handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
|
|
1340
|
-
}
|
|
1341
|
-
else if (isNumericColumnType(columnType)) {
|
|
1342
|
-
const newSubtree = deepCopy(defaultNumericComparison);
|
|
1343
|
-
newSubtree.left.column = event.target.value;
|
|
1344
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1345
|
-
}
|
|
1346
|
-
else if (isBoolColumnType(columnType)) {
|
|
1347
|
-
const newSubtree = deepCopy(defaultBoolComparison);
|
|
1348
|
-
newSubtree.left.column = event.target.value;
|
|
1349
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1350
|
-
}
|
|
1351
|
-
else {
|
|
1352
|
-
const newSubtree = deepCopy(defaultEntry);
|
|
1353
|
-
newSubtree.left.args.value[0].column = event.target.value;
|
|
1354
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1355
|
-
}
|
|
1356
|
-
}, options: options, width: 200 }), _jsx(SelectComponent, { value: 'IN_THE_PREVIOUS', onChange: (event) => {
|
|
1357
|
-
handleOperatorChange(event.target.value, node, keyPrefix, node.left.column);
|
|
1358
|
-
}, options: [
|
|
1359
|
-
{ label: 'in the last', value: 'IN_THE_LAST' },
|
|
1360
|
-
{ label: 'in the previous', value: 'IN_THE_PREVIOUS' },
|
|
1361
|
-
{ label: 'in the current', value: 'IN_THE_CURRENT' },
|
|
1362
|
-
{ label: 'equals', value: 'EQUALS' },
|
|
1363
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1364
|
-
{ label: 'is null', value: 'IS' },
|
|
1365
|
-
// { label: 'equals', value: 'equals' },
|
|
1366
|
-
], width: 200 }), _jsx(SelectComponent, { value: node.left.args.value[1].column, onChange: (event) => {
|
|
1367
|
-
const dayConversion = {
|
|
1368
|
-
YEAR: 365,
|
|
1369
|
-
QUARTER: 90,
|
|
1370
|
-
MONTH: 30,
|
|
1371
|
-
WEEK: 7,
|
|
1372
|
-
};
|
|
1373
|
-
handleChange([
|
|
1374
|
-
{
|
|
1375
|
-
value: event.target.value,
|
|
1376
|
-
path: 'left.args.value||1.column',
|
|
1377
|
-
},
|
|
1378
|
-
{
|
|
1379
|
-
value: event.target.value,
|
|
1380
|
-
path: 'right.args.value||1.column',
|
|
1381
|
-
},
|
|
1382
|
-
{
|
|
1383
|
-
value: dayConversion[event.target.value] || 30,
|
|
1384
|
-
path: 'right.args.value||0.args.value||1.expr.value',
|
|
1385
|
-
},
|
|
1386
|
-
]);
|
|
1387
|
-
}, options: [
|
|
1388
|
-
{ label: `year`, value: 'YEAR' },
|
|
1389
|
-
{ label: `quarter`, value: 'QUARTER' },
|
|
1390
|
-
{ label: `month`, value: 'MONTH' },
|
|
1391
|
-
{ label: `week`, value: 'WEEK' },
|
|
1392
|
-
], width: 200 })] }));
|
|
1393
|
-
}
|
|
1394
|
-
else if (isEquals(node, client.databaseType)) {
|
|
1395
|
-
const options = getAllPossibleColumns().map((column) => ({
|
|
1396
|
-
label: snakeAndCamelCaseToTitleCase(column.displayName),
|
|
1397
|
-
value: column.name,
|
|
1398
|
-
}));
|
|
1399
|
-
return (_jsxs("div", { style: {
|
|
1400
|
-
display: 'flex',
|
|
1401
|
-
flexDirection: 'row',
|
|
1402
|
-
alignItems: 'center',
|
|
1403
|
-
gap: 20,
|
|
1404
|
-
}, children: [_jsx(SelectComponent, { value: node.left.column, onChange: (event) => {
|
|
1405
|
-
const columnType = getColumnTypeByName(event.target.value);
|
|
1406
|
-
if (isDateishColumnType(columnType)) {
|
|
1407
|
-
// handleChange(value, keyPrefix + dateColumnPath, "text");
|
|
1408
|
-
handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
|
|
1409
|
-
}
|
|
1410
|
-
else if (isNumericColumnType(columnType)) {
|
|
1411
|
-
const newSubtree = deepCopy(defaultNumericComparison);
|
|
1412
|
-
newSubtree.left.column = event.target.value;
|
|
1413
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1414
|
-
}
|
|
1415
|
-
else if (isBoolColumnType(columnType)) {
|
|
1416
|
-
const newSubtree = deepCopy(defaultBoolComparison);
|
|
1417
|
-
newSubtree.left.column = event.target.value;
|
|
1418
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1419
|
-
}
|
|
1420
|
-
else {
|
|
1421
|
-
const newSubtree = deepCopy(defaultEntry);
|
|
1422
|
-
newSubtree.left.args.value[0].column = event.target.value;
|
|
1423
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1424
|
-
}
|
|
1425
|
-
}, options: options, width: 200 }), _jsx(SelectComponent, { value: 'EQUALS', onChange: (event) => {
|
|
1426
|
-
handleOperatorChange(event.target.value, node, keyPrefix, node.left.column);
|
|
1427
|
-
}, options: [
|
|
1428
|
-
{ label: 'in the last', value: 'IN_THE_LAST' },
|
|
1429
|
-
{ label: 'in the previous', value: 'IN_THE_PREVIOUS' },
|
|
1430
|
-
{ label: 'in the current', value: 'IN_THE_CURRENT' },
|
|
1431
|
-
{ label: 'equals', value: 'EQUALS' },
|
|
1432
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1433
|
-
{ label: 'is null', value: 'IS' },
|
|
1434
|
-
// { label: 'equals', value: 'equals' },
|
|
1435
|
-
], width: 200 }), _jsx(SelectComponent, { value: node.right.args.value[1].column, onChange: (event) => {
|
|
1436
|
-
handleChange([
|
|
1437
|
-
{
|
|
1438
|
-
value: event.target.value,
|
|
1439
|
-
path: 'right.args.value||1.column',
|
|
1440
|
-
},
|
|
1441
|
-
{
|
|
1442
|
-
value: event.target.value,
|
|
1443
|
-
path: 'left.args.value||1.column',
|
|
1444
|
-
},
|
|
1445
|
-
]);
|
|
1446
|
-
}, options: [
|
|
1447
|
-
{ label: `year`, value: 'YEAR' },
|
|
1448
|
-
{ label: `quarter`, value: 'QUARTER' },
|
|
1449
|
-
{ label: `month`, value: 'MONTH' },
|
|
1450
|
-
{ label: `week`, value: 'WEEK' },
|
|
1451
|
-
], width: 200 }), _jsx(TextInputComponent, { id: 'quoted_string', value: node.right.args.value[0].value, width: 120, onChange: (e) => handleChange([
|
|
1452
|
-
{
|
|
1453
|
-
value: e.target.value,
|
|
1454
|
-
path: 'right.args.value||0.value',
|
|
1455
|
-
},
|
|
1456
|
-
]) })] }));
|
|
1457
|
-
}
|
|
1458
|
-
else if (isColumnComparison(node)) {
|
|
1459
|
-
const options = getAllPossibleColumns().map((column) => ({
|
|
1460
|
-
label: snakeAndCamelCaseToTitleCase(column.displayName),
|
|
1461
|
-
value: column.name,
|
|
1462
|
-
}));
|
|
1463
|
-
// grab the value of the left child of the column comparison
|
|
1464
|
-
// operator (ie. the column name)
|
|
1465
|
-
const leftChildValue = getColumnValueForColumnComparison(node);
|
|
1466
|
-
const tables = getTableNames(baseAst);
|
|
1467
|
-
const table = tables.length === 1 ? tables[0] : initialTableName;
|
|
1468
|
-
const column = schema
|
|
1469
|
-
.find((tableInfo) => tableInfo.name === table)
|
|
1470
|
-
?.columns.find((col) => col.name === leftChildValue);
|
|
1471
|
-
const columnType = column?.fieldType;
|
|
1472
|
-
const operatorOptions = [
|
|
1473
|
-
...(isNumericColumnType(columnType)
|
|
1474
|
-
? [
|
|
1475
|
-
{ label: 'equal to', value: '=' },
|
|
1476
|
-
{ label: 'not equal to', value: '!=' },
|
|
1477
|
-
{ label: 'greater than', value: '>' },
|
|
1478
|
-
{ label: 'less than', value: '<' },
|
|
1479
|
-
{ label: 'greater than or equal to', value: '>=' },
|
|
1480
|
-
{ label: 'less than or equal to', value: '<=' },
|
|
1481
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1482
|
-
{ label: 'is null', value: 'IS' },
|
|
1483
|
-
]
|
|
1484
|
-
: []),
|
|
1485
|
-
...(isTextColumnType(columnType)
|
|
1486
|
-
? [
|
|
1487
|
-
{ label: 'is exactly', value: 'LIKE' },
|
|
1488
|
-
{ label: 'is not exactly', value: 'NOT LIKE' },
|
|
1489
|
-
{ label: 'is', value: 'IN' },
|
|
1490
|
-
{ label: 'is not', value: 'NOT IN' },
|
|
1491
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1492
|
-
{ label: 'is null', value: 'IS' },
|
|
1493
|
-
]
|
|
1494
|
-
: []),
|
|
1495
|
-
...(isDateishColumnType(columnType)
|
|
1496
|
-
? [
|
|
1497
|
-
{ label: 'in the last', value: 'IN_THE_LAST' },
|
|
1498
|
-
{
|
|
1499
|
-
label: 'in the previous',
|
|
1500
|
-
value: 'IN_THE_PREVIOUS',
|
|
1501
|
-
},
|
|
1502
|
-
{ label: 'in the current', value: 'IN_THE_CURRENT' },
|
|
1503
|
-
{ label: 'equals', value: 'equals' },
|
|
1504
|
-
]
|
|
1505
|
-
: []),
|
|
1506
|
-
];
|
|
1507
|
-
return (_jsxs("div", { style: {
|
|
1508
|
-
display: 'flex',
|
|
1509
|
-
gap: 12,
|
|
1510
|
-
flexDirection: 'column',
|
|
1511
|
-
width: '100%',
|
|
1512
|
-
padding: '6px 0px',
|
|
1513
|
-
}, children: [_jsxs("div", { style: {
|
|
1514
|
-
display: 'flex',
|
|
1515
|
-
gap: 20,
|
|
1516
|
-
flexDirection: showNodeAsRow(node, formData)
|
|
1517
|
-
? 'row'
|
|
1518
|
-
: 'column',
|
|
1519
|
-
width: '100%',
|
|
1520
|
-
}, children: [_jsx(SelectComponent, { value: leftChildValue, onChange: (event) => {
|
|
1521
|
-
const columnType = getColumnTypeByName(event.target.value);
|
|
1522
|
-
if (isDateishColumnType(columnType)) {
|
|
1523
|
-
handleOperatorChange('IN_THE_LAST', node, keyPrefix, event.target.value);
|
|
1524
|
-
}
|
|
1525
|
-
else if (isNumericColumnType(columnType)) {
|
|
1526
|
-
const newSubtree = deepCopy(defaultNumericComparison);
|
|
1527
|
-
newSubtree.left.column = event.target.value;
|
|
1528
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1529
|
-
}
|
|
1530
|
-
else if (isBoolColumnType(columnType)) {
|
|
1531
|
-
const newSubtree = deepCopy(defaultBoolComparison);
|
|
1532
|
-
newSubtree.left.column = event.target.value;
|
|
1533
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1534
|
-
}
|
|
1535
|
-
else {
|
|
1536
|
-
const newSubtree = deepCopy(defaultEntry);
|
|
1537
|
-
newSubtree.left.args.value[0].column = event.target.value;
|
|
1538
|
-
handleReplaceSubtree(keyPrefix, newSubtree);
|
|
1539
|
-
}
|
|
1540
|
-
}, options: options, width: 200 }), operatorOptions.length > 0 && (_jsx(SelectComponent, { value: node.operator, onChange: (event) => {
|
|
1541
|
-
handleOperatorChange(event.target.value, node, keyPrefix, leftChildValue);
|
|
1542
|
-
}, options: operatorOptions, width: 200 })), node.right &&
|
|
1543
|
-
node.right.type !== 'expr_list' &&
|
|
1544
|
-
renderNode(node.right, keyPrefix + 'right.')] }, keyPrefix), node.right && node.right.type === 'expr_list' && (_jsx("div", { style: {
|
|
1545
|
-
display: 'grid',
|
|
1546
|
-
gridTemplateColumns: 'repeat(2, 1fr)',
|
|
1547
|
-
gap: 12,
|
|
1548
|
-
}, children: uniqueValues[table] &&
|
|
1549
|
-
Object.keys(uniqueValues[table][leftChildValue] ?? {}).map((key) => (_jsx(CheckboxComponent, { label: key, isChecked: uniqueValues[table][leftChildValue][key], onChange: (event) => {
|
|
1550
|
-
const newValues = deepCopy(uniqueValues);
|
|
1551
|
-
newValues[table][leftChildValue][key] =
|
|
1552
|
-
event.target.checked;
|
|
1553
|
-
setUniqueValues(newValues);
|
|
1554
|
-
if (event.target.checked) {
|
|
1555
|
-
handleInsertVariant(keyPrefix + 'right.' + 'value', key);
|
|
1556
|
-
}
|
|
1557
|
-
else {
|
|
1558
|
-
handleDeleteVariant(keyPrefix + 'right.' + 'value', key);
|
|
1559
|
-
}
|
|
1560
|
-
} }))) }, keyPrefix + 'right.'))] }));
|
|
1561
|
-
}
|
|
1562
|
-
else {
|
|
1563
|
-
const columnName = node.left.column;
|
|
1564
|
-
const column = schema
|
|
1565
|
-
.find((tableInfo) => tableInfo.name === currentTable)
|
|
1566
|
-
?.columns.find((col) => col.name === columnName);
|
|
1567
|
-
const columnType = column?.fieldType;
|
|
1568
|
-
return (_jsxs("div", { style: {
|
|
1569
|
-
display: 'flex',
|
|
1570
|
-
gap: 12,
|
|
1571
|
-
justifyContent: 'space-between',
|
|
1572
|
-
flexDirection: showNodeAsRow(node, formData) ? 'row' : 'column',
|
|
1573
|
-
width: '100%',
|
|
1574
|
-
}, children: [node.left && renderNode(node.left, keyPrefix + 'left.'), _jsx(SelectComponent, { value: node.operator, onChange: (event) => {
|
|
1575
|
-
handleOperatorChange(event.target.value, node, keyPrefix);
|
|
1576
|
-
}, options: [
|
|
1577
|
-
// { label: `and`, value: "AND" },
|
|
1578
|
-
// { label: `or`, value: "OR" },
|
|
1579
|
-
...(isNumericColumnType(columnType)
|
|
1580
|
-
? [
|
|
1581
|
-
{ label: 'equal to', value: '=' },
|
|
1582
|
-
{ label: 'not equal to', value: '!=' },
|
|
1583
|
-
{ label: 'greater than', value: '>' },
|
|
1584
|
-
{ label: 'less than', value: '<' },
|
|
1585
|
-
{ label: 'greater than or equal to', value: '>=' },
|
|
1586
|
-
{ label: 'less than or equal to', value: '<=' },
|
|
1587
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1588
|
-
{ label: 'is null', value: 'IS' },
|
|
1589
|
-
]
|
|
1590
|
-
: []),
|
|
1591
|
-
...(isTextColumnType(columnType)
|
|
1592
|
-
? [
|
|
1593
|
-
{ label: 'is exactly', value: 'LIKE' },
|
|
1594
|
-
{ label: 'is not exactly', value: 'NOT LIKE' },
|
|
1595
|
-
{ label: 'is', value: 'IN' },
|
|
1596
|
-
{ label: 'is not', value: 'NOT IN' },
|
|
1597
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1598
|
-
{ label: 'is null', value: 'IS' },
|
|
1599
|
-
]
|
|
1600
|
-
: []),
|
|
1601
|
-
...(isDateishColumnType(columnType)
|
|
1602
|
-
? [
|
|
1603
|
-
{ label: 'in the last', value: 'IN_THE_LAST' },
|
|
1604
|
-
{ label: 'in the previous', value: 'IN_THE_PREVIOUS' },
|
|
1605
|
-
{ label: 'in the current', value: 'IN_THE_CURRENT' },
|
|
1606
|
-
{ label: 'equals', value: 'EQUALS' },
|
|
1607
|
-
{ label: 'is not null', value: 'IS NOT' },
|
|
1608
|
-
{ label: 'is null', value: 'IS' },
|
|
1609
|
-
]
|
|
1610
|
-
: []),
|
|
1611
|
-
// { label: `minus`, value: "-" },
|
|
1612
|
-
// { label: `plus`, value: "+" },
|
|
1613
|
-
], width: 200 }), node.right && renderNode(node.right, keyPrefix + 'right.')] }, keyPrefix));
|
|
1614
|
-
}
|
|
1615
|
-
case 'column_ref': {
|
|
1616
|
-
const options = getAllPossibleColumns().map((column) => ({
|
|
1617
|
-
label: snakeAndCamelCaseToTitleCase(column.displayName),
|
|
1618
|
-
value: column.name,
|
|
1619
|
-
}));
|
|
1620
|
-
return (_jsx(SelectComponent, { value: node.column ?? options[0]?.value, onChange: (event) => {
|
|
1621
|
-
handleChange([
|
|
1622
|
-
{ value: event.target.value, path: keyPrefix + 'column' },
|
|
1623
|
-
]);
|
|
1624
|
-
}, options: options, width: 200 }));
|
|
1625
|
-
}
|
|
1626
|
-
case 'expr_list': {
|
|
1627
|
-
const len = node.value.length;
|
|
1628
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: 12 }, children: [node.value.map((elem, index) => {
|
|
1629
|
-
if (elem.value) {
|
|
1630
|
-
return (_jsx(TextInputComponent, { id: `expr_list_${index}`, width: 200, value: elem.value, onChange: (e) => handleChange([
|
|
1631
|
-
{
|
|
1632
|
-
value: e.target.value,
|
|
1633
|
-
path: keyPrefix + `value.${index}.`,
|
|
1634
|
-
},
|
|
1635
|
-
]) }, `input_${index}`));
|
|
1636
|
-
}
|
|
1637
|
-
return renderNode(elem, keyPrefix + `value.${index}.`);
|
|
1638
|
-
}), len > 1 && (_jsx(SecondaryButtonComponent, { label: '-', onClick: () => handleDeleteVariant(keyPrefix + 'value') })), _jsx(SecondaryButtonComponent, { onClick: () => handleInsertVariant(keyPrefix + 'value'), label: '+' })] }, keyPrefix));
|
|
1639
|
-
}
|
|
1640
|
-
case 'double_quote_string':
|
|
1641
|
-
case 'single_quote_string':
|
|
1642
|
-
return (_jsx(TextInputComponent, { id: 'quoted_string', value: node.value.replaceAll('%', ''), width: 120, onChange: (e) => handleChange([
|
|
1643
|
-
{
|
|
1644
|
-
value: e.target.value,
|
|
1645
|
-
path: keyPrefix + 'value',
|
|
1646
|
-
},
|
|
1647
|
-
]) }));
|
|
1648
|
-
case 'null':
|
|
1649
|
-
return _jsx("div", {});
|
|
1650
|
-
case 'number':
|
|
1651
|
-
return (_jsx(TextInputComponent, { id: "quill_number_input", value: node.value, width: 120, onChange: (e) => {
|
|
1652
|
-
handleChange([
|
|
1653
|
-
{
|
|
1654
|
-
value: e.target.value,
|
|
1655
|
-
path: keyPrefix + 'value',
|
|
1656
|
-
},
|
|
1657
|
-
]);
|
|
1658
|
-
} }));
|
|
1659
|
-
case 'bool':
|
|
1660
|
-
return (_jsx(SelectComponent, { value: node.value.toString(), onChange: (event) => {
|
|
1661
|
-
let formatted = true;
|
|
1662
|
-
if (event.target.value === 'false') {
|
|
1663
|
-
formatted = false;
|
|
1664
|
-
}
|
|
1665
|
-
handleChange([
|
|
1666
|
-
{
|
|
1667
|
-
value: formatted,
|
|
1668
|
-
path: keyPrefix + 'value',
|
|
1669
|
-
},
|
|
1670
|
-
]);
|
|
1671
|
-
}, options: [
|
|
1672
|
-
{ label: 'is true', value: 'true' },
|
|
1673
|
-
{ label: 'is false', value: 'false' },
|
|
1674
|
-
], width: 200 }));
|
|
1675
|
-
case 'function':
|
|
1676
|
-
if (!node.args) {
|
|
1677
|
-
return _jsx("label", {});
|
|
1678
|
-
}
|
|
1679
|
-
else if (node.args.type === 'expr_list' &&
|
|
1680
|
-
node.args.value.length === 1) {
|
|
1681
|
-
return (_jsx("div", { style: { display: 'flex', flexDirection: 'row' }, children: node.args.value[0] &&
|
|
1682
|
-
renderNode(node.args.value[0], keyPrefix + 'args.value.0.') }));
|
|
1683
|
-
}
|
|
1684
|
-
else if (node.args.type === 'expr_list' &&
|
|
1685
|
-
node.args.value.length === 2) {
|
|
1686
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: 20 }, children: [node.args.value[0] &&
|
|
1687
|
-
renderNode(node.args.value[0], keyPrefix + 'args.value.0.'), node.args.value[1] &&
|
|
1688
|
-
renderNode(node.args.value[1], keyPrefix + 'args.value.1.')] }));
|
|
1689
|
-
}
|
|
1690
|
-
return node.name;
|
|
1691
|
-
case 'interval':
|
|
1692
|
-
return (_jsx("div", { style: { display: 'flex', flexDirection: 'row', gap: 20 }, children: renderNode(node.expr, keyPrefix + 'expr.') }));
|
|
1693
|
-
default:
|
|
1694
|
-
return null;
|
|
1695
|
-
}
|
|
1696
|
-
};
|
|
1697
|
-
const isValidPivot = (fields) => {
|
|
1698
|
-
let validPivot = true;
|
|
1699
|
-
if (pivot.rowField &&
|
|
1700
|
-
!fields.find((field) => field.name === pivot.rowField)) {
|
|
1701
|
-
validPivot = false;
|
|
1702
|
-
}
|
|
1703
|
-
if (pivot.valueField &&
|
|
1704
|
-
!fields.find((field) => field.name === pivot.valueField)) {
|
|
1705
|
-
validPivot = false;
|
|
1706
|
-
}
|
|
1707
|
-
if (pivot.columnField &&
|
|
1708
|
-
!fields.find((field) => field.name === pivot.columnField)) {
|
|
1709
|
-
validPivot = false;
|
|
1710
|
-
}
|
|
1711
|
-
return validPivot;
|
|
1712
|
-
};
|
|
1713
759
|
/**
|
|
1714
760
|
* @param filterTree
|
|
1715
761
|
* Returns a list of filters to be displayed
|
|
@@ -1805,7 +851,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
1805
851
|
...defaultAST,
|
|
1806
852
|
...baseAst,
|
|
1807
853
|
...(!baseAst?.columns && {
|
|
1808
|
-
columns: getAllPossibleColumns().map((c) => {
|
|
854
|
+
columns: getAllPossibleColumns(baseAst, schema).map((c) => {
|
|
1809
855
|
const newColumn = deepCopy(defaultColumn);
|
|
1810
856
|
newColumn.expr.column = c.name;
|
|
1811
857
|
return newColumn;
|
|
@@ -1832,7 +878,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
1832
878
|
...defaultAST,
|
|
1833
879
|
...baseAst,
|
|
1834
880
|
...(!baseAst?.columns && {
|
|
1835
|
-
columns: getAllPossibleColumns().map((c) => {
|
|
881
|
+
columns: getAllPossibleColumns(baseAst, schema).map((c) => {
|
|
1836
882
|
const newColumn = deepCopy(defaultColumn);
|
|
1837
883
|
newColumn.expr.column = c.name;
|
|
1838
884
|
return newColumn;
|
|
@@ -1867,7 +913,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
1867
913
|
...defaultAST,
|
|
1868
914
|
...baseAst,
|
|
1869
915
|
...(!baseAst?.columns && {
|
|
1870
|
-
columns: getAllPossibleColumns().map((c) => {
|
|
916
|
+
columns: getAllPossibleColumns(baseAst, schema).map((c) => {
|
|
1871
917
|
const newColumn = deepCopy(defaultColumn);
|
|
1872
918
|
newColumn.expr.column = c.name;
|
|
1873
919
|
return newColumn;
|
|
@@ -1885,38 +931,6 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
1885
931
|
}
|
|
1886
932
|
}) }));
|
|
1887
933
|
};
|
|
1888
|
-
const getAllPossibleColumns = () => {
|
|
1889
|
-
if (!baseAst || !baseAst.from) {
|
|
1890
|
-
return schema.flatMap((table) => table.columns.map((c) => ({
|
|
1891
|
-
...c,
|
|
1892
|
-
table: table.displayName,
|
|
1893
|
-
})));
|
|
1894
|
-
}
|
|
1895
|
-
// TODO: support infinitely nested FROM table lookups.
|
|
1896
|
-
// This currently only supports top-level table names in the FROM section
|
|
1897
|
-
// of queries (eg. FROM "table_name", not "FROM (SELECT * FROM other) AS table_name")
|
|
1898
|
-
const tableNamesInQuery = baseAst.from.map((tbl) => tbl.table);
|
|
1899
|
-
return schema
|
|
1900
|
-
.filter((t) => tableNamesInQuery.includes(t.displayName))
|
|
1901
|
-
.flatMap((table) => table.columns
|
|
1902
|
-
.map((c) => ({
|
|
1903
|
-
...c,
|
|
1904
|
-
table: table.displayName,
|
|
1905
|
-
}))
|
|
1906
|
-
.sort((a, b) => {
|
|
1907
|
-
const aIsId = a.name.toLowerCase() === 'id' ||
|
|
1908
|
-
a.name.toLowerCase().endsWith('_id') ||
|
|
1909
|
-
a.name.endsWith('Id');
|
|
1910
|
-
const bIsId = b.name.toLowerCase() === 'id' ||
|
|
1911
|
-
b.name.toLowerCase().endsWith('_id') ||
|
|
1912
|
-
b.name.endsWith('Id');
|
|
1913
|
-
if (aIsId && !bIsId)
|
|
1914
|
-
return 1;
|
|
1915
|
-
if (bIsId && !aIsId)
|
|
1916
|
-
return -1;
|
|
1917
|
-
return 0;
|
|
1918
|
-
}));
|
|
1919
|
-
};
|
|
1920
934
|
/**
|
|
1921
935
|
* Return whether all columns have been selected (used to hide select all
|
|
1922
936
|
* and show clear button).
|
|
@@ -1940,497 +954,81 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
1940
954
|
},
|
|
1941
955
|
as: null,
|
|
1942
956
|
});
|
|
1943
|
-
const
|
|
1944
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx("h1", { style: {
|
|
1945
|
-
fontWeight: '600',
|
|
1946
|
-
fontSize: 18,
|
|
1947
|
-
margin: 0,
|
|
1948
|
-
textAlign: 'left',
|
|
1949
|
-
}, children: "Add condition" }), _jsx(TabsComponent, { value: topLevelBinaryOperator, options: DEFAULT_TAB_OPTIONS, onChange: (event) => setTopLevelBinaryOperator(event.target.value) }), activeEditItem && renderNode(activeEditItem), _jsx("div", { style: {
|
|
1950
|
-
display: 'flex',
|
|
1951
|
-
flexDirection: 'row',
|
|
1952
|
-
gap: 8,
|
|
1953
|
-
justifyContent: 'end',
|
|
1954
|
-
}, children: _jsx(ButtonComponent, { onClick: onSave, label: 'Add condition' }) })] }));
|
|
1955
|
-
};
|
|
1956
|
-
const fetchUponChange = async (baseAst, newFormData) => {
|
|
1957
|
-
// if newFormData is null still use it
|
|
957
|
+
const fetchReportFromASTHelper = async (baseAst, newFormData, curPivot, curSchema, previousReport) => {
|
|
1958
958
|
const curFormData = newFormData !== undefined ? newFormData : formData;
|
|
1959
|
-
let
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
clientId: client.publicKey,
|
|
1966
|
-
ast: { ...baseAst, where: curFormData },
|
|
1967
|
-
publicKey: client.publicKey,
|
|
1968
|
-
orgId: client.customerId,
|
|
1969
|
-
task: 'patterns',
|
|
1970
|
-
getCustomFields: false,
|
|
1971
|
-
customFields,
|
|
1972
|
-
additionalProcessing: { page: { currentPage: 0, rowsPerPage: 20 } },
|
|
1973
|
-
useUpdatedDataGathering: true,
|
|
1974
|
-
useNewNodeSql: true, // new flag
|
|
1975
|
-
},
|
|
1976
|
-
};
|
|
1977
|
-
const tables = getTableNames(baseAst);
|
|
1978
|
-
const table = tables.length >= 1 ? tables[0] : initialTableName;
|
|
1979
|
-
let newUniqueValues = uniqueValues;
|
|
1980
|
-
let dateRangesTemp = dateRanges;
|
|
1981
|
-
let curReport = tempReport;
|
|
1982
|
-
if ((newUniqueValues && Object.keys(newUniqueValues).length === 0) ||
|
|
1983
|
-
table !== currentTable) {
|
|
1984
|
-
const tableInfo = schema.find((tableInfo) => tableInfo.name === table);
|
|
1985
|
-
if (tableInfo) {
|
|
1986
|
-
newUniqueValues = await getUniqueStringValues(tableInfo.columns, table);
|
|
1987
|
-
if (hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
|
|
1988
|
-
setUniqueValues(newUniqueValues);
|
|
1989
|
-
}
|
|
1990
|
-
dateRangesTemp = await getDateRanges(tableInfo.columns, table);
|
|
1991
|
-
setDateRanges(dateRangesTemp || {});
|
|
1992
|
-
}
|
|
1993
|
-
setCurrentTable(table);
|
|
1994
|
-
}
|
|
1995
|
-
const cloudBody = {};
|
|
1996
|
-
const data2 = await getData(client, 'dashquery', 'same-origin', hostedBody, cloudBody);
|
|
1997
|
-
if (data2.success === false) {
|
|
1998
|
-
throw new Error(data2.errorMessage);
|
|
1999
|
-
}
|
|
2000
|
-
if (client.databaseType &&
|
|
2001
|
-
client.databaseType.toLowerCase() === 'bigquery') {
|
|
2002
|
-
parseValueFromBigQueryDates(data2.rows, columns);
|
|
2003
|
-
}
|
|
2004
|
-
rows = data2.rows;
|
|
2005
|
-
if (data2.rowCount) {
|
|
2006
|
-
setNumberOfRows(data2.rowCount);
|
|
2007
|
-
}
|
|
2008
|
-
if (data2.rows && data2.rows.length) {
|
|
2009
|
-
if (pivot) {
|
|
2010
|
-
// check if any of the pivot fields aren't in the data2.fields array
|
|
2011
|
-
if (!isValidPivot(data2.fields)) {
|
|
2012
|
-
const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
|
|
2013
|
-
setPivot(null);
|
|
2014
|
-
setPivotData(null);
|
|
2015
|
-
setRows(data2.rows);
|
|
2016
|
-
setColumns(processedFields);
|
|
2017
|
-
if (data2.rowCount) {
|
|
2018
|
-
const processedFormData = report
|
|
2019
|
-
? report
|
|
2020
|
-
: createInitialFormData(processedFields);
|
|
2021
|
-
setNumberOfRows(data2.rowCount);
|
|
2022
|
-
curReport = {
|
|
2023
|
-
...formData,
|
|
2024
|
-
...processedFormData,
|
|
2025
|
-
itemQuery: data2.itemQuery,
|
|
2026
|
-
rowCount: data2.rowCount,
|
|
2027
|
-
filtersApplied: [],
|
|
2028
|
-
rows: data2.rows,
|
|
2029
|
-
columns: processedFields,
|
|
2030
|
-
};
|
|
2031
|
-
setTempReport(curReport);
|
|
2032
|
-
}
|
|
2033
|
-
const formattedRows = formatRows(data2.rows, processedFields, false);
|
|
2034
|
-
setFormattedRows(formattedRows);
|
|
2035
|
-
return;
|
|
2036
|
-
}
|
|
2037
|
-
curReport = {
|
|
2038
|
-
...formData,
|
|
2039
|
-
itemQuery: data2.itemQuery,
|
|
2040
|
-
rowCount: data2.rowCount,
|
|
2041
|
-
filtersApplied: [],
|
|
2042
|
-
rows: data2.rows,
|
|
2043
|
-
};
|
|
2044
|
-
// Do all of this to make sure we have the right unique columns when applying a pivot
|
|
2045
|
-
let dateBucket = undefined;
|
|
2046
|
-
const tempDateRange = dateRangesTemp &&
|
|
2047
|
-
pivot.rowField &&
|
|
2048
|
-
dateRangesTemp[pivot.rowField];
|
|
2049
|
-
if (tempDateRange) {
|
|
2050
|
-
dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
|
|
2051
|
-
}
|
|
2052
|
-
let distinctValuesForQuery = {};
|
|
2053
|
-
if (pivot.columnField) {
|
|
2054
|
-
const sqlQuery = await fetchSqlQuery({ ...baseAst, where: curFormData }, null, false);
|
|
2055
|
-
distinctValuesForQuery = await getUniqueValuesByColumns([
|
|
2056
|
-
{
|
|
2057
|
-
field: pivot.columnField,
|
|
2058
|
-
label: pivot.columnField,
|
|
2059
|
-
format: 'string',
|
|
2060
|
-
},
|
|
2061
|
-
], sqlQuery, [], client, customFields);
|
|
2062
|
-
}
|
|
2063
|
-
const pivotedData = await generatePivotTable(
|
|
2064
|
-
// @ts-ignore
|
|
2065
|
-
pivot, data2.rows, undefined, false, -1, undefined, dateBucket, curReport, client, distinctValuesForQuery ? distinctValuesForQuery : undefined);
|
|
2066
|
-
console.info(`%c[Pivot]: ${JSON.stringify(pivot)}`, 'color: dimgray');
|
|
2067
|
-
const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
|
|
2068
|
-
setPivotData(pivotedData);
|
|
2069
|
-
setRows(data2.rows);
|
|
2070
|
-
setColumns(processedFields);
|
|
2071
|
-
if (data2.rowCount) {
|
|
2072
|
-
const processedFormData = report
|
|
2073
|
-
? report
|
|
2074
|
-
: createInitialFormData(processedFields);
|
|
2075
|
-
setNumberOfRows(data2.rowCount);
|
|
2076
|
-
setTempReport({
|
|
2077
|
-
...formData,
|
|
2078
|
-
...processedFormData,
|
|
2079
|
-
itemQuery: data2.itemQuery,
|
|
2080
|
-
rowCount: data2.rowCount,
|
|
2081
|
-
filtersApplied: [],
|
|
2082
|
-
rows: data2.rows,
|
|
2083
|
-
columns: processedFields,
|
|
2084
|
-
});
|
|
2085
|
-
}
|
|
2086
|
-
const formattedRows = formatRows(pivotedData.rows, processedFields, true, pivot.aggregationType);
|
|
2087
|
-
setSelectedColumns(processedFields.map((column) => {
|
|
2088
|
-
return `${table}.${column.field}`;
|
|
2089
|
-
}));
|
|
2090
|
-
setFormattedRows(formattedRows);
|
|
2091
|
-
}
|
|
2092
|
-
else {
|
|
2093
|
-
const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
|
|
2094
|
-
setRows(data2.rows);
|
|
2095
|
-
setColumns(processedFields);
|
|
2096
|
-
if (data2.rowCount) {
|
|
2097
|
-
const processedFormData = report
|
|
2098
|
-
? report
|
|
2099
|
-
: createInitialFormData(processedFields);
|
|
2100
|
-
setNumberOfRows(data2.rowCount);
|
|
2101
|
-
setTempReport({
|
|
2102
|
-
...formData,
|
|
2103
|
-
...processedFormData,
|
|
2104
|
-
itemQuery: data2.itemQuery,
|
|
2105
|
-
rowCount: data2.rowCount,
|
|
2106
|
-
filtersApplied: [],
|
|
2107
|
-
rows: data2.rows,
|
|
2108
|
-
columns: processedFields,
|
|
2109
|
-
});
|
|
2110
|
-
}
|
|
2111
|
-
setSelectedColumns(processedFields.map((column) => {
|
|
2112
|
-
return `${table}.${column.field}`;
|
|
2113
|
-
}));
|
|
2114
|
-
const formattedRows = formatRows(data2.rows, processedFields, false);
|
|
2115
|
-
setFormattedRows(formattedRows);
|
|
2116
|
-
if (data2.errorMessage) {
|
|
2117
|
-
setErrorMessage(`Error: ${data2.errorMessage}`);
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
else {
|
|
2122
|
-
setRows([]);
|
|
2123
|
-
setColumns([]);
|
|
2124
|
-
setFormattedRows([]);
|
|
2125
|
-
setPivotData(null);
|
|
2126
|
-
}
|
|
2127
|
-
setLoading(false);
|
|
2128
|
-
setDataDisplayed(true);
|
|
2129
|
-
return rows;
|
|
959
|
+
let reportBuilderInfo = undefined;
|
|
960
|
+
try {
|
|
961
|
+
setLoading(true);
|
|
962
|
+
reportBuilderInfo = await fetchReportBuilderDataFromAST(baseAst, curFormData, curSchema ?? schema, client, curPivot ?? pivot, formData, currentTable, { uniqueStrings: uniqueValues, dateRanges: dateRanges ?? {} }, previousReport ?? reportInfo ?? undefined, customFields);
|
|
963
|
+
if (reportBuilderInfo.error) {
|
|
964
|
+
throw new Error(reportBuilderInfo.error);
|
|
2130
965
|
}
|
|
2131
|
-
|
|
2132
|
-
|
|
966
|
+
}
|
|
967
|
+
catch (err) {
|
|
968
|
+
if (err instanceof Error) {
|
|
969
|
+
setErrorMessage(err.message);
|
|
2133
970
|
setLoading(false);
|
|
2134
|
-
|
|
2135
|
-
setRows([]);
|
|
2136
|
-
setColumns([]);
|
|
2137
|
-
setFormattedRows([]);
|
|
2138
|
-
setPivotData(null);
|
|
2139
|
-
return { error: true, message: e.message };
|
|
971
|
+
return { error: true, message: err.message, rows: [] };
|
|
2140
972
|
}
|
|
973
|
+
setLoading(false);
|
|
974
|
+
setErrorMessage('Failed to fetch');
|
|
975
|
+
return { error: true, message: 'Failed to fetch', rows: [] };
|
|
2141
976
|
}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
if (!node)
|
|
2146
|
-
return false;
|
|
2147
|
-
if (node.ast)
|
|
2148
|
-
return true;
|
|
2149
|
-
if (node.left && isSubquery(node.left))
|
|
2150
|
-
return true;
|
|
2151
|
-
if (node.right && isSubquery(node.right))
|
|
2152
|
-
return true;
|
|
2153
|
-
if (node.value && Array.isArray(node.value)) {
|
|
2154
|
-
for (const value of node.value) {
|
|
2155
|
-
if (isSubquery(value))
|
|
2156
|
-
return true;
|
|
2157
|
-
}
|
|
977
|
+
if (!reportBuilderInfo) {
|
|
978
|
+
setErrorMessage('Failed to fetch');
|
|
979
|
+
return;
|
|
2158
980
|
}
|
|
2159
|
-
|
|
981
|
+
const reportTable = reportBuilderInfo.table;
|
|
982
|
+
const reportBuilderInfoColumns = reportBuilderInfo.columns.map((column) => {
|
|
983
|
+
return `${reportTable}.${column.field}`;
|
|
984
|
+
});
|
|
985
|
+
setRows(reportBuilderInfo.rows);
|
|
986
|
+
setColumns(reportBuilderInfo.columns);
|
|
987
|
+
setNumberOfRows(reportBuilderInfo.rowCount);
|
|
988
|
+
setPivot(reportBuilderInfo.pivot);
|
|
989
|
+
setPivotData(reportBuilderInfo.pivotData);
|
|
990
|
+
setFormattedRows(reportBuilderInfo.formattedRows);
|
|
991
|
+
setTempReport(reportBuilderInfo.report);
|
|
992
|
+
setSelectedColumns(reportBuilderInfoColumns);
|
|
993
|
+
setActiveQuery(reportBuilderInfo.query);
|
|
994
|
+
setUniqueValues(reportBuilderInfo.uniqueValues);
|
|
995
|
+
setDateRanges(reportBuilderInfo.dateRanges);
|
|
996
|
+
setLoading(false);
|
|
997
|
+
setDataDisplayed(true);
|
|
998
|
+
setCurrentTable(reportBuilderInfo.table);
|
|
999
|
+
setFormData(curFormData);
|
|
1000
|
+
if (reportBuilderInfo.pivot) {
|
|
1001
|
+
setPivotRowField(reportBuilderInfo.pivot.rowField);
|
|
1002
|
+
setPivotAggregation(reportBuilderInfo.pivot.aggregationType);
|
|
1003
|
+
setPivotColumnField(reportBuilderInfo.pivot.columnField);
|
|
1004
|
+
setPivotValueField(reportBuilderInfo.pivot.valueField);
|
|
1005
|
+
}
|
|
1006
|
+
setReportInfo(reportBuilderInfo.report);
|
|
2160
1007
|
};
|
|
2161
|
-
const
|
|
2162
|
-
|
|
1008
|
+
const fetchAstFromPromptHelper = async (overridePrompt) => {
|
|
1009
|
+
let astInfo = {};
|
|
1010
|
+
const prompt = overridePrompt || aiPrompt;
|
|
1011
|
+
if (!prompt) {
|
|
1012
|
+
setErrorMessage('Please supply a prompt.');
|
|
2163
1013
|
return;
|
|
2164
1014
|
}
|
|
2165
1015
|
try {
|
|
2166
1016
|
setLoading(true);
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
let numRetries = 0;
|
|
2171
|
-
const MAX_RETRIES = 3;
|
|
2172
|
-
// refetch the request if it comes back and we know it's invalid.
|
|
2173
|
-
// TODO: remove this to allow joins later down the road
|
|
2174
|
-
let isTableJoin = !ast || !ast.from || ast.from.length !== 1;
|
|
2175
|
-
while (isTableJoin || isSubquery(ast?.where)) {
|
|
2176
|
-
if (numRetries === MAX_RETRIES)
|
|
2177
|
-
break;
|
|
2178
|
-
if (!activeQuery || (ast && (isTableJoin || isSubquery(ast?.where)))) {
|
|
2179
|
-
res = await fetch(`${QUILL_SERVER}/magic`, {
|
|
2180
|
-
method: 'POST',
|
|
2181
|
-
headers: { 'Content-Type': 'application/json' },
|
|
2182
|
-
body: JSON.stringify({
|
|
2183
|
-
initialQuestion: aiPrompt || overridePrompt,
|
|
2184
|
-
publicKey: client.publicKey,
|
|
2185
|
-
useNewNodeSql: true, // new flag
|
|
2186
|
-
}),
|
|
2187
|
-
});
|
|
2188
|
-
}
|
|
2189
|
-
else {
|
|
2190
|
-
res = await fetch(`${QUILL_SERVER}/magic/edit`, {
|
|
2191
|
-
method: 'POST',
|
|
2192
|
-
headers: { 'Content-Type': 'application/json' },
|
|
2193
|
-
body: JSON.stringify({
|
|
2194
|
-
sqlQuery: activeQuery,
|
|
2195
|
-
initialQuestion: aiPrompt,
|
|
2196
|
-
publicKey: client.publicKey,
|
|
2197
|
-
useNewNodeSql: true, // new flag
|
|
2198
|
-
}),
|
|
2199
|
-
});
|
|
2200
|
-
}
|
|
2201
|
-
data = await res.json();
|
|
2202
|
-
ast = data?.ast?.length ? data?.ast[0] : data?.ast;
|
|
2203
|
-
// TODO: Debug invalid table joins in handleAsk
|
|
2204
|
-
isTableJoin =
|
|
2205
|
-
ast?.type !== 'bigquery' &&
|
|
2206
|
-
(!ast || !ast.from || ast.from.length !== 1);
|
|
2207
|
-
numRetries += 1;
|
|
2208
|
-
}
|
|
2209
|
-
if (numRetries === MAX_RETRIES) {
|
|
2210
|
-
console.error('[Error]: Max retries exceeded.');
|
|
2211
|
-
console.info(`%c[Prompt]: ${aiPrompt}`, 'color: dimgray');
|
|
2212
|
-
setErrorMessage("Error: Couldn't process your request, please re-word your prompt.");
|
|
2213
|
-
return;
|
|
2214
|
-
}
|
|
2215
|
-
let currentSchema = schema;
|
|
2216
|
-
if (currentSchema && currentSchema.length === 0) {
|
|
2217
|
-
currentSchema = await fetchSchema();
|
|
2218
|
-
}
|
|
2219
|
-
let newAst, groupByPivot;
|
|
2220
|
-
if (ast) {
|
|
2221
|
-
// Unwrap the ast object, supporting many possible types
|
|
2222
|
-
ast = ast.length ? ast[0] : ast;
|
|
2223
|
-
newAst = convertBigQuery(ast);
|
|
2224
|
-
newAst = convertWildcardColumns(newAst, currentSchema); // must go before groupby
|
|
2225
|
-
({ ast: newAst, pivot: groupByPivot } = convertGroupBy(newAst, pivot, currentSchema));
|
|
2226
|
-
newAst = convertStringComparison(newAst, client.databaseType);
|
|
2227
|
-
newAst = convertRemoveSimpleParentheses(newAst);
|
|
2228
|
-
const table = getTableNames(newAst)[0] ?? initialTableName;
|
|
2229
|
-
const tableAlias = getTableAliases(newAst)[0] ?? initialTableName;
|
|
2230
|
-
newAst = convertUnaryToBinary(newAst);
|
|
2231
|
-
newAst = removeNonSelectedTableReferences(newAst, tableAlias ?? table, getAllPossibleColumns().map((col) => col.name));
|
|
2232
|
-
const procesedColumns = deepCopy(newAst).columns?.map((column) => {
|
|
2233
|
-
if (column.expr.type === 'column_ref') {
|
|
2234
|
-
const columnName = extractColumnish(column.expr);
|
|
2235
|
-
return `${table}.${columnName}`;
|
|
2236
|
-
}
|
|
2237
|
-
else if (column.as) {
|
|
2238
|
-
return `${table}.${column.as}`;
|
|
2239
|
-
}
|
|
2240
|
-
return `${table}.${column.expr.value}`;
|
|
2241
|
-
});
|
|
2242
|
-
setSelectedColumns(procesedColumns);
|
|
2243
|
-
if (groupByPivot) {
|
|
2244
|
-
setBaseAst(deepCopy({ ...newAst, orderby: null, limit: null }));
|
|
2245
|
-
newAst = deepCopy({ ...newAst, orderby: null, limit: null });
|
|
2246
|
-
}
|
|
2247
|
-
else {
|
|
2248
|
-
setBaseAst(deepCopy({ ...newAst }));
|
|
2249
|
-
}
|
|
2250
|
-
setFormData(deepCopy(newAst.where));
|
|
2251
|
-
setTopLevelBinaryOperator(
|
|
2252
|
-
// @ts-ignore
|
|
2253
|
-
newAst?.where ? newAst?.where?.operator : 'AND');
|
|
2254
|
-
}
|
|
2255
|
-
ast = newAst; // so we fetch data for newAst later.
|
|
2256
|
-
fetchSqlQuery(ast, undefined, false);
|
|
2257
|
-
const table = getTableNames(newAst)[0] ?? initialTableName;
|
|
2258
|
-
const hostedBody = {
|
|
2259
|
-
metadata: {
|
|
2260
|
-
clientId: client.publicKey,
|
|
2261
|
-
ast,
|
|
2262
|
-
publicKey: client.publicKey,
|
|
2263
|
-
orgId: client.customerId,
|
|
2264
|
-
task: 'patterns',
|
|
2265
|
-
additionalProcessing: { page: { currentPage: 0, rowsPerPage: 20 } },
|
|
2266
|
-
useUpdatedDataGathering: true,
|
|
2267
|
-
pivot: groupByPivot,
|
|
2268
|
-
useNewNodeSql: true, // new flag
|
|
2269
|
-
},
|
|
2270
|
-
};
|
|
2271
|
-
let currentUniqueValues = uniqueValues;
|
|
2272
|
-
let dateRangesTemp = dateRanges;
|
|
2273
|
-
if ((currentUniqueValues &&
|
|
2274
|
-
currentUniqueValues[table] &&
|
|
2275
|
-
Object.keys(currentUniqueValues[table]).length === 0) ||
|
|
2276
|
-
table !== currentTable) {
|
|
2277
|
-
const tableInfo = currentSchema.find((tableInfo) => tableInfo.name === table);
|
|
2278
|
-
if (tableInfo) {
|
|
2279
|
-
const newUniqueValues = await getUniqueStringValues(tableInfo.columns, table);
|
|
2280
|
-
currentUniqueValues = newUniqueValues;
|
|
2281
|
-
if (hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
|
|
2282
|
-
setUniqueValues(newUniqueValues);
|
|
2283
|
-
}
|
|
2284
|
-
dateRangesTemp = await getDateRanges(tableInfo.columns, table);
|
|
2285
|
-
setDateRanges(dateRangesTemp);
|
|
2286
|
-
}
|
|
2287
|
-
setCurrentTable(table);
|
|
2288
|
-
}
|
|
2289
|
-
const cloudBody = {};
|
|
2290
|
-
const data2 = await getData(client, 'patterns', 'same-origin', hostedBody, cloudBody);
|
|
2291
|
-
if (!data2 || data2.status === 'error') {
|
|
2292
|
-
throw new Error('Error querying data from patterns');
|
|
2293
|
-
}
|
|
2294
|
-
if (data2.rows && data2.rows.length) {
|
|
2295
|
-
const processedFields = data2.fields
|
|
2296
|
-
.map((elem) => convertPostgresColumn(elem))
|
|
2297
|
-
.map((elem) => {
|
|
2298
|
-
const tableInfo = currentSchema.find((t) => t.name === table);
|
|
2299
|
-
const columnInfo = tableInfo?.columns.find((column) => column.name === elem.field);
|
|
2300
|
-
return columnInfo
|
|
2301
|
-
? convertColumnInfoToColumnInternal(columnInfo)
|
|
2302
|
-
: null;
|
|
2303
|
-
})
|
|
2304
|
-
.filter((elem) => elem);
|
|
2305
|
-
let possiblePivot = true;
|
|
2306
|
-
const possibleColumns = getPossiblePivotFieldOptions(processedFields, currentUniqueValues[table]);
|
|
2307
|
-
if (groupByPivot &&
|
|
2308
|
-
((groupByPivot.columnField &&
|
|
2309
|
-
!possibleColumns.columnFields.includes(groupByPivot?.columnField)) ||
|
|
2310
|
-
(groupByPivot.rowField &&
|
|
2311
|
-
!possibleColumns.rowFields.includes(groupByPivot?.rowField)) ||
|
|
2312
|
-
(groupByPivot.valueField &&
|
|
2313
|
-
!possibleColumns.valueFields.includes(groupByPivot?.valueField || '')))) {
|
|
2314
|
-
possiblePivot = false;
|
|
2315
|
-
let errorMessageEnding = '';
|
|
2316
|
-
if (groupByPivot.columnField &&
|
|
2317
|
-
!possibleColumns.columnFields.includes(groupByPivot?.columnField || '')) {
|
|
2318
|
-
if (currentUniqueValues[table]?.[groupByPivot?.columnField || '']) {
|
|
2319
|
-
errorMessageEnding = `The column ${groupByPivot?.columnField} has more than 24 unique values to pivot on.`;
|
|
2320
|
-
}
|
|
2321
|
-
else {
|
|
2322
|
-
errorMessageEnding = `The column ${groupByPivot?.columnField} is not a proper column field.`;
|
|
2323
|
-
}
|
|
2324
|
-
}
|
|
2325
|
-
else if (groupByPivot.rowField &&
|
|
2326
|
-
!possibleColumns.rowFields.includes(groupByPivot?.rowField || '')) {
|
|
2327
|
-
if (currentUniqueValues[table]?.[groupByPivot?.rowField || '']) {
|
|
2328
|
-
errorMessageEnding = `The column ${groupByPivot?.rowField} has more than 36 unique values to pivot on.`;
|
|
2329
|
-
}
|
|
2330
|
-
else {
|
|
2331
|
-
errorMessageEnding = `The column ${groupByPivot?.rowField} is not a proper row field.`;
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
|
-
else if (groupByPivot.valueField &&
|
|
2335
|
-
!possibleColumns.valueFields.includes(groupByPivot?.valueField || '')) {
|
|
2336
|
-
errorMessageEnding = `The column ${groupByPivot?.valueField} is not a proper value field.`;
|
|
2337
|
-
}
|
|
2338
|
-
setErrorMessage(`The requested pivot is not supported. ${errorMessageEnding}`);
|
|
2339
|
-
}
|
|
2340
|
-
if (groupByPivot && possiblePivot) {
|
|
2341
|
-
let curReport = report ? report : undefined;
|
|
2342
|
-
if (data2.rowCount) {
|
|
2343
|
-
const processedFormData = report
|
|
2344
|
-
? report
|
|
2345
|
-
: createInitialFormData(processedFields);
|
|
2346
|
-
setNumberOfRows(data2.rowCount);
|
|
2347
|
-
curReport = {
|
|
2348
|
-
...formData,
|
|
2349
|
-
...processedFormData,
|
|
2350
|
-
itemQuery: data2.itemQuery,
|
|
2351
|
-
rowCount: data2.rowCount,
|
|
2352
|
-
filtersApplied: [],
|
|
2353
|
-
rows: data2.rows,
|
|
2354
|
-
columns: processedFields,
|
|
2355
|
-
};
|
|
2356
|
-
setTempReport(curReport || null);
|
|
2357
|
-
}
|
|
2358
|
-
let dateBucket = undefined;
|
|
2359
|
-
const tempDateRange = dateRangesTemp &&
|
|
2360
|
-
groupByPivot.rowField &&
|
|
2361
|
-
dateRangesTemp[groupByPivot.rowField];
|
|
2362
|
-
if (tempDateRange) {
|
|
2363
|
-
dateBucket = getDateBucketFromRange(tempDateRange.dateRange);
|
|
2364
|
-
}
|
|
2365
|
-
const pivotedData = await generatePivotTable(
|
|
2366
|
-
// @ts-ignore
|
|
2367
|
-
groupByPivot, data2.rows, undefined, false, -1, undefined, dateBucket, curReport, client, groupByPivot.columnField
|
|
2368
|
-
? currentUniqueValues[groupByPivot.columnField]
|
|
2369
|
-
: undefined);
|
|
2370
|
-
console.info(`%c[Pivot]: ${JSON.stringify(groupByPivot)}`, 'color: dimgray');
|
|
2371
|
-
setPivotData(pivotedData);
|
|
2372
|
-
setPivot(groupByPivot);
|
|
2373
|
-
if (client.databaseType &&
|
|
2374
|
-
client.databaseType.toLowerCase() === 'bigquery') {
|
|
2375
|
-
parseValueFromBigQueryDates(data2.rows, processedFields);
|
|
2376
|
-
}
|
|
2377
|
-
setRows(data2.rows);
|
|
2378
|
-
setPivotRowField(groupByPivot?.rowField);
|
|
2379
|
-
setPivotColumnField(groupByPivot?.columnField);
|
|
2380
|
-
setPivotValueField(groupByPivot?.valueField);
|
|
2381
|
-
setPivotAggregation(groupByPivot?.aggregationType);
|
|
2382
|
-
setColumns(processedFields);
|
|
2383
|
-
const formattedRows = formatRows(pivotedData.rows, processedFields, true, groupByPivot.aggregationType);
|
|
2384
|
-
setFormattedRows(formattedRows);
|
|
2385
|
-
}
|
|
2386
|
-
else {
|
|
2387
|
-
const processedFields = data2.fields.map((elem) => convertPostgresColumn(elem));
|
|
2388
|
-
if (client.databaseType &&
|
|
2389
|
-
client.databaseType.toLowerCase() === 'bigquery') {
|
|
2390
|
-
parseValueFromBigQueryDates(data2.rows, processedFields);
|
|
2391
|
-
}
|
|
2392
|
-
setRows(data2.rows);
|
|
2393
|
-
setColumns(processedFields);
|
|
2394
|
-
if (data2.rowCount) {
|
|
2395
|
-
setNumberOfRows(data2.rowCount);
|
|
2396
|
-
setTempReport({
|
|
2397
|
-
...formData,
|
|
2398
|
-
itemQuery: data2.itemQuery,
|
|
2399
|
-
rowCount: data2.rowCount,
|
|
2400
|
-
filtersApplied: [],
|
|
2401
|
-
rows: data2.rows,
|
|
2402
|
-
columns: processedFields,
|
|
2403
|
-
});
|
|
2404
|
-
}
|
|
2405
|
-
const formattedRows = formatRows(data2.rows, processedFields, false);
|
|
2406
|
-
setFormattedRows(formattedRows);
|
|
2407
|
-
}
|
|
2408
|
-
return data2.rows;
|
|
1017
|
+
astInfo = await fetchAndProcessASTFromPrompt(prompt, schema, client, pivot, activeQuery);
|
|
1018
|
+
if (astInfo.error) {
|
|
1019
|
+
throw new Error(astInfo.error);
|
|
2409
1020
|
}
|
|
2410
|
-
else {
|
|
2411
|
-
setPivotData([]);
|
|
2412
|
-
setRows([]);
|
|
2413
|
-
setColumns([]);
|
|
2414
|
-
setFormattedRows([]);
|
|
2415
|
-
}
|
|
2416
|
-
if (data2.query) {
|
|
2417
|
-
setActiveQuery(data2.query);
|
|
2418
|
-
}
|
|
2419
|
-
else {
|
|
2420
|
-
setActiveQuery('');
|
|
2421
|
-
}
|
|
2422
|
-
if (data2.errorMessage) {
|
|
2423
|
-
setErrorMessage(`Error: Couldn't process your request, please re-word your prompt.`);
|
|
2424
|
-
}
|
|
2425
|
-
}
|
|
2426
|
-
catch (e) {
|
|
2427
|
-
console.error(e);
|
|
2428
|
-
setErrorMessage(`Error: Couldn't process your request, please re-word your prompt.`);
|
|
2429
1021
|
}
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
1022
|
+
catch (err) {
|
|
1023
|
+
if (err instanceof Error) {
|
|
1024
|
+
setErrorMessage(err.message);
|
|
1025
|
+
setLoading(false);
|
|
1026
|
+
}
|
|
1027
|
+
return;
|
|
2433
1028
|
}
|
|
1029
|
+
setBaseAst(astInfo.ast);
|
|
1030
|
+
setFormData(astInfo.whereAst);
|
|
1031
|
+
await fetchReportFromASTHelper(astInfo.ast, astInfo.whereAST, astInfo.pivot);
|
|
2434
1032
|
};
|
|
2435
1033
|
const handleDeleteColumn = (name) => {
|
|
2436
1034
|
if (!baseAst || !baseAst.columns.length || selectedColumns.length === 1) {
|
|
@@ -2622,46 +1220,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
2622
1220
|
setIsPending(false);
|
|
2623
1221
|
const item = filterToAst(filter, client.databaseType.toLowerCase());
|
|
2624
1222
|
handleInsertion(item, 'AND', false);
|
|
2625
|
-
}, onDeleteFilter: () => { }, ButtonComponent: ButtonComponent, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, SecondaryButtonComponent: SecondaryButtonComponent, MultiSelectComponent: MultiSelectComponent }) }) }),
|
|
2626
|
-
false && ( // temp removed the AddConditionPopover
|
|
2627
|
-
_jsxs(_Fragment, { children: [_jsx(SecondaryButtonComponent, { onClick: () => {
|
|
2628
|
-
if (!openPopover) {
|
|
2629
|
-
setActiveEditItem(deepCopy(defaultEntry));
|
|
2630
|
-
setOpenPopover('AddConditionPopover');
|
|
2631
|
-
setActivePath('');
|
|
2632
|
-
setIsPending(true);
|
|
2633
|
-
}
|
|
2634
|
-
}, label: "Add condition" }), _jsx(PopoverComponent, { isOpen: openPopover === 'AddConditionPopover', setIsOpen: (isOpen) => {
|
|
2635
|
-
if (!isOpen) {
|
|
2636
|
-
setIsPending(false);
|
|
2637
|
-
setTimeout(() => {
|
|
2638
|
-
clearCheckboxes();
|
|
2639
|
-
setActiveEditItem(null);
|
|
2640
|
-
}, 300);
|
|
2641
|
-
setActivePath(null);
|
|
2642
|
-
setOpenPopover(null);
|
|
2643
|
-
}
|
|
2644
|
-
}, popoverTitle: "Add condition", popoverChildren: _jsx(AddConditionPopover, { onSave: () => {
|
|
2645
|
-
if (isNodeEmptyCollection(activeEditItem)) {
|
|
2646
|
-
setIsPending(false);
|
|
2647
|
-
setTimeout(() => {
|
|
2648
|
-
setActiveEditItem(null);
|
|
2649
|
-
clearCheckboxes();
|
|
2650
|
-
}, 300);
|
|
2651
|
-
setActivePath(null);
|
|
2652
|
-
setOpenPopover(null);
|
|
2653
|
-
}
|
|
2654
|
-
else {
|
|
2655
|
-
setIsPending(false);
|
|
2656
|
-
handleInsertion(activeEditItem, topLevelBinaryOperator, true);
|
|
2657
|
-
setTimeout(() => {
|
|
2658
|
-
setActiveEditItem(null);
|
|
2659
|
-
clearCheckboxes();
|
|
2660
|
-
}, 300);
|
|
2661
|
-
setActivePath(null);
|
|
2662
|
-
setOpenPopover(null);
|
|
2663
|
-
}
|
|
2664
|
-
} }) })] }))] })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Pivot" }), _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, CardComponent: CardComponent, SelectComponent: SelectComponent, ButtonComponent: ButtonComponent, 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: () => {
|
|
1223
|
+
}, onDeleteFilter: () => { }, ButtonComponent: ButtonComponent, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, SecondaryButtonComponent: SecondaryButtonComponent, MultiSelectComponent: MultiSelectComponent }) }) })] })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Pivot" }), _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, CardComponent: CardComponent, SelectComponent: SelectComponent, ButtonComponent: ButtonComponent, 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: () => {
|
|
2665
1224
|
setPivot(null);
|
|
2666
1225
|
setPivotData(null);
|
|
2667
1226
|
const formattedRows = formatRows(rows, columns, false);
|
|
@@ -2670,7 +1229,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
2670
1229
|
// TODOs
|
|
2671
1230
|
selectPivot: () => {
|
|
2672
1231
|
return;
|
|
2673
|
-
}, selectPivotOnEdit: true, showTrigger: !pivot, theme: theme, LabelComponent: LabelComponent, HeaderComponent: HeaderComponent, dateRange: undefined, pivotCountRequest: 4, SecondaryButtonComponent: SecondaryButtonComponent, query: activeQuery, initialUniqueValues: uniqueValues[currentTable], disabled: !loading && (!baseAst || !dataDisplayed), pivotRecommendationsEnabled: pivotRecommendationsEnabled && overrideRecommendations, report: tempReport ??
|
|
1232
|
+
}, selectPivotOnEdit: true, showTrigger: !pivot, theme: theme, LabelComponent: LabelComponent, HeaderComponent: HeaderComponent, dateRange: undefined, pivotCountRequest: 4, SecondaryButtonComponent: SecondaryButtonComponent, query: activeQuery, initialUniqueValues: uniqueValues[currentTable], disabled: !loading && (!baseAst || !dataDisplayed), pivotRecommendationsEnabled: pivotRecommendationsEnabled && overrideRecommendations, report: tempReport ?? reportInfo }), pivot && (_jsx(PivotForm, { columns: columns, uniqueValues: uniqueValues[currentTable], setPivotRowField: (value) => {
|
|
2674
1233
|
setPivotRowField(value);
|
|
2675
1234
|
}, setPivotColumnField: setPivotColumnField, setPivotValueField: setPivotValueField, setPivotAggregation: setPivotAggregation, pivotRowField: pivotRowField, pivotColumnField: pivotColumnField, pivotValueField: pivotValueField, pivotAggregation: pivotAggregation, onDelete: () => {
|
|
2676
1235
|
setPivot(null);
|
|
@@ -2816,7 +1375,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
2816
1375
|
display: 'flex',
|
|
2817
1376
|
flexDirection: 'row',
|
|
2818
1377
|
gap: '12px',
|
|
2819
|
-
}, children: [_jsx("div", { style: { width: '100%' } }), !hideCopySQL && (_jsx(SecondaryButtonComponent, { onClick: () => copySQLToClipboard(), label: isCopying ? '✅ Copied' : 'Copy SQL' })), _jsx(ButtonComponent, { label:
|
|
1378
|
+
}, children: [_jsx("div", { style: { width: '100%' } }), !hideCopySQL && (_jsx(SecondaryButtonComponent, { onClick: () => copySQLToClipboard(), label: isCopying ? '✅ Copied' : 'Copy SQL' })), _jsx(ButtonComponent, { label: reportInfo ? 'Save changes' : 'Add to dashboard', onClick: () => { } })] }))] })] }), _jsx("style", { children: `body{margin:0;}` })] }));
|
|
2820
1379
|
}
|
|
2821
1380
|
return (_jsxs("div", { style: { backgroundColor: theme.backgroundColor, ...containerStyle }, className: className, children: [(!isChartBuilderHorizontalView ||
|
|
2822
1381
|
(isChartBuilderHorizontalView && !isChartBuilderOpen)) && (_jsxs("div", { ref: parentRef, style: {
|
|
@@ -2903,47 +1462,7 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
2903
1462
|
setIsPending(false);
|
|
2904
1463
|
const item = filterToAst(filter, client.databaseType.toLowerCase());
|
|
2905
1464
|
handleInsertion(item, 'AND', false);
|
|
2906
|
-
}, onDeleteFilter: () => { }, ButtonComponent: ButtonComponent, SelectComponent: SelectComponent, TextInputComponent: TextInputComponent, MultiSelectComponent: MultiSelectComponent }) }) }),
|
|
2907
|
-
false && ( // temp removed the AddConditionPopover
|
|
2908
|
-
_jsxs(_Fragment, { children: [_jsx(SecondaryButtonComponent, { onClick: () => {
|
|
2909
|
-
if (!openPopover) {
|
|
2910
|
-
setActiveEditItem(deepCopy(defaultEntry));
|
|
2911
|
-
setOpenPopover('AddConditionPopover');
|
|
2912
|
-
setActivePath('');
|
|
2913
|
-
setIsPending(true);
|
|
2914
|
-
}
|
|
2915
|
-
}, label: 'Add condition' }), _jsx(PopoverComponent, { isOpen: openPopover === 'AddConditionPopover', setIsOpen: (isOpen) => {
|
|
2916
|
-
if (!isOpen) {
|
|
2917
|
-
// delay onClose callback so onClick no-ops
|
|
2918
|
-
setTimeout(() => {
|
|
2919
|
-
setIsPending(false);
|
|
2920
|
-
setActiveEditItem(null);
|
|
2921
|
-
setActivePath(null);
|
|
2922
|
-
setOpenPopover(null);
|
|
2923
|
-
clearCheckboxes();
|
|
2924
|
-
}, 200);
|
|
2925
|
-
}
|
|
2926
|
-
}, popoverChildren: _jsx(AddConditionPopover, { onSave: () => {
|
|
2927
|
-
if (isNodeEmptyCollection(activeEditItem)) {
|
|
2928
|
-
setIsPending(false);
|
|
2929
|
-
setTimeout(() => {
|
|
2930
|
-
setActiveEditItem(null);
|
|
2931
|
-
}, 300);
|
|
2932
|
-
setActivePath(null);
|
|
2933
|
-
setOpenPopover(null);
|
|
2934
|
-
clearCheckboxes();
|
|
2935
|
-
}
|
|
2936
|
-
else {
|
|
2937
|
-
setIsPending(false);
|
|
2938
|
-
handleInsertion(activeEditItem, topLevelBinaryOperator, true);
|
|
2939
|
-
setTimeout(() => {
|
|
2940
|
-
setActiveEditItem(null);
|
|
2941
|
-
}, 300);
|
|
2942
|
-
setActivePath(null);
|
|
2943
|
-
setOpenPopover(null);
|
|
2944
|
-
clearCheckboxes();
|
|
2945
|
-
}
|
|
2946
|
-
} }) })] }))] })] }), _jsxs("div", { style: { width: '100%' }, children: [_jsx(SidebarHeadingComponent, { label: "Pivot" }), _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: 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: () => {
|
|
1465
|
+
}, 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, setPivotValueField: setPivotValueField, 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: () => {
|
|
2947
1466
|
setPivot(null);
|
|
2948
1467
|
setPivotData(null);
|
|
2949
1468
|
const formattedRows = formatRows(rows, columns, false);
|
|
@@ -3238,7 +1757,9 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
3238
1757
|
? askAIInputWidth
|
|
3239
1758
|
: askAILoadingContainerWidth, onChange: (e) => setAiPrompt(e.target.value), placeholder: askedAQuestion
|
|
3240
1759
|
? 'Ask a follow-up question...'
|
|
3241
|
-
: 'Ask a question...' }), _jsx(ButtonComponent, { onClick:
|
|
1760
|
+
: 'Ask a question...' }), _jsx(ButtonComponent, { onClick: () => {
|
|
1761
|
+
fetchAstFromPromptHelper();
|
|
1762
|
+
}, label: 'Ask AI' }), ((baseAst && dataDisplayed) || initialLoad) && (_jsx(SecondaryButtonComponent, { label: 'New report', onClick: clearAllState }))] }) })), baseAst && (_jsx(TableComponent, { isLoading: tableLoading ||
|
|
3242
1763
|
(loading && errorMessage.length === 0) ||
|
|
3243
1764
|
initialChartLoad, rows: formattedRows, rowCount: pivot ? undefined : numberOfRows, columns: pivot
|
|
3244
1765
|
? pivotData?.columns || emptyPivotColumns()
|
|
@@ -3259,15 +1780,17 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
3259
1780
|
width: '100%',
|
|
3260
1781
|
gap: 12,
|
|
3261
1782
|
alignItems: 'center',
|
|
3262
|
-
}, children: [_jsx(ErrorMessageComponent, { errorMessage: errorMessage }), _jsx(SecondaryButtonComponent, { onClick:
|
|
1783
|
+
}, children: [_jsx(ErrorMessageComponent, { errorMessage: errorMessage }), _jsx(SecondaryButtonComponent, { onClick: () => {
|
|
1784
|
+
fetchAstFromPromptHelper();
|
|
1785
|
+
}, label: 'Retry' })] })) : (_jsx("div", { style: { width: '100%' } })), baseAst && dataDisplayed && !initialChartLoad && (_jsxs(_Fragment, { children: [!hideCopySQL && (_jsx(SecondaryButtonComponent, { label: isCopying ? '✅ Copied' : 'Copy SQL', onClick: () => copySQLToClipboard() })), _jsx(ButtonComponent, { onClick: () => {
|
|
3263
1786
|
setIsChartBuilderOpen(true);
|
|
3264
|
-
}, disabled: !!errorMessage, label:
|
|
1787
|
+
}, disabled: !!errorMessage, label: reportInfo ? 'Save changes' : 'Add to dashboard' })] }))] })] }), _jsx("style", { children: `body{margin:0;}` })] })), (!isChartBuilderHorizontalView || isChartBuilderOpen) && (_jsx(ChartBuilderWithModal, { hideDeleteButton: true, report: reportInfo
|
|
3265
1788
|
? {
|
|
3266
|
-
...
|
|
1789
|
+
...reportInfo,
|
|
3267
1790
|
...tempReport,
|
|
3268
1791
|
pivot: pivot,
|
|
3269
|
-
yAxisFields:
|
|
3270
|
-
columns:
|
|
1792
|
+
yAxisFields: reportInfo.pivot && !pivot ? [] : reportInfo.yAxisFields,
|
|
1793
|
+
columns: reportInfo.columns.filter((col) => {
|
|
3271
1794
|
return columns.find((c) => {
|
|
3272
1795
|
return col.field === c.field;
|
|
3273
1796
|
});
|
|
@@ -3275,5 +1798,5 @@ export default function ReportBuilder({ initialTableName = '', onSubmitEditRepor
|
|
|
3275
1798
|
queryString: activeQuery,
|
|
3276
1799
|
rows: rows,
|
|
3277
1800
|
}
|
|
3278
|
-
: tempReport, rows: rows, columns: columns, pivot: pivot, query: activeQuery, showTableFormatOptions: showChartBuilderTableFormatOptions, showDateFieldOptions: isAdminEnabled, showAccessControlOptions: isAdminEnabled, title:
|
|
1801
|
+
: tempReport, rows: rows, columns: columns, pivot: pivot, query: activeQuery, showTableFormatOptions: showChartBuilderTableFormatOptions, showDateFieldOptions: isAdminEnabled, showAccessControlOptions: isAdminEnabled, title: reportInfo ? 'Save changes' : 'Add to dashboard', isHorizontalView: true, isOpen: isChartBuilderOpen, setIsOpen: setIsChartBuilderOpen, onAddToDashboardComplete: reportInfo ? onSubmitEditReport : onSubmitCreateReport, destinationDashboard: destinationDashboard, organizationName: organizationName, pivotData: pivotData, initialUniqueValues: uniqueValues[currentTable], pivotRecommendationsEnabled: pivotRecommendationsEnabled && overrideRecommendations, 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: reportInfo ? 'Save changes' : 'Add to dashboard', onClickChartElement: onClickChartElement, rowCount: numberOfRows, onPageChange: onPageChange, onSortChange: onSortChange, isLoading: tableLoading }))] }));
|
|
3279
1802
|
}
|