@quillsql/react 2.16.0 → 2.16.1
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/index.cjs +2230 -870
- package/dist/index.d.cts +36 -5
- package/dist/index.d.ts +36 -5
- package/dist/index.js +2234 -874
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14787,6 +14787,21 @@ function isDateFormat(xAxisFormat) {
|
|
|
14787
14787
|
const isDate = DATE_FORMATS.includes(xAxisFormat);
|
|
14788
14788
|
return isDate;
|
|
14789
14789
|
}
|
|
14790
|
+
function getComparisonInterval(comparisonRange, dateBucket) {
|
|
14791
|
+
const dayCount = differenceInDays2(
|
|
14792
|
+
comparisonRange.endDate,
|
|
14793
|
+
comparisonRange.startDate
|
|
14794
|
+
);
|
|
14795
|
+
if (!isNaN(dayCount)) {
|
|
14796
|
+
if (dateBucket === "month") {
|
|
14797
|
+
return Math.floor(dayCount / 30) + " month";
|
|
14798
|
+
} else if (dateBucket === "year") {
|
|
14799
|
+
return Math.floor(dayCount / 365) + " year";
|
|
14800
|
+
} else {
|
|
14801
|
+
return dayCount + " day";
|
|
14802
|
+
}
|
|
14803
|
+
}
|
|
14804
|
+
}
|
|
14790
14805
|
function getDateBucketFromRange(dateRange) {
|
|
14791
14806
|
const difference = differenceInDays2(dateRange.end, dateRange.start);
|
|
14792
14807
|
if (difference < 14) {
|
|
@@ -16600,759 +16615,305 @@ function parseValueFromBigQueryDates(rows, columns) {
|
|
|
16600
16615
|
});
|
|
16601
16616
|
}
|
|
16602
16617
|
|
|
16603
|
-
// src/utils/
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
|
|
16607
|
-
|
|
16608
|
-
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16613
|
-
|
|
16614
|
-
|
|
16615
|
-
|
|
16616
|
-
|
|
16617
|
-
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
pivot.aggregations = [
|
|
16623
|
-
{
|
|
16624
|
-
aggregationType: pivot.aggregationType,
|
|
16625
|
-
valueField: pivot.valueField,
|
|
16626
|
-
valueFieldType: pivot.valueFieldType,
|
|
16627
|
-
valueField2: pivot.valueField2,
|
|
16628
|
-
valueField2Type: pivot.valueField2Type
|
|
16618
|
+
// src/utils/merge.ts
|
|
16619
|
+
import {
|
|
16620
|
+
add,
|
|
16621
|
+
startOfDay as startOfDay3,
|
|
16622
|
+
startOfMonth,
|
|
16623
|
+
startOfWeek as startOfWeek3,
|
|
16624
|
+
startOfYear
|
|
16625
|
+
} from "date-fns";
|
|
16626
|
+
import { utcToZonedTime as utcToZonedTime2 } from "date-fns-tz";
|
|
16627
|
+
function mergeComparisonRange(resp) {
|
|
16628
|
+
if (resp.chartType === "table") return resp;
|
|
16629
|
+
const compRows = resp.compareRows;
|
|
16630
|
+
if (!compRows) return resp;
|
|
16631
|
+
const newRows = resp.rows.map((row, i) => {
|
|
16632
|
+
if (i < compRows.length) {
|
|
16633
|
+
const compRow = compRows[i];
|
|
16634
|
+
const newRow = { ...row };
|
|
16635
|
+
for (const [key, value] of Object.entries(compRow)) {
|
|
16636
|
+
newRow[`comparison_${key}`] = value;
|
|
16629
16637
|
}
|
|
16630
|
-
|
|
16631
|
-
|
|
16632
|
-
|
|
16633
|
-
rowField: pivot.rowField,
|
|
16634
|
-
rowFieldType: pivot.rowFieldType,
|
|
16635
|
-
columnField: pivot.columnField,
|
|
16636
|
-
aggregations: pivot.aggregations?.map((agg) => ({
|
|
16637
|
-
aggregationType: agg.aggregationType,
|
|
16638
|
-
valueField: agg.valueField,
|
|
16639
|
-
valueFieldType: agg.valueFieldType
|
|
16640
|
-
}))
|
|
16641
|
-
};
|
|
16642
|
-
const resp = await quillFetch({
|
|
16643
|
-
client,
|
|
16644
|
-
task: "pivot-template",
|
|
16645
|
-
metadata: {
|
|
16646
|
-
clientId: client.clientId,
|
|
16647
|
-
pivot: pivotConfig,
|
|
16648
|
-
itemQuery: report?.queryString,
|
|
16649
|
-
dashboardName,
|
|
16650
|
-
tenants
|
|
16651
|
-
},
|
|
16652
|
-
credentials: "same-origin",
|
|
16653
|
-
getToken
|
|
16638
|
+
return newRow;
|
|
16639
|
+
}
|
|
16640
|
+
return row;
|
|
16654
16641
|
});
|
|
16655
|
-
|
|
16656
|
-
|
|
16642
|
+
return { ...resp, rows: newRows };
|
|
16643
|
+
}
|
|
16644
|
+
function dateAdder(date, interval2) {
|
|
16645
|
+
const match = interval2.match(/^(\d+)\s+(day|month|year)$/);
|
|
16646
|
+
if (!match) {
|
|
16647
|
+
throw new Error(`Invalid interval format: ${interval2}`);
|
|
16657
16648
|
}
|
|
16658
|
-
const
|
|
16659
|
-
|
|
16660
|
-
|
|
16661
|
-
parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
|
|
16662
|
-
const responseRows = queryResponseRows;
|
|
16663
|
-
const responseFields = queryResponseFields;
|
|
16664
|
-
const rows = pivot.rowField ? responseRows.map(
|
|
16665
|
-
(row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
|
|
16666
|
-
) : responseRows;
|
|
16667
|
-
if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
|
|
16668
|
-
rows.forEach((row) => {
|
|
16669
|
-
Object.keys(row).forEach((key) => {
|
|
16670
|
-
const processedKey = processColumnName(key);
|
|
16671
|
-
if (processedKey !== key) {
|
|
16672
|
-
row[processedKey] = row[key];
|
|
16673
|
-
delete row[key];
|
|
16674
|
-
}
|
|
16675
|
-
});
|
|
16676
|
-
});
|
|
16649
|
+
const [, valueStr, unit] = match;
|
|
16650
|
+
if (!valueStr || !unit) {
|
|
16651
|
+
throw new Error("Could not parse interval");
|
|
16677
16652
|
}
|
|
16678
|
-
const
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
|
|
16684
|
-
|
|
16685
|
-
|
|
16686
|
-
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
jsType: field.jsType,
|
|
16690
|
-
dataTypeID: field.dataTypeID
|
|
16691
|
-
})).filter(
|
|
16692
|
-
(field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
|
|
16693
|
-
).sort((a, b) => {
|
|
16694
|
-
if (a.field === pivot.rowField) {
|
|
16695
|
-
return -1;
|
|
16696
|
-
}
|
|
16697
|
-
if (b.field === pivot.rowField) {
|
|
16698
|
-
return 1;
|
|
16699
|
-
}
|
|
16700
|
-
return 0;
|
|
16701
|
-
});
|
|
16702
|
-
if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
|
|
16703
|
-
rows.forEach((row) => {
|
|
16704
|
-
row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
16705
|
-
let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
16706
|
-
if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
|
|
16707
|
-
const rowDate = new Date(value);
|
|
16708
|
-
if (rowDate < dateFilter.startDate) {
|
|
16709
|
-
value = dateFilter.startDate.toISOString();
|
|
16710
|
-
} else if (rowDate > dateFilter.endDate) {
|
|
16711
|
-
value = dateFilter.endDate.toISOString();
|
|
16712
|
-
}
|
|
16713
|
-
}
|
|
16714
|
-
const dateString = getDateString(
|
|
16715
|
-
value,
|
|
16716
|
-
dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
|
|
16717
|
-
dateBucket,
|
|
16718
|
-
databaseType
|
|
16719
|
-
);
|
|
16720
|
-
row[pivot.rowField || ""] = dateString;
|
|
16721
|
-
});
|
|
16722
|
-
if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
|
|
16723
|
-
const dateSet = new Set(
|
|
16724
|
-
rows.map((row) => row[pivot.rowField || ""])
|
|
16725
|
-
);
|
|
16726
|
-
for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
|
|
16727
|
-
const formattedDate = getDateString(
|
|
16728
|
-
date.toISOString(),
|
|
16729
|
-
{ start: dateFilter.startDate, end: dateFilter.endDate },
|
|
16730
|
-
dateBucket,
|
|
16731
|
-
databaseType
|
|
16732
|
-
);
|
|
16733
|
-
if (!dateSet.has(formattedDate)) {
|
|
16734
|
-
const newRow = {};
|
|
16735
|
-
newRow[pivot.rowField] = formattedDate;
|
|
16736
|
-
newRow.__quillRawDate = date.toISOString();
|
|
16737
|
-
rows.push(newRow);
|
|
16738
|
-
dateSet.add(formattedDate);
|
|
16739
|
-
}
|
|
16740
|
-
}
|
|
16741
|
-
}
|
|
16742
|
-
if (!pivot.sort) {
|
|
16743
|
-
rows.sort((a, b) => {
|
|
16744
|
-
if (a.__quillRawDate < b.__quillRawDate) {
|
|
16745
|
-
return -1;
|
|
16746
|
-
}
|
|
16747
|
-
if (a.__quillRawDate > b.__quillRawDate) {
|
|
16748
|
-
return 1;
|
|
16749
|
-
}
|
|
16750
|
-
return 0;
|
|
16751
|
-
});
|
|
16752
|
-
}
|
|
16653
|
+
const value = parseInt(valueStr, 10);
|
|
16654
|
+
const parsedDate = typeof date === "string" ? new Date(date) : date;
|
|
16655
|
+
switch (unit) {
|
|
16656
|
+
case "day":
|
|
16657
|
+
return add(parsedDate, { days: value });
|
|
16658
|
+
case "month":
|
|
16659
|
+
return add(parsedDate, { months: value });
|
|
16660
|
+
case "year":
|
|
16661
|
+
return add(parsedDate, { years: value });
|
|
16662
|
+
default:
|
|
16663
|
+
throw new Error(`Unsupported interval unit: ${unit}`);
|
|
16753
16664
|
}
|
|
16754
|
-
columns?.forEach((column, index) => {
|
|
16755
|
-
if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
|
|
16756
|
-
column.label = "Count";
|
|
16757
|
-
}
|
|
16758
|
-
});
|
|
16759
|
-
const numericColumns = columns?.filter(
|
|
16760
|
-
(column) => column.format === "whole_number" || column.format === "percentage"
|
|
16761
|
-
);
|
|
16762
|
-
rows.forEach((row) => {
|
|
16763
|
-
numericColumns?.forEach((column) => {
|
|
16764
|
-
row[column.field] = row[column.field] ?? 0;
|
|
16765
|
-
});
|
|
16766
|
-
});
|
|
16767
|
-
return {
|
|
16768
|
-
rows,
|
|
16769
|
-
columns: columns ?? [],
|
|
16770
|
-
rowCount: rowCount || rows.length,
|
|
16771
|
-
pivotQuery: report?.queryString || "",
|
|
16772
|
-
comparisonPivotQuery: comparisonPivotQuery || ""
|
|
16773
|
-
};
|
|
16774
16665
|
}
|
|
16775
|
-
function
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16781
|
-
|
|
16782
|
-
|
|
16783
|
-
|
|
16666
|
+
function dateTrunc(date, granularity = "day", databaseType) {
|
|
16667
|
+
const weekStartsOn = databaseType === "mssql" ? 0 : 1;
|
|
16668
|
+
const timeZone = "UTC";
|
|
16669
|
+
const zonedDate = utcToZonedTime2(date, timeZone);
|
|
16670
|
+
switch (granularity.toLowerCase()) {
|
|
16671
|
+
case "week":
|
|
16672
|
+
return startOfWeek3(zonedDate, { weekStartsOn });
|
|
16673
|
+
case "month":
|
|
16674
|
+
return startOfMonth(zonedDate);
|
|
16675
|
+
case "day":
|
|
16676
|
+
return startOfDay3(zonedDate);
|
|
16677
|
+
case "year":
|
|
16678
|
+
return startOfYear(zonedDate);
|
|
16679
|
+
default:
|
|
16680
|
+
throw new Error(`Unsupported granularity: ${granularity}`);
|
|
16784
16681
|
}
|
|
16785
|
-
return [
|
|
16786
|
-
{
|
|
16787
|
-
field: pivot.valueField ?? "count",
|
|
16788
|
-
label: yAxisField.label,
|
|
16789
|
-
format: yAxisField.format
|
|
16790
|
-
}
|
|
16791
|
-
];
|
|
16792
16682
|
}
|
|
16793
|
-
function
|
|
16794
|
-
|
|
16795
|
-
|
|
16796
|
-
|
|
16797
|
-
|
|
16798
|
-
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
`${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
|
|
16802
|
-
`
|
|
16803
|
-
);
|
|
16804
|
-
}
|
|
16805
|
-
return snakeAndCamelCaseToTitleCase(
|
|
16806
|
-
`${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
|
|
16807
|
-
);
|
|
16683
|
+
function mergeComparisonPivotColumns({
|
|
16684
|
+
pivot,
|
|
16685
|
+
rows,
|
|
16686
|
+
compRows
|
|
16687
|
+
}) {
|
|
16688
|
+
if (!compRows || !compRows.length) return rows;
|
|
16689
|
+
const mappedCompRows = compRows.filter((compRow) => compRow.name !== pivot.rowField).map((compRow) => ({ ...compRow, name: `comparison_${compRow.name}` }));
|
|
16690
|
+
return rows.concat(mappedCompRows);
|
|
16808
16691
|
}
|
|
16809
|
-
|
|
16692
|
+
function mergeComparisonPivotRows({
|
|
16810
16693
|
pivot,
|
|
16694
|
+
rows,
|
|
16695
|
+
compRows,
|
|
16696
|
+
databaseType,
|
|
16811
16697
|
dateBucket,
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
client,
|
|
16815
|
-
getToken,
|
|
16816
|
-
eventTracking,
|
|
16817
|
-
uniqueValues,
|
|
16818
|
-
dashboardName,
|
|
16819
|
-
tenants,
|
|
16820
|
-
additionalProcessing,
|
|
16821
|
-
caller,
|
|
16822
|
-
pivotQuery
|
|
16698
|
+
comparisonInterval,
|
|
16699
|
+
columnFieldValues
|
|
16823
16700
|
}) {
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
additionalProcessing,
|
|
16836
|
-
caller,
|
|
16837
|
-
getToken
|
|
16838
|
-
});
|
|
16839
|
-
return pivotTable;
|
|
16840
|
-
}
|
|
16841
|
-
} catch (e) {
|
|
16842
|
-
eventTracking?.logError?.({
|
|
16843
|
-
type: "bug",
|
|
16844
|
-
// TODO: determine type
|
|
16845
|
-
severity: "high",
|
|
16846
|
-
message: "Error generating pivot table",
|
|
16847
|
-
errorMessage: e.message,
|
|
16848
|
-
errorStack: e.stack,
|
|
16849
|
-
errorData: {
|
|
16850
|
-
caller: "PivotModal",
|
|
16851
|
-
function: "generatePivotTable"
|
|
16852
|
-
}
|
|
16853
|
-
});
|
|
16854
|
-
throw Error(`Failed to generate pivot table with SQL: ${e}`);
|
|
16701
|
+
if (!compRows || !compRows.length) return rows;
|
|
16702
|
+
if (pivot.columnField && columnFieldValues && columnFieldValues.length > 0) {
|
|
16703
|
+
return merge2DPivotRows(
|
|
16704
|
+
pivot,
|
|
16705
|
+
rows,
|
|
16706
|
+
compRows,
|
|
16707
|
+
columnFieldValues,
|
|
16708
|
+
databaseType,
|
|
16709
|
+
dateBucket,
|
|
16710
|
+
comparisonInterval
|
|
16711
|
+
);
|
|
16855
16712
|
}
|
|
16856
|
-
|
|
16713
|
+
if (pivot.rowField) {
|
|
16714
|
+
return merge1DPivotRows(
|
|
16715
|
+
pivot,
|
|
16716
|
+
rows,
|
|
16717
|
+
compRows,
|
|
16718
|
+
databaseType,
|
|
16719
|
+
dateBucket,
|
|
16720
|
+
comparisonInterval
|
|
16721
|
+
);
|
|
16722
|
+
}
|
|
16723
|
+
return mergeAggregatedRows(pivot, rows, compRows);
|
|
16857
16724
|
}
|
|
16858
|
-
|
|
16859
|
-
|
|
16860
|
-
|
|
16861
|
-
page: 0,
|
|
16862
|
-
rowsPerPage: 10,
|
|
16863
|
-
rowsPerRequest: 600
|
|
16864
|
-
};
|
|
16865
|
-
var DEFAULT_TABLE_PAGINATION = {
|
|
16866
|
-
page: 0,
|
|
16867
|
-
rowsPerPage: 10,
|
|
16868
|
-
rowsPerRequest: 50
|
|
16869
|
-
};
|
|
16870
|
-
function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
|
|
16871
|
-
if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
|
|
16872
|
-
return false;
|
|
16725
|
+
function merge2DPivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
|
|
16726
|
+
if (!pivot || !pivot.columnField) {
|
|
16727
|
+
return [];
|
|
16873
16728
|
}
|
|
16874
|
-
|
|
16875
|
-
|
|
16876
|
-
|
|
16877
|
-
|
|
16878
|
-
|
|
16879
|
-
|
|
16880
|
-
|
|
16729
|
+
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
16730
|
+
return merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues);
|
|
16731
|
+
}
|
|
16732
|
+
return merge2DDatePivotRows(
|
|
16733
|
+
pivot,
|
|
16734
|
+
rows,
|
|
16735
|
+
compRows,
|
|
16736
|
+
columnFieldValues,
|
|
16737
|
+
databaseType,
|
|
16738
|
+
dateBucket,
|
|
16739
|
+
comparisonInterval
|
|
16881
16740
|
);
|
|
16882
|
-
return pageInterval > previousPageInterval;
|
|
16883
16741
|
}
|
|
16884
|
-
function
|
|
16885
|
-
if (!
|
|
16886
|
-
return
|
|
16742
|
+
function merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues) {
|
|
16743
|
+
if (!pivot.rowField || !pivot.aggregations?.some((agg) => agg.valueField)) {
|
|
16744
|
+
return rows;
|
|
16887
16745
|
}
|
|
16888
|
-
return
|
|
16746
|
+
return rows.map((row) => {
|
|
16747
|
+
const matchingCompRow = compRows.find(
|
|
16748
|
+
(compRow) => compRow[pivot.rowField] === row[pivot.rowField]
|
|
16749
|
+
);
|
|
16750
|
+
const comparisonFields = columnFieldValues.reduce(
|
|
16751
|
+
(acc, fieldValue) => {
|
|
16752
|
+
acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
|
|
16753
|
+
return acc;
|
|
16754
|
+
},
|
|
16755
|
+
{}
|
|
16756
|
+
);
|
|
16757
|
+
return {
|
|
16758
|
+
...row,
|
|
16759
|
+
...comparisonFields
|
|
16760
|
+
};
|
|
16761
|
+
});
|
|
16889
16762
|
}
|
|
16890
|
-
|
|
16891
|
-
|
|
16892
|
-
|
|
16893
|
-
|
|
16894
|
-
|
|
16895
|
-
|
|
16896
|
-
|
|
16897
|
-
|
|
16898
|
-
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
|
|
16902
|
-
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
client,
|
|
16917
|
-
dateBucket,
|
|
16918
|
-
additionalProcessing,
|
|
16919
|
-
customFields,
|
|
16920
|
-
skipPivotFetch,
|
|
16921
|
-
tenants
|
|
16922
|
-
}) {
|
|
16923
|
-
if (!item) return defaultDashboardItem;
|
|
16924
|
-
if (!item.rows) {
|
|
16763
|
+
function merge2DDatePivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
|
|
16764
|
+
if (!comparisonInterval || !pivot.rowField) {
|
|
16765
|
+
return rows;
|
|
16766
|
+
}
|
|
16767
|
+
return rows.map((row) => {
|
|
16768
|
+
const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
|
|
16769
|
+
const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
|
|
16770
|
+
const matchingCompRow = compRows.find((compRow) => {
|
|
16771
|
+
const comparisonDateWithInterval = dateAdder(
|
|
16772
|
+
compRow[pivot.rowField],
|
|
16773
|
+
comparisonInterval
|
|
16774
|
+
);
|
|
16775
|
+
const truncatedCompRowDate = dateTrunc(
|
|
16776
|
+
comparisonDateWithInterval,
|
|
16777
|
+
dateBucket,
|
|
16778
|
+
databaseType
|
|
16779
|
+
);
|
|
16780
|
+
return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
|
|
16781
|
+
});
|
|
16782
|
+
const comparisonFields = columnFieldValues.reduce(
|
|
16783
|
+
(acc, fieldValue) => {
|
|
16784
|
+
acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
|
|
16785
|
+
return acc;
|
|
16786
|
+
},
|
|
16787
|
+
{}
|
|
16788
|
+
);
|
|
16925
16789
|
return {
|
|
16926
|
-
...
|
|
16927
|
-
|
|
16928
|
-
name: item.name
|
|
16790
|
+
...row,
|
|
16791
|
+
...comparisonFields
|
|
16929
16792
|
};
|
|
16793
|
+
});
|
|
16794
|
+
}
|
|
16795
|
+
function merge1DPivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
|
|
16796
|
+
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
16797
|
+
return merge1DStringPivotRows(pivot, rows, compRows);
|
|
16930
16798
|
}
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
|
|
16940
|
-
|
|
16941
|
-
|
|
16942
|
-
|
|
16943
|
-
field: field.field,
|
|
16944
|
-
format: converted_field.format,
|
|
16945
|
-
label: snakeAndCamelCaseToTitleCase(field.field),
|
|
16946
|
-
fieldType: converted_field.fieldType,
|
|
16947
|
-
dataTypeID: converted_field.dataTypeID,
|
|
16948
|
-
jsType: converted_field.jsType,
|
|
16949
|
-
inferFormat: isJsonCustomField
|
|
16950
|
-
});
|
|
16951
|
-
}
|
|
16952
|
-
});
|
|
16953
|
-
});
|
|
16799
|
+
return merge1DDatePivotRows(
|
|
16800
|
+
pivot,
|
|
16801
|
+
rows,
|
|
16802
|
+
compRows,
|
|
16803
|
+
databaseType,
|
|
16804
|
+
dateBucket,
|
|
16805
|
+
comparisonInterval
|
|
16806
|
+
);
|
|
16807
|
+
}
|
|
16808
|
+
function merge1DStringPivotRows(pivot, rows, compRows) {
|
|
16809
|
+
if (!pivot.rowField || !pivot.valueField) {
|
|
16810
|
+
return rows;
|
|
16954
16811
|
}
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
|
|
16959
|
-
|
|
16960
|
-
|
|
16812
|
+
return rows.map((row) => {
|
|
16813
|
+
const matchingCompRow = compRows.find(
|
|
16814
|
+
(compRow) => compRow[pivot.rowField] === row[pivot.rowField]
|
|
16815
|
+
);
|
|
16816
|
+
let aggregationSuffix = "";
|
|
16817
|
+
if (matchingCompRow && pivot.aggregationType === "percentage") {
|
|
16818
|
+
if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
|
|
16819
|
+
aggregationSuffix = "_Percentage";
|
|
16820
|
+
} else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
|
|
16821
|
+
aggregationSuffix = "_PERCENTAGE";
|
|
16822
|
+
} else {
|
|
16823
|
+
aggregationSuffix = "_percentage";
|
|
16824
|
+
}
|
|
16825
|
+
}
|
|
16961
16826
|
return {
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
jsType: converted_field.jsType,
|
|
16965
|
-
...col,
|
|
16966
|
-
label: snakeAndCamelCaseToTitleCase(col.label)
|
|
16827
|
+
...row,
|
|
16828
|
+
[`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow ? matchingCompRow[`${pivot.valueField}${aggregationSuffix}`] : null
|
|
16967
16829
|
};
|
|
16968
16830
|
});
|
|
16969
|
-
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16831
|
+
}
|
|
16832
|
+
function merge1DDatePivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
|
|
16833
|
+
if (!comparisonInterval || !pivot.rowField) {
|
|
16834
|
+
return rows;
|
|
16835
|
+
}
|
|
16836
|
+
return rows.map((row) => {
|
|
16837
|
+
const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
|
|
16838
|
+
const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
|
|
16839
|
+
const matchingCompRow = compRows.find((compRow) => {
|
|
16840
|
+
const comparisonDateWithInterval = dateAdder(
|
|
16841
|
+
compRow[`${pivot.rowField}`],
|
|
16842
|
+
comparisonInterval
|
|
16843
|
+
);
|
|
16844
|
+
const truncatedCompRowDate = dateTrunc(
|
|
16845
|
+
comparisonDateWithInterval,
|
|
16846
|
+
dateBucket,
|
|
16847
|
+
databaseType
|
|
16848
|
+
);
|
|
16849
|
+
return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
|
|
16850
|
+
});
|
|
16851
|
+
let aggregationSuffix = "";
|
|
16852
|
+
if (matchingCompRow && pivot.aggregationType === "percentage") {
|
|
16853
|
+
if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
|
|
16854
|
+
aggregationSuffix = "_Percentage";
|
|
16855
|
+
} else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
|
|
16856
|
+
aggregationSuffix = "_PERCENTAGE";
|
|
16857
|
+
} else {
|
|
16858
|
+
aggregationSuffix = "_percentage";
|
|
16859
|
+
}
|
|
16860
|
+
}
|
|
16861
|
+
return {
|
|
16862
|
+
...row,
|
|
16863
|
+
[`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow?.[`${pivot.valueField}${aggregationSuffix}`] || null
|
|
16975
16864
|
};
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
}
|
|
16989
|
-
]
|
|
16990
|
-
} : void 0
|
|
16991
|
-
},
|
|
16992
|
-
dashboardFilters,
|
|
16993
|
-
item.dashboardName,
|
|
16994
|
-
getToken,
|
|
16995
|
-
client,
|
|
16996
|
-
eventTracking,
|
|
16997
|
-
dateBucket,
|
|
16998
|
-
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
16999
|
-
tenants,
|
|
17000
|
-
customFields
|
|
17001
|
-
);
|
|
17002
|
-
} catch (e) {
|
|
17003
|
-
pivotTable = void 0;
|
|
17004
|
-
eventTracking?.logError?.({
|
|
17005
|
-
type: "bug",
|
|
17006
|
-
// TODO: determine type
|
|
17007
|
-
severity: "high",
|
|
17008
|
-
message: "Error fetching pivot table",
|
|
17009
|
-
errorMessage: e.message,
|
|
17010
|
-
errorStack: e.stack,
|
|
17011
|
-
errorData: {
|
|
17012
|
-
caller: "cleanDashboardItem",
|
|
17013
|
-
function: "cleanDashboardItem"
|
|
16865
|
+
});
|
|
16866
|
+
}
|
|
16867
|
+
function mergeAggregatedRows(pivot, rows, compRows) {
|
|
16868
|
+
return rows.map((row, i) => {
|
|
16869
|
+
let aggregationSuffix = "";
|
|
16870
|
+
if (compRows[i] && pivot.aggregationType === "percentage") {
|
|
16871
|
+
if (compRows[i][`${pivot.valueField}_Percentage`]) {
|
|
16872
|
+
aggregationSuffix = "_Percentage";
|
|
16873
|
+
} else if (compRows[i][`${pivot.valueField}_PERCENTAGE`]) {
|
|
16874
|
+
aggregationSuffix = "_PERCENTAGE";
|
|
16875
|
+
} else {
|
|
16876
|
+
aggregationSuffix = "_percentage";
|
|
17014
16877
|
}
|
|
17015
|
-
});
|
|
17016
|
-
console.error("Error fetching pivot table", e);
|
|
17017
|
-
pivotError = "Error fetching pivot table";
|
|
17018
|
-
}
|
|
17019
|
-
const referenceLineYValues = [];
|
|
17020
|
-
for (const key in item) {
|
|
17021
|
-
if (key.startsWith("referenceLine_")) {
|
|
17022
|
-
const field = key.slice(14);
|
|
17023
|
-
if (!item[key] || !item[key][0]) continue;
|
|
17024
|
-
const value = Object.values(item[key][0])[0];
|
|
17025
|
-
referenceLineYValues.push({ label: field, query: [value, value] });
|
|
17026
16878
|
}
|
|
16879
|
+
const compRow = {
|
|
16880
|
+
[`comparison_${pivot.valueField}${aggregationSuffix}`]: compRows[i]?.[`${pivot.valueField}${aggregationSuffix}`]
|
|
16881
|
+
};
|
|
16882
|
+
return { ...row, ...compRow };
|
|
16883
|
+
});
|
|
16884
|
+
}
|
|
16885
|
+
|
|
16886
|
+
// src/utils/queryConstructor.ts
|
|
16887
|
+
function processSingleQuotes(value, databaseType) {
|
|
16888
|
+
if (["postgresql", "snowflake", "clickhouse"].includes(
|
|
16889
|
+
databaseType.toLowerCase()
|
|
16890
|
+
)) {
|
|
16891
|
+
return value.replaceAll("'", "''");
|
|
17027
16892
|
}
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
16893
|
+
return value.replaceAll("'", "\\'");
|
|
16894
|
+
}
|
|
16895
|
+
function processAggType(aggType, hasColumnField = false) {
|
|
16896
|
+
if (aggType === "count" && hasColumnField) return "SUM";
|
|
16897
|
+
return aggType?.toLowerCase() === "average" ? "AVG" : aggType?.toLowerCase();
|
|
16898
|
+
}
|
|
16899
|
+
function replaceBigQuerySpecialCharacters(column) {
|
|
16900
|
+
return column.replaceAll("/", "quill_forward_slash");
|
|
16901
|
+
}
|
|
16902
|
+
function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
|
|
16903
|
+
switch (databaseType.toLowerCase()) {
|
|
16904
|
+
case "postgresql":
|
|
16905
|
+
case "clickhouse": {
|
|
16906
|
+
if (column === "") {
|
|
16907
|
+
return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
|
|
16908
|
+
}
|
|
16909
|
+
if (isColumnFieldAlias) {
|
|
16910
|
+
return `"${column.replaceAll('"', "")}"`;
|
|
16911
|
+
}
|
|
16912
|
+
const columnParts = column.split(".");
|
|
16913
|
+
if (columnParts.length > 1) {
|
|
16914
|
+
return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
|
|
17042
16915
|
}
|
|
17043
|
-
|
|
17044
|
-
}
|
|
17045
|
-
return {
|
|
17046
|
-
id: item._id ?? item.id,
|
|
17047
|
-
name: item.name,
|
|
17048
|
-
dashboardName: item.dashboardName,
|
|
17049
|
-
// section: item.section,
|
|
17050
|
-
rows: item.rows,
|
|
17051
|
-
pivotRows: pivotTable ? pivotTable.rows : void 0,
|
|
17052
|
-
pivotColumns: pivotTable ? pivotTable.columns : void 0,
|
|
17053
|
-
compareRows: item.compareRows,
|
|
17054
|
-
columns: processedColumns.map((column) => {
|
|
17055
|
-
return {
|
|
17056
|
-
field: column.field,
|
|
17057
|
-
format: column.format,
|
|
17058
|
-
label: column.label,
|
|
17059
|
-
inferFormat: column.inferFormat
|
|
17060
|
-
};
|
|
17061
|
-
}),
|
|
17062
|
-
includeCustomFields: item.includeCustomFields,
|
|
17063
|
-
columnInternal,
|
|
17064
|
-
columnsWithCustomFields,
|
|
17065
|
-
chartType: item.chartType,
|
|
17066
|
-
dateField: item.dateField,
|
|
17067
|
-
pivot: pivotError ? void 0 : item.pivot ? {
|
|
17068
|
-
...item.pivot,
|
|
17069
|
-
aggregations: item.pivot.aggregations ?? [
|
|
17070
|
-
{
|
|
17071
|
-
valueField: item.pivot.valueField,
|
|
17072
|
-
valueFieldType: item.pivot.valueFieldType,
|
|
17073
|
-
valueField2: item.pivot.valueField2,
|
|
17074
|
-
valueField2Type: item.pivot.valueField2Type,
|
|
17075
|
-
aggregationType: item.pivot.aggregationType
|
|
17076
|
-
}
|
|
17077
|
-
],
|
|
17078
|
-
columnValues: item.distinctStrings
|
|
17079
|
-
} : void 0,
|
|
17080
|
-
yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
|
|
17081
|
-
xAxisLabel: item.xAxisLabel,
|
|
17082
|
-
xAxisField: item.xAxisField,
|
|
17083
|
-
xAxisFormat: item.xAxisFormat,
|
|
17084
|
-
order: item.order,
|
|
17085
|
-
filtersApplied: item.filtersApplied,
|
|
17086
|
-
filterMap: item.filterMap,
|
|
17087
|
-
flags: item.flags,
|
|
17088
|
-
rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
|
|
17089
|
-
pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
|
|
17090
|
-
template: item.template,
|
|
17091
|
-
sort: item.sort,
|
|
17092
|
-
itemQuery: item.itemQuery,
|
|
17093
|
-
queryString: item.queryString,
|
|
17094
|
-
pivotQuery: pivotTable?.pivotQuery,
|
|
17095
|
-
comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
|
|
17096
|
-
referencedTables: item?.referencedTables || [],
|
|
17097
|
-
referencedColumns: item?.referencedColumns || {},
|
|
17098
|
-
error: item.error ?? pivotError,
|
|
17099
|
-
referenceLineYValues,
|
|
17100
|
-
referenceLines: item.referenceLines
|
|
17101
|
-
};
|
|
17102
|
-
}
|
|
17103
|
-
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
17104
|
-
if (!report) return void 0;
|
|
17105
|
-
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
17106
|
-
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
17107
|
-
);
|
|
17108
|
-
if (dateFilter?.operator === "BETWEEN") {
|
|
17109
|
-
dateFilter.startDate = dateFilter.value[0];
|
|
17110
|
-
dateFilter.endDate = dateFilter.value[1];
|
|
17111
|
-
}
|
|
17112
|
-
const pivot = report?.pivot;
|
|
17113
|
-
const data = report || {};
|
|
17114
|
-
if (pivot && client) {
|
|
17115
|
-
if (report.rowCount === 0 || report.rows.length === 0) {
|
|
17116
|
-
const columns = [];
|
|
17117
|
-
if (pivot.rowField) {
|
|
17118
|
-
columns.push({
|
|
17119
|
-
field: pivot.rowField,
|
|
17120
|
-
label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
|
|
17121
|
-
format: pivot.rowFieldType || "string",
|
|
17122
|
-
jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
|
|
17123
|
-
fieldType: pivot.rowFieldType || "string",
|
|
17124
|
-
dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
|
|
17125
|
-
});
|
|
17126
|
-
}
|
|
17127
|
-
for (const agg of pivot.aggregations ?? []) {
|
|
17128
|
-
if (agg.valueField) {
|
|
17129
|
-
columns.push({
|
|
17130
|
-
field: agg.valueField,
|
|
17131
|
-
label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
|
|
17132
|
-
//FIXME: valueFieldType is not always the same as the format
|
|
17133
|
-
format: agg.valueFieldType ?? "whole_number",
|
|
17134
|
-
jsType: agg.valueFieldType ?? "number",
|
|
17135
|
-
fieldType: agg.valueFieldType ?? "number",
|
|
17136
|
-
dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
|
|
17137
|
-
});
|
|
17138
|
-
}
|
|
17139
|
-
}
|
|
17140
|
-
return {
|
|
17141
|
-
rows: [],
|
|
17142
|
-
rowCount: 0,
|
|
17143
|
-
pivotQuery: report.queryString ?? "",
|
|
17144
|
-
columns
|
|
17145
|
-
};
|
|
17146
|
-
}
|
|
17147
|
-
try {
|
|
17148
|
-
let dateBucket = dateBucketInitial;
|
|
17149
|
-
let filterDateRange = void 0;
|
|
17150
|
-
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
17151
|
-
filterDateRange = {
|
|
17152
|
-
start: dateFilter.startDate,
|
|
17153
|
-
end: dateFilter.endDate
|
|
17154
|
-
};
|
|
17155
|
-
} else if (report.dateRange) {
|
|
17156
|
-
filterDateRange = report.dateRange;
|
|
17157
|
-
}
|
|
17158
|
-
if (!dateBucket && filterDateRange) {
|
|
17159
|
-
dateBucket = getDateBucketFromRange(filterDateRange);
|
|
17160
|
-
}
|
|
17161
|
-
const pivotTable = await generatePivotWithSQL({
|
|
17162
|
-
pivot,
|
|
17163
|
-
report,
|
|
17164
|
-
client,
|
|
17165
|
-
dateBucket,
|
|
17166
|
-
dateFilter,
|
|
17167
|
-
dashboardName,
|
|
17168
|
-
tenants,
|
|
17169
|
-
additionalProcessing,
|
|
17170
|
-
getToken
|
|
17171
|
-
});
|
|
17172
|
-
return pivotTable;
|
|
17173
|
-
} catch (e) {
|
|
17174
|
-
eventTracking?.logError?.({
|
|
17175
|
-
type: "bug",
|
|
17176
|
-
// TODO: determine type
|
|
17177
|
-
severity: "high",
|
|
17178
|
-
message: "Error fetching pivot table",
|
|
17179
|
-
errorMessage: e.message,
|
|
17180
|
-
errorStack: e.stack,
|
|
17181
|
-
errorData: {
|
|
17182
|
-
caller: "getPivotTable",
|
|
17183
|
-
function: "getPivotTable"
|
|
17184
|
-
}
|
|
17185
|
-
});
|
|
17186
|
-
console.error("Error fetching pivot table", e);
|
|
17187
|
-
throw e;
|
|
17188
|
-
}
|
|
17189
|
-
}
|
|
17190
|
-
return pivot && data.rows ? generatePivotTable({
|
|
17191
|
-
pivot,
|
|
17192
|
-
report,
|
|
17193
|
-
client,
|
|
17194
|
-
uniqueValues: report.distinctStrings,
|
|
17195
|
-
dashboardName,
|
|
17196
|
-
tenants,
|
|
17197
|
-
dateFilter,
|
|
17198
|
-
additionalProcessing,
|
|
17199
|
-
getToken,
|
|
17200
|
-
eventTracking
|
|
17201
|
-
}) : void 0;
|
|
17202
|
-
}
|
|
17203
|
-
function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
|
|
17204
|
-
if (!pivotTable) return itemInfo?.yAxisFields ?? [];
|
|
17205
|
-
const pivot = itemInfo?.pivot || config?.pivot;
|
|
17206
|
-
if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
|
|
17207
|
-
const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
|
|
17208
|
-
return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
|
|
17209
|
-
}
|
|
17210
|
-
async function getDashboard(dashboardName, client, getToken, tenants, flags) {
|
|
17211
|
-
const { data: resp } = await quillFetch({
|
|
17212
|
-
client,
|
|
17213
|
-
task: "dashboard",
|
|
17214
|
-
metadata: {
|
|
17215
|
-
name: dashboardName,
|
|
17216
|
-
clientId: client.publicKey,
|
|
17217
|
-
databaseType: client.databaseType,
|
|
17218
|
-
useNewNodeSql: true,
|
|
17219
|
-
tenants,
|
|
17220
|
-
flags
|
|
17221
|
-
},
|
|
17222
|
-
getToken
|
|
17223
|
-
});
|
|
17224
|
-
return {
|
|
17225
|
-
...resp,
|
|
17226
|
-
createdAt: resp.createdAt && new Date(resp.createdAt),
|
|
17227
|
-
dateFilter: resp.dateFilter ? {
|
|
17228
|
-
...resp.dateFilter,
|
|
17229
|
-
presetOptions: resp.dateFilter.presetOptions?.map(
|
|
17230
|
-
(preset) => ({
|
|
17231
|
-
...preset,
|
|
17232
|
-
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
17233
|
-
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
17234
|
-
})
|
|
17235
|
-
),
|
|
17236
|
-
defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
|
|
17237
|
-
(preset) => ({
|
|
17238
|
-
...preset,
|
|
17239
|
-
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
17240
|
-
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
17241
|
-
})
|
|
17242
|
-
)
|
|
17243
|
-
} : void 0
|
|
17244
|
-
};
|
|
17245
|
-
}
|
|
17246
|
-
|
|
17247
|
-
// src/utils/chartBuilder.ts
|
|
17248
|
-
var numberFormatOptions = [
|
|
17249
|
-
"whole_number",
|
|
17250
|
-
"one_decimal_place",
|
|
17251
|
-
"two_decimal_places",
|
|
17252
|
-
"dollar_amount",
|
|
17253
|
-
"dollar_cents",
|
|
17254
|
-
"percentage"
|
|
17255
|
-
];
|
|
17256
|
-
var dateFormatOptions = [
|
|
17257
|
-
"MMM_yyyy",
|
|
17258
|
-
"MMM_dd",
|
|
17259
|
-
"MMM_dd_yyyy",
|
|
17260
|
-
"MMM_dd_hh:mm_ap_pm",
|
|
17261
|
-
"hh_ap_pm",
|
|
17262
|
-
"date",
|
|
17263
|
-
"timestamptz"
|
|
17264
|
-
];
|
|
17265
|
-
var NUMBER_OPTIONS = [
|
|
17266
|
-
{ value: "whole_number", label: "whole number" },
|
|
17267
|
-
{ value: "one_decimal_place", label: "one decimal place" },
|
|
17268
|
-
{ value: "two_decimal_places", label: "two decimal places" },
|
|
17269
|
-
{ value: "dollar_amount", label: "dollar amount" },
|
|
17270
|
-
{ value: "dollar_cents", label: "dollar and cent amount" },
|
|
17271
|
-
{ value: "percent", label: "percentage" }
|
|
17272
|
-
];
|
|
17273
|
-
var DATE_OPTIONS = [
|
|
17274
|
-
{ value: "MMM_yyyy", label: "month" },
|
|
17275
|
-
{ value: "MMM_dd", label: "day" },
|
|
17276
|
-
{ value: "MMM_dd_yyyy", label: "day and year" },
|
|
17277
|
-
{ value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
|
|
17278
|
-
{ value: "hh_ap_pm", label: "hour" }
|
|
17279
|
-
];
|
|
17280
|
-
var ALL_FORMAT_OPTIONS = [
|
|
17281
|
-
...NUMBER_OPTIONS,
|
|
17282
|
-
...DATE_OPTIONS,
|
|
17283
|
-
{ value: "string", label: "string" }
|
|
17284
|
-
];
|
|
17285
|
-
function createInitialFormData(columns) {
|
|
17286
|
-
const firstNumberColumn = columns?.find(
|
|
17287
|
-
(col) => numberFormatOptions.includes(col.format)
|
|
17288
|
-
);
|
|
17289
|
-
const firstStringColumn = columns?.find(
|
|
17290
|
-
(col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
|
|
17291
|
-
);
|
|
17292
|
-
const firstDateColumn = columns?.find(
|
|
17293
|
-
(col) => dateFormatOptions.includes(col.format)
|
|
17294
|
-
);
|
|
17295
|
-
const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
|
|
17296
|
-
const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
|
|
17297
|
-
const formEmptyState = {
|
|
17298
|
-
name: "",
|
|
17299
|
-
columns: columns.map((col) => {
|
|
17300
|
-
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
17301
|
-
}),
|
|
17302
|
-
xAxisField,
|
|
17303
|
-
xAxisFormat,
|
|
17304
|
-
yAxisFields: [
|
|
17305
|
-
{
|
|
17306
|
-
field: firstNumberColumn?.field || columns?.[0]?.field || "",
|
|
17307
|
-
label: "",
|
|
17308
|
-
format: firstNumberColumn?.format || columns?.[0]?.format || "string"
|
|
17309
|
-
}
|
|
17310
|
-
],
|
|
17311
|
-
xAxisLabel: "",
|
|
17312
|
-
chartType: firstNumberColumn ? "line" : "table",
|
|
17313
|
-
pivot: null,
|
|
17314
|
-
template: true,
|
|
17315
|
-
referenceLines: []
|
|
17316
|
-
};
|
|
17317
|
-
return formEmptyState;
|
|
17318
|
-
}
|
|
17319
|
-
|
|
17320
|
-
// src/utils/error.ts
|
|
17321
|
-
var DataLoadError = class extends Error {
|
|
17322
|
-
data;
|
|
17323
|
-
constructor(message, data) {
|
|
17324
|
-
super(message);
|
|
17325
|
-
this.name = "DataLoadError";
|
|
17326
|
-
this.data = data;
|
|
17327
|
-
}
|
|
17328
|
-
};
|
|
17329
|
-
|
|
17330
|
-
// src/utils/errorProcessing.ts
|
|
17331
|
-
function processFilterErrorList(resp) {
|
|
17332
|
-
if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
|
|
17333
|
-
return;
|
|
17334
|
-
}
|
|
17335
|
-
}
|
|
17336
|
-
|
|
17337
|
-
// src/utils/queryConstructor.ts
|
|
17338
|
-
function replaceBigQuerySpecialCharacters(column) {
|
|
17339
|
-
return column.replaceAll("/", "quill_forward_slash");
|
|
17340
|
-
}
|
|
17341
|
-
function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
|
|
17342
|
-
switch (databaseType.toLowerCase()) {
|
|
17343
|
-
case "postgresql":
|
|
17344
|
-
case "clickhouse": {
|
|
17345
|
-
if (column === "") {
|
|
17346
|
-
return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
|
|
17347
|
-
}
|
|
17348
|
-
if (isColumnFieldAlias) {
|
|
17349
|
-
return `"${column.replaceAll('"', "")}"`;
|
|
17350
|
-
}
|
|
17351
|
-
const columnParts = column.split(".");
|
|
17352
|
-
if (columnParts.length > 1) {
|
|
17353
|
-
return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
|
|
17354
|
-
}
|
|
17355
|
-
return `"${column.replaceAll('"', "")}"`;
|
|
16916
|
+
return `"${column.replaceAll('"', "")}"`;
|
|
17356
16917
|
}
|
|
17357
16918
|
case "mysql": {
|
|
17358
16919
|
if (column === "") {
|
|
@@ -17426,6 +16987,51 @@ function processColumnReference(column, databaseType, fallbackOnNull, isColumnFi
|
|
|
17426
16987
|
function replaceSpacesWithUnderscores(column) {
|
|
17427
16988
|
return column.replaceAll(" ", "_");
|
|
17428
16989
|
}
|
|
16990
|
+
function processInterval(interval2, rowField, databaseType) {
|
|
16991
|
+
if (["postgresql", "snowflake", "clickhouse"].includes(
|
|
16992
|
+
databaseType.toLowerCase()
|
|
16993
|
+
)) {
|
|
16994
|
+
return `(${processColumnReference(rowField, databaseType)} + INTERVAL '${interval2}')`;
|
|
16995
|
+
} else if (databaseType.toLowerCase() === "mysql") {
|
|
16996
|
+
return `(${processColumnReference(rowField, databaseType)} + INTERVAL ${interval2})`;
|
|
16997
|
+
}
|
|
16998
|
+
return `TIMESTAMP_ADD(${processColumnReference(rowField, databaseType)}, INTERVAL ${interval2} )`;
|
|
16999
|
+
}
|
|
17000
|
+
function processDateTrunc(dateBucket, rowField, databaseType, comparisonInterval) {
|
|
17001
|
+
const dateField = comparisonInterval ? processInterval(comparisonInterval, rowField, databaseType) : processColumnReference(rowField, databaseType);
|
|
17002
|
+
if (["postgresql", "snowflake"].includes(databaseType.toLowerCase())) {
|
|
17003
|
+
return `date_trunc('${dateBucket}', ${dateField})`;
|
|
17004
|
+
}
|
|
17005
|
+
if (["clickhouse"].includes(databaseType.toLowerCase())) {
|
|
17006
|
+
return `dateTrunc('${dateBucket}', ${dateField})`;
|
|
17007
|
+
}
|
|
17008
|
+
if (["databricks"].includes(databaseType.toLowerCase())) {
|
|
17009
|
+
return `DATE_TRUNC('${dateBucket}', ${dateField})`;
|
|
17010
|
+
}
|
|
17011
|
+
if (["mysql"].includes(databaseType.toLowerCase())) {
|
|
17012
|
+
switch (dateBucket.toLowerCase()) {
|
|
17013
|
+
case "year":
|
|
17014
|
+
return `DATE_FORMAT(${dateField}, '%Y-01-01 00:00:00')`;
|
|
17015
|
+
case "month":
|
|
17016
|
+
return `DATE_FORMAT(${dateField}, '%Y-%m-01 00:00:00')`;
|
|
17017
|
+
case "week":
|
|
17018
|
+
return `DATE_FORMAT(${dateField}, '%Y-%U-1 00:00:00')`;
|
|
17019
|
+
case "day":
|
|
17020
|
+
default:
|
|
17021
|
+
return `DATE(${dateField})`;
|
|
17022
|
+
}
|
|
17023
|
+
}
|
|
17024
|
+
if (["mssql"].includes(databaseType.toLowerCase())) {
|
|
17025
|
+
return `DATETRUNC(${dateBucket}, ${dateField})`;
|
|
17026
|
+
}
|
|
17027
|
+
return `TIMESTAMP_TRUNC(${dateField}, ${dateBucket})`;
|
|
17028
|
+
}
|
|
17029
|
+
function processValueField(aggType, databaseType, valueField) {
|
|
17030
|
+
if (aggType === "min" || aggType === "max" || aggType?.toLowerCase() === "average")
|
|
17031
|
+
return `${processColumnReference(valueField, databaseType)} ELSE null`;
|
|
17032
|
+
if (aggType === "count") return `1 ELSE 0`;
|
|
17033
|
+
return valueField ? `${processColumnReference(valueField, databaseType)} ELSE 0` : `1 ELSE 0`;
|
|
17034
|
+
}
|
|
17429
17035
|
function generateCountQuery(fields, query, databaseType) {
|
|
17430
17036
|
let countQuery = [];
|
|
17431
17037
|
let cteQuery = `WITH querytable AS (${query.replace(";", "")}) `;
|
|
@@ -17544,12 +17150,1123 @@ function generateMinMaxDateRangeQueries(columnFields, query, databaseType) {
|
|
|
17544
17150
|
const distinctQueries = columnFields.map((field) => {
|
|
17545
17151
|
const wrappedField = ["postgresql", "clickhouse"].includes(
|
|
17546
17152
|
databaseType.toLowerCase()
|
|
17547
|
-
) ?
|
|
17548
|
-
return `SELECT '${field}' AS
|
|
17153
|
+
) ? `"${field}"` : field;
|
|
17154
|
+
return `SELECT '${field}' AS field, ${min2}(${wrappedField})${cast} AS min_range, ${max2}(${wrappedField})${cast} AS max_range FROM querytable`;
|
|
17549
17155
|
});
|
|
17550
17156
|
const distinctQuery = distinctQueries.join(" UNION ALL ");
|
|
17551
17157
|
return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
|
|
17552
17158
|
}
|
|
17159
|
+
function generatePivotQuery(pivot, itemQuery, databaseType, distinctStrings, dateBucket) {
|
|
17160
|
+
if (!isValidPivot(pivot).valid) {
|
|
17161
|
+
return void 0;
|
|
17162
|
+
}
|
|
17163
|
+
if (pivot.columnField && distinctStrings && distinctStrings.length > 0) {
|
|
17164
|
+
return create2DPivotQuery(
|
|
17165
|
+
pivot,
|
|
17166
|
+
itemQuery,
|
|
17167
|
+
databaseType,
|
|
17168
|
+
distinctStrings,
|
|
17169
|
+
dateBucket
|
|
17170
|
+
);
|
|
17171
|
+
}
|
|
17172
|
+
if (pivot.rowField) {
|
|
17173
|
+
return create1DPivotQuery(pivot, itemQuery, dateBucket, databaseType);
|
|
17174
|
+
}
|
|
17175
|
+
return createAggregationValuePivot(pivot, itemQuery, databaseType);
|
|
17176
|
+
}
|
|
17177
|
+
function create2DPivotQuery(pivot, itemQuery, databaseType, columnFieldValues, dateBucket) {
|
|
17178
|
+
if (!pivot || !pivot.columnField) {
|
|
17179
|
+
return void 0;
|
|
17180
|
+
}
|
|
17181
|
+
if (isStringType(pivot.rowFieldType ?? "") || !pivot.rowFieldType) {
|
|
17182
|
+
return create2DStringPivotQuery(
|
|
17183
|
+
pivot,
|
|
17184
|
+
itemQuery,
|
|
17185
|
+
columnFieldValues,
|
|
17186
|
+
databaseType
|
|
17187
|
+
);
|
|
17188
|
+
}
|
|
17189
|
+
return create2DDatePivotQuery(
|
|
17190
|
+
pivot,
|
|
17191
|
+
itemQuery,
|
|
17192
|
+
columnFieldValues,
|
|
17193
|
+
databaseType,
|
|
17194
|
+
dateBucket
|
|
17195
|
+
);
|
|
17196
|
+
}
|
|
17197
|
+
function create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType) {
|
|
17198
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17199
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17200
|
+
);
|
|
17201
|
+
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField)
|
|
17202
|
+
return void 0;
|
|
17203
|
+
const rowField = pivot.rowField;
|
|
17204
|
+
if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
|
|
17205
|
+
throw new Error("No value field provided for pivot");
|
|
17206
|
+
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
17207
|
+
throw new Error("No aggregation type provided for pivot");
|
|
17208
|
+
const columnField = pivot.columnField;
|
|
17209
|
+
const rowFieldAlias = processColumnReference(
|
|
17210
|
+
rowField,
|
|
17211
|
+
databaseType,
|
|
17212
|
+
void 0,
|
|
17213
|
+
false,
|
|
17214
|
+
true
|
|
17215
|
+
);
|
|
17216
|
+
const columnFieldAlias = processColumnReference(
|
|
17217
|
+
columnField,
|
|
17218
|
+
databaseType,
|
|
17219
|
+
void 0,
|
|
17220
|
+
false,
|
|
17221
|
+
true
|
|
17222
|
+
);
|
|
17223
|
+
let caseWhens = [];
|
|
17224
|
+
let valueAliases = [];
|
|
17225
|
+
const seenAggs = {};
|
|
17226
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17227
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17228
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17229
|
+
} else {
|
|
17230
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17231
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17232
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17233
|
+
};
|
|
17234
|
+
}
|
|
17235
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
|
|
17236
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17237
|
+
const valueFieldAlias = processColumnReference(
|
|
17238
|
+
currentAgg.valueField || rowField || "count",
|
|
17239
|
+
databaseType,
|
|
17240
|
+
void 0,
|
|
17241
|
+
false,
|
|
17242
|
+
true
|
|
17243
|
+
);
|
|
17244
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17245
|
+
let value2AliasSubstring = "";
|
|
17246
|
+
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
|
|
17247
|
+
(acc, v) => acc + v
|
|
17248
|
+
) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
|
|
17249
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
|
|
17250
|
+
const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
|
|
17251
|
+
currentAgg.aggregationType,
|
|
17252
|
+
databaseType,
|
|
17253
|
+
valueFieldAlias
|
|
17254
|
+
);
|
|
17255
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17256
|
+
if (!currentAgg.valueField)
|
|
17257
|
+
throw new Error("No value field provided for pivot");
|
|
17258
|
+
const valueField2Alias = processColumnReference(
|
|
17259
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17260
|
+
databaseType,
|
|
17261
|
+
void 0,
|
|
17262
|
+
false,
|
|
17263
|
+
true
|
|
17264
|
+
);
|
|
17265
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17266
|
+
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
17267
|
+
caseWhens = [
|
|
17268
|
+
...caseWhens,
|
|
17269
|
+
...columnFieldValues.map((column) => {
|
|
17270
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17271
|
+
column,
|
|
17272
|
+
databaseType
|
|
17273
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
|
|
17274
|
+
column + disambiguation,
|
|
17275
|
+
databaseType,
|
|
17276
|
+
"_",
|
|
17277
|
+
true
|
|
17278
|
+
)}`;
|
|
17279
|
+
})
|
|
17280
|
+
];
|
|
17281
|
+
} else {
|
|
17282
|
+
value2AliasSubstring = `${processColumnReference(
|
|
17283
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17284
|
+
databaseType,
|
|
17285
|
+
void 0,
|
|
17286
|
+
true
|
|
17287
|
+
)} AS ${valueField2Alias}`;
|
|
17288
|
+
caseWhens = [
|
|
17289
|
+
...caseWhens,
|
|
17290
|
+
...columnFieldValues.map((column) => {
|
|
17291
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17292
|
+
column,
|
|
17293
|
+
databaseType
|
|
17294
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17295
|
+
column,
|
|
17296
|
+
databaseType
|
|
17297
|
+
)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
|
|
17298
|
+
column + disambiguation,
|
|
17299
|
+
databaseType,
|
|
17300
|
+
"_",
|
|
17301
|
+
true
|
|
17302
|
+
)}`;
|
|
17303
|
+
})
|
|
17304
|
+
];
|
|
17305
|
+
}
|
|
17306
|
+
} else {
|
|
17307
|
+
caseWhens = [
|
|
17308
|
+
...caseWhens,
|
|
17309
|
+
...columnFieldValues.map((column) => {
|
|
17310
|
+
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17311
|
+
column,
|
|
17312
|
+
databaseType
|
|
17313
|
+
)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
|
|
17314
|
+
})
|
|
17315
|
+
];
|
|
17316
|
+
}
|
|
17317
|
+
if (valueAliasSubstring) valueAliases.push(valueAliasSubstring);
|
|
17318
|
+
if (value2AliasSubstring) valueAliases.push(value2AliasSubstring);
|
|
17319
|
+
});
|
|
17320
|
+
valueAliases = [
|
|
17321
|
+
`${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
|
|
17322
|
+
...valueAliases,
|
|
17323
|
+
`${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
|
|
17324
|
+
];
|
|
17325
|
+
valueAliases = Array.from(new Set(valueAliases));
|
|
17326
|
+
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
|
|
17327
|
+
const pivotQuery = `
|
|
17328
|
+
,quill_alias AS (
|
|
17329
|
+
SELECT ${valueAliases.length > 0 ? `${valueAliases.join(", ")}` : ""}
|
|
17330
|
+
FROM quill_base_table
|
|
17331
|
+
),
|
|
17332
|
+
quill_qt_cw AS (
|
|
17333
|
+
SELECT ${rowFieldAlias}
|
|
17334
|
+
${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""}
|
|
17335
|
+
FROM quill_alias
|
|
17336
|
+
GROUP BY ${rowFieldAlias}
|
|
17337
|
+
),
|
|
17338
|
+
quill_base_pivot AS (
|
|
17339
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
|
|
17340
|
+
FROM quill_qt_cw qt
|
|
17341
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17342
|
+
)
|
|
17343
|
+
SELECT * FROM quill_base_pivot
|
|
17344
|
+
`.replace(/\s+/g, " ").trim();
|
|
17345
|
+
return itemQuery.replace(
|
|
17346
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17347
|
+
pivotQuery
|
|
17348
|
+
);
|
|
17349
|
+
}
|
|
17350
|
+
function create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket = "month") {
|
|
17351
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17352
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17353
|
+
);
|
|
17354
|
+
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
|
|
17355
|
+
return void 0;
|
|
17356
|
+
}
|
|
17357
|
+
if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
|
|
17358
|
+
throw new Error("No value field provided for pivot");
|
|
17359
|
+
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
17360
|
+
throw new Error("No aggregation type provided for pivot");
|
|
17361
|
+
const rowField = pivot.rowField;
|
|
17362
|
+
const columnField = pivot.columnField;
|
|
17363
|
+
const rowFieldAlias = processColumnReference(
|
|
17364
|
+
rowField,
|
|
17365
|
+
databaseType,
|
|
17366
|
+
void 0,
|
|
17367
|
+
false,
|
|
17368
|
+
true
|
|
17369
|
+
);
|
|
17370
|
+
const columnFieldAlias = processColumnReference(
|
|
17371
|
+
columnField,
|
|
17372
|
+
databaseType,
|
|
17373
|
+
void 0,
|
|
17374
|
+
false,
|
|
17375
|
+
true
|
|
17376
|
+
);
|
|
17377
|
+
let caseWhens = [];
|
|
17378
|
+
let valueFieldAliases = [];
|
|
17379
|
+
const seenAggs = {};
|
|
17380
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17381
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17382
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17383
|
+
} else {
|
|
17384
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17385
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17386
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17387
|
+
};
|
|
17388
|
+
}
|
|
17389
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
|
|
17390
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17391
|
+
const valueFieldAlias = processColumnReference(
|
|
17392
|
+
currentAgg.valueField ?? rowField,
|
|
17393
|
+
databaseType,
|
|
17394
|
+
void 0,
|
|
17395
|
+
false,
|
|
17396
|
+
true
|
|
17397
|
+
);
|
|
17398
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17399
|
+
let value2AliasSubstring = "";
|
|
17400
|
+
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
|
|
17401
|
+
(acc, v) => acc + v
|
|
17402
|
+
) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
|
|
17403
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
|
|
17404
|
+
const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
|
|
17405
|
+
currentAgg.aggregationType,
|
|
17406
|
+
databaseType,
|
|
17407
|
+
valueFieldAlias
|
|
17408
|
+
);
|
|
17409
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17410
|
+
if (!currentAgg.valueField)
|
|
17411
|
+
throw new Error("No value field provided for pivot");
|
|
17412
|
+
const valueField2Alias = processColumnReference(
|
|
17413
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17414
|
+
databaseType,
|
|
17415
|
+
void 0,
|
|
17416
|
+
false,
|
|
17417
|
+
true
|
|
17418
|
+
);
|
|
17419
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17420
|
+
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
17421
|
+
caseWhens = [
|
|
17422
|
+
...caseWhens,
|
|
17423
|
+
...columnFieldValues.map((column) => {
|
|
17424
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17425
|
+
column,
|
|
17426
|
+
databaseType
|
|
17427
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
|
|
17428
|
+
column + disambiguation,
|
|
17429
|
+
databaseType,
|
|
17430
|
+
"_",
|
|
17431
|
+
true
|
|
17432
|
+
)}`;
|
|
17433
|
+
})
|
|
17434
|
+
];
|
|
17435
|
+
} else {
|
|
17436
|
+
value2AliasSubstring = `${processColumnReference(
|
|
17437
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17438
|
+
databaseType,
|
|
17439
|
+
void 0,
|
|
17440
|
+
true
|
|
17441
|
+
)} AS ${valueField2Alias}`;
|
|
17442
|
+
caseWhens = [
|
|
17443
|
+
...caseWhens,
|
|
17444
|
+
...columnFieldValues.map((column) => {
|
|
17445
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17446
|
+
column,
|
|
17447
|
+
databaseType
|
|
17448
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17449
|
+
column,
|
|
17450
|
+
databaseType
|
|
17451
|
+
)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
|
|
17452
|
+
column + disambiguation,
|
|
17453
|
+
databaseType,
|
|
17454
|
+
"_",
|
|
17455
|
+
true
|
|
17456
|
+
)}`;
|
|
17457
|
+
})
|
|
17458
|
+
];
|
|
17459
|
+
}
|
|
17460
|
+
} else {
|
|
17461
|
+
caseWhens = [
|
|
17462
|
+
...caseWhens,
|
|
17463
|
+
...columnFieldValues.map((column) => {
|
|
17464
|
+
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17465
|
+
column,
|
|
17466
|
+
databaseType
|
|
17467
|
+
)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
|
|
17468
|
+
})
|
|
17469
|
+
];
|
|
17470
|
+
}
|
|
17471
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17472
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17473
|
+
});
|
|
17474
|
+
valueFieldAliases = [
|
|
17475
|
+
`${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
|
|
17476
|
+
...valueFieldAliases,
|
|
17477
|
+
`${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
|
|
17478
|
+
];
|
|
17479
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17480
|
+
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17481
|
+
const pivotQuery = `
|
|
17482
|
+
, quill_alias AS (SELECT ${valueFieldAliases.length > 0 ? `${valueFieldAliases.join(", ")}` : ""} FROM quill_base_table),
|
|
17483
|
+
quill_qt_agg AS (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
|
|
17484
|
+
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17485
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
|
|
17486
|
+
SELECT * FROM quill_base_pivot
|
|
17487
|
+
`.replace(/\s+/g, " ").trim();
|
|
17488
|
+
return itemQuery.replace(
|
|
17489
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17490
|
+
pivotQuery
|
|
17491
|
+
);
|
|
17492
|
+
}
|
|
17493
|
+
function create1DPivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
|
|
17494
|
+
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
17495
|
+
return create1DStringPivotQuery(pivot, itemQuery, databaseType);
|
|
17496
|
+
}
|
|
17497
|
+
return create1DDatePivotQuery(pivot, itemQuery, dateBucket, databaseType);
|
|
17498
|
+
}
|
|
17499
|
+
function create1DStringPivotQuery(pivot, itemQuery, databaseType) {
|
|
17500
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17501
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17502
|
+
);
|
|
17503
|
+
if (!isValidBaseQuery) return void 0;
|
|
17504
|
+
const rowField = pivot.rowField;
|
|
17505
|
+
const rowAlias = processColumnReference(
|
|
17506
|
+
rowField,
|
|
17507
|
+
databaseType,
|
|
17508
|
+
void 0,
|
|
17509
|
+
true
|
|
17510
|
+
);
|
|
17511
|
+
let quillAggSelects = [rowAlias];
|
|
17512
|
+
let valueFieldAliases = [];
|
|
17513
|
+
const seenAggs = {};
|
|
17514
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17515
|
+
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17516
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17517
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17518
|
+
} else {
|
|
17519
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17520
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17521
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17522
|
+
};
|
|
17523
|
+
}
|
|
17524
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17525
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17526
|
+
const valueFieldAlias = processColumnReference(
|
|
17527
|
+
currentAgg.valueField || rowField || "count",
|
|
17528
|
+
databaseType,
|
|
17529
|
+
void 0,
|
|
17530
|
+
false,
|
|
17531
|
+
true
|
|
17532
|
+
);
|
|
17533
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17534
|
+
let value2AliasSubstring = "";
|
|
17535
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
|
|
17536
|
+
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17537
|
+
if (currentAgg.valueFieldType === "bool") {
|
|
17538
|
+
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
17539
|
+
}
|
|
17540
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17541
|
+
let countPercentage = false;
|
|
17542
|
+
if (!currentAgg.valueField) {
|
|
17543
|
+
countPercentage = true;
|
|
17544
|
+
}
|
|
17545
|
+
const valueField2Alias = processColumnReference(
|
|
17546
|
+
currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
|
|
17547
|
+
databaseType,
|
|
17548
|
+
void 0,
|
|
17549
|
+
false,
|
|
17550
|
+
true
|
|
17551
|
+
);
|
|
17552
|
+
let value2Expr = valueField2Alias;
|
|
17553
|
+
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
|
|
17554
|
+
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
17555
|
+
}
|
|
17556
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17557
|
+
const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
|
|
17558
|
+
quillAggSelects = [
|
|
17559
|
+
...quillAggSelects,
|
|
17560
|
+
`${percentageExpr} as ${processColumnReference(
|
|
17561
|
+
`${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
|
|
17562
|
+
databaseType,
|
|
17563
|
+
void 0,
|
|
17564
|
+
false,
|
|
17565
|
+
true
|
|
17566
|
+
)}`
|
|
17567
|
+
];
|
|
17568
|
+
} else {
|
|
17569
|
+
quillAggSelects = [
|
|
17570
|
+
...quillAggSelects,
|
|
17571
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
|
|
17572
|
+
(currentAgg.valueField || "count") + disambiguation,
|
|
17573
|
+
databaseType
|
|
17574
|
+
)}`
|
|
17575
|
+
];
|
|
17576
|
+
}
|
|
17577
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17578
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17579
|
+
});
|
|
17580
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17581
|
+
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17582
|
+
const pivotQuery = `, quill_alias AS (
|
|
17583
|
+
SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
|
|
17584
|
+
FROM quill_base_table
|
|
17585
|
+
),
|
|
17586
|
+
quill_qt_cw AS (
|
|
17587
|
+
SELECT ${quillAggSelects.join(", ")} FROM quill_alias GROUP BY ${rowAlias}
|
|
17588
|
+
),
|
|
17589
|
+
quill_base_pivot AS (
|
|
17590
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
|
|
17591
|
+
FROM quill_qt_cw qt ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17592
|
+
)
|
|
17593
|
+
SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
|
|
17594
|
+
return itemQuery.replace(
|
|
17595
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17596
|
+
pivotQuery
|
|
17597
|
+
);
|
|
17598
|
+
}
|
|
17599
|
+
function create1DDatePivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
|
|
17600
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17601
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17602
|
+
);
|
|
17603
|
+
if (!isValidBaseQuery) {
|
|
17604
|
+
return void 0;
|
|
17605
|
+
}
|
|
17606
|
+
const rowField = pivot.rowField || "";
|
|
17607
|
+
const rowFieldAlias = processColumnReference(
|
|
17608
|
+
rowField,
|
|
17609
|
+
databaseType,
|
|
17610
|
+
void 0
|
|
17611
|
+
);
|
|
17612
|
+
let quillAggSelects = [
|
|
17613
|
+
`${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(rowField, databaseType)}`
|
|
17614
|
+
];
|
|
17615
|
+
let valueFieldAliases = [];
|
|
17616
|
+
const seenAggs = {};
|
|
17617
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17618
|
+
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17619
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17620
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17621
|
+
} else {
|
|
17622
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17623
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17624
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17625
|
+
};
|
|
17626
|
+
}
|
|
17627
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17628
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17629
|
+
const valueFieldAlias = processColumnReference(
|
|
17630
|
+
currentAgg.valueField || rowField || "count",
|
|
17631
|
+
databaseType,
|
|
17632
|
+
void 0,
|
|
17633
|
+
false,
|
|
17634
|
+
true
|
|
17635
|
+
);
|
|
17636
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17637
|
+
let value2AliasSubstring = "";
|
|
17638
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
|
|
17639
|
+
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17640
|
+
if (currentAgg.valueFieldType === "bool") {
|
|
17641
|
+
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
17642
|
+
}
|
|
17643
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17644
|
+
let countPercentage = false;
|
|
17645
|
+
if (!currentAgg.valueField) {
|
|
17646
|
+
countPercentage = true;
|
|
17647
|
+
}
|
|
17648
|
+
const valueField2Alias = processColumnReference(
|
|
17649
|
+
currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
|
|
17650
|
+
databaseType,
|
|
17651
|
+
void 0,
|
|
17652
|
+
false,
|
|
17653
|
+
true
|
|
17654
|
+
);
|
|
17655
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17656
|
+
let value2Expr = valueField2Alias;
|
|
17657
|
+
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
|
|
17658
|
+
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
17659
|
+
}
|
|
17660
|
+
const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
|
|
17661
|
+
quillAggSelects = [
|
|
17662
|
+
...quillAggSelects,
|
|
17663
|
+
`${percentageExpr} as ${processColumnReference(
|
|
17664
|
+
`${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
|
|
17665
|
+
databaseType,
|
|
17666
|
+
void 0,
|
|
17667
|
+
false,
|
|
17668
|
+
true
|
|
17669
|
+
)}`
|
|
17670
|
+
];
|
|
17671
|
+
} else {
|
|
17672
|
+
quillAggSelects = [
|
|
17673
|
+
...quillAggSelects,
|
|
17674
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || "count") + disambiguation, databaseType)}`
|
|
17675
|
+
];
|
|
17676
|
+
}
|
|
17677
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17678
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17679
|
+
});
|
|
17680
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17681
|
+
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17682
|
+
const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowFieldAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
|
|
17683
|
+
FROM quill_base_table),
|
|
17684
|
+
quill_qt_agg AS (SELECT ${quillAggSelects.join(", ")}
|
|
17685
|
+
FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
|
|
17686
|
+
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17687
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
|
|
17688
|
+
SELECT * FROM quill_base_pivot
|
|
17689
|
+
`.replace(/\s+/g, " ").trim();
|
|
17690
|
+
return itemQuery.replace(
|
|
17691
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17692
|
+
pivotQuery
|
|
17693
|
+
);
|
|
17694
|
+
}
|
|
17695
|
+
function createAggregationValuePivot(pivot, itemQuery, databaseType) {
|
|
17696
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17697
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17698
|
+
);
|
|
17699
|
+
if (!isValidBaseQuery) return void 0;
|
|
17700
|
+
let quillAggSelects = [];
|
|
17701
|
+
let valueFieldAliases = [];
|
|
17702
|
+
const seenAggs = {};
|
|
17703
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17704
|
+
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17705
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17706
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17707
|
+
} else {
|
|
17708
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17709
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17710
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17711
|
+
};
|
|
17712
|
+
}
|
|
17713
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17714
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17715
|
+
const valueFieldAlias = processColumnReference(
|
|
17716
|
+
currentAgg.valueField || "count",
|
|
17717
|
+
databaseType,
|
|
17718
|
+
void 0,
|
|
17719
|
+
false,
|
|
17720
|
+
true
|
|
17721
|
+
);
|
|
17722
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17723
|
+
let value2AliasSubstring = "";
|
|
17724
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}_${currentAgg.aggregationType}` : "";
|
|
17725
|
+
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17726
|
+
valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : valueExpr;
|
|
17727
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17728
|
+
if (!currentAgg.valueField) {
|
|
17729
|
+
throw new Error("No value field provided for percentage aggregation");
|
|
17730
|
+
}
|
|
17731
|
+
const valueField2Alias = processColumnReference(
|
|
17732
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17733
|
+
databaseType,
|
|
17734
|
+
void 0,
|
|
17735
|
+
false,
|
|
17736
|
+
true
|
|
17737
|
+
);
|
|
17738
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17739
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17740
|
+
const percentageExpr = currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
|
|
17741
|
+
quillAggSelects = [
|
|
17742
|
+
...quillAggSelects,
|
|
17743
|
+
`${percentageExpr} as ${processColumnReference(
|
|
17744
|
+
`${currentAgg.valueField ?? ""}${disambiguation}`,
|
|
17745
|
+
databaseType,
|
|
17746
|
+
void 0,
|
|
17747
|
+
false,
|
|
17748
|
+
true
|
|
17749
|
+
)}`
|
|
17750
|
+
];
|
|
17751
|
+
} else {
|
|
17752
|
+
quillAggSelects = [
|
|
17753
|
+
...quillAggSelects,
|
|
17754
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
|
|
17755
|
+
(currentAgg.valueField || "count") + disambiguation,
|
|
17756
|
+
databaseType
|
|
17757
|
+
)}`
|
|
17758
|
+
];
|
|
17759
|
+
}
|
|
17760
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17761
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17762
|
+
});
|
|
17763
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17764
|
+
if (valueFieldAliases.length === 0) {
|
|
17765
|
+
valueFieldAliases = ["*"];
|
|
17766
|
+
}
|
|
17767
|
+
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
|
|
17768
|
+
const pivotQuery = `, quill_alias AS (
|
|
17769
|
+
SELECT ${valueFieldAliases.join(", ")} FROM quill_base_table
|
|
17770
|
+
),
|
|
17771
|
+
quill_qt_agg AS (
|
|
17772
|
+
SELECT ${quillAggSelects.join(", ")} FROM quill_alias
|
|
17773
|
+
),
|
|
17774
|
+
quill_base_pivot AS (
|
|
17775
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17776
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17777
|
+
)
|
|
17778
|
+
SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
|
|
17779
|
+
return itemQuery.replace(
|
|
17780
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17781
|
+
pivotQuery
|
|
17782
|
+
);
|
|
17783
|
+
}
|
|
17784
|
+
function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, databaseType = "postgresql") {
|
|
17785
|
+
if (!additionalProcessing || !query) return query;
|
|
17786
|
+
const isValidBaseQuery = query.match(
|
|
17787
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
|
|
17788
|
+
);
|
|
17789
|
+
if (!isValidBaseQuery) {
|
|
17790
|
+
return void 0;
|
|
17791
|
+
}
|
|
17792
|
+
if (!pivot.aggregations || pivot.aggregations.length === 0) {
|
|
17793
|
+
if (pivot.aggregationType) {
|
|
17794
|
+
pivot.aggregations = [
|
|
17795
|
+
{
|
|
17796
|
+
aggregationType: pivot.aggregationType,
|
|
17797
|
+
valueField: pivot.valueField,
|
|
17798
|
+
valueField2: pivot.valueField2
|
|
17799
|
+
}
|
|
17800
|
+
];
|
|
17801
|
+
} else {
|
|
17802
|
+
throw new Error("No aggregations provided for pivot");
|
|
17803
|
+
}
|
|
17804
|
+
}
|
|
17805
|
+
let rowsPerPage = 0;
|
|
17806
|
+
let currentInterval = 0;
|
|
17807
|
+
let offset = 0;
|
|
17808
|
+
let limit = 1e3;
|
|
17809
|
+
let sortQuery = "";
|
|
17810
|
+
if (additionalProcessing.page) {
|
|
17811
|
+
const page = additionalProcessing.page.page || 0;
|
|
17812
|
+
if (additionalProcessing.page.rowsPerRequest) {
|
|
17813
|
+
limit = additionalProcessing.page.rowsPerRequest;
|
|
17814
|
+
}
|
|
17815
|
+
rowsPerPage = additionalProcessing.page.rowsPerPage || 0;
|
|
17816
|
+
currentInterval = page ? Math.floor(page / (limit / rowsPerPage)) : 0;
|
|
17817
|
+
offset = currentInterval * limit;
|
|
17818
|
+
}
|
|
17819
|
+
const disambiguation = pivot.aggregations.length > 1 ? `_${matchCasing(pivot.aggregations?.[0]?.aggregationType, pivot.aggregations?.[0]?.valueField)}` : "";
|
|
17820
|
+
if (additionalProcessing.sort) {
|
|
17821
|
+
sortQuery = `ORDER BY ${processColumnReference(additionalProcessing.sort.field, databaseType, void 0, true)} ${additionalProcessing.sort.direction || ""}`;
|
|
17822
|
+
} else {
|
|
17823
|
+
const valueFieldAlias = processColumnReference(
|
|
17824
|
+
(pivot.aggregations?.[0]?.valueField ?? "") + disambiguation,
|
|
17825
|
+
databaseType,
|
|
17826
|
+
void 0,
|
|
17827
|
+
false,
|
|
17828
|
+
true
|
|
17829
|
+
);
|
|
17830
|
+
const defaultSortField = pivot.sortField || pivot.rowField || valueFieldAlias;
|
|
17831
|
+
const defaultSortDirection = pivot.sortDirection || "";
|
|
17832
|
+
if (defaultSortField !== `"_"`) {
|
|
17833
|
+
sortQuery = `ORDER BY ${processColumnReference(defaultSortField, databaseType, void 0, true)} ${defaultSortDirection}`;
|
|
17834
|
+
} else {
|
|
17835
|
+
sortQuery = "";
|
|
17836
|
+
}
|
|
17837
|
+
}
|
|
17838
|
+
const additionalProcessingQuery = `
|
|
17839
|
+
SELECT *
|
|
17840
|
+
FROM quill_base_pivot ${sortQuery}${databaseType.toLowerCase() === "mssql" ? ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY` : ` LIMIT ${limit} OFFSET ${offset}`}
|
|
17841
|
+
`.replace(/\s+/g, " ").trim();
|
|
17842
|
+
return query.replace(
|
|
17843
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
|
|
17844
|
+
additionalProcessingQuery
|
|
17845
|
+
);
|
|
17846
|
+
}
|
|
17847
|
+
function generateRowCountQuery(query, databaseType) {
|
|
17848
|
+
if (!query) return query;
|
|
17849
|
+
const isValidBaseQuery = query.match(
|
|
17850
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
|
|
17851
|
+
);
|
|
17852
|
+
if (!isValidBaseQuery) {
|
|
17853
|
+
return void 0;
|
|
17854
|
+
}
|
|
17855
|
+
const rowCountQuery = `, subview_row_count_cte AS (SELECT * FROM quill_base_pivot)
|
|
17856
|
+
SELECT count(*) as ${processColumnReference("row_count", databaseType || "postgresql", void 0, true)} FROM subview_row_count_cte
|
|
17857
|
+
`.replace(/\s+/g, " ").trim();
|
|
17858
|
+
return query.replace(
|
|
17859
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
|
|
17860
|
+
rowCountQuery
|
|
17861
|
+
);
|
|
17862
|
+
}
|
|
17863
|
+
|
|
17864
|
+
// src/utils/pivotConstructor.ts
|
|
17865
|
+
async function generatePivotWithSQL({
|
|
17866
|
+
pivot,
|
|
17867
|
+
report,
|
|
17868
|
+
client,
|
|
17869
|
+
dateBucket,
|
|
17870
|
+
dateFilter,
|
|
17871
|
+
distinctStrings,
|
|
17872
|
+
dashboardName,
|
|
17873
|
+
tenants,
|
|
17874
|
+
additionalProcessing,
|
|
17875
|
+
pivotQuery,
|
|
17876
|
+
comparisonPivotQuery,
|
|
17877
|
+
getPivotRowCount = true,
|
|
17878
|
+
caller,
|
|
17879
|
+
getToken
|
|
17880
|
+
}) {
|
|
17881
|
+
let sqlQuery = pivotQuery;
|
|
17882
|
+
let comparisonPivotSql = comparisonPivotQuery;
|
|
17883
|
+
const databaseType = client.databaseType || "postgresql";
|
|
17884
|
+
if (!pivotQuery && pivot.columnField && !pivot.columnValues && !distinctStrings) {
|
|
17885
|
+
if (!report?.rows) {
|
|
17886
|
+
throw new Error("No distinct strings provided for column field");
|
|
17887
|
+
} else {
|
|
17888
|
+
distinctStrings = Array.from(
|
|
17889
|
+
new Set(
|
|
17890
|
+
report.rows.map((row) => row[pivot.columnField]).filter((value) => value !== null && value !== void 0)
|
|
17891
|
+
)
|
|
17892
|
+
);
|
|
17893
|
+
}
|
|
17894
|
+
}
|
|
17895
|
+
if (!pivot.aggregations?.length && pivot.aggregationType) {
|
|
17896
|
+
pivot.aggregations = [
|
|
17897
|
+
{
|
|
17898
|
+
aggregationType: pivot.aggregationType,
|
|
17899
|
+
valueField: pivot.valueField,
|
|
17900
|
+
valueFieldType: pivot.valueFieldType,
|
|
17901
|
+
valueField2: pivot.valueField2,
|
|
17902
|
+
valueField2Type: pivot.valueField2Type
|
|
17903
|
+
}
|
|
17904
|
+
];
|
|
17905
|
+
}
|
|
17906
|
+
let comparisonInterval = void 0;
|
|
17907
|
+
if (dateFilter && dateFilter.comparisonRange) {
|
|
17908
|
+
comparisonInterval = getComparisonInterval(
|
|
17909
|
+
{
|
|
17910
|
+
startDate: dateFilter.comparisonRange.startDate,
|
|
17911
|
+
endDate: dateFilter.comparisonRange.endDate
|
|
17912
|
+
},
|
|
17913
|
+
dateBucket
|
|
17914
|
+
);
|
|
17915
|
+
}
|
|
17916
|
+
if (pivot.rowField && !pivot.rowFieldType) {
|
|
17917
|
+
const rowColumn = report?.columns.find(
|
|
17918
|
+
(column) => column.field === pivot.rowField
|
|
17919
|
+
);
|
|
17920
|
+
pivot.rowFieldType = rowColumn?.format || "string";
|
|
17921
|
+
}
|
|
17922
|
+
const filteredDistinctStrings = distinctStrings?.filter(
|
|
17923
|
+
(value) => value !== null && value !== void 0 && value !== ""
|
|
17924
|
+
);
|
|
17925
|
+
const pivotColumnFields = filteredDistinctStrings?.slice(
|
|
17926
|
+
0,
|
|
17927
|
+
MAX_PIVOT_UNIQUE_VALUES
|
|
17928
|
+
);
|
|
17929
|
+
if (!pivotQuery && report) {
|
|
17930
|
+
if (!report.itemQuery) {
|
|
17931
|
+
throw Error("No item query found in report");
|
|
17932
|
+
}
|
|
17933
|
+
const itemQuery = report.itemQuery[0];
|
|
17934
|
+
const comparisonQuery = report.itemQuery[1];
|
|
17935
|
+
if (!itemQuery) {
|
|
17936
|
+
throw Error("No item query found in report");
|
|
17937
|
+
}
|
|
17938
|
+
sqlQuery = generatePivotQuery(
|
|
17939
|
+
pivot,
|
|
17940
|
+
itemQuery,
|
|
17941
|
+
databaseType,
|
|
17942
|
+
pivotColumnFields,
|
|
17943
|
+
dateBucket
|
|
17944
|
+
);
|
|
17945
|
+
comparisonPivotSql = comparisonQuery ? generatePivotQuery(
|
|
17946
|
+
pivot,
|
|
17947
|
+
comparisonQuery,
|
|
17948
|
+
databaseType,
|
|
17949
|
+
pivotColumnFields,
|
|
17950
|
+
dateBucket
|
|
17951
|
+
) : "";
|
|
17952
|
+
}
|
|
17953
|
+
if (!sqlQuery) {
|
|
17954
|
+
throw "Error generating pivot query";
|
|
17955
|
+
}
|
|
17956
|
+
const paginatedSqlQuery = additionalProcessingOnPivotQuery(
|
|
17957
|
+
pivot,
|
|
17958
|
+
sqlQuery,
|
|
17959
|
+
additionalProcessing,
|
|
17960
|
+
client.databaseType
|
|
17961
|
+
);
|
|
17962
|
+
const paginatedComparisonQuery = comparisonPivotSql ? additionalProcessingOnPivotQuery(
|
|
17963
|
+
pivot,
|
|
17964
|
+
comparisonPivotSql,
|
|
17965
|
+
additionalProcessing,
|
|
17966
|
+
client.databaseType
|
|
17967
|
+
) : "";
|
|
17968
|
+
const preQueries = [paginatedSqlQuery];
|
|
17969
|
+
getPivotRowCount = getPivotRowCount && (report?.chartType === "table" || caller === "ReportBuilder");
|
|
17970
|
+
if (getPivotRowCount) {
|
|
17971
|
+
const pivotRowCountQuery = generateRowCountQuery(
|
|
17972
|
+
sqlQuery,
|
|
17973
|
+
client.databaseType
|
|
17974
|
+
);
|
|
17975
|
+
preQueries.push(pivotRowCountQuery);
|
|
17976
|
+
}
|
|
17977
|
+
if (paginatedComparisonQuery) {
|
|
17978
|
+
preQueries.push(paginatedComparisonQuery);
|
|
17979
|
+
}
|
|
17980
|
+
const { data: resp } = await quillFetch({
|
|
17981
|
+
client,
|
|
17982
|
+
task: "query",
|
|
17983
|
+
metadata: {
|
|
17984
|
+
preQueries,
|
|
17985
|
+
clientId: client.publicKey,
|
|
17986
|
+
databaseType,
|
|
17987
|
+
runQueryConfig: {
|
|
17988
|
+
overridePost: true,
|
|
17989
|
+
convertDatatypes: true
|
|
17990
|
+
},
|
|
17991
|
+
useNewNodeSql: true,
|
|
17992
|
+
dashboardName,
|
|
17993
|
+
tenants
|
|
17994
|
+
},
|
|
17995
|
+
urlParameters: `caller=generatePivot&task=query`,
|
|
17996
|
+
credentials: "same-origin",
|
|
17997
|
+
getToken
|
|
17998
|
+
});
|
|
17999
|
+
if (resp.success === false) {
|
|
18000
|
+
throw resp.errorMessage;
|
|
18001
|
+
}
|
|
18002
|
+
const queryResponseRows = resp?.queryResults?.[0]?.rows || [];
|
|
18003
|
+
const queryResponseFields = resp?.queryResults?.[0]?.fields || [];
|
|
18004
|
+
const queryComparisonResponseRows = (getPivotRowCount ? resp?.queryResults?.[2]?.rows : resp?.queryResults?.[1]?.rows) || [];
|
|
18005
|
+
const queryComparisonResponseFields = (getPivotRowCount ? resp?.queryResults?.[2]?.fields : resp?.queryResults?.[1]?.fields) || [];
|
|
18006
|
+
parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
|
|
18007
|
+
parseValueFromBigQueryDates(
|
|
18008
|
+
queryComparisonResponseRows,
|
|
18009
|
+
queryComparisonResponseFields
|
|
18010
|
+
);
|
|
18011
|
+
const responseRows = mergeComparisonPivotRows({
|
|
18012
|
+
pivot,
|
|
18013
|
+
rows: queryResponseRows,
|
|
18014
|
+
compRows: queryComparisonResponseRows,
|
|
18015
|
+
databaseType,
|
|
18016
|
+
dateBucket,
|
|
18017
|
+
comparisonInterval,
|
|
18018
|
+
columnFieldValues: pivotColumnFields
|
|
18019
|
+
});
|
|
18020
|
+
const responseFields = mergeComparisonPivotColumns({
|
|
18021
|
+
pivot,
|
|
18022
|
+
rows: queryResponseFields,
|
|
18023
|
+
compRows: queryComparisonResponseFields
|
|
18024
|
+
});
|
|
18025
|
+
const rows = pivot.rowField ? responseRows.map(
|
|
18026
|
+
(row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
|
|
18027
|
+
) : responseRows;
|
|
18028
|
+
if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
|
|
18029
|
+
rows.forEach((row) => {
|
|
18030
|
+
Object.keys(row).forEach((key) => {
|
|
18031
|
+
const processedKey = processColumnName(key);
|
|
18032
|
+
if (processedKey !== key) {
|
|
18033
|
+
row[processedKey] = row[key];
|
|
18034
|
+
delete row[key];
|
|
18035
|
+
}
|
|
18036
|
+
});
|
|
18037
|
+
});
|
|
18038
|
+
}
|
|
18039
|
+
const columns = responseFields?.map((field) => ({
|
|
18040
|
+
field: processColumnName(field.name),
|
|
18041
|
+
label: snakeCaseToTitleCase(
|
|
18042
|
+
processColumnName(field.name.replace("comparison_", "comparison "))
|
|
18043
|
+
),
|
|
18044
|
+
format: field.name === pivot.rowField ? "string" : (
|
|
18045
|
+
// This scary equation is calculating which aggregation a column is associated with.
|
|
18046
|
+
// Eg you have 7 columns and 2 aggregations, you can assume column 0 is the row field, 1-3 is aggregation 0, and 4-6 is aggregation 1.
|
|
18047
|
+
// pivot.aggregations?.[
|
|
18048
|
+
// Math.floor(
|
|
18049
|
+
// (index - 1) /
|
|
18050
|
+
// Math.floor(
|
|
18051
|
+
// (responseFields.length - 1) /
|
|
18052
|
+
// (pivot.aggregations?.length ?? 1),
|
|
18053
|
+
// ),
|
|
18054
|
+
// )
|
|
18055
|
+
// ]?.aggregationType === 'percentage'
|
|
18056
|
+
pivot.aggregations?.find(
|
|
18057
|
+
(agg) => agg.valueField === field.name || `${agg.valueField}_percentage` === field.name || !agg.valueField && agg.aggregationType === "percentage" && field.name.endsWith("percentage")
|
|
18058
|
+
)?.aggregationType === "percentage" ? "percent" : "whole_number"
|
|
18059
|
+
),
|
|
18060
|
+
fieldType: field.fieldType,
|
|
18061
|
+
jsType: field.jsType,
|
|
18062
|
+
dataTypeID: field.dataTypeID
|
|
18063
|
+
})).filter(
|
|
18064
|
+
(field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
|
|
18065
|
+
).sort((a, b) => {
|
|
18066
|
+
if (a.field === pivot.rowField) {
|
|
18067
|
+
return -1;
|
|
18068
|
+
}
|
|
18069
|
+
if (b.field === pivot.rowField) {
|
|
18070
|
+
return 1;
|
|
18071
|
+
}
|
|
18072
|
+
return 0;
|
|
18073
|
+
});
|
|
18074
|
+
if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
|
|
18075
|
+
rows.forEach((row) => {
|
|
18076
|
+
row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
18077
|
+
let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
18078
|
+
if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
|
|
18079
|
+
const rowDate = new Date(value);
|
|
18080
|
+
if (rowDate < dateFilter.startDate) {
|
|
18081
|
+
value = dateFilter.startDate.toISOString();
|
|
18082
|
+
} else if (rowDate > dateFilter.endDate) {
|
|
18083
|
+
value = dateFilter.endDate.toISOString();
|
|
18084
|
+
}
|
|
18085
|
+
}
|
|
18086
|
+
const dateString = getDateString(
|
|
18087
|
+
value,
|
|
18088
|
+
dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
|
|
18089
|
+
dateBucket,
|
|
18090
|
+
databaseType
|
|
18091
|
+
);
|
|
18092
|
+
row[pivot.rowField || ""] = dateString;
|
|
18093
|
+
});
|
|
18094
|
+
if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
|
|
18095
|
+
const dateSet = new Set(
|
|
18096
|
+
rows.map((row) => row[pivot.rowField || ""])
|
|
18097
|
+
);
|
|
18098
|
+
for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
|
|
18099
|
+
const formattedDate = getDateString(
|
|
18100
|
+
date.toISOString(),
|
|
18101
|
+
{ start: dateFilter.startDate, end: dateFilter.endDate },
|
|
18102
|
+
dateBucket,
|
|
18103
|
+
databaseType
|
|
18104
|
+
);
|
|
18105
|
+
if (!dateSet.has(formattedDate)) {
|
|
18106
|
+
const newRow = {};
|
|
18107
|
+
newRow[pivot.rowField] = formattedDate;
|
|
18108
|
+
newRow.__quillRawDate = date.toISOString();
|
|
18109
|
+
rows.push(newRow);
|
|
18110
|
+
dateSet.add(formattedDate);
|
|
18111
|
+
}
|
|
18112
|
+
}
|
|
18113
|
+
}
|
|
18114
|
+
if (!pivot.sort) {
|
|
18115
|
+
rows.sort((a, b) => {
|
|
18116
|
+
if (a.__quillRawDate < b.__quillRawDate) {
|
|
18117
|
+
return -1;
|
|
18118
|
+
}
|
|
18119
|
+
if (a.__quillRawDate > b.__quillRawDate) {
|
|
18120
|
+
return 1;
|
|
18121
|
+
}
|
|
18122
|
+
return 0;
|
|
18123
|
+
});
|
|
18124
|
+
}
|
|
18125
|
+
}
|
|
18126
|
+
columns?.forEach((column, index) => {
|
|
18127
|
+
if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
|
|
18128
|
+
column.label = "Count";
|
|
18129
|
+
}
|
|
18130
|
+
});
|
|
18131
|
+
const numericColumns = columns?.filter(
|
|
18132
|
+
(column) => column.format === "whole_number" || column.format === "percentage"
|
|
18133
|
+
);
|
|
18134
|
+
rows.forEach((row) => {
|
|
18135
|
+
numericColumns?.forEach((column) => {
|
|
18136
|
+
row[column.field] = row[column.field] ?? 0;
|
|
18137
|
+
});
|
|
18138
|
+
});
|
|
18139
|
+
return {
|
|
18140
|
+
rows,
|
|
18141
|
+
columns: columns ?? [],
|
|
18142
|
+
rowCount: getPivotRowCount ? Number(resp?.queryResults?.[1]?.rows?.[0]?.["row_count"]) ?? rows.length : 0,
|
|
18143
|
+
pivotQuery: sqlQuery,
|
|
18144
|
+
comparisonPivotQuery: comparisonPivotSql
|
|
18145
|
+
};
|
|
18146
|
+
}
|
|
18147
|
+
function generatePivotTableYAxis(pivot, cols, yAxisField) {
|
|
18148
|
+
if (pivot?.aggregationType === "count") {
|
|
18149
|
+
return [
|
|
18150
|
+
{
|
|
18151
|
+
field: pivot.valueField ?? "count",
|
|
18152
|
+
label: yAxisField.label,
|
|
18153
|
+
format: yAxisField.format
|
|
18154
|
+
}
|
|
18155
|
+
];
|
|
18156
|
+
}
|
|
18157
|
+
return [
|
|
18158
|
+
{
|
|
18159
|
+
field: pivot.valueField ?? "count",
|
|
18160
|
+
label: yAxisField.label,
|
|
18161
|
+
format: yAxisField.format
|
|
18162
|
+
}
|
|
18163
|
+
];
|
|
18164
|
+
}
|
|
18165
|
+
function generatePivotTitle(pivot) {
|
|
18166
|
+
if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
|
|
18167
|
+
return snakeAndCamelCaseToTitleCase(
|
|
18168
|
+
`${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
|
|
18169
|
+
`
|
|
18170
|
+
);
|
|
18171
|
+
} else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
|
|
18172
|
+
return snakeAndCamelCaseToTitleCase(
|
|
18173
|
+
`${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
|
|
18174
|
+
`
|
|
18175
|
+
);
|
|
18176
|
+
}
|
|
18177
|
+
return snakeAndCamelCaseToTitleCase(
|
|
18178
|
+
`${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
|
|
18179
|
+
);
|
|
18180
|
+
}
|
|
18181
|
+
async function generatePivotTable({
|
|
18182
|
+
pivot,
|
|
18183
|
+
dateBucket,
|
|
18184
|
+
dateFilter,
|
|
18185
|
+
report,
|
|
18186
|
+
client,
|
|
18187
|
+
getToken,
|
|
18188
|
+
eventTracking,
|
|
18189
|
+
uniqueValues,
|
|
18190
|
+
dashboardName,
|
|
18191
|
+
tenants,
|
|
18192
|
+
additionalProcessing,
|
|
18193
|
+
caller,
|
|
18194
|
+
pivotQuery
|
|
18195
|
+
}) {
|
|
18196
|
+
try {
|
|
18197
|
+
if (report && client) {
|
|
18198
|
+
const pivotTable = await generatePivotWithSQL({
|
|
18199
|
+
pivotQuery,
|
|
18200
|
+
pivot,
|
|
18201
|
+
report,
|
|
18202
|
+
client,
|
|
18203
|
+
dateBucket,
|
|
18204
|
+
dateFilter,
|
|
18205
|
+
distinctStrings: pivot.columnField && uniqueValues?.[pivot.columnField] ? uniqueValues[pivot.columnField] : [],
|
|
18206
|
+
dashboardName,
|
|
18207
|
+
tenants,
|
|
18208
|
+
additionalProcessing,
|
|
18209
|
+
caller,
|
|
18210
|
+
getToken
|
|
18211
|
+
});
|
|
18212
|
+
return pivotTable;
|
|
18213
|
+
}
|
|
18214
|
+
} catch (e) {
|
|
18215
|
+
eventTracking?.logError?.({
|
|
18216
|
+
type: "bug",
|
|
18217
|
+
// TODO: determine type
|
|
18218
|
+
severity: "high",
|
|
18219
|
+
message: "Error generating pivot table",
|
|
18220
|
+
errorMessage: e.message,
|
|
18221
|
+
errorStack: e.stack,
|
|
18222
|
+
errorData: {
|
|
18223
|
+
caller: "PivotModal",
|
|
18224
|
+
function: "generatePivotTable"
|
|
18225
|
+
}
|
|
18226
|
+
});
|
|
18227
|
+
throw Error(`Failed to generate pivot table with SQL: ${e}`);
|
|
18228
|
+
}
|
|
18229
|
+
throw Error("Failed to generate pivot table: invalid report");
|
|
18230
|
+
}
|
|
18231
|
+
|
|
18232
|
+
// src/utils/errorProcessing.ts
|
|
18233
|
+
function processFilterErrorList(resp) {
|
|
18234
|
+
if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
|
|
18235
|
+
return;
|
|
18236
|
+
}
|
|
18237
|
+
}
|
|
18238
|
+
|
|
18239
|
+
// src/utils/paginationProcessing.ts
|
|
18240
|
+
var DEFAULT_PAGINATION = {
|
|
18241
|
+
page: 0,
|
|
18242
|
+
rowsPerPage: 10,
|
|
18243
|
+
rowsPerRequest: 600
|
|
18244
|
+
};
|
|
18245
|
+
var DEFAULT_TABLE_PAGINATION = {
|
|
18246
|
+
page: 0,
|
|
18247
|
+
rowsPerPage: 10,
|
|
18248
|
+
rowsPerRequest: 50
|
|
18249
|
+
};
|
|
18250
|
+
function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
|
|
18251
|
+
if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
|
|
18252
|
+
return false;
|
|
18253
|
+
}
|
|
18254
|
+
const indexAdjustedPage = page;
|
|
18255
|
+
const pageInterval = Math.floor(
|
|
18256
|
+
indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
18257
|
+
);
|
|
18258
|
+
const indexAdjustedPreviousPage = maxPage;
|
|
18259
|
+
const previousPageInterval = Math.floor(
|
|
18260
|
+
indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
18261
|
+
);
|
|
18262
|
+
return pageInterval > previousPageInterval;
|
|
18263
|
+
}
|
|
18264
|
+
function shouldSortInMemory(pagination, rowCount) {
|
|
18265
|
+
if (!rowCount || rowCount < pagination.rowsPerRequest) {
|
|
18266
|
+
return true;
|
|
18267
|
+
}
|
|
18268
|
+
return false;
|
|
18269
|
+
}
|
|
17553
18270
|
|
|
17554
18271
|
// src/utils/tableProcessing.ts
|
|
17555
18272
|
var getUniqueValuesByQuery = async ({
|
|
@@ -18209,86 +18926,571 @@ var fetchResultsByReport = async ({
|
|
|
18209
18926
|
if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
|
|
18210
18927
|
parseValueFromBigQueryDates(rows, columns);
|
|
18211
18928
|
}
|
|
18212
|
-
return { rows, columns, rowCount, error };
|
|
18213
|
-
};
|
|
18214
|
-
var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dashboardName, processing, customFields, rowsOnly, rowCountOnly) => {
|
|
18215
|
-
let rows = [];
|
|
18216
|
-
let columns = [];
|
|
18217
|
-
let rowCount;
|
|
18218
|
-
let error;
|
|
18219
|
-
let itemQuery;
|
|
18220
|
-
let referencedTables;
|
|
18221
|
-
try {
|
|
18222
|
-
const fetchResp = await quillFetch({
|
|
18223
|
-
client,
|
|
18224
|
-
task: "patterns",
|
|
18225
|
-
metadata: {
|
|
18226
|
-
clientId: client.publicKey,
|
|
18227
|
-
ast,
|
|
18228
|
-
customFields,
|
|
18229
|
-
additionalProcessing: processing,
|
|
18230
|
-
useUpdatedDataGathering: true,
|
|
18231
|
-
useNewNodeSql: true,
|
|
18232
|
-
rowsOnly,
|
|
18233
|
-
rowCountOnly,
|
|
18234
|
-
dashboardName,
|
|
18235
|
-
tenants
|
|
18236
|
-
},
|
|
18237
|
-
getToken
|
|
18238
|
-
});
|
|
18239
|
-
const resp = await parseFetchResponse(
|
|
18240
|
-
client,
|
|
18241
|
-
"patterns",
|
|
18242
|
-
fetchResp,
|
|
18243
|
-
getToken
|
|
18244
|
-
);
|
|
18245
|
-
if (resp.errorMessage || resp.name === "error") {
|
|
18246
|
-
throw new Error(resp.errorMessage);
|
|
18247
|
-
}
|
|
18248
|
-
processFilterErrorList(resp);
|
|
18249
|
-
if (resp.rowCount !== void 0) {
|
|
18250
|
-
rowCount = resp.rowCount;
|
|
18929
|
+
return { rows, columns, rowCount, error };
|
|
18930
|
+
};
|
|
18931
|
+
var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dashboardName, processing, customFields, rowsOnly, rowCountOnly) => {
|
|
18932
|
+
let rows = [];
|
|
18933
|
+
let columns = [];
|
|
18934
|
+
let rowCount;
|
|
18935
|
+
let error;
|
|
18936
|
+
let itemQuery;
|
|
18937
|
+
let referencedTables;
|
|
18938
|
+
try {
|
|
18939
|
+
const fetchResp = await quillFetch({
|
|
18940
|
+
client,
|
|
18941
|
+
task: "patterns",
|
|
18942
|
+
metadata: {
|
|
18943
|
+
clientId: client.publicKey,
|
|
18944
|
+
ast,
|
|
18945
|
+
customFields,
|
|
18946
|
+
additionalProcessing: processing,
|
|
18947
|
+
useUpdatedDataGathering: true,
|
|
18948
|
+
useNewNodeSql: true,
|
|
18949
|
+
rowsOnly,
|
|
18950
|
+
rowCountOnly,
|
|
18951
|
+
dashboardName,
|
|
18952
|
+
tenants
|
|
18953
|
+
},
|
|
18954
|
+
getToken
|
|
18955
|
+
});
|
|
18956
|
+
const resp = await parseFetchResponse(
|
|
18957
|
+
client,
|
|
18958
|
+
"patterns",
|
|
18959
|
+
fetchResp,
|
|
18960
|
+
getToken
|
|
18961
|
+
);
|
|
18962
|
+
if (resp.errorMessage || resp.name === "error") {
|
|
18963
|
+
throw new Error(resp.errorMessage);
|
|
18964
|
+
}
|
|
18965
|
+
processFilterErrorList(resp);
|
|
18966
|
+
if (resp.rowCount !== void 0) {
|
|
18967
|
+
rowCount = resp.rowCount;
|
|
18968
|
+
}
|
|
18969
|
+
const gatheredRows = resp.rows && resp.rows.length ? resp.rows : [];
|
|
18970
|
+
columns = resp.fields.map((elem) => convertPostgresColumn(elem));
|
|
18971
|
+
rows = gatheredRows;
|
|
18972
|
+
itemQuery = resp.itemQuery;
|
|
18973
|
+
referencedTables = resp.referencedTables;
|
|
18974
|
+
if (customFields) {
|
|
18975
|
+
const tables = referencedTables ?? [];
|
|
18976
|
+
tables.forEach((table) => {
|
|
18977
|
+
const _customFields = customFields?.[table] ?? [];
|
|
18978
|
+
columns.forEach((col) => {
|
|
18979
|
+
if (_customFields.some((field) => {
|
|
18980
|
+
return field.field === col.field;
|
|
18981
|
+
})) {
|
|
18982
|
+
col.inferFormat = true;
|
|
18983
|
+
}
|
|
18984
|
+
});
|
|
18985
|
+
});
|
|
18986
|
+
}
|
|
18987
|
+
} catch (e) {
|
|
18988
|
+
eventTracking?.logError?.({
|
|
18989
|
+
type: "bug",
|
|
18990
|
+
// TODO: determine type
|
|
18991
|
+
severity: "high",
|
|
18992
|
+
message: "Error fetching table by AST",
|
|
18993
|
+
errorMessage: e.message,
|
|
18994
|
+
errorStack: e.stack,
|
|
18995
|
+
errorData: {
|
|
18996
|
+
caller: "fetchTableByAST",
|
|
18997
|
+
function: "fetchTableByAST"
|
|
18998
|
+
}
|
|
18999
|
+
});
|
|
19000
|
+
rows = [];
|
|
19001
|
+
columns = [];
|
|
19002
|
+
rowCount = 0;
|
|
19003
|
+
error = e.message;
|
|
19004
|
+
}
|
|
19005
|
+
if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
|
|
19006
|
+
parseValueFromBigQueryDates(rows, columns);
|
|
19007
|
+
}
|
|
19008
|
+
return { rows, columns, rowCount, error, itemQuery, referencedTables };
|
|
19009
|
+
};
|
|
19010
|
+
|
|
19011
|
+
// src/utils/dashboard.ts
|
|
19012
|
+
var defaultDashboardItem = {
|
|
19013
|
+
id: "",
|
|
19014
|
+
name: "",
|
|
19015
|
+
dashboardName: "",
|
|
19016
|
+
rows: [],
|
|
19017
|
+
compareRows: [],
|
|
19018
|
+
columns: [],
|
|
19019
|
+
chartType: "",
|
|
19020
|
+
pivot: null,
|
|
19021
|
+
yAxisFields: [],
|
|
19022
|
+
xAxisLabel: "",
|
|
19023
|
+
xAxisField: "",
|
|
19024
|
+
xAxisFormat: "string",
|
|
19025
|
+
order: -1,
|
|
19026
|
+
filtersApplied: [],
|
|
19027
|
+
queryString: "",
|
|
19028
|
+
rowCount: 0,
|
|
19029
|
+
columnInternal: []
|
|
19030
|
+
};
|
|
19031
|
+
async function cleanDashboardItem({
|
|
19032
|
+
item,
|
|
19033
|
+
dashboardFilters,
|
|
19034
|
+
getToken,
|
|
19035
|
+
eventTracking,
|
|
19036
|
+
client,
|
|
19037
|
+
dateBucket,
|
|
19038
|
+
additionalProcessing,
|
|
19039
|
+
customFields,
|
|
19040
|
+
skipPivotFetch,
|
|
19041
|
+
tenants
|
|
19042
|
+
}) {
|
|
19043
|
+
if (!item) return defaultDashboardItem;
|
|
19044
|
+
if (!item.rows) {
|
|
19045
|
+
return {
|
|
19046
|
+
...defaultDashboardItem,
|
|
19047
|
+
id: item._id,
|
|
19048
|
+
name: item.name
|
|
19049
|
+
};
|
|
19050
|
+
}
|
|
19051
|
+
const fields = item.fields || [];
|
|
19052
|
+
const columnsWithCustomFields = [...item.columns ?? []];
|
|
19053
|
+
if (item.includeCustomFields && item.rows?.length > 0) {
|
|
19054
|
+
const tables = item.referencedTables ?? [];
|
|
19055
|
+
tables.forEach((table) => {
|
|
19056
|
+
const _customFields = customFields?.[table] ?? [];
|
|
19057
|
+
_customFields.forEach((field) => {
|
|
19058
|
+
const isJsonCustomField = !!field.refColumn;
|
|
19059
|
+
if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
|
|
19060
|
+
const result_field = fields.find((f) => f.name === field.field);
|
|
19061
|
+
const converted_field = convertPostgresColumn(result_field ?? {});
|
|
19062
|
+
columnsWithCustomFields.push({
|
|
19063
|
+
field: field.field,
|
|
19064
|
+
format: converted_field.format,
|
|
19065
|
+
label: snakeAndCamelCaseToTitleCase(field.field),
|
|
19066
|
+
fieldType: converted_field.fieldType,
|
|
19067
|
+
dataTypeID: converted_field.dataTypeID,
|
|
19068
|
+
jsType: converted_field.jsType,
|
|
19069
|
+
inferFormat: isJsonCustomField
|
|
19070
|
+
});
|
|
19071
|
+
}
|
|
19072
|
+
});
|
|
19073
|
+
});
|
|
19074
|
+
}
|
|
19075
|
+
const processedColumns = item.columns.map((col) => {
|
|
19076
|
+
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
19077
|
+
});
|
|
19078
|
+
const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
|
|
19079
|
+
const field = item.fields?.find((f) => f.name === col.field);
|
|
19080
|
+
const converted_field = convertPostgresColumn(field ?? {});
|
|
19081
|
+
return {
|
|
19082
|
+
fieldType: converted_field.fieldType,
|
|
19083
|
+
dataTypeID: converted_field.dataTypeID,
|
|
19084
|
+
jsType: converted_field.jsType,
|
|
19085
|
+
...col,
|
|
19086
|
+
label: snakeAndCamelCaseToTitleCase(col.label)
|
|
19087
|
+
};
|
|
19088
|
+
});
|
|
19089
|
+
let pivotTable;
|
|
19090
|
+
let pivotError;
|
|
19091
|
+
try {
|
|
19092
|
+
const shouldPaginatePivotAsTable = item.chartType === "table";
|
|
19093
|
+
const pivotChartProcessing = {
|
|
19094
|
+
page: DEFAULT_PAGINATION
|
|
19095
|
+
};
|
|
19096
|
+
pivotTable = await getPivotTable(
|
|
19097
|
+
{
|
|
19098
|
+
...item,
|
|
19099
|
+
pivot: item.pivot && !skipPivotFetch ? {
|
|
19100
|
+
...item.pivot,
|
|
19101
|
+
aggregations: item.pivot.aggregations ?? [
|
|
19102
|
+
{
|
|
19103
|
+
valueField: item.pivot.valueField,
|
|
19104
|
+
valueFieldType: item.pivot.valueFieldType,
|
|
19105
|
+
valueField2: item.pivot.valueField2,
|
|
19106
|
+
valueField2Type: item.pivot.valueField2Type,
|
|
19107
|
+
aggregationType: item.pivot.aggregationType
|
|
19108
|
+
}
|
|
19109
|
+
]
|
|
19110
|
+
} : void 0
|
|
19111
|
+
},
|
|
19112
|
+
dashboardFilters,
|
|
19113
|
+
item.dashboardName,
|
|
19114
|
+
getToken,
|
|
19115
|
+
client,
|
|
19116
|
+
eventTracking,
|
|
19117
|
+
dateBucket,
|
|
19118
|
+
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
19119
|
+
tenants,
|
|
19120
|
+
customFields
|
|
19121
|
+
);
|
|
19122
|
+
} catch (e) {
|
|
19123
|
+
pivotTable = void 0;
|
|
19124
|
+
eventTracking?.logError?.({
|
|
19125
|
+
type: "bug",
|
|
19126
|
+
// TODO: determine type
|
|
19127
|
+
severity: "high",
|
|
19128
|
+
message: "Error fetching pivot table",
|
|
19129
|
+
errorMessage: e.message,
|
|
19130
|
+
errorStack: e.stack,
|
|
19131
|
+
errorData: {
|
|
19132
|
+
caller: "cleanDashboardItem",
|
|
19133
|
+
function: "cleanDashboardItem"
|
|
19134
|
+
}
|
|
19135
|
+
});
|
|
19136
|
+
console.error("Error fetching pivot table", e);
|
|
19137
|
+
pivotError = "Error fetching pivot table";
|
|
19138
|
+
}
|
|
19139
|
+
const referenceLineYValues = [];
|
|
19140
|
+
for (const key in item) {
|
|
19141
|
+
if (key.startsWith("referenceLine_")) {
|
|
19142
|
+
const field = key.slice(14);
|
|
19143
|
+
if (!item[key] || !item[key][0]) continue;
|
|
19144
|
+
const value = Object.values(item[key][0])[0];
|
|
19145
|
+
referenceLineYValues.push({ label: field, query: [value, value] });
|
|
19146
|
+
}
|
|
19147
|
+
}
|
|
19148
|
+
if (item.referenceLines) {
|
|
19149
|
+
for (const referenceLine of item.referenceLines) {
|
|
19150
|
+
if (Array.isArray(referenceLine.query)) {
|
|
19151
|
+
referenceLineYValues.push({
|
|
19152
|
+
label: referenceLine.label,
|
|
19153
|
+
query: referenceLine.query
|
|
19154
|
+
});
|
|
19155
|
+
} else if (referenceLine.query === "") {
|
|
19156
|
+
referenceLineYValues.push({
|
|
19157
|
+
label: referenceLine.label,
|
|
19158
|
+
query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
|
|
19159
|
+
(row) => Number(row[referenceLine.label]) || 0
|
|
19160
|
+
)
|
|
19161
|
+
});
|
|
19162
|
+
}
|
|
19163
|
+
}
|
|
19164
|
+
}
|
|
19165
|
+
return {
|
|
19166
|
+
id: item._id ?? item.id,
|
|
19167
|
+
name: item.name,
|
|
19168
|
+
dashboardName: item.dashboardName,
|
|
19169
|
+
// section: item.section,
|
|
19170
|
+
rows: item.rows,
|
|
19171
|
+
pivotRows: pivotTable ? pivotTable.rows : void 0,
|
|
19172
|
+
pivotColumns: pivotTable ? pivotTable.columns : void 0,
|
|
19173
|
+
compareRows: item.compareRows,
|
|
19174
|
+
columns: processedColumns.map((column) => {
|
|
19175
|
+
return {
|
|
19176
|
+
field: column.field,
|
|
19177
|
+
format: column.format,
|
|
19178
|
+
label: column.label,
|
|
19179
|
+
inferFormat: column.inferFormat
|
|
19180
|
+
};
|
|
19181
|
+
}),
|
|
19182
|
+
includeCustomFields: item.includeCustomFields,
|
|
19183
|
+
columnInternal,
|
|
19184
|
+
columnsWithCustomFields,
|
|
19185
|
+
chartType: item.chartType,
|
|
19186
|
+
dateField: item.dateField,
|
|
19187
|
+
pivot: pivotError ? void 0 : item.pivot ? {
|
|
19188
|
+
...item.pivot,
|
|
19189
|
+
aggregations: item.pivot.aggregations ?? [
|
|
19190
|
+
{
|
|
19191
|
+
valueField: item.pivot.valueField,
|
|
19192
|
+
valueFieldType: item.pivot.valueFieldType,
|
|
19193
|
+
valueField2: item.pivot.valueField2,
|
|
19194
|
+
valueField2Type: item.pivot.valueField2Type,
|
|
19195
|
+
aggregationType: item.pivot.aggregationType
|
|
19196
|
+
}
|
|
19197
|
+
],
|
|
19198
|
+
columnValues: item.distinctStrings
|
|
19199
|
+
} : void 0,
|
|
19200
|
+
yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
|
|
19201
|
+
xAxisLabel: item.xAxisLabel,
|
|
19202
|
+
xAxisField: item.xAxisField,
|
|
19203
|
+
xAxisFormat: item.xAxisFormat,
|
|
19204
|
+
order: item.order,
|
|
19205
|
+
filtersApplied: item.filtersApplied,
|
|
19206
|
+
filterMap: item.filterMap,
|
|
19207
|
+
flags: item.flags,
|
|
19208
|
+
rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
|
|
19209
|
+
pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
|
|
19210
|
+
template: item.template,
|
|
19211
|
+
sort: item.sort,
|
|
19212
|
+
itemQuery: item.itemQuery,
|
|
19213
|
+
queryString: item.queryString,
|
|
19214
|
+
pivotQuery: pivotTable?.pivotQuery,
|
|
19215
|
+
comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
|
|
19216
|
+
referencedTables: item?.referencedTables || [],
|
|
19217
|
+
referencedColumns: item?.referencedColumns || {},
|
|
19218
|
+
error: item.error ?? pivotError,
|
|
19219
|
+
referenceLineYValues,
|
|
19220
|
+
referenceLines: item.referenceLines
|
|
19221
|
+
};
|
|
19222
|
+
}
|
|
19223
|
+
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
19224
|
+
if (!report) return void 0;
|
|
19225
|
+
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
19226
|
+
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
19227
|
+
);
|
|
19228
|
+
if (dateFilter?.operator === "BETWEEN") {
|
|
19229
|
+
dateFilter.startDate = dateFilter.value[0];
|
|
19230
|
+
dateFilter.endDate = dateFilter.value[1];
|
|
19231
|
+
}
|
|
19232
|
+
const pivot = report?.pivot;
|
|
19233
|
+
const data = report || {};
|
|
19234
|
+
if (pivot && client) {
|
|
19235
|
+
if (report.rowCount === 0 || report.rows.length === 0) {
|
|
19236
|
+
const columns = [];
|
|
19237
|
+
if (pivot.rowField) {
|
|
19238
|
+
columns.push({
|
|
19239
|
+
field: pivot.rowField,
|
|
19240
|
+
label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
|
|
19241
|
+
format: pivot.rowFieldType || "string",
|
|
19242
|
+
jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
|
|
19243
|
+
fieldType: pivot.rowFieldType || "string",
|
|
19244
|
+
dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
|
|
19245
|
+
});
|
|
19246
|
+
}
|
|
19247
|
+
for (const agg of pivot.aggregations ?? []) {
|
|
19248
|
+
if (agg.valueField) {
|
|
19249
|
+
columns.push({
|
|
19250
|
+
field: agg.valueField,
|
|
19251
|
+
label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
|
|
19252
|
+
//FIXME: valueFieldType is not always the same as the format
|
|
19253
|
+
format: agg.valueFieldType ?? "whole_number",
|
|
19254
|
+
jsType: agg.valueFieldType ?? "number",
|
|
19255
|
+
fieldType: agg.valueFieldType ?? "number",
|
|
19256
|
+
dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
|
|
19257
|
+
});
|
|
19258
|
+
}
|
|
19259
|
+
}
|
|
19260
|
+
const pivotQuery = generatePivotQuery(
|
|
19261
|
+
pivot,
|
|
19262
|
+
report.itemQuery?.[0],
|
|
19263
|
+
client.databaseType
|
|
19264
|
+
);
|
|
19265
|
+
return {
|
|
19266
|
+
rows: [],
|
|
19267
|
+
rowCount: 0,
|
|
19268
|
+
pivotQuery: pivotQuery ?? "",
|
|
19269
|
+
columns
|
|
19270
|
+
};
|
|
18251
19271
|
}
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18258
|
-
|
|
18259
|
-
|
|
18260
|
-
|
|
18261
|
-
|
|
18262
|
-
|
|
18263
|
-
|
|
18264
|
-
|
|
18265
|
-
|
|
18266
|
-
|
|
19272
|
+
try {
|
|
19273
|
+
let dateBucket = dateBucketInitial;
|
|
19274
|
+
let filterDateRange = void 0;
|
|
19275
|
+
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
19276
|
+
filterDateRange = {
|
|
19277
|
+
start: dateFilter.startDate,
|
|
19278
|
+
end: dateFilter.endDate
|
|
19279
|
+
};
|
|
19280
|
+
} else if (report.dateRange) {
|
|
19281
|
+
filterDateRange = report.dateRange;
|
|
19282
|
+
}
|
|
19283
|
+
if (!dateBucket && filterDateRange) {
|
|
19284
|
+
dateBucket = getDateBucketFromRange(filterDateRange);
|
|
19285
|
+
}
|
|
19286
|
+
if (pivot.columnField && !report.distinctStrings) {
|
|
19287
|
+
const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
|
|
19288
|
+
if (!columnFieldColumn) {
|
|
19289
|
+
console.error(
|
|
19290
|
+
"could not find pivot column field on report",
|
|
19291
|
+
pivot.columnField
|
|
19292
|
+
);
|
|
19293
|
+
}
|
|
19294
|
+
const unique = await getUniqueValuesByQuery({
|
|
19295
|
+
columns: [columnFieldColumn],
|
|
19296
|
+
query: report.queryString,
|
|
19297
|
+
client,
|
|
19298
|
+
getToken,
|
|
19299
|
+
dashboardName,
|
|
19300
|
+
tenants,
|
|
19301
|
+
customFields: customFields ?? {},
|
|
19302
|
+
eventTracking
|
|
19303
|
+
});
|
|
19304
|
+
report.distinctStrings = unique?.[pivot.columnField] ?? [];
|
|
19305
|
+
}
|
|
19306
|
+
if (pivot.columnField && !report.distinctStrings) {
|
|
19307
|
+
const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
|
|
19308
|
+
if (!columnFieldColumn) {
|
|
19309
|
+
console.error(
|
|
19310
|
+
"could not find pivot column field on report",
|
|
19311
|
+
pivot.columnField
|
|
19312
|
+
);
|
|
19313
|
+
}
|
|
19314
|
+
const unique = await getUniqueValuesByQuery({
|
|
19315
|
+
columns: [columnFieldColumn],
|
|
19316
|
+
query: report.queryString,
|
|
19317
|
+
client,
|
|
19318
|
+
getToken,
|
|
19319
|
+
dashboardName,
|
|
19320
|
+
tenants,
|
|
19321
|
+
customFields: customFields ?? {},
|
|
19322
|
+
eventTracking
|
|
18267
19323
|
});
|
|
19324
|
+
report.distinctStrings = unique?.[pivot.columnField] ?? [];
|
|
19325
|
+
}
|
|
19326
|
+
const pivotTable = await generatePivotWithSQL({
|
|
19327
|
+
pivot,
|
|
19328
|
+
report,
|
|
19329
|
+
client,
|
|
19330
|
+
dateBucket,
|
|
19331
|
+
dateFilter,
|
|
19332
|
+
distinctStrings: report.distinctStrings,
|
|
19333
|
+
dashboardName,
|
|
19334
|
+
tenants,
|
|
19335
|
+
additionalProcessing,
|
|
19336
|
+
getToken
|
|
19337
|
+
});
|
|
19338
|
+
return pivotTable;
|
|
19339
|
+
} catch (e) {
|
|
19340
|
+
eventTracking?.logError?.({
|
|
19341
|
+
type: "bug",
|
|
19342
|
+
// TODO: determine type
|
|
19343
|
+
severity: "high",
|
|
19344
|
+
message: "Error fetching pivot table",
|
|
19345
|
+
errorMessage: e.message,
|
|
19346
|
+
errorStack: e.stack,
|
|
19347
|
+
errorData: {
|
|
19348
|
+
caller: "getPivotTable",
|
|
19349
|
+
function: "getPivotTable"
|
|
19350
|
+
}
|
|
18268
19351
|
});
|
|
19352
|
+
console.error("Error fetching pivot table", e);
|
|
19353
|
+
throw e;
|
|
18269
19354
|
}
|
|
18270
|
-
} catch (e) {
|
|
18271
|
-
eventTracking?.logError?.({
|
|
18272
|
-
type: "bug",
|
|
18273
|
-
// TODO: determine type
|
|
18274
|
-
severity: "high",
|
|
18275
|
-
message: "Error fetching table by AST",
|
|
18276
|
-
errorMessage: e.message,
|
|
18277
|
-
errorStack: e.stack,
|
|
18278
|
-
errorData: {
|
|
18279
|
-
caller: "fetchTableByAST",
|
|
18280
|
-
function: "fetchTableByAST"
|
|
18281
|
-
}
|
|
18282
|
-
});
|
|
18283
|
-
rows = [];
|
|
18284
|
-
columns = [];
|
|
18285
|
-
rowCount = 0;
|
|
18286
|
-
error = e.message;
|
|
18287
19355
|
}
|
|
18288
|
-
|
|
18289
|
-
|
|
19356
|
+
return pivot && data.rows ? generatePivotTable({
|
|
19357
|
+
pivot,
|
|
19358
|
+
report,
|
|
19359
|
+
client,
|
|
19360
|
+
uniqueValues: report.distinctStrings,
|
|
19361
|
+
dashboardName,
|
|
19362
|
+
tenants,
|
|
19363
|
+
dateFilter,
|
|
19364
|
+
additionalProcessing,
|
|
19365
|
+
getToken,
|
|
19366
|
+
eventTracking
|
|
19367
|
+
}) : void 0;
|
|
19368
|
+
}
|
|
19369
|
+
function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
|
|
19370
|
+
if (!pivotTable) return itemInfo?.yAxisFields ?? [];
|
|
19371
|
+
const pivot = itemInfo?.pivot || config?.pivot;
|
|
19372
|
+
if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
|
|
19373
|
+
const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
|
|
19374
|
+
return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
|
|
19375
|
+
}
|
|
19376
|
+
async function getDashboard(dashboardName, client, getToken, tenants, flags) {
|
|
19377
|
+
const { data: resp } = await quillFetch({
|
|
19378
|
+
client,
|
|
19379
|
+
task: "dashboard",
|
|
19380
|
+
metadata: {
|
|
19381
|
+
name: dashboardName,
|
|
19382
|
+
clientId: client.publicKey,
|
|
19383
|
+
databaseType: client.databaseType,
|
|
19384
|
+
useNewNodeSql: true,
|
|
19385
|
+
tenants,
|
|
19386
|
+
flags
|
|
19387
|
+
},
|
|
19388
|
+
getToken
|
|
19389
|
+
});
|
|
19390
|
+
return {
|
|
19391
|
+
...resp,
|
|
19392
|
+
createdAt: resp.createdAt && new Date(resp.createdAt),
|
|
19393
|
+
dateFilter: resp.dateFilter ? {
|
|
19394
|
+
...resp.dateFilter,
|
|
19395
|
+
presetOptions: resp.dateFilter.presetOptions?.map(
|
|
19396
|
+
(preset) => ({
|
|
19397
|
+
...preset,
|
|
19398
|
+
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
19399
|
+
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
19400
|
+
})
|
|
19401
|
+
),
|
|
19402
|
+
defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
|
|
19403
|
+
(preset) => ({
|
|
19404
|
+
...preset,
|
|
19405
|
+
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
19406
|
+
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
19407
|
+
})
|
|
19408
|
+
)
|
|
19409
|
+
} : void 0
|
|
19410
|
+
};
|
|
19411
|
+
}
|
|
19412
|
+
|
|
19413
|
+
// src/utils/chartBuilder.ts
|
|
19414
|
+
var numberFormatOptions = [
|
|
19415
|
+
"whole_number",
|
|
19416
|
+
"one_decimal_place",
|
|
19417
|
+
"two_decimal_places",
|
|
19418
|
+
"dollar_amount",
|
|
19419
|
+
"dollar_cents",
|
|
19420
|
+
"percentage"
|
|
19421
|
+
];
|
|
19422
|
+
var dateFormatOptions = [
|
|
19423
|
+
"MMM_yyyy",
|
|
19424
|
+
"MMM_dd",
|
|
19425
|
+
"MMM_dd_yyyy",
|
|
19426
|
+
"MMM_dd_hh:mm_ap_pm",
|
|
19427
|
+
"hh_ap_pm",
|
|
19428
|
+
"date",
|
|
19429
|
+
"timestamptz"
|
|
19430
|
+
];
|
|
19431
|
+
var NUMBER_OPTIONS = [
|
|
19432
|
+
{ value: "whole_number", label: "whole number" },
|
|
19433
|
+
{ value: "one_decimal_place", label: "one decimal place" },
|
|
19434
|
+
{ value: "two_decimal_places", label: "two decimal places" },
|
|
19435
|
+
{ value: "dollar_amount", label: "dollar amount" },
|
|
19436
|
+
{ value: "dollar_cents", label: "dollar and cent amount" },
|
|
19437
|
+
{ value: "percent", label: "percentage" }
|
|
19438
|
+
];
|
|
19439
|
+
var DATE_OPTIONS = [
|
|
19440
|
+
{ value: "MMM_yyyy", label: "month" },
|
|
19441
|
+
{ value: "MMM_dd", label: "day" },
|
|
19442
|
+
{ value: "MMM_dd_yyyy", label: "day and year" },
|
|
19443
|
+
{ value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
|
|
19444
|
+
{ value: "hh_ap_pm", label: "hour" }
|
|
19445
|
+
];
|
|
19446
|
+
var ALL_FORMAT_OPTIONS = [
|
|
19447
|
+
...NUMBER_OPTIONS,
|
|
19448
|
+
...DATE_OPTIONS,
|
|
19449
|
+
{ value: "string", label: "string" }
|
|
19450
|
+
];
|
|
19451
|
+
function createInitialFormData(columns) {
|
|
19452
|
+
const firstNumberColumn = columns?.find(
|
|
19453
|
+
(col) => numberFormatOptions.includes(col.format)
|
|
19454
|
+
);
|
|
19455
|
+
const firstStringColumn = columns?.find(
|
|
19456
|
+
(col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
|
|
19457
|
+
);
|
|
19458
|
+
const firstDateColumn = columns?.find(
|
|
19459
|
+
(col) => dateFormatOptions.includes(col.format)
|
|
19460
|
+
);
|
|
19461
|
+
const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
|
|
19462
|
+
const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
|
|
19463
|
+
const formEmptyState = {
|
|
19464
|
+
name: "",
|
|
19465
|
+
columns: columns.map((col) => {
|
|
19466
|
+
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
19467
|
+
}),
|
|
19468
|
+
xAxisField,
|
|
19469
|
+
xAxisFormat,
|
|
19470
|
+
yAxisFields: [
|
|
19471
|
+
{
|
|
19472
|
+
field: firstNumberColumn?.field || columns?.[0]?.field || "",
|
|
19473
|
+
label: "",
|
|
19474
|
+
format: firstNumberColumn?.format || columns?.[0]?.format || "string"
|
|
19475
|
+
}
|
|
19476
|
+
],
|
|
19477
|
+
xAxisLabel: "",
|
|
19478
|
+
chartType: firstNumberColumn ? "line" : "table",
|
|
19479
|
+
pivot: null,
|
|
19480
|
+
template: true,
|
|
19481
|
+
referenceLines: []
|
|
19482
|
+
};
|
|
19483
|
+
return formEmptyState;
|
|
19484
|
+
}
|
|
19485
|
+
|
|
19486
|
+
// src/utils/error.ts
|
|
19487
|
+
var DataLoadError = class extends Error {
|
|
19488
|
+
data;
|
|
19489
|
+
constructor(message, data) {
|
|
19490
|
+
super(message);
|
|
19491
|
+
this.name = "DataLoadError";
|
|
19492
|
+
this.data = data;
|
|
18290
19493
|
}
|
|
18291
|
-
return { rows, columns, rowCount, error, itemQuery, referencedTables };
|
|
18292
19494
|
};
|
|
18293
19495
|
|
|
18294
19496
|
// src/components/ReportBuilder/convert.ts
|
|
@@ -21942,35 +23144,6 @@ import jsPDF from "jspdf";
|
|
|
21942
23144
|
|
|
21943
23145
|
// src/hooks/useDashboard.ts
|
|
21944
23146
|
import { useContext, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
21945
|
-
|
|
21946
|
-
// src/utils/merge.ts
|
|
21947
|
-
import {
|
|
21948
|
-
add,
|
|
21949
|
-
startOfDay as startOfDay3,
|
|
21950
|
-
startOfMonth,
|
|
21951
|
-
startOfWeek as startOfWeek3,
|
|
21952
|
-
startOfYear
|
|
21953
|
-
} from "date-fns";
|
|
21954
|
-
import { utcToZonedTime as utcToZonedTime2 } from "date-fns-tz";
|
|
21955
|
-
function mergeComparisonRange(resp) {
|
|
21956
|
-
if (resp.chartType === "table") return resp;
|
|
21957
|
-
const compRows = resp.compareRows;
|
|
21958
|
-
if (!compRows) return resp;
|
|
21959
|
-
const newRows = resp.rows.map((row, i) => {
|
|
21960
|
-
if (i < compRows.length) {
|
|
21961
|
-
const compRow = compRows[i];
|
|
21962
|
-
const newRow = { ...row };
|
|
21963
|
-
for (const [key, value] of Object.entries(compRow)) {
|
|
21964
|
-
newRow[`comparison_${key}`] = value;
|
|
21965
|
-
}
|
|
21966
|
-
return newRow;
|
|
21967
|
-
}
|
|
21968
|
-
return row;
|
|
21969
|
-
});
|
|
21970
|
-
return { ...resp, rows: newRows };
|
|
21971
|
-
}
|
|
21972
|
-
|
|
21973
|
-
// src/hooks/useDashboard.ts
|
|
21974
23147
|
var useDashboardInternal = (dashboardName, customFilters) => {
|
|
21975
23148
|
const [dashboard] = useContext(DashboardContext);
|
|
21976
23149
|
const {
|
|
@@ -30549,23 +31722,53 @@ function QuillMetricComponent({
|
|
|
30549
31722
|
width: "100%"
|
|
30550
31723
|
}
|
|
30551
31724
|
}
|
|
30552
|
-
) : !report?.rows?.[0] || report.rows[0][report.xAxisField] ===
|
|
31725
|
+
) : !report?.rows || report?.rows?.length === 0 || report.rows[0]?.[report.xAxisField] === null || report.rows[0]?.[report.xAxisField] === void 0 ? /* @__PURE__ */ jsx43(
|
|
30553
31726
|
"div",
|
|
30554
31727
|
{
|
|
30555
31728
|
style: {
|
|
30556
|
-
|
|
30557
|
-
|
|
30558
|
-
|
|
30559
|
-
|
|
30560
|
-
|
|
30561
|
-
alignItems: "center",
|
|
30562
|
-
fontSize: 13,
|
|
30563
|
-
fontFamily: theme?.fontFamily,
|
|
30564
|
-
color: theme?.secondaryTextColor,
|
|
30565
|
-
maxWidth: "100%",
|
|
30566
|
-
width: "100%"
|
|
31729
|
+
padding: 0,
|
|
31730
|
+
height: "100%",
|
|
31731
|
+
width: "100%",
|
|
31732
|
+
boxSizing: "content-box",
|
|
31733
|
+
flex: 1
|
|
30567
31734
|
},
|
|
30568
|
-
children:
|
|
31735
|
+
children: /* @__PURE__ */ jsx43(
|
|
31736
|
+
"div",
|
|
31737
|
+
{
|
|
31738
|
+
style: {
|
|
31739
|
+
fontFamily: theme?.fontFamily,
|
|
31740
|
+
fontSize: 32,
|
|
31741
|
+
color: theme?.primaryTextColor,
|
|
31742
|
+
fontWeight: "600",
|
|
31743
|
+
textOverflow: "ellipsis",
|
|
31744
|
+
margin: 0,
|
|
31745
|
+
whiteSpace: "nowrap",
|
|
31746
|
+
boxSizing: "content-box",
|
|
31747
|
+
maxWidth: "100%",
|
|
31748
|
+
textAlign: "left",
|
|
31749
|
+
overflow: "hidden",
|
|
31750
|
+
height: "100%",
|
|
31751
|
+
minHeight: "80px",
|
|
31752
|
+
display: "flex",
|
|
31753
|
+
width: "100%",
|
|
31754
|
+
flexDirection: "row",
|
|
31755
|
+
justifyContent: "center",
|
|
31756
|
+
alignItems: "center"
|
|
31757
|
+
},
|
|
31758
|
+
children: /* @__PURE__ */ jsx43(
|
|
31759
|
+
"span",
|
|
31760
|
+
{
|
|
31761
|
+
style: {
|
|
31762
|
+
fontFamily: theme?.fontFamily,
|
|
31763
|
+
fontSize: 13,
|
|
31764
|
+
color: theme?.secondaryTextColor,
|
|
31765
|
+
fontWeight: "normal"
|
|
31766
|
+
},
|
|
31767
|
+
children: "No results"
|
|
31768
|
+
}
|
|
31769
|
+
)
|
|
31770
|
+
}
|
|
31771
|
+
)
|
|
30569
31772
|
}
|
|
30570
31773
|
) : /* @__PURE__ */ jsx43(
|
|
30571
31774
|
MetricDisplay,
|
|
@@ -31756,7 +32959,7 @@ function USMap({
|
|
|
31756
32959
|
acc[curr[xAxisField]?.toString()] = curr;
|
|
31757
32960
|
return acc;
|
|
31758
32961
|
}, {});
|
|
31759
|
-
const measureField = yAxisFields[0]
|
|
32962
|
+
const measureField = yAxisFields[0]?.field;
|
|
31760
32963
|
const [scaleLog, setScaleLog] = useState14(null);
|
|
31761
32964
|
useEffect12(() => {
|
|
31762
32965
|
import("d3-scale").then((scale) => {
|
|
@@ -31792,6 +32995,29 @@ function USMap({
|
|
|
31792
32995
|
const hoveredValue = useMemo12(() => {
|
|
31793
32996
|
return !hoveredState ? void 0 : mappedData[fipsToNames[hoveredState]?.abbreviation ?? ""]?.[measureField] ?? mappedData[fipsToNames[hoveredState]?.name ?? ""]?.[measureField] ?? mappedData[fipsToNames[hoveredState]?.abbreviation?.toLowerCase() ?? ""]?.[measureField] ?? mappedData[fipsToNames[hoveredState]?.name?.toLowerCase() ?? ""]?.[measureField];
|
|
31794
32997
|
}, [hoveredState, mappedData, measureField]);
|
|
32998
|
+
if (!measureField) {
|
|
32999
|
+
return /* @__PURE__ */ jsx45(
|
|
33000
|
+
"div",
|
|
33001
|
+
{
|
|
33002
|
+
style: {
|
|
33003
|
+
display: "flex",
|
|
33004
|
+
flex: "1 0 auto",
|
|
33005
|
+
marginLeft: "auto",
|
|
33006
|
+
marginRight: "auto",
|
|
33007
|
+
marginTop: "auto",
|
|
33008
|
+
marginBottom: "auto",
|
|
33009
|
+
justifyContent: "center",
|
|
33010
|
+
alignItems: "center",
|
|
33011
|
+
fontSize: 13,
|
|
33012
|
+
color: theme?.secondaryTextColor,
|
|
33013
|
+
fontFamily: theme?.fontFamily,
|
|
33014
|
+
...containerStyle
|
|
33015
|
+
},
|
|
33016
|
+
className,
|
|
33017
|
+
children: "No results"
|
|
33018
|
+
}
|
|
33019
|
+
);
|
|
33020
|
+
}
|
|
31795
33021
|
return /* @__PURE__ */ jsxs34(
|
|
31796
33022
|
"div",
|
|
31797
33023
|
{
|
|
@@ -31924,7 +33150,7 @@ function WorldMap({
|
|
|
31924
33150
|
acc[curr[xAxisField]?.toString()] = curr;
|
|
31925
33151
|
return acc;
|
|
31926
33152
|
}, {});
|
|
31927
|
-
const measureField = yAxisFields[0]
|
|
33153
|
+
const measureField = yAxisFields[0]?.field;
|
|
31928
33154
|
const [scaleLog, setScaleLog] = useState14(null);
|
|
31929
33155
|
useEffect12(() => {
|
|
31930
33156
|
import("d3-scale").then((scale) => {
|
|
@@ -31960,6 +33186,29 @@ function WorldMap({
|
|
|
31960
33186
|
const hoveredValue = useMemo12(() => {
|
|
31961
33187
|
return !hoveredCountry ? void 0 : mappedData[isoToNames[hoveredCountry]?.abbreviation ?? ""]?.[measureField] ?? mappedData[isoToNames[hoveredCountry]?.name ?? ""]?.[measureField] ?? mappedData[isoToNames[hoveredCountry]?.abbreviation?.toLowerCase() ?? ""]?.[measureField] ?? mappedData[isoToNames[hoveredCountry]?.name?.toLowerCase() ?? ""]?.[measureField];
|
|
31962
33188
|
}, [hoveredCountry, mappedData, measureField]);
|
|
33189
|
+
if (!measureField) {
|
|
33190
|
+
return /* @__PURE__ */ jsx45(
|
|
33191
|
+
"div",
|
|
33192
|
+
{
|
|
33193
|
+
style: {
|
|
33194
|
+
display: "flex",
|
|
33195
|
+
flex: "1 0 auto",
|
|
33196
|
+
marginLeft: "auto",
|
|
33197
|
+
marginRight: "auto",
|
|
33198
|
+
marginTop: "auto",
|
|
33199
|
+
marginBottom: "auto",
|
|
33200
|
+
justifyContent: "center",
|
|
33201
|
+
alignItems: "center",
|
|
33202
|
+
fontSize: 13,
|
|
33203
|
+
color: theme?.secondaryTextColor,
|
|
33204
|
+
fontFamily: theme?.fontFamily,
|
|
33205
|
+
...containerStyle
|
|
33206
|
+
},
|
|
33207
|
+
className,
|
|
33208
|
+
children: "No results"
|
|
33209
|
+
}
|
|
33210
|
+
);
|
|
33211
|
+
}
|
|
31963
33212
|
return /* @__PURE__ */ jsxs34(
|
|
31964
33213
|
"div",
|
|
31965
33214
|
{
|
|
@@ -34467,27 +35716,41 @@ var ChartDisplay = ({
|
|
|
34467
35716
|
);
|
|
34468
35717
|
}
|
|
34469
35718
|
if (config?.chartType?.toLowerCase() === "metric") {
|
|
34470
|
-
if (!config?.rows || config?.rows?.length === 0 ||
|
|
34471
|
-
config?.rows[0][config?.xAxisField] === null) {
|
|
35719
|
+
if (!config?.rows || config?.rows?.length === 0 || config?.rows[0]?.[config?.xAxisField] === null || config?.rows[0]?.[config?.xAxisField] === void 0) {
|
|
34472
35720
|
return /* @__PURE__ */ jsx48(
|
|
34473
35721
|
"div",
|
|
34474
35722
|
{
|
|
34475
35723
|
style: {
|
|
34476
|
-
display: "flex",
|
|
34477
|
-
flex: "1 0 auto",
|
|
34478
|
-
// height: containerStyle?.height || '100%',
|
|
34479
|
-
margin: "auto",
|
|
34480
|
-
justifyContent: "center",
|
|
34481
|
-
alignItems: "center",
|
|
34482
|
-
fontSize: 13,
|
|
34483
35724
|
fontFamily: theme?.fontFamily,
|
|
34484
|
-
|
|
35725
|
+
fontSize: 32,
|
|
35726
|
+
color: theme?.primaryTextColor,
|
|
35727
|
+
fontWeight: "600",
|
|
35728
|
+
textOverflow: "ellipsis",
|
|
35729
|
+
margin: 0,
|
|
35730
|
+
whiteSpace: "nowrap",
|
|
35731
|
+
boxSizing: "content-box",
|
|
34485
35732
|
maxWidth: "100%",
|
|
35733
|
+
textAlign: "left",
|
|
35734
|
+
overflow: "hidden",
|
|
35735
|
+
height: containerStyle?.height || "100%",
|
|
35736
|
+
display: "flex",
|
|
34486
35737
|
width: "100%",
|
|
35738
|
+
flexDirection: "row",
|
|
35739
|
+
alignItems: "center",
|
|
34487
35740
|
...containerStyle
|
|
34488
35741
|
},
|
|
34489
35742
|
className,
|
|
34490
|
-
children:
|
|
35743
|
+
children: /* @__PURE__ */ jsx48(
|
|
35744
|
+
"span",
|
|
35745
|
+
{
|
|
35746
|
+
style: {
|
|
35747
|
+
fontFamily: theme?.fontFamily,
|
|
35748
|
+
fontSize: 13,
|
|
35749
|
+
color: theme?.secondaryTextColor
|
|
35750
|
+
},
|
|
35751
|
+
children: "No results"
|
|
35752
|
+
}
|
|
35753
|
+
)
|
|
34491
35754
|
}
|
|
34492
35755
|
);
|
|
34493
35756
|
}
|
|
@@ -41440,15 +42703,19 @@ function ChartBuilderWithModal(props) {
|
|
|
41440
42703
|
title: title || "Add to dashboard",
|
|
41441
42704
|
width: isHorizontalView ? modalWidth : void 0,
|
|
41442
42705
|
height: isHorizontalView ? modalHeight : void 0,
|
|
41443
|
-
children: (
|
|
41444
|
-
|
|
41445
|
-
|
|
41446
|
-
|
|
41447
|
-
|
|
41448
|
-
|
|
41449
|
-
|
|
41450
|
-
|
|
41451
|
-
|
|
42706
|
+
children: (() => {
|
|
42707
|
+
const resolvedReport = props.reportId ? dashboard[props.reportId] ?? props.tempReport : props.tempReport;
|
|
42708
|
+
return resolvedReport ? /* @__PURE__ */ jsx65(
|
|
42709
|
+
ChartBuilder,
|
|
42710
|
+
{
|
|
42711
|
+
...props,
|
|
42712
|
+
tempReport: resolvedReport,
|
|
42713
|
+
filtersEnabled: filtersEnabledState,
|
|
42714
|
+
onFiltersEnabledChanged: setFiltersEnabledState,
|
|
42715
|
+
runQueryOnMount: filtersEnabledState
|
|
42716
|
+
}
|
|
42717
|
+
) : /* @__PURE__ */ jsx65("div", { style: { padding: 20 }, children: /* @__PURE__ */ jsx65(QuillLoadingComponent, {}) });
|
|
42718
|
+
})()
|
|
41452
42719
|
}
|
|
41453
42720
|
) });
|
|
41454
42721
|
}
|
|
@@ -41498,6 +42765,7 @@ function ChartBuilder({
|
|
|
41498
42765
|
hideSubmitButton = false,
|
|
41499
42766
|
hideDateRangeFilter = false,
|
|
41500
42767
|
showTableFormatOptions,
|
|
42768
|
+
showDashboardFilterFields,
|
|
41501
42769
|
initialUniqueValues,
|
|
41502
42770
|
initialUniqueValuesIsLoading,
|
|
41503
42771
|
pivotRecommendationsEnabled = true,
|
|
@@ -41527,9 +42795,10 @@ function ChartBuilder({
|
|
|
41527
42795
|
const { tenants, flags } = useContext26(TenantContext);
|
|
41528
42796
|
const report = useMemo21(() => {
|
|
41529
42797
|
return reportId && !tempReport ? allReportsById[reportId] : tempReport;
|
|
41530
|
-
}, [reportId]);
|
|
42798
|
+
}, [reportId, tempReport, allReportsById]);
|
|
41531
42799
|
const [windowWidth, setWindowWidth] = useState28(1200);
|
|
41532
42800
|
const [rows, setRows] = useState28(report?.rows ?? []);
|
|
42801
|
+
const [itemQuery, setItemQuery] = useState28(report?.itemQuery);
|
|
41533
42802
|
const [rowCount, setRowCount] = useState28(report?.rowCount ?? 0);
|
|
41534
42803
|
const [maxPage, setMaxPage] = useState28(0);
|
|
41535
42804
|
const [isLoading, setIsLoading] = useState28(false);
|
|
@@ -42259,7 +43528,7 @@ function ChartBuilder({
|
|
|
42259
43528
|
pivot,
|
|
42260
43529
|
dateBucket,
|
|
42261
43530
|
dateFilter,
|
|
42262
|
-
report: report ? { ...report, ...tableInfo } : void 0,
|
|
43531
|
+
report: report ? { ...report, ...tableInfo ?? { itemQuery } } : void 0,
|
|
42263
43532
|
client,
|
|
42264
43533
|
uniqueValues,
|
|
42265
43534
|
dashboardName: destinationDashboardName,
|
|
@@ -42420,6 +43689,7 @@ function ChartBuilder({
|
|
|
42420
43689
|
setCurrentProcessing(processing);
|
|
42421
43690
|
setRows(tableInfo.rows);
|
|
42422
43691
|
setProcessedColumns(processColumns(tableInfo.columns));
|
|
43692
|
+
setItemQuery(tableInfo.itemQuery);
|
|
42423
43693
|
fetchRowCount(processing, overrideFilters);
|
|
42424
43694
|
if (formData.pivot) {
|
|
42425
43695
|
try {
|
|
@@ -43325,7 +44595,7 @@ function ChartBuilder({
|
|
|
43325
44595
|
uniqueValuesIsLoading: initialUniqueValuesIsLoading,
|
|
43326
44596
|
initialSelectedPivotTable: selectedPivotTable,
|
|
43327
44597
|
pivotRecommendationsEnabled,
|
|
43328
|
-
report,
|
|
44598
|
+
report: report ? { ...report, ...{ itemQuery } } : void 0,
|
|
43329
44599
|
dashboardName: destinationDashboardName || "",
|
|
43330
44600
|
dateFilter: filtersEnabled ? currentDashboardFilters?.find(
|
|
43331
44601
|
(f) => f.filterType === "date_range"
|
|
@@ -44018,7 +45288,7 @@ function ChartBuilder({
|
|
|
44018
45288
|
]
|
|
44019
45289
|
}
|
|
44020
45290
|
),
|
|
44021
|
-
specificDashboardFilters.length > 0 && isAdmin && /* @__PURE__ */ jsxs47(
|
|
45291
|
+
specificDashboardFilters.length > 0 && (showDashboardFilterFields || isAdmin) && /* @__PURE__ */ jsxs47(
|
|
44022
45292
|
"div",
|
|
44023
45293
|
{
|
|
44024
45294
|
style: {
|
|
@@ -44029,7 +45299,7 @@ function ChartBuilder({
|
|
|
44029
45299
|
},
|
|
44030
45300
|
children: [
|
|
44031
45301
|
/* @__PURE__ */ jsx65(HeaderComponent, { label: "Dashboard filter fields" }),
|
|
44032
|
-
isAdmin && formData.dateField && dashboardConfig[formData.dashboardName ?? destinationDashboardName ?? ""]?.config.dateFilter?.label && /* @__PURE__ */ jsxs47(ChartBuilderInputRowContainer, { children: [
|
|
45302
|
+
(showDashboardFilterFields || isAdmin) && formData.dateField && dashboardConfig[formData.dashboardName ?? destinationDashboardName ?? ""]?.config.dateFilter?.label && /* @__PURE__ */ jsxs47(ChartBuilderInputRowContainer, { children: [
|
|
44033
45303
|
/* @__PURE__ */ jsx65(
|
|
44034
45304
|
TextInputComponent,
|
|
44035
45305
|
{
|
|
@@ -44968,6 +46238,7 @@ function SQLEditor({
|
|
|
44968
46238
|
CheckboxComponent = QuillChartBuilderCheckboxComponent,
|
|
44969
46239
|
defaultQuery,
|
|
44970
46240
|
destinationDashboard,
|
|
46241
|
+
destinationSection,
|
|
44971
46242
|
onChangeQuery,
|
|
44972
46243
|
onChangeData,
|
|
44973
46244
|
onChangeColumns,
|
|
@@ -44977,12 +46248,16 @@ function SQLEditor({
|
|
|
44977
46248
|
onCloseChartBuilder,
|
|
44978
46249
|
isChartBuilderEnabled = false,
|
|
44979
46250
|
isAdminEnabled = false,
|
|
46251
|
+
chartBuilderOptions,
|
|
44980
46252
|
chartBuilderTitle,
|
|
44981
46253
|
runQueryOnMount = false,
|
|
44982
46254
|
onAddToDashboardComplete,
|
|
46255
|
+
onSubmitCreateReport,
|
|
46256
|
+
onSubmitEditReport,
|
|
44983
46257
|
onSaveQueryComplete,
|
|
44984
46258
|
addToDashboardButtonLabel = "Add to dashboard",
|
|
44985
46259
|
report = void 0,
|
|
46260
|
+
reportId = void 0,
|
|
44986
46261
|
organizationName = void 0,
|
|
44987
46262
|
isChartBuilderHorizontalView = true,
|
|
44988
46263
|
containerStyle = { height: "100vh" },
|
|
@@ -44993,7 +46268,7 @@ function SQLEditor({
|
|
|
44993
46268
|
const [sqlPrompt, setSqlPrompt] = useState30("");
|
|
44994
46269
|
const [client] = useContext28(ClientContext);
|
|
44995
46270
|
const [theme] = useContext28(ThemeContext);
|
|
44996
|
-
const { tenants } = useContext28(TenantContext);
|
|
46271
|
+
const { tenants, flags } = useContext28(TenantContext);
|
|
44997
46272
|
const { dashboards } = useDashboards();
|
|
44998
46273
|
const {
|
|
44999
46274
|
data,
|
|
@@ -45002,6 +46277,7 @@ function SQLEditor({
|
|
|
45002
46277
|
} = useDashboardInternal(destinationDashboard);
|
|
45003
46278
|
const { getToken, quillFetchWithToken } = useContext28(FetchContext);
|
|
45004
46279
|
const { eventTracking } = useContext28(EventTrackingContext);
|
|
46280
|
+
const { allReportsById } = useAllReports();
|
|
45005
46281
|
const destinationDashboardConfig = useMemo22(() => {
|
|
45006
46282
|
return dashboards?.find((d) => d.name === destinationDashboard);
|
|
45007
46283
|
}, [dashboards, destinationDashboard]);
|
|
@@ -45069,6 +46345,46 @@ function SQLEditor({
|
|
|
45069
46345
|
reload();
|
|
45070
46346
|
}
|
|
45071
46347
|
}, [data, dashboardIsLoading]);
|
|
46348
|
+
useEffect24(() => {
|
|
46349
|
+
const loadReport = async () => {
|
|
46350
|
+
let reportToLoad;
|
|
46351
|
+
if (!client) {
|
|
46352
|
+
return;
|
|
46353
|
+
}
|
|
46354
|
+
try {
|
|
46355
|
+
if (!reportId) {
|
|
46356
|
+
throw new Error("Report ID is required");
|
|
46357
|
+
}
|
|
46358
|
+
reportToLoad = allReportsById[reportId];
|
|
46359
|
+
if (!reportToLoad) {
|
|
46360
|
+
throw new Error("Report not found");
|
|
46361
|
+
}
|
|
46362
|
+
setQuery(reportToLoad.queryString || "");
|
|
46363
|
+
setTempReport(reportToLoad);
|
|
46364
|
+
if (reportToLoad.rows && reportToLoad.rows.length > 0) {
|
|
46365
|
+
setRows(reportToLoad.rows);
|
|
46366
|
+
setDisplayTable(true);
|
|
46367
|
+
}
|
|
46368
|
+
} catch (err) {
|
|
46369
|
+
console.error(err);
|
|
46370
|
+
eventTracking?.logError?.({
|
|
46371
|
+
type: "bug",
|
|
46372
|
+
severity: "high",
|
|
46373
|
+
message: "Error loading report",
|
|
46374
|
+
errorMessage: err.message,
|
|
46375
|
+
errorStack: err.stack,
|
|
46376
|
+
errorData: {
|
|
46377
|
+
caller: "SQLEditor",
|
|
46378
|
+
function: "loadReport"
|
|
46379
|
+
}
|
|
46380
|
+
});
|
|
46381
|
+
setErrorMessage("Error when loading report");
|
|
46382
|
+
}
|
|
46383
|
+
};
|
|
46384
|
+
if (reportId && client) {
|
|
46385
|
+
loadReport();
|
|
46386
|
+
}
|
|
46387
|
+
}, [allReportsById[reportId || ""], client]);
|
|
45072
46388
|
const dynamicHeight = tableRef.current ? tableRef.current.clientHeight : cachedHeight;
|
|
45073
46389
|
const rowsPerPage = Math.max(
|
|
45074
46390
|
DEFAULT_ROWS_PER_PAGE,
|
|
@@ -45887,13 +47203,38 @@ function SQLEditor({
|
|
|
45887
47203
|
isHorizontalView: isChartBuilderHorizontalView,
|
|
45888
47204
|
isOpen: isChartBuilderOpen,
|
|
45889
47205
|
setIsOpen: setIsChartBuilderOpen,
|
|
45890
|
-
onAddToDashboardComplete
|
|
47206
|
+
onAddToDashboardComplete: reportId || report?.id ? (data2) => {
|
|
47207
|
+
if (onSubmitEditReport) {
|
|
47208
|
+
onSubmitEditReport(data2);
|
|
47209
|
+
} else if (onAddToDashboardComplete) {
|
|
47210
|
+
onAddToDashboardComplete(data2);
|
|
47211
|
+
}
|
|
47212
|
+
if (!isAdminEnabled && destinationDashboard) {
|
|
47213
|
+
reload(destinationDashboard, false, {
|
|
47214
|
+
report: data2,
|
|
47215
|
+
action: "upsert"
|
|
47216
|
+
});
|
|
47217
|
+
}
|
|
47218
|
+
} : (data2) => {
|
|
47219
|
+
if (onSubmitCreateReport) {
|
|
47220
|
+
onSubmitCreateReport(data2);
|
|
47221
|
+
} else if (onAddToDashboardComplete) {
|
|
47222
|
+
onAddToDashboardComplete(data2);
|
|
47223
|
+
}
|
|
47224
|
+
if (!isAdminEnabled && destinationDashboard) {
|
|
47225
|
+
reload(destinationDashboard, false, {
|
|
47226
|
+
report: data2,
|
|
47227
|
+
action: "upsert"
|
|
47228
|
+
});
|
|
47229
|
+
}
|
|
47230
|
+
},
|
|
45891
47231
|
destinationDashboard,
|
|
47232
|
+
destinationSection,
|
|
45892
47233
|
isAdmin: isAdminEnabled,
|
|
45893
47234
|
title: chartBuilderTitle,
|
|
45894
47235
|
buttonLabel: addToDashboardButtonLabel,
|
|
45895
47236
|
tempReport,
|
|
45896
|
-
reportId: report?.id,
|
|
47237
|
+
reportId: reportId || report?.id,
|
|
45897
47238
|
organizationName,
|
|
45898
47239
|
CardComponent,
|
|
45899
47240
|
TableComponent,
|
|
@@ -45918,6 +47259,8 @@ function SQLEditor({
|
|
|
45918
47259
|
CheckboxComponent,
|
|
45919
47260
|
hideDateRangeFilter: true,
|
|
45920
47261
|
hideDeleteButton: true,
|
|
47262
|
+
showTableFormatOptions: chartBuilderOptions?.showTableFormatOptions,
|
|
47263
|
+
showDashboardFilterFields: chartBuilderOptions?.showDashboardFilterFields,
|
|
45921
47264
|
onClickChartElement,
|
|
45922
47265
|
isEditingMode: true
|
|
45923
47266
|
}
|
|
@@ -45937,7 +47280,7 @@ function SQLEditor({
|
|
|
45937
47280
|
isAdmin: false,
|
|
45938
47281
|
title: "Save query",
|
|
45939
47282
|
buttonLabel: "Save query",
|
|
45940
|
-
tempReport,
|
|
47283
|
+
tempReport: { ...tempReport, dashboardName: SAVED_QUERIES_DASHBOARD },
|
|
45941
47284
|
reportId: report?.id,
|
|
45942
47285
|
organizationName,
|
|
45943
47286
|
CardComponent,
|
|
@@ -47705,7 +49048,6 @@ var useReportBuilderInternal = ({
|
|
|
47705
49048
|
}
|
|
47706
49049
|
report = allReportsById[reportId];
|
|
47707
49050
|
if (!report) {
|
|
47708
|
-
console.log("no report");
|
|
47709
49051
|
throw new Error("Report not found");
|
|
47710
49052
|
}
|
|
47711
49053
|
const { ast: newAst, pivot: newPivot } = await fetchASTFromQuillReport(
|
|
@@ -50255,6 +51597,8 @@ var SaveReport = ({
|
|
|
50255
51597
|
onSubmitEditReport = () => void 0,
|
|
50256
51598
|
onSubmitCreateReport = () => void 0,
|
|
50257
51599
|
destinationSection,
|
|
51600
|
+
showTableFormatOptions,
|
|
51601
|
+
showDashboardFilterFields,
|
|
50258
51602
|
SelectComponent = QuillSelectComponent,
|
|
50259
51603
|
TextInputComponent = QuillTextInput,
|
|
50260
51604
|
ButtonComponent = MemoizedButton,
|
|
@@ -50287,6 +51631,7 @@ var SaveReport = ({
|
|
|
50287
51631
|
),
|
|
50288
51632
|
submitButtonLabel
|
|
50289
51633
|
}) => {
|
|
51634
|
+
const { reload } = useDashboardInternal(reportBuilder.destinationDashboard ?? null);
|
|
50290
51635
|
return /* @__PURE__ */ jsxs59("div", { children: [
|
|
50291
51636
|
SaveTrigger,
|
|
50292
51637
|
/* @__PURE__ */ jsx79(
|
|
@@ -50299,7 +51644,17 @@ var SaveReport = ({
|
|
|
50299
51644
|
isHorizontalView: true,
|
|
50300
51645
|
isOpen,
|
|
50301
51646
|
setIsOpen,
|
|
50302
|
-
onAddToDashboardComplete: reportBuilder.reportId ?
|
|
51647
|
+
onAddToDashboardComplete: reportBuilder.reportId ? (data) => {
|
|
51648
|
+
onSubmitEditReport(data);
|
|
51649
|
+
if (!isAdminEnabled && reportBuilder.destinationDashboard) {
|
|
51650
|
+
reload(reportBuilder.destinationDashboard, false, { report: data, action: "upsert" });
|
|
51651
|
+
}
|
|
51652
|
+
} : (data) => {
|
|
51653
|
+
onSubmitCreateReport(data);
|
|
51654
|
+
if (!isAdminEnabled && reportBuilder.destinationDashboard) {
|
|
51655
|
+
reload(reportBuilder.destinationDashboard, false, { report: data, action: "upsert" });
|
|
51656
|
+
}
|
|
51657
|
+
},
|
|
50303
51658
|
destinationDashboard: reportBuilder.destinationDashboard,
|
|
50304
51659
|
destinationSection,
|
|
50305
51660
|
initialUniqueValues: reportBuilder.columnUniqueValues,
|
|
@@ -50328,6 +51683,8 @@ var SaveReport = ({
|
|
|
50328
51683
|
FormContainer: ChartBuilderFormContainer,
|
|
50329
51684
|
hideDateRangeFilter: true,
|
|
50330
51685
|
hideDeleteButton: true,
|
|
51686
|
+
showTableFormatOptions,
|
|
51687
|
+
showDashboardFilterFields,
|
|
50331
51688
|
buttonLabel: submitButtonLabel ?? (!!reportBuilder.reportId ? "Save changes" : "Add to dashboard"),
|
|
50332
51689
|
onClickChartElement,
|
|
50333
51690
|
isEditingMode: true
|
|
@@ -50423,6 +51780,7 @@ function ReportBuilder({
|
|
|
50423
51780
|
containerStyle,
|
|
50424
51781
|
className,
|
|
50425
51782
|
pivotRecommendationsEnabled = true,
|
|
51783
|
+
chartBuilderOptions,
|
|
50426
51784
|
reportId,
|
|
50427
51785
|
hideCopySQL = true,
|
|
50428
51786
|
isChartBuilderHorizontalView = true,
|
|
@@ -50862,6 +52220,8 @@ function ReportBuilder({
|
|
|
50862
52220
|
ErrorMessageComponent,
|
|
50863
52221
|
PivotRowContainer,
|
|
50864
52222
|
PivotColumnContainer,
|
|
52223
|
+
showTableFormatOptions: chartBuilderOptions?.showTableFormatOptions,
|
|
52224
|
+
showDashboardFilterFields: chartBuilderOptions?.showDashboardFilterFields,
|
|
50865
52225
|
onClickChartElement,
|
|
50866
52226
|
submitButtonLabel
|
|
50867
52227
|
}
|
|
@@ -50882,7 +52242,7 @@ function ReportBuilder({
|
|
|
50882
52242
|
isAdmin: false,
|
|
50883
52243
|
title: "Save query",
|
|
50884
52244
|
buttonLabel: "Save query",
|
|
50885
|
-
tempReport,
|
|
52245
|
+
tempReport: { ...tempReport, dashboardName: SAVED_QUERIES_DASHBOARD },
|
|
50886
52246
|
reportId,
|
|
50887
52247
|
organizationName,
|
|
50888
52248
|
CardComponent,
|