@quillsql/react 2.16.20 → 2.16.22
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 +2591 -179
- package/dist/index.d.cts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +2588 -158
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -277,6 +277,9 @@ var init_valueFormatter = __esm({
|
|
|
277
277
|
maximumFractionDigits: 2
|
|
278
278
|
});
|
|
279
279
|
formatPercent = (value) => {
|
|
280
|
+
if (typeof value === "string" && /^\s*[+-]?(?:\d+(?:\.\d+)?|\.\d+)\s*%\s*$/.test(value)) {
|
|
281
|
+
return value;
|
|
282
|
+
}
|
|
280
283
|
return formatterPercent.format(Number(value));
|
|
281
284
|
};
|
|
282
285
|
_getUTCDateHelper = (value, fmt) => {
|
|
@@ -1572,6 +1575,7 @@ var init_dateRangePickerUtils = __esm({
|
|
|
1572
1575
|
}
|
|
1573
1576
|
});
|
|
1574
1577
|
const defaultCustomIntervals = defaultIntervals.flatMap((interval2) => {
|
|
1578
|
+
const normalizedLabel = interval2.label?.toLowerCase().trim();
|
|
1575
1579
|
let createdIntervals = [];
|
|
1576
1580
|
if (interval2.label === "This week") {
|
|
1577
1581
|
createdIntervals = [
|
|
@@ -1721,13 +1725,13 @@ var init_dateRangePickerUtils = __esm({
|
|
|
1721
1725
|
unit: "months"
|
|
1722
1726
|
}
|
|
1723
1727
|
];
|
|
1724
|
-
} else if (
|
|
1728
|
+
} else if (normalizedLabel === "last month") {
|
|
1725
1729
|
createdIntervals = [
|
|
1726
1730
|
{
|
|
1727
1731
|
type: "previous_month"
|
|
1728
1732
|
}
|
|
1729
1733
|
];
|
|
1730
|
-
} else if (
|
|
1734
|
+
} else if (normalizedLabel === "previous quarter" || normalizedLabel === "last quarter") {
|
|
1731
1735
|
createdIntervals = [
|
|
1732
1736
|
{
|
|
1733
1737
|
type: "previous_quarter"
|
|
@@ -2121,13 +2125,13 @@ var init_Filter = __esm({
|
|
|
2121
2125
|
TimeUnit2[TimeUnit2["Hour"] = HOUR] = "Hour";
|
|
2122
2126
|
return TimeUnit2;
|
|
2123
2127
|
})(TimeUnit || {});
|
|
2124
|
-
FieldType = /* @__PURE__ */ ((
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
return
|
|
2128
|
+
FieldType = /* @__PURE__ */ ((FieldType3) => {
|
|
2129
|
+
FieldType3[FieldType3["String"] = STRING] = "String";
|
|
2130
|
+
FieldType3[FieldType3["Number"] = NUMBER] = "Number";
|
|
2131
|
+
FieldType3[FieldType3["Date"] = DATE] = "Date";
|
|
2132
|
+
FieldType3[FieldType3["Null"] = NULL] = "Null";
|
|
2133
|
+
FieldType3[FieldType3["Boolean"] = BOOLEAN] = "Boolean";
|
|
2134
|
+
return FieldType3;
|
|
2131
2135
|
})(FieldType || {});
|
|
2132
2136
|
InternalFilterType = /* @__PURE__ */ ((InternalFilterType2) => {
|
|
2133
2137
|
InternalFilterType2["StringFilter"] = "string-filter";
|
|
@@ -2273,7 +2277,7 @@ var init_Filter = __esm({
|
|
|
2273
2277
|
fieldType = FieldType.Boolean;
|
|
2274
2278
|
operator = filter.operator;
|
|
2275
2279
|
field = filter.field;
|
|
2276
|
-
value =
|
|
2280
|
+
value = filter.value;
|
|
2277
2281
|
table = filter.table;
|
|
2278
2282
|
return {
|
|
2279
2283
|
filterType,
|
|
@@ -2284,7 +2288,7 @@ var init_Filter = __esm({
|
|
|
2284
2288
|
operator
|
|
2285
2289
|
};
|
|
2286
2290
|
case "date" /* Date */:
|
|
2287
|
-
if (typeof filter.value === "object" && filter.value && "
|
|
2291
|
+
if (typeof filter.value === "object" && filter.value && "unit" in filter.value) {
|
|
2288
2292
|
if (filter.value.value && typeof filter.value.value !== "number" || typeof filter.value.unit !== "string") {
|
|
2289
2293
|
throw new Error(
|
|
2290
2294
|
`Invalid value for DateFilter, expected { value: number, unit: string }, got ${filter.value}`
|
|
@@ -2340,7 +2344,7 @@ var init_Filter = __esm({
|
|
|
2340
2344
|
table = filter.table;
|
|
2341
2345
|
} else {
|
|
2342
2346
|
throw new Error(
|
|
2343
|
-
`Invalid value for DateFilter, expected { value
|
|
2347
|
+
`Invalid value for DateFilter, expected { value?: number, unit: string }, { startDate: string, endDate: string}, or string, got ${filter.value}`
|
|
2344
2348
|
);
|
|
2345
2349
|
}
|
|
2346
2350
|
return {
|
|
@@ -15951,7 +15955,7 @@ var init_dataProcessing = __esm({
|
|
|
15951
15955
|
} else {
|
|
15952
15956
|
if (data.dateField && data.dateField.field) {
|
|
15953
15957
|
const dateField = data.dateField.field.replaceAll('"', "");
|
|
15954
|
-
const
|
|
15958
|
+
const maxDate2 = new Date(
|
|
15955
15959
|
data.rows.reduce((acc, row) => {
|
|
15956
15960
|
const rowValue = row[dateField];
|
|
15957
15961
|
if (rowValue) {
|
|
@@ -15960,7 +15964,7 @@ var init_dataProcessing = __esm({
|
|
|
15960
15964
|
return Math.max(acc, 0);
|
|
15961
15965
|
}, 0)
|
|
15962
15966
|
);
|
|
15963
|
-
const
|
|
15967
|
+
const minDate2 = new Date(
|
|
15964
15968
|
data.rows.reduce((acc, row) => {
|
|
15965
15969
|
const rowValue = row[dateField];
|
|
15966
15970
|
if (rowValue) {
|
|
@@ -15970,16 +15974,16 @@ var init_dataProcessing = __esm({
|
|
|
15970
15974
|
}, (/* @__PURE__ */ new Date("3022-01-01")).getTime())
|
|
15971
15975
|
);
|
|
15972
15976
|
const dateBucket = getDateBucketFromRange({
|
|
15973
|
-
start:
|
|
15974
|
-
end:
|
|
15977
|
+
start: minDate2,
|
|
15978
|
+
end: maxDate2
|
|
15975
15979
|
});
|
|
15976
15980
|
const minDateBucket = getDateString(
|
|
15977
|
-
|
|
15981
|
+
minDate2.toISOString(),
|
|
15978
15982
|
void 0,
|
|
15979
15983
|
dateBucket
|
|
15980
15984
|
);
|
|
15981
15985
|
const maxDateBucket = getDateString(
|
|
15982
|
-
|
|
15986
|
+
maxDate2.toISOString(),
|
|
15983
15987
|
void 0,
|
|
15984
15988
|
dateBucket
|
|
15985
15989
|
);
|
|
@@ -16096,8 +16100,9 @@ async function generatePivotWithSQL({
|
|
|
16096
16100
|
getPivotRowCount = true,
|
|
16097
16101
|
caller,
|
|
16098
16102
|
getToken,
|
|
16099
|
-
reportBuilderState
|
|
16103
|
+
reportBuilderState,
|
|
16100
16104
|
// Add reportBuilderState parameter
|
|
16105
|
+
overwriteCache = false
|
|
16101
16106
|
}) {
|
|
16102
16107
|
const databaseType = client.databaseType || "postgresql";
|
|
16103
16108
|
if (!pivot.aggregations?.length && pivot.aggregationType) {
|
|
@@ -16146,7 +16151,8 @@ async function generatePivotWithSQL({
|
|
|
16146
16151
|
})),
|
|
16147
16152
|
// Only pass dashboard filters in Dashboard context, not ReportBuilder
|
|
16148
16153
|
tenants,
|
|
16149
|
-
additionalProcessing
|
|
16154
|
+
additionalProcessing,
|
|
16155
|
+
overwriteCache
|
|
16150
16156
|
},
|
|
16151
16157
|
getToken
|
|
16152
16158
|
});
|
|
@@ -16320,8 +16326,9 @@ async function generatePivotTable({
|
|
|
16320
16326
|
additionalProcessing,
|
|
16321
16327
|
caller,
|
|
16322
16328
|
pivotQuery,
|
|
16323
|
-
reportBuilderState
|
|
16329
|
+
reportBuilderState,
|
|
16324
16330
|
// Add reportBuilderState parameter
|
|
16331
|
+
overwriteCache
|
|
16325
16332
|
}) {
|
|
16326
16333
|
try {
|
|
16327
16334
|
if (report && client) {
|
|
@@ -16338,8 +16345,9 @@ async function generatePivotTable({
|
|
|
16338
16345
|
additionalProcessing,
|
|
16339
16346
|
caller,
|
|
16340
16347
|
getToken,
|
|
16341
|
-
reportBuilderState
|
|
16348
|
+
reportBuilderState,
|
|
16342
16349
|
// Pass reportBuilderState
|
|
16350
|
+
overwriteCache
|
|
16343
16351
|
});
|
|
16344
16352
|
return pivotTable;
|
|
16345
16353
|
}
|
|
@@ -18224,7 +18232,7 @@ var init_tableProcessing = __esm({
|
|
|
18224
18232
|
try {
|
|
18225
18233
|
let data;
|
|
18226
18234
|
if (reportBuilderState) {
|
|
18227
|
-
|
|
18235
|
+
({ data } = await quillFetch({
|
|
18228
18236
|
client,
|
|
18229
18237
|
task: "report-builder-counts",
|
|
18230
18238
|
metadata: {
|
|
@@ -18238,9 +18246,9 @@ var init_tableProcessing = __esm({
|
|
|
18238
18246
|
tenants
|
|
18239
18247
|
},
|
|
18240
18248
|
getToken
|
|
18241
|
-
});
|
|
18249
|
+
}));
|
|
18242
18250
|
} else {
|
|
18243
|
-
|
|
18251
|
+
({ data } = await quillFetch({
|
|
18244
18252
|
client,
|
|
18245
18253
|
task: "query",
|
|
18246
18254
|
metadata: {
|
|
@@ -18254,7 +18262,7 @@ var init_tableProcessing = __esm({
|
|
|
18254
18262
|
},
|
|
18255
18263
|
urlParameters: `caller=getCounts&task=query`,
|
|
18256
18264
|
getToken
|
|
18257
|
-
});
|
|
18265
|
+
}));
|
|
18258
18266
|
}
|
|
18259
18267
|
if (data.errorMessage) {
|
|
18260
18268
|
return { filteredColumns: columns, exceededColumns: void 0 };
|
|
@@ -19244,9 +19252,9 @@ var init_dataFetcher = __esm({
|
|
|
19244
19252
|
return { error: "Failed to fetch data" };
|
|
19245
19253
|
}
|
|
19246
19254
|
};
|
|
19247
|
-
parseFetchResponse = async (client, task, response, getToken) => {
|
|
19255
|
+
parseFetchResponse = async (client, task, response, getToken, useInMemory = false) => {
|
|
19248
19256
|
try {
|
|
19249
|
-
if (response.status === "error" || response.data?.error) {
|
|
19257
|
+
if (response.status === "error" || response.data?.error && !useInMemory) {
|
|
19250
19258
|
let errorPrefix = "Error: ";
|
|
19251
19259
|
let errorMessage = "Failed to fetch report: " + (response.error || response.data?.error);
|
|
19252
19260
|
if (task === "query" || task === "report-builder") {
|
|
@@ -19831,7 +19839,8 @@ async function cleanDashboardItem({
|
|
|
19831
19839
|
additionalProcessing,
|
|
19832
19840
|
customFields,
|
|
19833
19841
|
skipPivotFetch,
|
|
19834
|
-
tenants
|
|
19842
|
+
tenants,
|
|
19843
|
+
overwriteCache
|
|
19835
19844
|
}) {
|
|
19836
19845
|
if (!item) return defaultDashboardItem;
|
|
19837
19846
|
if (!item.rows) {
|
|
@@ -19887,11 +19896,12 @@ async function cleanDashboardItem({
|
|
|
19887
19896
|
page: DEFAULT_PAGINATION
|
|
19888
19897
|
};
|
|
19889
19898
|
if (item.pivot && skipPivotFetch && item.rows && item.fields) {
|
|
19899
|
+
const pivotSourceRows = item.rows.map((row) => ({ ...row }));
|
|
19890
19900
|
const dateFilter = dashboardFilters?.find(
|
|
19891
19901
|
(filter) => filter.filterType === "date_range"
|
|
19892
19902
|
);
|
|
19893
19903
|
pivotTable = processPivotData({
|
|
19894
|
-
rows:
|
|
19904
|
+
rows: pivotSourceRows,
|
|
19895
19905
|
fields: item.fields,
|
|
19896
19906
|
pivot: {
|
|
19897
19907
|
...item.pivot,
|
|
@@ -19935,7 +19945,8 @@ async function cleanDashboardItem({
|
|
|
19935
19945
|
dateBucket,
|
|
19936
19946
|
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
19937
19947
|
tenants,
|
|
19938
|
-
customFields
|
|
19948
|
+
customFields,
|
|
19949
|
+
overwriteCache
|
|
19939
19950
|
);
|
|
19940
19951
|
}
|
|
19941
19952
|
} catch (e) {
|
|
@@ -20040,7 +20051,7 @@ async function cleanDashboardItem({
|
|
|
20040
20051
|
referenceLines: item.referenceLines
|
|
20041
20052
|
};
|
|
20042
20053
|
}
|
|
20043
|
-
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
20054
|
+
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields, overwriteCache) {
|
|
20044
20055
|
if (!report) return void 0;
|
|
20045
20056
|
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
20046
20057
|
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
@@ -20108,7 +20119,8 @@ async function getPivotTable(report, dashboardFilters, dashboardName, getToken,
|
|
|
20108
20119
|
dashboardFilters,
|
|
20109
20120
|
tenants,
|
|
20110
20121
|
additionalProcessing,
|
|
20111
|
-
getToken
|
|
20122
|
+
getToken,
|
|
20123
|
+
overwriteCache
|
|
20112
20124
|
});
|
|
20113
20125
|
return pivotTable;
|
|
20114
20126
|
} catch (e) {
|
|
@@ -20356,7 +20368,8 @@ async function fetchReportRows({
|
|
|
20356
20368
|
filters = [],
|
|
20357
20369
|
getToken,
|
|
20358
20370
|
abortSignal,
|
|
20359
|
-
additionalProcessing
|
|
20371
|
+
additionalProcessing,
|
|
20372
|
+
overwriteCache = false
|
|
20360
20373
|
}) {
|
|
20361
20374
|
const fetchResp = await quillFetch({
|
|
20362
20375
|
client,
|
|
@@ -20368,7 +20381,8 @@ async function fetchReportRows({
|
|
|
20368
20381
|
filters: filters.map((filter) => ({ ...filter, options: void 0 })),
|
|
20369
20382
|
useNewNodeSql: true,
|
|
20370
20383
|
tenants,
|
|
20371
|
-
additionalProcessing
|
|
20384
|
+
additionalProcessing,
|
|
20385
|
+
overwriteCache
|
|
20372
20386
|
},
|
|
20373
20387
|
abortSignal,
|
|
20374
20388
|
getToken
|
|
@@ -20399,7 +20413,8 @@ async function fetchReport({
|
|
|
20399
20413
|
abortSignal,
|
|
20400
20414
|
getToken,
|
|
20401
20415
|
eventTracking,
|
|
20402
|
-
usePivotTask = false
|
|
20416
|
+
usePivotTask = false,
|
|
20417
|
+
overwriteCache = false
|
|
20403
20418
|
}) {
|
|
20404
20419
|
let reportInfo = void 0;
|
|
20405
20420
|
let errorMessage = void 0;
|
|
@@ -20419,7 +20434,8 @@ async function fetchReport({
|
|
|
20419
20434
|
rowsOnly,
|
|
20420
20435
|
rowCountOnly,
|
|
20421
20436
|
tenants,
|
|
20422
|
-
flags
|
|
20437
|
+
flags,
|
|
20438
|
+
overwriteCache
|
|
20423
20439
|
},
|
|
20424
20440
|
abortSignal,
|
|
20425
20441
|
getToken
|
|
@@ -20440,7 +20456,9 @@ async function fetchReport({
|
|
|
20440
20456
|
getToken,
|
|
20441
20457
|
eventTracking,
|
|
20442
20458
|
tenants,
|
|
20443
|
-
|
|
20459
|
+
// When not using pivot-template, avoid fallback pivot-template fetches.
|
|
20460
|
+
skipPivotFetch: !usePivotTask,
|
|
20461
|
+
overwriteCache
|
|
20444
20462
|
});
|
|
20445
20463
|
} catch (error) {
|
|
20446
20464
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -20490,7 +20508,8 @@ async function processReportResponse({
|
|
|
20490
20508
|
getToken,
|
|
20491
20509
|
eventTracking,
|
|
20492
20510
|
tenants,
|
|
20493
|
-
skipPivotFetch = false
|
|
20511
|
+
skipPivotFetch = false,
|
|
20512
|
+
overwriteCache
|
|
20494
20513
|
}) {
|
|
20495
20514
|
const shouldSkipPivotFetch = skipPivotFetch || !!resp?.pivotRows && !!resp?.fields;
|
|
20496
20515
|
const dashboardItem = {
|
|
@@ -20523,7 +20542,8 @@ async function processReportResponse({
|
|
|
20523
20542
|
getToken,
|
|
20524
20543
|
tenants,
|
|
20525
20544
|
eventTracking,
|
|
20526
|
-
skipPivotFetch: shouldSkipPivotFetch
|
|
20545
|
+
skipPivotFetch: shouldSkipPivotFetch,
|
|
20546
|
+
overwriteCache
|
|
20527
20547
|
});
|
|
20528
20548
|
if (additionalProcessing) {
|
|
20529
20549
|
reportInfo.pagination = additionalProcessing.page;
|
|
@@ -21600,6 +21620,1952 @@ async function getClientTenantIds({
|
|
|
21600
21620
|
|
|
21601
21621
|
// src/Context.tsx
|
|
21602
21622
|
init_columnProcessing();
|
|
21623
|
+
|
|
21624
|
+
// src/utils/cacheCab.ts
|
|
21625
|
+
init_dataFetcher();
|
|
21626
|
+
|
|
21627
|
+
// src/utils/inMemoryFilterEngine.ts
|
|
21628
|
+
init_Filter();
|
|
21629
|
+
init_dateRangePickerUtils();
|
|
21630
|
+
import {
|
|
21631
|
+
addHours,
|
|
21632
|
+
addMonths,
|
|
21633
|
+
addWeeks,
|
|
21634
|
+
addYears,
|
|
21635
|
+
addDays as addDays2,
|
|
21636
|
+
isValid as isValid4,
|
|
21637
|
+
startOfDay as startOfDay3,
|
|
21638
|
+
startOfHour,
|
|
21639
|
+
startOfMonth as startOfMonth2,
|
|
21640
|
+
startOfQuarter as startOfQuarter2,
|
|
21641
|
+
startOfWeek as startOfWeek3,
|
|
21642
|
+
startOfYear,
|
|
21643
|
+
subDays as subDays2,
|
|
21644
|
+
subHours as subHours2,
|
|
21645
|
+
subMonths as subMonths3,
|
|
21646
|
+
subWeeks as subWeeks2,
|
|
21647
|
+
subYears as subYears2
|
|
21648
|
+
} from "date-fns";
|
|
21649
|
+
var UNSET = Symbol("unset");
|
|
21650
|
+
var isFilter = (f) => {
|
|
21651
|
+
return f && typeof f === "object" && "filterType" in f && !("id" in f);
|
|
21652
|
+
};
|
|
21653
|
+
var isDashboardFilterUpdate = (f) => {
|
|
21654
|
+
return f && typeof f === "object" && "label" in f;
|
|
21655
|
+
};
|
|
21656
|
+
var normalizeFilterString = (value) => value.replaceAll("%", "").toLowerCase();
|
|
21657
|
+
var normalizeRowString = (value) => value.toLowerCase();
|
|
21658
|
+
var resolveFieldKeys = (field, table, resolver) => {
|
|
21659
|
+
if (!field) return [];
|
|
21660
|
+
const resolved = resolver?.(field, table);
|
|
21661
|
+
if (Array.isArray(resolved)) return resolved;
|
|
21662
|
+
if (typeof resolved === "string") return [resolved];
|
|
21663
|
+
return [field];
|
|
21664
|
+
};
|
|
21665
|
+
var getRowValue = (row, fieldKeys, cache) => {
|
|
21666
|
+
if (fieldKeys.length === 0) return void 0;
|
|
21667
|
+
const cacheKey = fieldKeys.join("|");
|
|
21668
|
+
if (Object.prototype.hasOwnProperty.call(cache, cacheKey)) {
|
|
21669
|
+
return cache[cacheKey];
|
|
21670
|
+
}
|
|
21671
|
+
for (const key of fieldKeys) {
|
|
21672
|
+
if (Object.prototype.hasOwnProperty.call(row, key)) {
|
|
21673
|
+
cache[cacheKey] = row[key];
|
|
21674
|
+
return row[key];
|
|
21675
|
+
}
|
|
21676
|
+
}
|
|
21677
|
+
cache[cacheKey] = void 0;
|
|
21678
|
+
return void 0;
|
|
21679
|
+
};
|
|
21680
|
+
var coerceNumber = (value) => {
|
|
21681
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
21682
|
+
if (typeof value === "string" && value !== "") {
|
|
21683
|
+
const parsed = Number(value);
|
|
21684
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
21685
|
+
}
|
|
21686
|
+
return null;
|
|
21687
|
+
};
|
|
21688
|
+
var coerceBoolean = (value) => {
|
|
21689
|
+
if (typeof value === "boolean") return value;
|
|
21690
|
+
if (typeof value === "number") return value !== 0;
|
|
21691
|
+
if (typeof value === "string") {
|
|
21692
|
+
const normalized = value.toLowerCase();
|
|
21693
|
+
if (normalized === "true" || normalized === "1") return true;
|
|
21694
|
+
if (normalized === "false" || normalized === "0") return false;
|
|
21695
|
+
}
|
|
21696
|
+
return null;
|
|
21697
|
+
};
|
|
21698
|
+
var toDateMs = (value) => {
|
|
21699
|
+
if (value instanceof Date) {
|
|
21700
|
+
return isValid4(value) ? value.getTime() : null;
|
|
21701
|
+
}
|
|
21702
|
+
if (typeof value === "number") {
|
|
21703
|
+
const date = new Date(value);
|
|
21704
|
+
return isValid4(date) ? date.getTime() : null;
|
|
21705
|
+
}
|
|
21706
|
+
if (typeof value === "string") {
|
|
21707
|
+
const date = new Date(value);
|
|
21708
|
+
return isValid4(date) ? date.getTime() : null;
|
|
21709
|
+
}
|
|
21710
|
+
return null;
|
|
21711
|
+
};
|
|
21712
|
+
var buildColumnTypeMap = (columns) => {
|
|
21713
|
+
if (!columns?.length) return null;
|
|
21714
|
+
const map = /* @__PURE__ */ Object.create(null);
|
|
21715
|
+
for (const column of columns) {
|
|
21716
|
+
map[column.field] = column.jsType;
|
|
21717
|
+
}
|
|
21718
|
+
return map;
|
|
21719
|
+
};
|
|
21720
|
+
var resolveDashboardField = (filter, options) => {
|
|
21721
|
+
const mapped = options.filterMap?.[filter.label];
|
|
21722
|
+
if (mapped?.field) {
|
|
21723
|
+
return { field: mapped.field, table: mapped.table };
|
|
21724
|
+
}
|
|
21725
|
+
if (filter.filterType === "date_range" /* Date */ && options.dateField?.field) {
|
|
21726
|
+
return { field: options.dateField.field, table: options.dateField.table };
|
|
21727
|
+
}
|
|
21728
|
+
if (filter.field) {
|
|
21729
|
+
return { field: filter.field, table: filter.table };
|
|
21730
|
+
}
|
|
21731
|
+
return null;
|
|
21732
|
+
};
|
|
21733
|
+
var buildRelativeDateRange = (operator, value, now2, weekStartsOn) => {
|
|
21734
|
+
const amount = value.value || 1;
|
|
21735
|
+
const unit = value.unit;
|
|
21736
|
+
const currentStart = (() => {
|
|
21737
|
+
switch (unit) {
|
|
21738
|
+
case TimeUnit.Hour:
|
|
21739
|
+
return startOfHour(now2);
|
|
21740
|
+
case TimeUnit.Day:
|
|
21741
|
+
return startOfDay3(now2);
|
|
21742
|
+
case TimeUnit.Week:
|
|
21743
|
+
return startOfWeek3(now2, { weekStartsOn });
|
|
21744
|
+
case TimeUnit.Month:
|
|
21745
|
+
return startOfMonth2(now2);
|
|
21746
|
+
case TimeUnit.Quarter:
|
|
21747
|
+
return startOfQuarter2(now2);
|
|
21748
|
+
case TimeUnit.Year:
|
|
21749
|
+
return startOfYear(now2);
|
|
21750
|
+
default:
|
|
21751
|
+
return startOfDay3(now2);
|
|
21752
|
+
}
|
|
21753
|
+
})();
|
|
21754
|
+
const addUnit = (base, multiplier) => {
|
|
21755
|
+
switch (unit) {
|
|
21756
|
+
case TimeUnit.Hour:
|
|
21757
|
+
return addHours(base, multiplier);
|
|
21758
|
+
case TimeUnit.Day:
|
|
21759
|
+
return addDays2(base, multiplier);
|
|
21760
|
+
case TimeUnit.Week:
|
|
21761
|
+
return addWeeks(base, multiplier);
|
|
21762
|
+
case TimeUnit.Month:
|
|
21763
|
+
return addMonths(base, multiplier);
|
|
21764
|
+
case TimeUnit.Quarter:
|
|
21765
|
+
return addMonths(base, multiplier * 3);
|
|
21766
|
+
case TimeUnit.Year:
|
|
21767
|
+
return addYears(base, multiplier);
|
|
21768
|
+
default:
|
|
21769
|
+
return addDays2(base, multiplier);
|
|
21770
|
+
}
|
|
21771
|
+
};
|
|
21772
|
+
const subUnit = (base, multiplier) => {
|
|
21773
|
+
switch (unit) {
|
|
21774
|
+
case TimeUnit.Hour:
|
|
21775
|
+
return subHours2(base, multiplier);
|
|
21776
|
+
case TimeUnit.Day:
|
|
21777
|
+
return subDays2(base, multiplier);
|
|
21778
|
+
case TimeUnit.Week:
|
|
21779
|
+
return subWeeks2(base, multiplier);
|
|
21780
|
+
case TimeUnit.Month:
|
|
21781
|
+
return subMonths3(base, multiplier);
|
|
21782
|
+
case TimeUnit.Quarter:
|
|
21783
|
+
return subMonths3(base, multiplier * 3);
|
|
21784
|
+
case TimeUnit.Year:
|
|
21785
|
+
return subYears2(base, multiplier);
|
|
21786
|
+
default:
|
|
21787
|
+
return subDays2(base, multiplier);
|
|
21788
|
+
}
|
|
21789
|
+
};
|
|
21790
|
+
switch (operator) {
|
|
21791
|
+
case DateOperator.InTheLast: {
|
|
21792
|
+
const start2 = subUnit(now2, amount);
|
|
21793
|
+
return { start: start2.getTime() };
|
|
21794
|
+
}
|
|
21795
|
+
case DateOperator.InThePrevious: {
|
|
21796
|
+
const start2 = subUnit(currentStart, amount);
|
|
21797
|
+
return { start: start2.getTime(), end: currentStart.getTime(), endExclusive: true };
|
|
21798
|
+
}
|
|
21799
|
+
case DateOperator.InTheCurrent: {
|
|
21800
|
+
const end = addUnit(currentStart, 1);
|
|
21801
|
+
return {
|
|
21802
|
+
start: currentStart.getTime(),
|
|
21803
|
+
end: end.getTime(),
|
|
21804
|
+
endExclusive: true
|
|
21805
|
+
};
|
|
21806
|
+
}
|
|
21807
|
+
default:
|
|
21808
|
+
return null;
|
|
21809
|
+
}
|
|
21810
|
+
};
|
|
21811
|
+
var buildStringPredicate = (operator, value, fieldKeys) => {
|
|
21812
|
+
if (value === void 0 || value === null) return null;
|
|
21813
|
+
const normalizedValue = Array.isArray(value) ? value.map((v) => normalizeFilterString(String(v))) : normalizeFilterString(String(value));
|
|
21814
|
+
if (Array.isArray(normalizedValue)) {
|
|
21815
|
+
if (normalizedValue.length === 0) return null;
|
|
21816
|
+
} else if (normalizedValue === "") {
|
|
21817
|
+
return null;
|
|
21818
|
+
}
|
|
21819
|
+
if (operator === StringOperator.Is || operator === StringOperator.IsNot) {
|
|
21820
|
+
const values = Array.isArray(normalizedValue) ? normalizedValue : [normalizedValue];
|
|
21821
|
+
const valueSet = new Set(values);
|
|
21822
|
+
return (row, cache) => {
|
|
21823
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21824
|
+
if (rowValue === null || rowValue === void 0) return false;
|
|
21825
|
+
const normalized = normalizeRowString(String(rowValue));
|
|
21826
|
+
const hasValue = valueSet.has(normalized);
|
|
21827
|
+
return operator === StringOperator.Is ? hasValue : !hasValue;
|
|
21828
|
+
};
|
|
21829
|
+
}
|
|
21830
|
+
if (Array.isArray(normalizedValue)) {
|
|
21831
|
+
return null;
|
|
21832
|
+
}
|
|
21833
|
+
return (row, cache) => {
|
|
21834
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21835
|
+
if (rowValue === null || rowValue === void 0) return false;
|
|
21836
|
+
const normalizedRow = normalizeRowString(String(rowValue));
|
|
21837
|
+
switch (operator) {
|
|
21838
|
+
case StringOperator.IsExactly:
|
|
21839
|
+
return normalizedRow === normalizedValue;
|
|
21840
|
+
case StringOperator.IsNotExactly:
|
|
21841
|
+
return normalizedRow !== normalizedValue;
|
|
21842
|
+
case StringOperator.Contains:
|
|
21843
|
+
return normalizedRow.includes(normalizedValue);
|
|
21844
|
+
default:
|
|
21845
|
+
return false;
|
|
21846
|
+
}
|
|
21847
|
+
};
|
|
21848
|
+
};
|
|
21849
|
+
var buildNumericPredicate = (operator, value, fieldKeys) => {
|
|
21850
|
+
const filterValue = coerceNumber(value);
|
|
21851
|
+
if (filterValue === null) return null;
|
|
21852
|
+
return (row, cache) => {
|
|
21853
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21854
|
+
const parsed = coerceNumber(rowValue);
|
|
21855
|
+
if (parsed === null) return false;
|
|
21856
|
+
switch (operator) {
|
|
21857
|
+
case NumberOperator.EqualTo:
|
|
21858
|
+
return parsed === filterValue;
|
|
21859
|
+
case NumberOperator.NotEqualTo:
|
|
21860
|
+
return parsed !== filterValue;
|
|
21861
|
+
case NumberOperator.GreaterThan:
|
|
21862
|
+
return parsed > filterValue;
|
|
21863
|
+
case NumberOperator.LessThan:
|
|
21864
|
+
return parsed < filterValue;
|
|
21865
|
+
case NumberOperator.GreaterThanOrEqualTo:
|
|
21866
|
+
return parsed >= filterValue;
|
|
21867
|
+
case NumberOperator.LessThanOrEqualTo:
|
|
21868
|
+
return parsed <= filterValue;
|
|
21869
|
+
default:
|
|
21870
|
+
return false;
|
|
21871
|
+
}
|
|
21872
|
+
};
|
|
21873
|
+
};
|
|
21874
|
+
var buildNullPredicate = (operator, fieldKeys) => {
|
|
21875
|
+
return (row, cache) => {
|
|
21876
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21877
|
+
const isNullish = rowValue === null || rowValue === void 0;
|
|
21878
|
+
return operator === NullOperator.IsNull ? isNullish : !isNullish;
|
|
21879
|
+
};
|
|
21880
|
+
};
|
|
21881
|
+
var buildBooleanPredicate = (operator, value, fieldKeys) => {
|
|
21882
|
+
const filterValue = coerceBoolean(value);
|
|
21883
|
+
if (filterValue === null) return null;
|
|
21884
|
+
return (row, cache) => {
|
|
21885
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21886
|
+
const parsed = coerceBoolean(rowValue);
|
|
21887
|
+
if (parsed === null) return false;
|
|
21888
|
+
return operator === BoolOperator.EqualTo ? parsed === filterValue : parsed !== filterValue;
|
|
21889
|
+
};
|
|
21890
|
+
};
|
|
21891
|
+
var buildDateComparisonPredicate = (operator, value, fieldKeys) => {
|
|
21892
|
+
const filterDate = toDateMs(value);
|
|
21893
|
+
if (filterDate === null) return null;
|
|
21894
|
+
return (row, cache) => {
|
|
21895
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21896
|
+
const rowDate = toDateMs(rowValue);
|
|
21897
|
+
if (rowDate === null) return false;
|
|
21898
|
+
switch (operator) {
|
|
21899
|
+
case DateOperator.EqualTo:
|
|
21900
|
+
return rowDate === filterDate;
|
|
21901
|
+
case DateOperator.NotEqualTo:
|
|
21902
|
+
return rowDate !== filterDate;
|
|
21903
|
+
case DateOperator.GreaterThan:
|
|
21904
|
+
return rowDate > filterDate;
|
|
21905
|
+
case DateOperator.LessThan:
|
|
21906
|
+
return rowDate < filterDate;
|
|
21907
|
+
case DateOperator.GreaterThanOrEqualTo:
|
|
21908
|
+
return rowDate >= filterDate;
|
|
21909
|
+
case DateOperator.LessThanOrEqualTo:
|
|
21910
|
+
return rowDate <= filterDate;
|
|
21911
|
+
default:
|
|
21912
|
+
return false;
|
|
21913
|
+
}
|
|
21914
|
+
};
|
|
21915
|
+
};
|
|
21916
|
+
var buildDateRangePredicate = (range, fieldKeys) => {
|
|
21917
|
+
if (range.start === void 0 && range.end === void 0) return null;
|
|
21918
|
+
return (row, cache) => {
|
|
21919
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21920
|
+
const rowDate = toDateMs(rowValue);
|
|
21921
|
+
if (rowDate === null) return false;
|
|
21922
|
+
if (range.start !== void 0 && rowDate < range.start) return false;
|
|
21923
|
+
if (range.end !== void 0) {
|
|
21924
|
+
if (range.endExclusive) {
|
|
21925
|
+
return rowDate < range.end;
|
|
21926
|
+
}
|
|
21927
|
+
return rowDate <= range.end;
|
|
21928
|
+
}
|
|
21929
|
+
return true;
|
|
21930
|
+
};
|
|
21931
|
+
};
|
|
21932
|
+
var buildCustomDatePredicate = (value, fieldKeys) => {
|
|
21933
|
+
const start2 = value.startDate ? toDateMs(value.startDate) : null;
|
|
21934
|
+
const end = value.endDate ? toDateMs(value.endDate) : null;
|
|
21935
|
+
if (start2 === null && end === null) return null;
|
|
21936
|
+
return buildDateRangePredicate(
|
|
21937
|
+
{
|
|
21938
|
+
start: start2 ?? void 0,
|
|
21939
|
+
end: end ?? void 0,
|
|
21940
|
+
endExclusive: false
|
|
21941
|
+
},
|
|
21942
|
+
fieldKeys
|
|
21943
|
+
);
|
|
21944
|
+
};
|
|
21945
|
+
var compileCustomFilter = (filter, options) => {
|
|
21946
|
+
const fieldKeys = resolveFieldKeys(
|
|
21947
|
+
filter.field,
|
|
21948
|
+
filter.table,
|
|
21949
|
+
options.fieldKeyResolver
|
|
21950
|
+
);
|
|
21951
|
+
if (fieldKeys.length === 0) return null;
|
|
21952
|
+
switch (filter.filterType) {
|
|
21953
|
+
case "string-filter" /* StringFilter */:
|
|
21954
|
+
case "string-in-filter" /* StringInFilter */:
|
|
21955
|
+
return buildStringPredicate(
|
|
21956
|
+
filter.operator,
|
|
21957
|
+
filter.value,
|
|
21958
|
+
fieldKeys
|
|
21959
|
+
);
|
|
21960
|
+
case "numeric-filter" /* NumericFilter */:
|
|
21961
|
+
return buildNumericPredicate(
|
|
21962
|
+
filter.operator,
|
|
21963
|
+
filter.value,
|
|
21964
|
+
fieldKeys
|
|
21965
|
+
);
|
|
21966
|
+
case "null-filter" /* NullFilter */:
|
|
21967
|
+
return buildNullPredicate(
|
|
21968
|
+
filter.operator,
|
|
21969
|
+
fieldKeys
|
|
21970
|
+
);
|
|
21971
|
+
case "boolean-filter" /* BooleanFilter */:
|
|
21972
|
+
return buildBooleanPredicate(
|
|
21973
|
+
filter.operator,
|
|
21974
|
+
filter.value,
|
|
21975
|
+
fieldKeys
|
|
21976
|
+
);
|
|
21977
|
+
case "date-custom-filter" /* DateCustomFilter */:
|
|
21978
|
+
return buildCustomDatePredicate(
|
|
21979
|
+
filter.value,
|
|
21980
|
+
fieldKeys
|
|
21981
|
+
);
|
|
21982
|
+
case "date-comparison-filter" /* DateComparisonFilter */:
|
|
21983
|
+
return buildDateComparisonPredicate(
|
|
21984
|
+
filter.operator,
|
|
21985
|
+
filter.value,
|
|
21986
|
+
fieldKeys
|
|
21987
|
+
);
|
|
21988
|
+
case "date-filter" /* DateFilter */: {
|
|
21989
|
+
const value = filter.value;
|
|
21990
|
+
if (!value?.unit) return null;
|
|
21991
|
+
const now2 = options.now ?? /* @__PURE__ */ new Date();
|
|
21992
|
+
const range = buildRelativeDateRange(
|
|
21993
|
+
filter.operator,
|
|
21994
|
+
value,
|
|
21995
|
+
now2,
|
|
21996
|
+
options.weekStartsOn ?? 0
|
|
21997
|
+
);
|
|
21998
|
+
if (!range) return null;
|
|
21999
|
+
return buildDateRangePredicate(range, fieldKeys);
|
|
22000
|
+
}
|
|
22001
|
+
default:
|
|
22002
|
+
return null;
|
|
22003
|
+
}
|
|
22004
|
+
};
|
|
22005
|
+
var compileDashboardFilter = (filter, options, columnTypeMap) => {
|
|
22006
|
+
const resolved = resolveDashboardField(filter, options);
|
|
22007
|
+
if (!resolved?.field) return null;
|
|
22008
|
+
const fieldKeys = resolveFieldKeys(
|
|
22009
|
+
resolved.field,
|
|
22010
|
+
resolved.table,
|
|
22011
|
+
options.fieldKeyResolver
|
|
22012
|
+
);
|
|
22013
|
+
if (fieldKeys.length === 0) return null;
|
|
22014
|
+
switch (filter.filterType) {
|
|
22015
|
+
case "string" /* String */: {
|
|
22016
|
+
const stringFilter = filter;
|
|
22017
|
+
if (stringFilter.stringFilterType === "multiselect" /* Multiselect */) {
|
|
22018
|
+
if (!stringFilter.values || stringFilter.values.length === 0) {
|
|
22019
|
+
return null;
|
|
22020
|
+
}
|
|
22021
|
+
return buildStringPredicate(
|
|
22022
|
+
StringOperator.Is,
|
|
22023
|
+
stringFilter.values,
|
|
22024
|
+
fieldKeys
|
|
22025
|
+
);
|
|
22026
|
+
}
|
|
22027
|
+
if (!stringFilter.selectedValue) return null;
|
|
22028
|
+
return buildStringPredicate(
|
|
22029
|
+
StringOperator.IsExactly,
|
|
22030
|
+
stringFilter.selectedValue,
|
|
22031
|
+
fieldKeys
|
|
22032
|
+
);
|
|
22033
|
+
}
|
|
22034
|
+
case "date_range" /* Date */: {
|
|
22035
|
+
const dateFilter = filter;
|
|
22036
|
+
const start2 = dateFilter.startDate ? dateFilter.startDate.getTime() : void 0;
|
|
22037
|
+
const end = dateFilter.endDate ? dateFilter.endDate.getTime() : void 0;
|
|
22038
|
+
return buildDateRangePredicate(
|
|
22039
|
+
{ start: start2, end, endExclusive: false },
|
|
22040
|
+
fieldKeys
|
|
22041
|
+
);
|
|
22042
|
+
}
|
|
22043
|
+
case "tenant" /* Tenant */: {
|
|
22044
|
+
const tenantFilter = filter;
|
|
22045
|
+
if (!tenantFilter.values || tenantFilter.values.length === 0) {
|
|
22046
|
+
return null;
|
|
22047
|
+
}
|
|
22048
|
+
const normalizedValues = tenantFilter.values.map(
|
|
22049
|
+
(v) => normalizeFilterString(String(v))
|
|
22050
|
+
);
|
|
22051
|
+
const valueSet = new Set(normalizedValues);
|
|
22052
|
+
const fieldType = columnTypeMap?.[resolved.field] ?? "string";
|
|
22053
|
+
return (row, cache) => {
|
|
22054
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
22055
|
+
if (rowValue === null || rowValue === void 0) return false;
|
|
22056
|
+
if (fieldType === "number") {
|
|
22057
|
+
const numeric = coerceNumber(rowValue);
|
|
22058
|
+
return numeric !== null && valueSet.has(normalizeFilterString(String(numeric)));
|
|
22059
|
+
}
|
|
22060
|
+
return valueSet.has(normalizeRowString(String(rowValue)));
|
|
22061
|
+
};
|
|
22062
|
+
}
|
|
22063
|
+
default:
|
|
22064
|
+
return null;
|
|
22065
|
+
}
|
|
22066
|
+
};
|
|
22067
|
+
var updateDashboardFilters = (filtersToUpdate, dashboardFilters) => {
|
|
22068
|
+
return dashboardFilters.map((filter) => {
|
|
22069
|
+
const update = filtersToUpdate.find((u) => u.label === filter.label);
|
|
22070
|
+
if (!update) return filter;
|
|
22071
|
+
if (filter.filterType === "string" /* String */) {
|
|
22072
|
+
if (filter.stringFilterType === "multiselect" /* Multiselect */) {
|
|
22073
|
+
return {
|
|
22074
|
+
...filter,
|
|
22075
|
+
values: update.value
|
|
22076
|
+
};
|
|
22077
|
+
}
|
|
22078
|
+
return {
|
|
22079
|
+
...filter,
|
|
22080
|
+
selectedValue: update.value
|
|
22081
|
+
};
|
|
22082
|
+
}
|
|
22083
|
+
if (filter.filterType === "date_range" /* Date */) {
|
|
22084
|
+
const presetOptions = convertPresetOptionsToSelectableList(
|
|
22085
|
+
filter.presetOptions ?? [],
|
|
22086
|
+
filter.defaultPresetRanges ?? []
|
|
22087
|
+
);
|
|
22088
|
+
const value = update.value;
|
|
22089
|
+
const preset = presetOptions.find((p) => {
|
|
22090
|
+
const pStart = p.startDate ? new Date(p.startDate).toISOString() : void 0;
|
|
22091
|
+
const vStart = value.startDate ? new Date(value.startDate).toISOString() : void 0;
|
|
22092
|
+
const pEnd = p.endDate ? new Date(p.endDate).toISOString() : void 0;
|
|
22093
|
+
const vEnd = value.endDate ? new Date(value.endDate).toISOString() : void 0;
|
|
22094
|
+
return pStart === vStart && pEnd === vEnd;
|
|
22095
|
+
});
|
|
22096
|
+
if (!preset) {
|
|
22097
|
+
return { ...filter, startDate: value.startDate, endDate: value.endDate };
|
|
22098
|
+
}
|
|
22099
|
+
return {
|
|
22100
|
+
...filter,
|
|
22101
|
+
preset,
|
|
22102
|
+
startDate: value.startDate,
|
|
22103
|
+
endDate: value.endDate
|
|
22104
|
+
};
|
|
22105
|
+
}
|
|
22106
|
+
if (filter.filterType === "tenant" /* Tenant */) {
|
|
22107
|
+
const value = update.value;
|
|
22108
|
+
let values;
|
|
22109
|
+
if (Array.isArray(value)) {
|
|
22110
|
+
values = value;
|
|
22111
|
+
} else if (typeof value === "string") {
|
|
22112
|
+
values = [value];
|
|
22113
|
+
} else {
|
|
22114
|
+
values = [];
|
|
22115
|
+
}
|
|
22116
|
+
return {
|
|
22117
|
+
...filter,
|
|
22118
|
+
values
|
|
22119
|
+
};
|
|
22120
|
+
}
|
|
22121
|
+
return filter;
|
|
22122
|
+
});
|
|
22123
|
+
};
|
|
22124
|
+
var compileApplyFiltersPredicate = (filters, options) => {
|
|
22125
|
+
const dashboardUpdates = filters.filter(isDashboardFilterUpdate);
|
|
22126
|
+
const customFilters = filters.filter(isFilter);
|
|
22127
|
+
const internalCustomFilters = customFilters.map((filter) => {
|
|
22128
|
+
try {
|
|
22129
|
+
return convertCustomFilter(filter);
|
|
22130
|
+
} catch (error) {
|
|
22131
|
+
return null;
|
|
22132
|
+
}
|
|
22133
|
+
}).concat(options.customFilters ?? []).filter((filter) => filter !== null && filter !== void 0);
|
|
22134
|
+
const dashboardFilters = options.dashboardFilters ?? [];
|
|
22135
|
+
const updatedDashboardFilters = dashboardUpdates.length ? updateDashboardFilters(dashboardUpdates, dashboardFilters) : dashboardFilters;
|
|
22136
|
+
const columnTypeMap = buildColumnTypeMap(options.columns);
|
|
22137
|
+
const predicates = [];
|
|
22138
|
+
for (const filter of internalCustomFilters) {
|
|
22139
|
+
const predicate = compileCustomFilter(filter, options);
|
|
22140
|
+
if (predicate) predicates.push(predicate);
|
|
22141
|
+
}
|
|
22142
|
+
for (const filter of updatedDashboardFilters) {
|
|
22143
|
+
const predicate = compileDashboardFilter(
|
|
22144
|
+
filter,
|
|
22145
|
+
options,
|
|
22146
|
+
columnTypeMap
|
|
22147
|
+
);
|
|
22148
|
+
if (predicate) predicates.push(predicate);
|
|
22149
|
+
}
|
|
22150
|
+
if (predicates.length === 0) {
|
|
22151
|
+
return { predicate: () => true, hasPredicates: false };
|
|
22152
|
+
}
|
|
22153
|
+
return {
|
|
22154
|
+
predicate: (row) => {
|
|
22155
|
+
const cache = /* @__PURE__ */ Object.create(null);
|
|
22156
|
+
for (const predicate of predicates) {
|
|
22157
|
+
if (!predicate(row, cache)) return false;
|
|
22158
|
+
}
|
|
22159
|
+
return true;
|
|
22160
|
+
},
|
|
22161
|
+
hasPredicates: true
|
|
22162
|
+
};
|
|
22163
|
+
};
|
|
22164
|
+
var applyFiltersInMemory = (rows, filters, options) => {
|
|
22165
|
+
if (!rows.length) return rows;
|
|
22166
|
+
const { predicate, hasPredicates } = compileApplyFiltersPredicate(
|
|
22167
|
+
filters,
|
|
22168
|
+
options
|
|
22169
|
+
);
|
|
22170
|
+
if (!hasPredicates) return rows;
|
|
22171
|
+
const results = [];
|
|
22172
|
+
for (let i = 0; i < rows.length; i += 1) {
|
|
22173
|
+
const row = rows[i];
|
|
22174
|
+
if (predicate(row)) {
|
|
22175
|
+
results.push(row);
|
|
22176
|
+
}
|
|
22177
|
+
}
|
|
22178
|
+
return results;
|
|
22179
|
+
};
|
|
22180
|
+
|
|
22181
|
+
// src/utils/inMemoryPivotEngine.ts
|
|
22182
|
+
init_columnType();
|
|
22183
|
+
var MS_IN_DAY = 24 * 60 * 60 * 1e3;
|
|
22184
|
+
var MONTHS = [
|
|
22185
|
+
"Jan",
|
|
22186
|
+
"Feb",
|
|
22187
|
+
"Mar",
|
|
22188
|
+
"Apr",
|
|
22189
|
+
"May",
|
|
22190
|
+
"Jun",
|
|
22191
|
+
"Jul",
|
|
22192
|
+
"Aug",
|
|
22193
|
+
"Sep",
|
|
22194
|
+
"Oct",
|
|
22195
|
+
"Nov",
|
|
22196
|
+
"Dec"
|
|
22197
|
+
];
|
|
22198
|
+
var INVALID_DATE_KEY = "-2026";
|
|
22199
|
+
function singleAggToMultiAgg(pivot) {
|
|
22200
|
+
if (pivot.aggregations) {
|
|
22201
|
+
return pivot;
|
|
22202
|
+
}
|
|
22203
|
+
const newPivot = { ...pivot };
|
|
22204
|
+
const newAgg = { aggregationType: pivot.aggregationType };
|
|
22205
|
+
const fieldsToCopy = [
|
|
22206
|
+
"valueField",
|
|
22207
|
+
"valueFieldType",
|
|
22208
|
+
"valueField2",
|
|
22209
|
+
"valueField2Type"
|
|
22210
|
+
];
|
|
22211
|
+
fieldsToCopy.forEach((x) => {
|
|
22212
|
+
if (pivot[x]) {
|
|
22213
|
+
newAgg[x] = pivot[x];
|
|
22214
|
+
delete newPivot[x];
|
|
22215
|
+
}
|
|
22216
|
+
});
|
|
22217
|
+
newPivot.aggregations = [newAgg];
|
|
22218
|
+
return newPivot;
|
|
22219
|
+
}
|
|
22220
|
+
function isDateFormat2(xAxisFormat) {
|
|
22221
|
+
const DATE_FORMATS = [
|
|
22222
|
+
"yyyy",
|
|
22223
|
+
"mmm_dd",
|
|
22224
|
+
"mmm_yyyy",
|
|
22225
|
+
"mmm_dd_yyyy",
|
|
22226
|
+
"hh_ap_pm",
|
|
22227
|
+
"mmm_dd-mmm_dd",
|
|
22228
|
+
"mmm_dd_hh:mm_ap_pm",
|
|
22229
|
+
"wo, yyyy"
|
|
22230
|
+
];
|
|
22231
|
+
const isDate = DATE_FORMATS.includes(xAxisFormat.toLowerCase());
|
|
22232
|
+
return isDate;
|
|
22233
|
+
}
|
|
22234
|
+
function isValidDate3(date) {
|
|
22235
|
+
try {
|
|
22236
|
+
return date instanceof Date && !isNaN(date.getTime());
|
|
22237
|
+
} catch {
|
|
22238
|
+
return false;
|
|
22239
|
+
}
|
|
22240
|
+
}
|
|
22241
|
+
function isDateLikeType(fieldType) {
|
|
22242
|
+
if (!fieldType) {
|
|
22243
|
+
return false;
|
|
22244
|
+
}
|
|
22245
|
+
return isDateType(fieldType) || isDateFormat2(fieldType);
|
|
22246
|
+
}
|
|
22247
|
+
function inferDateBucketFromFilters(pivot, filters) {
|
|
22248
|
+
if (!pivot?.rowFieldType) {
|
|
22249
|
+
return void 0;
|
|
22250
|
+
}
|
|
22251
|
+
const normalizedType = String(pivot.rowFieldType).toLowerCase();
|
|
22252
|
+
if (isDateFormat2(normalizedType)) {
|
|
22253
|
+
switch (normalizedType) {
|
|
22254
|
+
case "mmm_dd-mmm_dd":
|
|
22255
|
+
return "week";
|
|
22256
|
+
case "yyyy":
|
|
22257
|
+
case "wo, yyyy":
|
|
22258
|
+
return "year";
|
|
22259
|
+
case "mmm_dd_hh:mm_ap_pm":
|
|
22260
|
+
case "hh_ap_pm":
|
|
22261
|
+
return "day";
|
|
22262
|
+
default:
|
|
22263
|
+
return "month";
|
|
22264
|
+
}
|
|
22265
|
+
}
|
|
22266
|
+
const isDateLike = isDateType(normalizedType);
|
|
22267
|
+
if (!isDateLike) {
|
|
22268
|
+
return void 0;
|
|
22269
|
+
}
|
|
22270
|
+
let earliest;
|
|
22271
|
+
let latest;
|
|
22272
|
+
const extractTimestamp = (value) => {
|
|
22273
|
+
if (!value) {
|
|
22274
|
+
return void 0;
|
|
22275
|
+
}
|
|
22276
|
+
if (value instanceof Date) {
|
|
22277
|
+
return value.getTime();
|
|
22278
|
+
}
|
|
22279
|
+
const parsed = Date.parse(value);
|
|
22280
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
22281
|
+
};
|
|
22282
|
+
(Array.isArray(filters) ? filters : []).forEach((filter) => {
|
|
22283
|
+
if (!filter || filter.filterType !== "date_range") {
|
|
22284
|
+
return;
|
|
22285
|
+
}
|
|
22286
|
+
if (filter.primaryRange?.value === "ALL_TIME") {
|
|
22287
|
+
earliest = -1;
|
|
22288
|
+
return;
|
|
22289
|
+
}
|
|
22290
|
+
const possibleStarts = [
|
|
22291
|
+
filter.startDate,
|
|
22292
|
+
filter.start,
|
|
22293
|
+
filter.primaryRange?.startDate,
|
|
22294
|
+
filter.primaryRange?.start,
|
|
22295
|
+
filter.range?.startDate,
|
|
22296
|
+
filter.range?.start
|
|
22297
|
+
];
|
|
22298
|
+
const possibleEnds = [
|
|
22299
|
+
filter.endDate,
|
|
22300
|
+
filter.end,
|
|
22301
|
+
filter.primaryRange?.endDate,
|
|
22302
|
+
filter.primaryRange?.end,
|
|
22303
|
+
filter.range?.endDate,
|
|
22304
|
+
filter.range?.end
|
|
22305
|
+
];
|
|
22306
|
+
possibleStarts.forEach((value) => {
|
|
22307
|
+
const timestamp = extractTimestamp(value);
|
|
22308
|
+
if (timestamp === void 0) {
|
|
22309
|
+
return;
|
|
22310
|
+
}
|
|
22311
|
+
earliest = earliest === void 0 ? timestamp : Math.min(earliest, timestamp);
|
|
22312
|
+
});
|
|
22313
|
+
possibleEnds.forEach((value) => {
|
|
22314
|
+
const timestamp = extractTimestamp(value);
|
|
22315
|
+
if (timestamp === void 0) {
|
|
22316
|
+
return;
|
|
22317
|
+
}
|
|
22318
|
+
latest = latest === void 0 ? timestamp : Math.max(latest, timestamp);
|
|
22319
|
+
});
|
|
22320
|
+
});
|
|
22321
|
+
if (earliest === -1) {
|
|
22322
|
+
return "month";
|
|
22323
|
+
}
|
|
22324
|
+
if (earliest === void 0 || latest === void 0) {
|
|
22325
|
+
return void 0;
|
|
22326
|
+
}
|
|
22327
|
+
if (latest < earliest) {
|
|
22328
|
+
[earliest, latest] = [latest, earliest];
|
|
22329
|
+
}
|
|
22330
|
+
const diffInDays = Math.max(1, Math.round((latest - earliest) / MS_IN_DAY));
|
|
22331
|
+
if (diffInDays < 20) {
|
|
22332
|
+
return "day";
|
|
22333
|
+
}
|
|
22334
|
+
if (diffInDays <= 59) {
|
|
22335
|
+
return "week";
|
|
22336
|
+
}
|
|
22337
|
+
if (diffInDays <= 400) {
|
|
22338
|
+
return "month";
|
|
22339
|
+
}
|
|
22340
|
+
return "year";
|
|
22341
|
+
}
|
|
22342
|
+
function getDateRangeFromFilters(filters) {
|
|
22343
|
+
let earliest;
|
|
22344
|
+
let latest;
|
|
22345
|
+
const extractTimestamp = (value) => {
|
|
22346
|
+
if (!value) return void 0;
|
|
22347
|
+
if (value instanceof Date) return value.getTime();
|
|
22348
|
+
const parsed = Date.parse(value);
|
|
22349
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
22350
|
+
};
|
|
22351
|
+
(Array.isArray(filters) ? filters : []).forEach((filter) => {
|
|
22352
|
+
if (!filter || filter.filterType !== "date_range") return;
|
|
22353
|
+
if (filter.primaryRange?.value === "ALL_TIME") return;
|
|
22354
|
+
const possibleStarts = [
|
|
22355
|
+
filter.startDate,
|
|
22356
|
+
filter.start,
|
|
22357
|
+
filter.primaryRange?.startDate,
|
|
22358
|
+
filter.primaryRange?.start,
|
|
22359
|
+
filter.range?.startDate,
|
|
22360
|
+
filter.range?.start
|
|
22361
|
+
];
|
|
22362
|
+
const possibleEnds = [
|
|
22363
|
+
filter.endDate,
|
|
22364
|
+
filter.end,
|
|
22365
|
+
filter.primaryRange?.endDate,
|
|
22366
|
+
filter.primaryRange?.end,
|
|
22367
|
+
filter.range?.endDate,
|
|
22368
|
+
filter.range?.end
|
|
22369
|
+
];
|
|
22370
|
+
possibleStarts.forEach((v) => {
|
|
22371
|
+
const ts = extractTimestamp(v);
|
|
22372
|
+
if (ts === void 0) return;
|
|
22373
|
+
earliest = earliest === void 0 ? ts : Math.min(earliest, ts);
|
|
22374
|
+
});
|
|
22375
|
+
possibleEnds.forEach((v) => {
|
|
22376
|
+
const ts = extractTimestamp(v);
|
|
22377
|
+
if (ts === void 0) return;
|
|
22378
|
+
latest = latest === void 0 ? ts : Math.max(latest, ts);
|
|
22379
|
+
});
|
|
22380
|
+
});
|
|
22381
|
+
if (earliest === void 0 || latest === void 0) return void 0;
|
|
22382
|
+
if (latest < earliest) [earliest, latest] = [latest, earliest];
|
|
22383
|
+
return {
|
|
22384
|
+
start: new Date(earliest),
|
|
22385
|
+
end: new Date(latest)
|
|
22386
|
+
};
|
|
22387
|
+
}
|
|
22388
|
+
function generateBucketKeys(start2, end, bucket) {
|
|
22389
|
+
const keys = /* @__PURE__ */ new Set();
|
|
22390
|
+
const startDay = new Date(
|
|
22391
|
+
Date.UTC(start2.getUTCFullYear(), start2.getUTCMonth(), start2.getUTCDate())
|
|
22392
|
+
);
|
|
22393
|
+
const endDay = new Date(
|
|
22394
|
+
Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate())
|
|
22395
|
+
);
|
|
22396
|
+
const cur = new Date(startDay);
|
|
22397
|
+
while (cur <= endDay) {
|
|
22398
|
+
keys.add(getDateKey(cur, bucket));
|
|
22399
|
+
cur.setUTCDate(cur.getUTCDate() + 1);
|
|
22400
|
+
}
|
|
22401
|
+
return Array.from(keys).sort((a, b) => parseInt(a) - parseInt(b));
|
|
22402
|
+
}
|
|
22403
|
+
function buildEmptyAggRow(aggregations) {
|
|
22404
|
+
const multiAgg = aggregations.length > 1;
|
|
22405
|
+
const empty = {};
|
|
22406
|
+
aggregations.forEach((agg) => {
|
|
22407
|
+
const { aggregationType: type, valueField } = agg;
|
|
22408
|
+
const key = !valueField ? `${type}` + (multiAgg ? `_${type}` : "") : `${valueField}` + (multiAgg ? `_${type}` : "");
|
|
22409
|
+
empty[key] = 0;
|
|
22410
|
+
});
|
|
22411
|
+
return empty;
|
|
22412
|
+
}
|
|
22413
|
+
function getBucketRange(dateKey, bucket) {
|
|
22414
|
+
const d = new Date(parseInt(dateKey, 10));
|
|
22415
|
+
let start2 = new Date(d);
|
|
22416
|
+
let end = new Date(d);
|
|
22417
|
+
switch (bucket) {
|
|
22418
|
+
case "day":
|
|
22419
|
+
start2 = new Date(
|
|
22420
|
+
Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())
|
|
22421
|
+
);
|
|
22422
|
+
end = new Date(start2);
|
|
22423
|
+
break;
|
|
22424
|
+
case "week":
|
|
22425
|
+
start2 = new Date(d);
|
|
22426
|
+
end = new Date(start2);
|
|
22427
|
+
end.setUTCDate(start2.getUTCDate() + 6);
|
|
22428
|
+
break;
|
|
22429
|
+
case "month":
|
|
22430
|
+
start2 = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1));
|
|
22431
|
+
end = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0));
|
|
22432
|
+
break;
|
|
22433
|
+
case "year":
|
|
22434
|
+
start2 = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
22435
|
+
end = new Date(Date.UTC(d.getUTCFullYear(), 11, 31));
|
|
22436
|
+
break;
|
|
22437
|
+
}
|
|
22438
|
+
return { start: start2, end };
|
|
22439
|
+
}
|
|
22440
|
+
function formatBucketNameFromRange(start2, end, bucket) {
|
|
22441
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
22442
|
+
switch (bucket) {
|
|
22443
|
+
case "day":
|
|
22444
|
+
return `${pad(start2.getUTCDate())} ${MONTHS[start2.getUTCMonth()]} ${start2.getUTCFullYear()}`;
|
|
22445
|
+
case "week": {
|
|
22446
|
+
const sameMonth = start2.getUTCMonth() === end.getUTCMonth();
|
|
22447
|
+
return sameMonth ? `${MONTHS[start2.getUTCMonth()]} ${start2.getUTCDate()} - ${end.getUTCDate()}` : `${MONTHS[start2.getUTCMonth()]} ${start2.getUTCDate()} - ${MONTHS[end.getUTCMonth()]} ${end.getUTCDate()}`;
|
|
22448
|
+
}
|
|
22449
|
+
case "month":
|
|
22450
|
+
return `${MONTHS[start2.getUTCMonth()]} ${start2.getUTCFullYear()}`;
|
|
22451
|
+
case "year":
|
|
22452
|
+
return `${start2.getUTCFullYear()}`;
|
|
22453
|
+
default:
|
|
22454
|
+
return "";
|
|
22455
|
+
}
|
|
22456
|
+
}
|
|
22457
|
+
function getDateKey(date, bucket) {
|
|
22458
|
+
if (!isValidDate3(date)) {
|
|
22459
|
+
return INVALID_DATE_KEY;
|
|
22460
|
+
}
|
|
22461
|
+
switch (bucket) {
|
|
22462
|
+
case "day":
|
|
22463
|
+
return Date.UTC(
|
|
22464
|
+
date.getUTCFullYear(),
|
|
22465
|
+
date.getUTCMonth(),
|
|
22466
|
+
date.getUTCDate()
|
|
22467
|
+
).toString();
|
|
22468
|
+
case "week": {
|
|
22469
|
+
const day = date.getUTCDay();
|
|
22470
|
+
const mondayUtc = Date.UTC(
|
|
22471
|
+
date.getUTCFullYear(),
|
|
22472
|
+
date.getUTCMonth(),
|
|
22473
|
+
date.getUTCDate() - (day + 6) % 7
|
|
22474
|
+
);
|
|
22475
|
+
return mondayUtc.toString();
|
|
22476
|
+
}
|
|
22477
|
+
case "month":
|
|
22478
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString();
|
|
22479
|
+
case "year":
|
|
22480
|
+
return Date.UTC(date.getUTCFullYear(), 0, 1).toString();
|
|
22481
|
+
default:
|
|
22482
|
+
return INVALID_DATE_KEY;
|
|
22483
|
+
}
|
|
22484
|
+
}
|
|
22485
|
+
function sortRows(rows, pivot) {
|
|
22486
|
+
try {
|
|
22487
|
+
const { sort, sortField, sortFieldType, sortDirection } = pivot;
|
|
22488
|
+
if (!sort || sortField == null || sortFieldType == null) return rows;
|
|
22489
|
+
const sortFunc = isBoolType(sortFieldType) ? (a, b) => a === b ? 0 : a ? 1 : -1 : isDateType(sortFieldType) ? (a, b) => {
|
|
22490
|
+
const ta = new Date(a), tb = new Date(b);
|
|
22491
|
+
const aValid = isValidDate3(ta), bValid = isValidDate3(tb);
|
|
22492
|
+
if (!aValid && !bValid) return 0;
|
|
22493
|
+
if (!aValid) return 1;
|
|
22494
|
+
if (!bValid) return -1;
|
|
22495
|
+
return ta.getTime() - tb.getTime();
|
|
22496
|
+
} : isStringType(sortFieldType) ? (a, b) => a.localeCompare(b) : (a, b) => a - b;
|
|
22497
|
+
const dir = sortDirection === "ASC" ? 1 : -1;
|
|
22498
|
+
rows.sort((a, b) => {
|
|
22499
|
+
const av = a[sortField], bv = b[sortField];
|
|
22500
|
+
if (av == null && bv == null) return 0;
|
|
22501
|
+
if (av == null) return 1;
|
|
22502
|
+
if (bv == null) return -1;
|
|
22503
|
+
return dir * sortFunc(av, bv);
|
|
22504
|
+
});
|
|
22505
|
+
} catch {
|
|
22506
|
+
console.warn(`Sorting failed.`);
|
|
22507
|
+
}
|
|
22508
|
+
return rows;
|
|
22509
|
+
}
|
|
22510
|
+
function assembleFinalRows(seen, rowKey, dateBucket, dateRange) {
|
|
22511
|
+
const allColumns = /* @__PURE__ */ new Set();
|
|
22512
|
+
Object.keys(seen).forEach((rowKeyVal) => {
|
|
22513
|
+
Object.keys(seen[rowKeyVal]).forEach((col) => {
|
|
22514
|
+
allColumns.add(col);
|
|
22515
|
+
});
|
|
22516
|
+
});
|
|
22517
|
+
const filled = {};
|
|
22518
|
+
Object.keys(seen).forEach((rowKeyVal) => {
|
|
22519
|
+
filled[rowKeyVal] = {};
|
|
22520
|
+
allColumns.forEach((col) => {
|
|
22521
|
+
const value = seen[rowKeyVal][col];
|
|
22522
|
+
filled[rowKeyVal][col] = value ?? 0;
|
|
22523
|
+
});
|
|
22524
|
+
});
|
|
22525
|
+
if (dateBucket) {
|
|
22526
|
+
return Object.keys(filled).sort((a, b) => parseInt(a) - parseInt(b)).map((k) => {
|
|
22527
|
+
if (k === INVALID_DATE_KEY) {
|
|
22528
|
+
return { [rowKey]: "Invalid Date", ...filled[k], __quillRawDate: 0 };
|
|
22529
|
+
}
|
|
22530
|
+
const { start: start2, end } = getBucketRange(k, dateBucket);
|
|
22531
|
+
let bucketStart = start2;
|
|
22532
|
+
let bucketEnd = end;
|
|
22533
|
+
if (dateRange) {
|
|
22534
|
+
if (bucketStart < dateRange.start) bucketStart = dateRange.start;
|
|
22535
|
+
if (bucketEnd > dateRange.end) bucketEnd = dateRange.end;
|
|
22536
|
+
}
|
|
22537
|
+
return {
|
|
22538
|
+
[rowKey]: formatBucketNameFromRange(
|
|
22539
|
+
bucketStart,
|
|
22540
|
+
bucketEnd,
|
|
22541
|
+
dateBucket
|
|
22542
|
+
),
|
|
22543
|
+
...filled[k],
|
|
22544
|
+
__quillRawDate: bucketStart.toISOString()
|
|
22545
|
+
};
|
|
22546
|
+
});
|
|
22547
|
+
}
|
|
22548
|
+
return Object.keys(filled).sort().map((k) => ({ [rowKey]: k, ...filled[k] }));
|
|
22549
|
+
}
|
|
22550
|
+
function anyToNum(valueFieldType, obj) {
|
|
22551
|
+
if (!valueFieldType) {
|
|
22552
|
+
if (typeof obj === "number") return obj;
|
|
22553
|
+
if (typeof obj === "string" && !isNaN(Number(obj))) return Number(obj);
|
|
22554
|
+
return obj ? 1 : 0;
|
|
22555
|
+
}
|
|
22556
|
+
if (isNumberType(valueFieldType)) {
|
|
22557
|
+
return Number(obj);
|
|
22558
|
+
}
|
|
22559
|
+
return obj ? 1 : 0;
|
|
22560
|
+
}
|
|
22561
|
+
function updateAccumulator(acc, row, agg, isOneRow) {
|
|
22562
|
+
const {
|
|
22563
|
+
aggregationType: type,
|
|
22564
|
+
valueField,
|
|
22565
|
+
valueFieldType,
|
|
22566
|
+
valueField2,
|
|
22567
|
+
valueField2Type
|
|
22568
|
+
} = agg;
|
|
22569
|
+
if (!valueField) return;
|
|
22570
|
+
const distinctDenom = !!valueField2 && !!valueField2Type && valueField !== valueField2;
|
|
22571
|
+
const rawVal = row[valueField];
|
|
22572
|
+
if (valueFieldType && (type === "min" || type === "max") && (isDateType(valueFieldType) || isDateFormat2(valueFieldType))) {
|
|
22573
|
+
const dateVal = rawVal instanceof Date ? rawVal : new Date(rawVal);
|
|
22574
|
+
if (!isNaN(dateVal.getTime())) {
|
|
22575
|
+
if (type === "min") {
|
|
22576
|
+
acc.minDate = acc.minDate && acc.minDate.getTime() < dateVal.getTime() ? acc.minDate : dateVal;
|
|
22577
|
+
} else {
|
|
22578
|
+
acc.maxDate = acc.maxDate && acc.maxDate.getTime() > dateVal.getTime() ? acc.maxDate : dateVal;
|
|
22579
|
+
}
|
|
22580
|
+
}
|
|
22581
|
+
return;
|
|
22582
|
+
}
|
|
22583
|
+
const numVal = anyToNum(valueFieldType, rawVal);
|
|
22584
|
+
switch (type) {
|
|
22585
|
+
case "sum":
|
|
22586
|
+
acc.sum += numVal;
|
|
22587
|
+
break;
|
|
22588
|
+
case "average":
|
|
22589
|
+
case "avg":
|
|
22590
|
+
acc.sum += numVal;
|
|
22591
|
+
acc.count++;
|
|
22592
|
+
break;
|
|
22593
|
+
case "min":
|
|
22594
|
+
acc.min = acc.hasVal ? Math.min(acc.min, numVal) : numVal;
|
|
22595
|
+
acc.hasVal = true;
|
|
22596
|
+
break;
|
|
22597
|
+
case "max":
|
|
22598
|
+
acc.max = acc.hasVal ? Math.max(acc.max, numVal) : numVal;
|
|
22599
|
+
acc.hasVal = true;
|
|
22600
|
+
break;
|
|
22601
|
+
case "count":
|
|
22602
|
+
acc.count += numVal;
|
|
22603
|
+
break;
|
|
22604
|
+
case "percentage":
|
|
22605
|
+
acc.sum += numVal;
|
|
22606
|
+
acc.count += distinctDenom ? anyToNum(valueField2Type, row[valueField2]) : isOneRow ? 1 : numVal;
|
|
22607
|
+
break;
|
|
22608
|
+
}
|
|
22609
|
+
}
|
|
22610
|
+
function getFinalAggregationValue({
|
|
22611
|
+
type,
|
|
22612
|
+
valueFieldType,
|
|
22613
|
+
valueField,
|
|
22614
|
+
acc,
|
|
22615
|
+
distinctDenom = false,
|
|
22616
|
+
sumOfDenom,
|
|
22617
|
+
rowsLength,
|
|
22618
|
+
totalRowsForCount
|
|
22619
|
+
}) {
|
|
22620
|
+
if (valueFieldType && (type === "min" || type === "max") && (isDateType(valueFieldType) || isDateFormat2(valueFieldType))) {
|
|
22621
|
+
const dateVal = type === "min" ? acc.minDate : acc.maxDate;
|
|
22622
|
+
return dateVal?.toISOString() ?? "";
|
|
22623
|
+
}
|
|
22624
|
+
if (type === "count") {
|
|
22625
|
+
return totalRowsForCount ?? acc.count;
|
|
22626
|
+
}
|
|
22627
|
+
let final;
|
|
22628
|
+
if (!valueField && type === "percentage" && rowsLength !== void 0) {
|
|
22629
|
+
final = rowsLength ? (totalRowsForCount ?? 0) / rowsLength : 0;
|
|
22630
|
+
} else {
|
|
22631
|
+
switch (type) {
|
|
22632
|
+
case "sum":
|
|
22633
|
+
final = acc.sum;
|
|
22634
|
+
break;
|
|
22635
|
+
case "average":
|
|
22636
|
+
case "avg":
|
|
22637
|
+
final = acc.count ? acc.sum / acc.count : 0;
|
|
22638
|
+
break;
|
|
22639
|
+
case "min":
|
|
22640
|
+
final = acc.hasVal ? acc.min : 0;
|
|
22641
|
+
break;
|
|
22642
|
+
case "max":
|
|
22643
|
+
final = acc.hasVal ? acc.max : 0;
|
|
22644
|
+
break;
|
|
22645
|
+
case "percentage": {
|
|
22646
|
+
const denom = distinctDenom ? acc.count : sumOfDenom ?? acc.count;
|
|
22647
|
+
final = denom ? acc.sum / denom : 0;
|
|
22648
|
+
break;
|
|
22649
|
+
}
|
|
22650
|
+
default:
|
|
22651
|
+
final = 0;
|
|
22652
|
+
}
|
|
22653
|
+
}
|
|
22654
|
+
return final;
|
|
22655
|
+
}
|
|
22656
|
+
function aggregateToOneRow(rows, aggregations) {
|
|
22657
|
+
const multiAgg = aggregations.length > 1;
|
|
22658
|
+
const resultArray = aggregations.map((agg) => {
|
|
22659
|
+
const { aggregationType: type, valueField, valueFieldType } = agg;
|
|
22660
|
+
if (!valueField) {
|
|
22661
|
+
if (type !== "count") {
|
|
22662
|
+
return {};
|
|
22663
|
+
}
|
|
22664
|
+
const finalKey2 = "count" + (multiAgg ? "_count" : "");
|
|
22665
|
+
return { [finalKey2]: rows.length };
|
|
22666
|
+
}
|
|
22667
|
+
const finalKey = `${valueField}` + (multiAgg ? `_${type}` : "");
|
|
22668
|
+
const acc = {
|
|
22669
|
+
sum: 0,
|
|
22670
|
+
count: 0,
|
|
22671
|
+
min: Infinity,
|
|
22672
|
+
max: -Infinity,
|
|
22673
|
+
hasVal: false,
|
|
22674
|
+
minDate: null,
|
|
22675
|
+
maxDate: null
|
|
22676
|
+
};
|
|
22677
|
+
for (const row of rows) {
|
|
22678
|
+
updateAccumulator(acc, row, agg, true);
|
|
22679
|
+
}
|
|
22680
|
+
return {
|
|
22681
|
+
[finalKey]: getFinalAggregationValue({
|
|
22682
|
+
type,
|
|
22683
|
+
valueFieldType,
|
|
22684
|
+
valueField,
|
|
22685
|
+
acc,
|
|
22686
|
+
totalRowsForCount: acc.count
|
|
22687
|
+
})
|
|
22688
|
+
};
|
|
22689
|
+
});
|
|
22690
|
+
return [
|
|
22691
|
+
resultArray.reduce((acc, current) => {
|
|
22692
|
+
return { ...acc, ...current };
|
|
22693
|
+
}, {})
|
|
22694
|
+
];
|
|
22695
|
+
}
|
|
22696
|
+
function aggregateWithColumn(rows, colKey, aggregations, getGroupKey) {
|
|
22697
|
+
if (!colKey) return;
|
|
22698
|
+
const seen = {};
|
|
22699
|
+
const multiAgg = aggregations.length > 1;
|
|
22700
|
+
aggregations.forEach((agg) => {
|
|
22701
|
+
const {
|
|
22702
|
+
aggregationType: type,
|
|
22703
|
+
valueField,
|
|
22704
|
+
valueFieldType,
|
|
22705
|
+
valueField2,
|
|
22706
|
+
valueField2Type
|
|
22707
|
+
} = agg;
|
|
22708
|
+
if (!valueField) {
|
|
22709
|
+
if (type !== "count" && type !== "percentage") return;
|
|
22710
|
+
}
|
|
22711
|
+
const distinctDenom = !!valueField2 && !!valueField2Type && valueField !== valueField2;
|
|
22712
|
+
const accs = {};
|
|
22713
|
+
rows.forEach((row) => {
|
|
22714
|
+
const groupKey = getGroupKey(row);
|
|
22715
|
+
const colVal = row[colKey];
|
|
22716
|
+
if (!accs[groupKey]) accs[groupKey] = {};
|
|
22717
|
+
if (!accs[groupKey][colVal]) {
|
|
22718
|
+
accs[groupKey][colVal] = {
|
|
22719
|
+
sum: 0,
|
|
22720
|
+
count: 0,
|
|
22721
|
+
min: Infinity,
|
|
22722
|
+
max: -Infinity,
|
|
22723
|
+
hasVal: false,
|
|
22724
|
+
minDate: null,
|
|
22725
|
+
maxDate: null,
|
|
22726
|
+
totalRows: 0
|
|
22727
|
+
};
|
|
22728
|
+
}
|
|
22729
|
+
const acc = accs[groupKey][colVal];
|
|
22730
|
+
acc.totalRows += 1;
|
|
22731
|
+
if (!valueField) {
|
|
22732
|
+
if (type === "count") acc.count += 1;
|
|
22733
|
+
else if (type === "percentage") acc.sum += 1;
|
|
22734
|
+
return;
|
|
22735
|
+
}
|
|
22736
|
+
updateAccumulator(acc, row, agg, false);
|
|
22737
|
+
});
|
|
22738
|
+
Object.keys(accs).forEach((groupKey) => {
|
|
22739
|
+
if (!seen[groupKey]) seen[groupKey] = {};
|
|
22740
|
+
const sumOfDenom = Object.values(accs[groupKey]).reduce(
|
|
22741
|
+
(t, a) => t + a.count,
|
|
22742
|
+
0
|
|
22743
|
+
);
|
|
22744
|
+
Object.keys(accs[groupKey]).forEach((colVal) => {
|
|
22745
|
+
const acc = accs[groupKey][colVal];
|
|
22746
|
+
const finalKey = `${colVal}` + (multiAgg ? `_${type}` : "");
|
|
22747
|
+
seen[groupKey][finalKey] = getFinalAggregationValue({
|
|
22748
|
+
type,
|
|
22749
|
+
valueFieldType,
|
|
22750
|
+
valueField,
|
|
22751
|
+
acc,
|
|
22752
|
+
distinctDenom,
|
|
22753
|
+
sumOfDenom,
|
|
22754
|
+
totalRowsForCount: acc.totalRows
|
|
22755
|
+
});
|
|
22756
|
+
});
|
|
22757
|
+
});
|
|
22758
|
+
});
|
|
22759
|
+
return seen;
|
|
22760
|
+
}
|
|
22761
|
+
function aggregateWithoutColumn(rows, aggregations, getGroupKey) {
|
|
22762
|
+
const seen = {};
|
|
22763
|
+
const multiAgg = aggregations.length > 1;
|
|
22764
|
+
aggregations.forEach((agg) => {
|
|
22765
|
+
const {
|
|
22766
|
+
aggregationType: type,
|
|
22767
|
+
valueField,
|
|
22768
|
+
valueFieldType,
|
|
22769
|
+
valueField2,
|
|
22770
|
+
valueField2Type
|
|
22771
|
+
} = agg;
|
|
22772
|
+
if (!valueField) {
|
|
22773
|
+
if (type !== "count" && type !== "percentage") return;
|
|
22774
|
+
}
|
|
22775
|
+
const finalKey = !valueField ? `${type}` + (multiAgg ? `_${type}` : "") : `${valueField}` + (multiAgg ? `_${type}` : "");
|
|
22776
|
+
const distinctDenom = !!valueField2 && !!valueField2Type && valueField !== valueField2;
|
|
22777
|
+
const accs = {};
|
|
22778
|
+
rows.forEach((row) => {
|
|
22779
|
+
const key = getGroupKey(row);
|
|
22780
|
+
if (!seen[key]) seen[key] = {};
|
|
22781
|
+
if (!accs[key]) {
|
|
22782
|
+
accs[key] = {
|
|
22783
|
+
sum: 0,
|
|
22784
|
+
count: 0,
|
|
22785
|
+
min: Infinity,
|
|
22786
|
+
max: -Infinity,
|
|
22787
|
+
hasVal: false,
|
|
22788
|
+
minDate: null,
|
|
22789
|
+
maxDate: null,
|
|
22790
|
+
totalRows: 0
|
|
22791
|
+
};
|
|
22792
|
+
}
|
|
22793
|
+
const acc = accs[key];
|
|
22794
|
+
acc.totalRows += 1;
|
|
22795
|
+
if (!valueField) {
|
|
22796
|
+
if (type === "count") acc.count += 1;
|
|
22797
|
+
else if (type === "percentage") acc.sum += 1;
|
|
22798
|
+
return;
|
|
22799
|
+
}
|
|
22800
|
+
updateAccumulator(acc, row, agg, false);
|
|
22801
|
+
});
|
|
22802
|
+
const sumOfDenom = Object.values(accs).reduce(
|
|
22803
|
+
(t, a) => t + a.count,
|
|
22804
|
+
0
|
|
22805
|
+
);
|
|
22806
|
+
Object.keys(accs).forEach((k) => {
|
|
22807
|
+
const acc = accs[k];
|
|
22808
|
+
seen[k][finalKey] = getFinalAggregationValue({
|
|
22809
|
+
type,
|
|
22810
|
+
valueFieldType,
|
|
22811
|
+
valueField,
|
|
22812
|
+
acc,
|
|
22813
|
+
distinctDenom,
|
|
22814
|
+
sumOfDenom,
|
|
22815
|
+
rowsLength: rows.length,
|
|
22816
|
+
totalRowsForCount: acc.totalRows
|
|
22817
|
+
});
|
|
22818
|
+
});
|
|
22819
|
+
});
|
|
22820
|
+
return seen;
|
|
22821
|
+
}
|
|
22822
|
+
function applyPivotInMemory(rows, pivot, filters) {
|
|
22823
|
+
if (!pivot) return rows;
|
|
22824
|
+
const multiAggPivot = pivot.aggregations ? pivot : singleAggToMultiAgg(pivot);
|
|
22825
|
+
if (multiAggPivot.rowField === void 0) {
|
|
22826
|
+
return aggregateToOneRow(rows, multiAggPivot.aggregations);
|
|
22827
|
+
}
|
|
22828
|
+
const { rowField, columnField, aggregations } = multiAggPivot;
|
|
22829
|
+
const dateBucket = inferDateBucketFromFilters(pivot, filters);
|
|
22830
|
+
const dateRange = dateBucket ? getDateRangeFromFilters(filters) : void 0;
|
|
22831
|
+
const getRowKey = dateBucket ? (row) => {
|
|
22832
|
+
const rawValue = row[rowField];
|
|
22833
|
+
const rawDateFromQuill = row.__quillRawDate;
|
|
22834
|
+
const rawDateValue = rawDateFromQuill ?? (rawValue !== null && typeof rawValue === "object" && rawValue.value ? rawValue.value : rawValue);
|
|
22835
|
+
return getDateKey(new Date(rawDateValue), dateBucket);
|
|
22836
|
+
} : (row) => row[rowField];
|
|
22837
|
+
const aggregated = columnField ? aggregateWithColumn(rows, columnField, aggregations, getRowKey) : aggregateWithoutColumn(rows, aggregations, getRowKey);
|
|
22838
|
+
const aggregatedRows = aggregated || {};
|
|
22839
|
+
if (rows.length === 0 && dateBucket && dateRange && !columnField) {
|
|
22840
|
+
const bucketKeys = generateBucketKeys(
|
|
22841
|
+
dateRange.start,
|
|
22842
|
+
dateRange.end,
|
|
22843
|
+
dateBucket
|
|
22844
|
+
);
|
|
22845
|
+
const emptyAgg = buildEmptyAggRow(aggregations);
|
|
22846
|
+
bucketKeys.forEach((k) => {
|
|
22847
|
+
aggregatedRows[k] = { ...emptyAgg };
|
|
22848
|
+
});
|
|
22849
|
+
}
|
|
22850
|
+
const finalRows = assembleFinalRows(
|
|
22851
|
+
aggregatedRows,
|
|
22852
|
+
rowField,
|
|
22853
|
+
dateBucket,
|
|
22854
|
+
rows.length === 0 ? dateRange : void 0
|
|
22855
|
+
);
|
|
22856
|
+
const sorted = sortRows(finalRows, pivot);
|
|
22857
|
+
if (pivot.rowLimit) {
|
|
22858
|
+
return sorted.slice(0, pivot.rowLimit);
|
|
22859
|
+
}
|
|
22860
|
+
return sorted;
|
|
22861
|
+
}
|
|
22862
|
+
function generatePivotColumnsInMemory({
|
|
22863
|
+
pivot,
|
|
22864
|
+
pivotRows,
|
|
22865
|
+
sourceColumns
|
|
22866
|
+
}) {
|
|
22867
|
+
if (!pivot?.rowField || !Array.isArray(pivotRows) || pivotRows.length === 0) {
|
|
22868
|
+
return void 0;
|
|
22869
|
+
}
|
|
22870
|
+
const columns = Array.isArray(sourceColumns) ? sourceColumns : [];
|
|
22871
|
+
const rowSource = columns.find((col) => col.field === pivot.rowField);
|
|
22872
|
+
const isRowFieldDate = isDateLikeType(pivot.rowFieldType);
|
|
22873
|
+
const rowFieldType = rowSource?.fieldType ?? pivot.rowFieldType ?? "string";
|
|
22874
|
+
const rowColumn = {
|
|
22875
|
+
field: pivot.rowField,
|
|
22876
|
+
label: rowSource?.label ?? pivot.rowField,
|
|
22877
|
+
format: isRowFieldDate ? "string" : rowSource?.format ?? "string",
|
|
22878
|
+
fieldType: rowFieldType,
|
|
22879
|
+
dataTypeID: rowSource?.dataTypeID ?? 1043,
|
|
22880
|
+
jsType: rowSource?.jsType ?? (isRowFieldDate ? "date" : "string")
|
|
22881
|
+
};
|
|
22882
|
+
const valueFieldFormat = (valueField) => columns.find((col) => col.field === valueField)?.format ?? "whole_number";
|
|
22883
|
+
const multiAgg = (pivot.aggregations?.length ?? 0) > 1;
|
|
22884
|
+
const aggregationBySuffix = new Map(
|
|
22885
|
+
(pivot.aggregations ?? []).map((agg) => [
|
|
22886
|
+
multiAgg ? `_${agg.aggregationType}` : "",
|
|
22887
|
+
agg
|
|
22888
|
+
])
|
|
22889
|
+
);
|
|
22890
|
+
const valueKeys = Array.from(
|
|
22891
|
+
new Set(
|
|
22892
|
+
pivotRows.flatMap(
|
|
22893
|
+
(row) => Object.keys(row).filter(
|
|
22894
|
+
(key) => key !== pivot.rowField && key !== "__quillRawDate"
|
|
22895
|
+
)
|
|
22896
|
+
)
|
|
22897
|
+
)
|
|
22898
|
+
);
|
|
22899
|
+
const valueColumns = valueKeys.map((key) => {
|
|
22900
|
+
const matchingSuffix = Array.from(aggregationBySuffix.keys()).find(
|
|
22901
|
+
(suffix) => suffix && key.endsWith(suffix)
|
|
22902
|
+
);
|
|
22903
|
+
const matchedAgg = matchingSuffix ? aggregationBySuffix.get(matchingSuffix) : pivot.aggregations?.[0];
|
|
22904
|
+
const format9 = matchedAgg?.aggregationType === "percentage" ? "percent" : valueFieldFormat(matchedAgg?.valueField);
|
|
22905
|
+
const valueFieldType = matchedAgg?.valueFieldType ?? "number";
|
|
22906
|
+
return {
|
|
22907
|
+
field: key,
|
|
22908
|
+
label: key,
|
|
22909
|
+
format: format9,
|
|
22910
|
+
fieldType: valueFieldType,
|
|
22911
|
+
jsType: valueFieldType,
|
|
22912
|
+
dataTypeID: columns.find((col) => col.field === matchedAgg?.valueField)?.dataTypeID ?? 20
|
|
22913
|
+
};
|
|
22914
|
+
});
|
|
22915
|
+
return [rowColumn, ...valueColumns];
|
|
22916
|
+
}
|
|
22917
|
+
|
|
22918
|
+
// src/utils/cacheCab.ts
|
|
22919
|
+
import { openDB } from "idb";
|
|
22920
|
+
import { endOfDay as endOfDay3, max as maxDate, subMonths as subMonths4, min as minDate, startOfDay as startOfDay4 } from "date-fns";
|
|
22921
|
+
import { utcToZonedTime as utcToZonedTime2, zonedTimeToUtc } from "date-fns-tz";
|
|
22922
|
+
var TZ = "America/Los_Angeles";
|
|
22923
|
+
var CacheCab = class {
|
|
22924
|
+
fetchedRange = {};
|
|
22925
|
+
cachedReportIds = [];
|
|
22926
|
+
uncacheableReportIDs = [];
|
|
22927
|
+
uncacheableInFlight = /* @__PURE__ */ new Map();
|
|
22928
|
+
storage;
|
|
22929
|
+
META_KEY = "cachecab:meta";
|
|
22930
|
+
DATA_PREFIX = "cachecab:data:";
|
|
22931
|
+
UNCACHEABLE_PREFIX = "cachecab:uncacheable:";
|
|
22932
|
+
constructor({
|
|
22933
|
+
storageType = "memory"
|
|
22934
|
+
} = {}) {
|
|
22935
|
+
this.storage = storageType !== "idb" ? new MemoryStorage() : new IdbStorage();
|
|
22936
|
+
void this.loadMetaFromStorage();
|
|
22937
|
+
}
|
|
22938
|
+
async get(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, pageSize, getToken, eventTracking, forceRefresh) {
|
|
22939
|
+
if (this.isCached(reportId, tenants) && !forceRefresh) {
|
|
22940
|
+
return this.getFromCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking);
|
|
22941
|
+
} else {
|
|
22942
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, true, forceRefresh);
|
|
22943
|
+
}
|
|
22944
|
+
}
|
|
22945
|
+
isCached(reportId, tenants) {
|
|
22946
|
+
return this.cachedReportIds.includes(this.getCacheKey(reportId, tenants));
|
|
22947
|
+
}
|
|
22948
|
+
isCacheable(reportId) {
|
|
22949
|
+
return !this.uncacheableReportIDs.includes(reportId);
|
|
22950
|
+
}
|
|
22951
|
+
async getUncacheableResult(reportId, client, tenants, flags, filters, additionalProcessing, pivot) {
|
|
22952
|
+
const key = this.getUncacheableRequestKey(
|
|
22953
|
+
reportId,
|
|
22954
|
+
client,
|
|
22955
|
+
tenants,
|
|
22956
|
+
flags,
|
|
22957
|
+
filters,
|
|
22958
|
+
additionalProcessing,
|
|
22959
|
+
pivot
|
|
22960
|
+
);
|
|
22961
|
+
try {
|
|
22962
|
+
const raw = await this.storage.getItem(key);
|
|
22963
|
+
return raw ? JSON.parse(raw) : null;
|
|
22964
|
+
} catch {
|
|
22965
|
+
return null;
|
|
22966
|
+
}
|
|
22967
|
+
}
|
|
22968
|
+
async setUncacheableResult(reportId, client, tenants, flags, filters, additionalProcessing, pivot, report) {
|
|
22969
|
+
const key = this.getUncacheableRequestKey(
|
|
22970
|
+
reportId,
|
|
22971
|
+
client,
|
|
22972
|
+
tenants,
|
|
22973
|
+
flags,
|
|
22974
|
+
filters,
|
|
22975
|
+
additionalProcessing,
|
|
22976
|
+
pivot
|
|
22977
|
+
);
|
|
22978
|
+
try {
|
|
22979
|
+
await this.storage.setItem(key, JSON.stringify(report));
|
|
22980
|
+
} catch {
|
|
22981
|
+
}
|
|
22982
|
+
}
|
|
22983
|
+
async getOrFetchUncacheableResult(reportId, client, tenants, flags, filters, additionalProcessing, pivot, fetcher, forceRefresh = false) {
|
|
22984
|
+
const key = this.getUncacheableRequestKey(
|
|
22985
|
+
reportId,
|
|
22986
|
+
client,
|
|
22987
|
+
tenants,
|
|
22988
|
+
flags,
|
|
22989
|
+
filters,
|
|
22990
|
+
additionalProcessing,
|
|
22991
|
+
pivot
|
|
22992
|
+
);
|
|
22993
|
+
if (!forceRefresh) {
|
|
22994
|
+
const raw = await this.storage.getItem(key);
|
|
22995
|
+
if (raw) {
|
|
22996
|
+
return { report: JSON.parse(raw), fromCache: true };
|
|
22997
|
+
}
|
|
22998
|
+
const inFlight = this.uncacheableInFlight.get(key);
|
|
22999
|
+
if (inFlight) {
|
|
23000
|
+
const report = await inFlight;
|
|
23001
|
+
return { report, fromCache: false };
|
|
23002
|
+
}
|
|
23003
|
+
}
|
|
23004
|
+
const requestPromise = (async () => {
|
|
23005
|
+
const report = await fetcher();
|
|
23006
|
+
try {
|
|
23007
|
+
await this.storage.setItem(key, JSON.stringify(report));
|
|
23008
|
+
} catch {
|
|
23009
|
+
}
|
|
23010
|
+
return report;
|
|
23011
|
+
})();
|
|
23012
|
+
this.uncacheableInFlight.set(key, requestPromise);
|
|
23013
|
+
try {
|
|
23014
|
+
const report = await requestPromise;
|
|
23015
|
+
return { report, fromCache: false };
|
|
23016
|
+
} finally {
|
|
23017
|
+
this.uncacheableInFlight.delete(key);
|
|
23018
|
+
}
|
|
23019
|
+
}
|
|
23020
|
+
async addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, firstTime = true, forceRefresh = false) {
|
|
23021
|
+
const tenantPart = tenants ? JSON.stringify(tenants) : "";
|
|
23022
|
+
const cacheKey = this.getCacheKey(reportId, tenants);
|
|
23023
|
+
if (firstTime) {
|
|
23024
|
+
const result = await this.fetchInitialReport({ reportId, client, tenants, flags, filters: dashboardFilters, getToken, eventTracking, forceRefresh });
|
|
23025
|
+
try {
|
|
23026
|
+
await this.storage.setItem(this.DATA_PREFIX + cacheKey, JSON.stringify(result));
|
|
23027
|
+
this.cachedReportIds.push(cacheKey);
|
|
23028
|
+
await this.persistMetaToStorage();
|
|
23029
|
+
} catch {
|
|
23030
|
+
console.warn(`Failed to cache report: ${reportId}. Cache full?`);
|
|
23031
|
+
}
|
|
23032
|
+
const newRows = await this.applyPivotsAndFilters(result, dashboardFilters, customFilters, pivot, tenantPart, false);
|
|
23033
|
+
if (pivot) {
|
|
23034
|
+
const pivotColumns = generatePivotColumnsInMemory({
|
|
23035
|
+
pivot,
|
|
23036
|
+
pivotRows: newRows,
|
|
23037
|
+
sourceColumns: result.columnInternal ?? result.columns
|
|
23038
|
+
});
|
|
23039
|
+
return { ...result, pivotRows: newRows, pivotColumns: pivotColumns ?? result.pivotColumns, pivotRowCount: newRows.length };
|
|
23040
|
+
}
|
|
23041
|
+
return { ...result, rows: newRows, rowCount: newRows.length };
|
|
23042
|
+
} else {
|
|
23043
|
+
const dbDateFilter = dashboardFilters.find((x) => x.filterType === "date_range");
|
|
23044
|
+
const { start: requestedStart, end: requestedEnd } = normalizePSTRanges(
|
|
23045
|
+
dbDateFilter?.startDate ? new Date(dbDateFilter.startDate) : void 0,
|
|
23046
|
+
dbDateFilter?.endDate ? new Date(dbDateFilter.endDate) : void 0
|
|
23047
|
+
);
|
|
23048
|
+
if (!requestedStart || !requestedEnd) {
|
|
23049
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, true);
|
|
23050
|
+
}
|
|
23051
|
+
const currentRange = this.fetchedRange[cacheKey];
|
|
23052
|
+
const rangeStart = currentRange?.start ?? requestedStart;
|
|
23053
|
+
const rangeEnd = currentRange?.end ?? endOfDayPST(/* @__PURE__ */ new Date());
|
|
23054
|
+
const existingRaw = await this.storage.getItem(this.DATA_PREFIX + cacheKey);
|
|
23055
|
+
let existing;
|
|
23056
|
+
let fetchedRows = [];
|
|
23057
|
+
try {
|
|
23058
|
+
existing = JSON.parse(existingRaw);
|
|
23059
|
+
if (!existing.rows) {
|
|
23060
|
+
throw new Error("Invalid Cache!");
|
|
23061
|
+
}
|
|
23062
|
+
if (requestedStart < rangeStart) {
|
|
23063
|
+
const olderReport = await this.fetchReport({
|
|
23064
|
+
reportId,
|
|
23065
|
+
client,
|
|
23066
|
+
tenants,
|
|
23067
|
+
flags,
|
|
23068
|
+
filters: dashboardFilters,
|
|
23069
|
+
getToken,
|
|
23070
|
+
eventTracking,
|
|
23071
|
+
start: requestedStart,
|
|
23072
|
+
end: rangeStart
|
|
23073
|
+
});
|
|
23074
|
+
fetchedRows = olderReport.rows;
|
|
23075
|
+
}
|
|
23076
|
+
if (requestedEnd && requestedEnd > rangeEnd) {
|
|
23077
|
+
const newerReport = await this.fetchReport({
|
|
23078
|
+
reportId,
|
|
23079
|
+
client,
|
|
23080
|
+
tenants,
|
|
23081
|
+
flags,
|
|
23082
|
+
filters: dashboardFilters,
|
|
23083
|
+
getToken,
|
|
23084
|
+
eventTracking,
|
|
23085
|
+
start: rangeEnd,
|
|
23086
|
+
end: requestedEnd
|
|
23087
|
+
});
|
|
23088
|
+
fetchedRows = fetchedRows.concat(newerReport.rows);
|
|
23089
|
+
}
|
|
23090
|
+
} catch {
|
|
23091
|
+
existing = await this.fetchReport({
|
|
23092
|
+
reportId,
|
|
23093
|
+
client,
|
|
23094
|
+
tenants,
|
|
23095
|
+
flags,
|
|
23096
|
+
filters: dashboardFilters,
|
|
23097
|
+
getToken,
|
|
23098
|
+
eventTracking,
|
|
23099
|
+
start: requestedStart,
|
|
23100
|
+
end: requestedEnd
|
|
23101
|
+
});
|
|
23102
|
+
fetchedRows = existing.rows;
|
|
23103
|
+
}
|
|
23104
|
+
const dateKey = existing.dateField?.field ? removeQuotes(existing.dateField.field) : void 0;
|
|
23105
|
+
let mergedRows;
|
|
23106
|
+
if (dateKey) {
|
|
23107
|
+
const startMs = rangeStart.getTime();
|
|
23108
|
+
const endMs = rangeEnd.getTime();
|
|
23109
|
+
const boundaryRows = existing.rows.filter((row) => {
|
|
23110
|
+
const raw = row[dateKey];
|
|
23111
|
+
if (!raw) return false;
|
|
23112
|
+
const t = new Date(raw).getTime();
|
|
23113
|
+
return Math.abs(t - startMs) <= MS_IN_DAY || Math.abs(t - endMs) <= MS_IN_DAY;
|
|
23114
|
+
});
|
|
23115
|
+
const filteredNew = filterNewRows(boundaryRows, fetchedRows);
|
|
23116
|
+
mergedRows = filteredNew.concat(existing.rows);
|
|
23117
|
+
} else {
|
|
23118
|
+
mergedRows = filterNewRows(existing.rows, fetchedRows).concat(existing.rows);
|
|
23119
|
+
}
|
|
23120
|
+
const merged = { ...existing, rows: mergedRows };
|
|
23121
|
+
await this.storage.setItem(this.DATA_PREFIX + cacheKey, JSON.stringify(merged));
|
|
23122
|
+
await this.persistMetaToStorage();
|
|
23123
|
+
const newRows = await this.applyPivotsAndFilters(merged, dashboardFilters, customFilters, pivot, tenantPart, false);
|
|
23124
|
+
if (pivot) {
|
|
23125
|
+
const pivotColumns = generatePivotColumnsInMemory({
|
|
23126
|
+
pivot,
|
|
23127
|
+
pivotRows: newRows,
|
|
23128
|
+
sourceColumns: merged.columnInternal ?? merged.columns
|
|
23129
|
+
});
|
|
23130
|
+
return { ...merged, pivotRows: newRows, pivotColumns: pivotColumns ?? merged.pivotColumns, pivotRowCount: newRows.length };
|
|
23131
|
+
}
|
|
23132
|
+
return { ...merged, rows: newRows, rowCount: newRows.length };
|
|
23133
|
+
}
|
|
23134
|
+
}
|
|
23135
|
+
/**
|
|
23136
|
+
* Returns cache entry (or re-queries if stale)
|
|
23137
|
+
*/
|
|
23138
|
+
async getFromCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking) {
|
|
23139
|
+
const dateRangeFilter = dashboardFilters.find((x) => x.filterType === "date_range");
|
|
23140
|
+
const cacheKey = this.getCacheKey(reportId, tenants);
|
|
23141
|
+
if (!dateRangeFilter || dateRangeFilter?.primaryRange.value === "ALL_TIME") {
|
|
23142
|
+
const fetchInfo = this.fetchedRange[cacheKey];
|
|
23143
|
+
if (!fetchInfo || fetchInfo?.allTimeDoneBefore === false || Date.now() - fetchInfo.fetchedAtUTCMS >= MS_IN_DAY) {
|
|
23144
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, true);
|
|
23145
|
+
}
|
|
23146
|
+
} else if (this.weShouldReQuery(cacheKey, dateRangeFilter)) {
|
|
23147
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, false);
|
|
23148
|
+
}
|
|
23149
|
+
try {
|
|
23150
|
+
const raw = await this.storage.getItem(this.DATA_PREFIX + cacheKey);
|
|
23151
|
+
if (!raw) {
|
|
23152
|
+
throw new Error("Invalid Cache!");
|
|
23153
|
+
}
|
|
23154
|
+
const parsed = JSON.parse(raw);
|
|
23155
|
+
const tenantPart = tenants ? JSON.stringify(tenants) : "";
|
|
23156
|
+
const newRows = await this.applyPivotsAndFilters(parsed, dashboardFilters, customFilters, pivot, tenantPart);
|
|
23157
|
+
if (pivot) {
|
|
23158
|
+
const pivotColumns = generatePivotColumnsInMemory({
|
|
23159
|
+
pivot,
|
|
23160
|
+
pivotRows: newRows,
|
|
23161
|
+
sourceColumns: parsed.columnInternal ?? parsed.columns
|
|
23162
|
+
});
|
|
23163
|
+
return { ...parsed, pivotRows: newRows, pivotColumns: pivotColumns ?? parsed.pivotColumns, pivotRowCount: newRows.length };
|
|
23164
|
+
}
|
|
23165
|
+
return { ...parsed, rows: newRows, rowCount: newRows.length };
|
|
23166
|
+
} catch (err) {
|
|
23167
|
+
console.error(err);
|
|
23168
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, false);
|
|
23169
|
+
}
|
|
23170
|
+
}
|
|
23171
|
+
weShouldReQuery(cacheKey, dateRangeFilter) {
|
|
23172
|
+
const start2 = dateRangeFilter.startDate;
|
|
23173
|
+
const end = dateRangeFilter.endDate;
|
|
23174
|
+
const range = this.fetchedRange[cacheKey];
|
|
23175
|
+
const { start: s, end: e } = normalizePSTRanges(
|
|
23176
|
+
start2 ? new Date(start2) : void 0,
|
|
23177
|
+
end ? new Date(end) : void 0
|
|
23178
|
+
);
|
|
23179
|
+
return !range || !s || !e || range.start > s || range.end < e;
|
|
23180
|
+
}
|
|
23181
|
+
async fetchInitialReport({
|
|
23182
|
+
reportId,
|
|
23183
|
+
client,
|
|
23184
|
+
tenants,
|
|
23185
|
+
flags,
|
|
23186
|
+
filters = [],
|
|
23187
|
+
getToken,
|
|
23188
|
+
eventTracking,
|
|
23189
|
+
forceRefresh
|
|
23190
|
+
}) {
|
|
23191
|
+
let start2;
|
|
23192
|
+
let end;
|
|
23193
|
+
const dateRangeFilter = filters.find((x) => x.filterType === "date_range");
|
|
23194
|
+
const cacheRange = dateRangeFilter?.initialCacheDateRange;
|
|
23195
|
+
if (cacheRange && cacheRange.startDate) {
|
|
23196
|
+
const startDate = dateRangeFilter?.startDate;
|
|
23197
|
+
start2 = startDate ? minDate([new Date(cacheRange.startDate), new Date(startDate)]) : new Date(cacheRange.startDate);
|
|
23198
|
+
end = endOfDayPST(/* @__PURE__ */ new Date());
|
|
23199
|
+
} else {
|
|
23200
|
+
const endDate = dateRangeFilter?.endDate ? new Date(dateRangeFilter.endDate) : void 0;
|
|
23201
|
+
const currentDay = endOfDayPST(/* @__PURE__ */ new Date());
|
|
23202
|
+
end = endDate ? maxDate([currentDay, endDate]) : currentDay;
|
|
23203
|
+
start2 = subMonths4(end, 7);
|
|
23204
|
+
}
|
|
23205
|
+
const normalized = normalizePSTRanges(start2, end);
|
|
23206
|
+
return this.fetchReport({
|
|
23207
|
+
reportId,
|
|
23208
|
+
client,
|
|
23209
|
+
tenants,
|
|
23210
|
+
flags,
|
|
23211
|
+
filters,
|
|
23212
|
+
getToken,
|
|
23213
|
+
eventTracking,
|
|
23214
|
+
start: normalized.start,
|
|
23215
|
+
end: normalized.end,
|
|
23216
|
+
forceRefresh
|
|
23217
|
+
});
|
|
23218
|
+
}
|
|
23219
|
+
async fetchReport({
|
|
23220
|
+
reportId,
|
|
23221
|
+
client,
|
|
23222
|
+
tenants,
|
|
23223
|
+
flags,
|
|
23224
|
+
filters = [],
|
|
23225
|
+
getToken,
|
|
23226
|
+
eventTracking,
|
|
23227
|
+
start: start2,
|
|
23228
|
+
end,
|
|
23229
|
+
forceRefresh
|
|
23230
|
+
}) {
|
|
23231
|
+
let reportInfo = void 0;
|
|
23232
|
+
try {
|
|
23233
|
+
const { start: s, end: e } = normalizePSTRanges(start2, end);
|
|
23234
|
+
const adjusted = [...filters].map((x) => {
|
|
23235
|
+
return { ...x, options: void 0 };
|
|
23236
|
+
});
|
|
23237
|
+
const dateFilterIndex = adjusted.findIndex((x) => x.filterType === "date_range");
|
|
23238
|
+
const isAllTime = dateFilterIndex !== -1 && adjusted[dateFilterIndex].primaryRange?.value === "ALL_TIME";
|
|
23239
|
+
if (!isAllTime) {
|
|
23240
|
+
const dateFilter = adjusted[dateFilterIndex];
|
|
23241
|
+
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
23242
|
+
adjusted[dateFilterIndex] = { ...dateFilter, startDate: s, endDate: e };
|
|
23243
|
+
}
|
|
23244
|
+
}
|
|
23245
|
+
const fetchResp = await quillFetch({
|
|
23246
|
+
client,
|
|
23247
|
+
task: "report",
|
|
23248
|
+
metadata: {
|
|
23249
|
+
reportId,
|
|
23250
|
+
clientId: client.publicKey,
|
|
23251
|
+
databaseType: client.databaseType,
|
|
23252
|
+
filters: adjusted,
|
|
23253
|
+
additionalProcessing: { page: { rowsPerPage: 1e3, rowsPerRequest: 1e5 } },
|
|
23254
|
+
useNewNodeSql: true,
|
|
23255
|
+
tenants,
|
|
23256
|
+
flags,
|
|
23257
|
+
overwriteCache: forceRefresh ?? false
|
|
23258
|
+
},
|
|
23259
|
+
getToken
|
|
23260
|
+
});
|
|
23261
|
+
const resp = await parseFetchResponse(
|
|
23262
|
+
client,
|
|
23263
|
+
"report",
|
|
23264
|
+
fetchResp,
|
|
23265
|
+
getToken,
|
|
23266
|
+
true
|
|
23267
|
+
);
|
|
23268
|
+
reportInfo = await processReportResponse({
|
|
23269
|
+
resp,
|
|
23270
|
+
client,
|
|
23271
|
+
filters: adjusted,
|
|
23272
|
+
dateBucket: resp?.dateBucket,
|
|
23273
|
+
additionalProcessing: { page: { rowsPerPage: 1e3, rowsPerRequest: 1e5 } },
|
|
23274
|
+
getToken,
|
|
23275
|
+
eventTracking,
|
|
23276
|
+
tenants,
|
|
23277
|
+
// CacheCab fetches with task: 'report'; keep pivot processing local.
|
|
23278
|
+
skipPivotFetch: true,
|
|
23279
|
+
overwriteCache: forceRefresh ?? false
|
|
23280
|
+
});
|
|
23281
|
+
const dateField = reportInfo.dateField?.field;
|
|
23282
|
+
if (!isAllTime && dateField !== void 0 && reportInfo.rows.length > 0) {
|
|
23283
|
+
const cleanedDateField = removeQuotes(dateField);
|
|
23284
|
+
const missingDateFieldCount = reportInfo.rows.some((row) => row[cleanedDateField] === void 0);
|
|
23285
|
+
if (missingDateFieldCount) {
|
|
23286
|
+
this.uncacheableReportIDs.push(reportId);
|
|
23287
|
+
return EMPTY_INTERNAL_REPORT;
|
|
23288
|
+
}
|
|
23289
|
+
}
|
|
23290
|
+
const requiredFilterFields = adjusted.flatMap((x, idx) => {
|
|
23291
|
+
if (idx === dateFilterIndex || !x.values && !x.selectedValue) return [];
|
|
23292
|
+
return removeQuotes(x.field);
|
|
23293
|
+
});
|
|
23294
|
+
const missingFields = [...new Set(requiredFilterFields.filter(
|
|
23295
|
+
(field) => reportInfo?.rows.some((row) => row[field] === void 0)
|
|
23296
|
+
))];
|
|
23297
|
+
if (missingFields.length > 0) {
|
|
23298
|
+
this.uncacheableReportIDs.push(reportId);
|
|
23299
|
+
return EMPTY_INTERNAL_REPORT;
|
|
23300
|
+
}
|
|
23301
|
+
const cacheKey = this.getCacheKey(reportId, tenants);
|
|
23302
|
+
if (isAllTime) {
|
|
23303
|
+
this.fetchedRange[cacheKey] = { start: /* @__PURE__ */ new Date(0), end: /* @__PURE__ */ new Date(), fetchedAtUTCMS: Date.now(), allTimeDoneBefore: true };
|
|
23304
|
+
} else {
|
|
23305
|
+
const existing = this.fetchedRange[cacheKey];
|
|
23306
|
+
if (existing && !forceRefresh) {
|
|
23307
|
+
const oldStart = existing.start;
|
|
23308
|
+
const oldEnd = existing.end;
|
|
23309
|
+
this.fetchedRange[cacheKey] = { start: getMinDate(oldStart, s), end: getMaxDate(oldEnd, e), fetchedAtUTCMS: Date.now(), allTimeDoneBefore: false };
|
|
23310
|
+
} else {
|
|
23311
|
+
this.fetchedRange[cacheKey] = { start: s, end: e, fetchedAtUTCMS: Date.now(), allTimeDoneBefore: false };
|
|
23312
|
+
}
|
|
23313
|
+
}
|
|
23314
|
+
} catch (error) {
|
|
23315
|
+
console.warn(error);
|
|
23316
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
23317
|
+
throw error;
|
|
23318
|
+
}
|
|
23319
|
+
}
|
|
23320
|
+
return reportInfo || EMPTY_INTERNAL_REPORT;
|
|
23321
|
+
}
|
|
23322
|
+
async applyPivotsAndFilters(report, dashboardFilters, customFilters, pivot, tenantPart, useCache = true) {
|
|
23323
|
+
const datasetVersion = this.fetchedRange[report.id + tenantPart]?.fetchedAtUTCMS ?? 0;
|
|
23324
|
+
const keyParts = [
|
|
23325
|
+
report.queryString,
|
|
23326
|
+
tenantPart,
|
|
23327
|
+
datasetVersion,
|
|
23328
|
+
// prevents fetching stale filters on hard refresh
|
|
23329
|
+
hashString(stableStringify(dashboardFilters)),
|
|
23330
|
+
hashString(stableStringify(customFilters))
|
|
23331
|
+
];
|
|
23332
|
+
const queryKey = this.DATA_PREFIX + keyParts.join("|");
|
|
23333
|
+
let filtersApplied;
|
|
23334
|
+
if (useCache) {
|
|
23335
|
+
try {
|
|
23336
|
+
const cache = await this.storage.getItem(queryKey);
|
|
23337
|
+
if (cache) {
|
|
23338
|
+
filtersApplied = JSON.parse(cache);
|
|
23339
|
+
}
|
|
23340
|
+
} catch {
|
|
23341
|
+
}
|
|
23342
|
+
}
|
|
23343
|
+
if (!filtersApplied) {
|
|
23344
|
+
const dateIndex = dashboardFilters.findIndex((x) => x.filterType === "date_range");
|
|
23345
|
+
const requiredFilterFields = dashboardFilters.flatMap((x, idx) => {
|
|
23346
|
+
if (idx === dateIndex || !x.values?.length && !x.selectedValue) return [];
|
|
23347
|
+
return removeQuotes(x.field);
|
|
23348
|
+
});
|
|
23349
|
+
const missingFields = [...new Set(requiredFilterFields.filter(
|
|
23350
|
+
(field) => report.rows.some((row) => row[field] === void 0)
|
|
23351
|
+
))];
|
|
23352
|
+
if (missingFields.length > 0) {
|
|
23353
|
+
this.uncacheableReportIDs.push(report.id);
|
|
23354
|
+
return [];
|
|
23355
|
+
}
|
|
23356
|
+
const dbDateFilter = dashboardFilters.find((x) => x.filterType === "date_range");
|
|
23357
|
+
if (report.dateField && dbDateFilter?.startDate) {
|
|
23358
|
+
const { start: startDate, end: endDate } = normalizePSTRanges(
|
|
23359
|
+
new Date(dbDateFilter.startDate),
|
|
23360
|
+
dbDateFilter.endDate ? new Date(dbDateFilter.endDate) : void 0
|
|
23361
|
+
);
|
|
23362
|
+
const fieldToUse = report.rows[0] && report.rows[0]["__quillRawDate"] ? "__quillRawDate" : removeQuotes(report.dateField.field);
|
|
23363
|
+
const dateFilteredRows = report.rows.filter((x) => {
|
|
23364
|
+
const rowDate = new Date(x[fieldToUse]);
|
|
23365
|
+
return startDate <= rowDate && (endDate ? rowDate <= endDate : true);
|
|
23366
|
+
});
|
|
23367
|
+
filtersApplied = applyFiltersInMemory(dateFilteredRows, [], { dashboardFilters, customFilters });
|
|
23368
|
+
} else {
|
|
23369
|
+
filtersApplied = applyFiltersInMemory(report.rows, [], { dashboardFilters, customFilters });
|
|
23370
|
+
}
|
|
23371
|
+
}
|
|
23372
|
+
try {
|
|
23373
|
+
await this.storage.setItem(queryKey, JSON.stringify(filtersApplied));
|
|
23374
|
+
} catch {
|
|
23375
|
+
}
|
|
23376
|
+
const withPivot = applyPivotInMemory(filtersApplied, pivot, dashboardFilters.concat(customFilters));
|
|
23377
|
+
return withPivot;
|
|
23378
|
+
}
|
|
23379
|
+
getCacheKey(reportId, tenants) {
|
|
23380
|
+
const tenantPart = tenants ? JSON.stringify(tenants) : "";
|
|
23381
|
+
return reportId + tenantPart;
|
|
23382
|
+
}
|
|
23383
|
+
getUncacheableRequestKey(reportId, client, tenants, flags, filters, additionalProcessing, pivot) {
|
|
23384
|
+
const canonicalFilters = filters.map(
|
|
23385
|
+
(f) => canonicalizeFilterForUncacheableKey(f)
|
|
23386
|
+
);
|
|
23387
|
+
const keyParts = [
|
|
23388
|
+
reportId,
|
|
23389
|
+
client.publicKey,
|
|
23390
|
+
client.databaseType,
|
|
23391
|
+
hashString(stableStringify(canonicalizeForKey(tenants ?? null))),
|
|
23392
|
+
hashString(stableStringify(canonicalizeForKey(flags ?? null))),
|
|
23393
|
+
hashString(stableStringify(canonicalFilters)),
|
|
23394
|
+
hashString(stableStringify(canonicalizeForKey(additionalProcessing ?? null))),
|
|
23395
|
+
hashString(stableStringify(canonicalizeForKey(pivot ?? null)))
|
|
23396
|
+
];
|
|
23397
|
+
return this.UNCACHEABLE_PREFIX + keyParts.join("|");
|
|
23398
|
+
}
|
|
23399
|
+
async loadMetaFromStorage() {
|
|
23400
|
+
const meta = await this.storage.getItem(this.META_KEY);
|
|
23401
|
+
if (!meta) return;
|
|
23402
|
+
try {
|
|
23403
|
+
const parsed = JSON.parse(meta);
|
|
23404
|
+
this.cachedReportIds = parsed.cached || [];
|
|
23405
|
+
this.uncacheableReportIDs = parsed.cannotBeCached;
|
|
23406
|
+
this.fetchedRange = Object.fromEntries(
|
|
23407
|
+
Object.entries(parsed.fetchedRange || {}).map(([id2, range]) => [
|
|
23408
|
+
id2,
|
|
23409
|
+
{ ...range, start: new Date(range.start), end: new Date(range.end) }
|
|
23410
|
+
])
|
|
23411
|
+
);
|
|
23412
|
+
} catch (err) {
|
|
23413
|
+
console.warn("CacheCab: could not parse meta from storage", err);
|
|
23414
|
+
}
|
|
23415
|
+
}
|
|
23416
|
+
async persistMetaToStorage() {
|
|
23417
|
+
const serializableRange = Object.fromEntries(
|
|
23418
|
+
Object.entries(this.fetchedRange).map(([id2, range]) => [
|
|
23419
|
+
id2,
|
|
23420
|
+
{ ...range }
|
|
23421
|
+
])
|
|
23422
|
+
);
|
|
23423
|
+
await this.storage.setItem(
|
|
23424
|
+
this.META_KEY,
|
|
23425
|
+
JSON.stringify({
|
|
23426
|
+
fetchedRange: serializableRange,
|
|
23427
|
+
cached: this.cachedReportIds,
|
|
23428
|
+
cannotBeCached: this.uncacheableReportIDs
|
|
23429
|
+
})
|
|
23430
|
+
);
|
|
23431
|
+
}
|
|
23432
|
+
};
|
|
23433
|
+
var MemoryStorage = class {
|
|
23434
|
+
store = /* @__PURE__ */ new Map();
|
|
23435
|
+
async getItem(key) {
|
|
23436
|
+
return this.store.get(key) ?? null;
|
|
23437
|
+
}
|
|
23438
|
+
async setItem(key, value) {
|
|
23439
|
+
this.store.set(key, value);
|
|
23440
|
+
}
|
|
23441
|
+
};
|
|
23442
|
+
var DB_NAME = "quill.cachecab";
|
|
23443
|
+
var STORE_NAME = "kv";
|
|
23444
|
+
var IdbStorage = class {
|
|
23445
|
+
dbPromise;
|
|
23446
|
+
constructor() {
|
|
23447
|
+
this.dbPromise = openDB(DB_NAME, 1, {
|
|
23448
|
+
upgrade(db) {
|
|
23449
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
23450
|
+
db.createObjectStore(STORE_NAME);
|
|
23451
|
+
}
|
|
23452
|
+
}
|
|
23453
|
+
});
|
|
23454
|
+
}
|
|
23455
|
+
async getItem(key) {
|
|
23456
|
+
const db = await this.dbPromise;
|
|
23457
|
+
return await db.get(STORE_NAME, key) ?? null;
|
|
23458
|
+
}
|
|
23459
|
+
async setItem(key, value) {
|
|
23460
|
+
const db = await this.dbPromise;
|
|
23461
|
+
await db.put(STORE_NAME, value, key);
|
|
23462
|
+
}
|
|
23463
|
+
};
|
|
23464
|
+
function removeQuotes(str) {
|
|
23465
|
+
return str.replace(/^['"]|['"]$/g, "");
|
|
23466
|
+
}
|
|
23467
|
+
function getMaxDate(d1, d2) {
|
|
23468
|
+
return d1 > d2 ? d1 : d2;
|
|
23469
|
+
}
|
|
23470
|
+
function getMinDate(d1, d2) {
|
|
23471
|
+
return d2 > d1 ? d1 : d2;
|
|
23472
|
+
}
|
|
23473
|
+
function hashString(str) {
|
|
23474
|
+
let h1 = 3735928559 ^ 0, h2 = 1103547991 ^ 0;
|
|
23475
|
+
for (let i = 0, ch; i < str.length; i++) {
|
|
23476
|
+
ch = str.charCodeAt(i);
|
|
23477
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
23478
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
23479
|
+
}
|
|
23480
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
23481
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
23482
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
|
|
23483
|
+
}
|
|
23484
|
+
function filterNewRows(existingRows, newRows) {
|
|
23485
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23486
|
+
const getKey = (row) => stableStringify(row);
|
|
23487
|
+
existingRows.forEach((row) => seen.add(getKey(row)));
|
|
23488
|
+
return newRows.filter((row) => {
|
|
23489
|
+
const k = getKey(row);
|
|
23490
|
+
if (seen.has(k)) return false;
|
|
23491
|
+
seen.add(k);
|
|
23492
|
+
return true;
|
|
23493
|
+
});
|
|
23494
|
+
}
|
|
23495
|
+
function stableStringify(obj) {
|
|
23496
|
+
if (obj === null || typeof obj !== "object") return JSON.stringify(obj);
|
|
23497
|
+
if (Array.isArray(obj)) {
|
|
23498
|
+
return `[${obj.map(stableStringify).join(",")}]`;
|
|
23499
|
+
}
|
|
23500
|
+
const keys = Object.keys(obj).sort();
|
|
23501
|
+
return `{${keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",")}}`;
|
|
23502
|
+
}
|
|
23503
|
+
function canonicalizeForKey(value) {
|
|
23504
|
+
if (value instanceof Date) {
|
|
23505
|
+
return value.toISOString();
|
|
23506
|
+
}
|
|
23507
|
+
if (Array.isArray(value)) {
|
|
23508
|
+
return value.map(canonicalizeForKey);
|
|
23509
|
+
}
|
|
23510
|
+
if (value && typeof value === "object") {
|
|
23511
|
+
const out = {};
|
|
23512
|
+
Object.keys(value).sort().forEach((key) => {
|
|
23513
|
+
if (value[key] !== void 0) {
|
|
23514
|
+
out[key] = canonicalizeForKey(value[key]);
|
|
23515
|
+
}
|
|
23516
|
+
});
|
|
23517
|
+
return out;
|
|
23518
|
+
}
|
|
23519
|
+
return value;
|
|
23520
|
+
}
|
|
23521
|
+
function canonicalizeFilterForUncacheableKey(filter) {
|
|
23522
|
+
const raw = canonicalizeForKey(filter) ?? {};
|
|
23523
|
+
const base = {
|
|
23524
|
+
filterType: raw.filterType,
|
|
23525
|
+
field: raw.field,
|
|
23526
|
+
table: raw.table,
|
|
23527
|
+
label: raw.label,
|
|
23528
|
+
operator: raw.operator
|
|
23529
|
+
};
|
|
23530
|
+
if (raw.selectedValue !== void 0) {
|
|
23531
|
+
base.selectedValue = raw.selectedValue;
|
|
23532
|
+
}
|
|
23533
|
+
if (Array.isArray(raw.values)) {
|
|
23534
|
+
base.values = [...raw.values].map(canonicalizeForKey).sort();
|
|
23535
|
+
}
|
|
23536
|
+
if (raw.value !== void 0) {
|
|
23537
|
+
base.value = canonicalizeForKey(raw.value);
|
|
23538
|
+
}
|
|
23539
|
+
if (raw.filterType === "date_range") {
|
|
23540
|
+
const { start: start2, end } = normalizePSTRanges(
|
|
23541
|
+
raw.startDate ? new Date(raw.startDate) : void 0,
|
|
23542
|
+
raw.endDate ? new Date(raw.endDate) : void 0
|
|
23543
|
+
);
|
|
23544
|
+
base.startDate = start2 ? start2.toISOString() : void 0;
|
|
23545
|
+
base.endDate = end ? end.toISOString() : void 0;
|
|
23546
|
+
base.primaryRange = raw.primaryRange?.value;
|
|
23547
|
+
base.comparisonRange = raw.comparisonRange?.value;
|
|
23548
|
+
}
|
|
23549
|
+
return canonicalizeForKey(base);
|
|
23550
|
+
}
|
|
23551
|
+
function startOfDayPST(date) {
|
|
23552
|
+
const pstDate = utcToZonedTime2(date, TZ);
|
|
23553
|
+
const startPst = startOfDay4(pstDate);
|
|
23554
|
+
return zonedTimeToUtc(startPst, TZ);
|
|
23555
|
+
}
|
|
23556
|
+
function endOfDayPST(date) {
|
|
23557
|
+
const pstDate = utcToZonedTime2(date, TZ);
|
|
23558
|
+
const endPst = endOfDay3(pstDate);
|
|
23559
|
+
return zonedTimeToUtc(endPst, TZ);
|
|
23560
|
+
}
|
|
23561
|
+
function normalizePSTRanges(start2, end) {
|
|
23562
|
+
return {
|
|
23563
|
+
start: start2 ? startOfDayPST(start2) : void 0,
|
|
23564
|
+
end: end ? endOfDayPST(end) : void 0
|
|
23565
|
+
};
|
|
23566
|
+
}
|
|
23567
|
+
|
|
23568
|
+
// src/Context.tsx
|
|
21603
23569
|
import { jsx } from "react/jsx-runtime";
|
|
21604
23570
|
var dummySetter = () => {
|
|
21605
23571
|
};
|
|
@@ -21931,7 +23897,9 @@ var ReportFiltersContext = createContext({
|
|
|
21931
23897
|
loadFiltersForReport: async () => {
|
|
21932
23898
|
},
|
|
21933
23899
|
abortLoadingFilters: () => {
|
|
21934
|
-
}
|
|
23900
|
+
},
|
|
23901
|
+
customFiltersLoaded: false,
|
|
23902
|
+
setCustomFiltersLoaded: dummySetter
|
|
21935
23903
|
});
|
|
21936
23904
|
var customDashboardFiltersReducer = (state, action) => {
|
|
21937
23905
|
switch (action.type) {
|
|
@@ -22021,6 +23989,9 @@ var FetchContext = createContext({
|
|
|
22021
23989
|
var EventTrackingContext = createContext({
|
|
22022
23990
|
eventTracking: null
|
|
22023
23991
|
});
|
|
23992
|
+
var CacheCabContext = createContext({
|
|
23993
|
+
getCacheCab: (storageType) => new CacheCab({ storageType })
|
|
23994
|
+
});
|
|
22024
23995
|
var ContextProvider = ({
|
|
22025
23996
|
children,
|
|
22026
23997
|
initialTheme,
|
|
@@ -22034,6 +24005,14 @@ var ContextProvider = ({
|
|
|
22034
24005
|
getAuthorizationToken = async () => "",
|
|
22035
24006
|
eventTracking = null
|
|
22036
24007
|
}) => {
|
|
24008
|
+
const cacheCabByTypeRef = useRef({});
|
|
24009
|
+
const getCacheCab = useCallback((storageType) => {
|
|
24010
|
+
const key = storageType === "idb" ? "idb" : "memory";
|
|
24011
|
+
if (!cacheCabByTypeRef.current[key]) {
|
|
24012
|
+
cacheCabByTypeRef.current[key] = new CacheCab({ storageType: key });
|
|
24013
|
+
}
|
|
24014
|
+
return cacheCabByTypeRef.current[key];
|
|
24015
|
+
}, []);
|
|
22037
24016
|
const [client, setClient] = useState(
|
|
22038
24017
|
typeof window !== "undefined" && sessionStorage ? JSON.parse(sessionStorage.getItem("quill-client") ?? "null") : null
|
|
22039
24018
|
);
|
|
@@ -22096,6 +24075,7 @@ var ContextProvider = ({
|
|
|
22096
24075
|
reportFiltersReducer,
|
|
22097
24076
|
{}
|
|
22098
24077
|
);
|
|
24078
|
+
const [customFiltersLoaded, setCustomFiltersLoaded] = useState(false);
|
|
22099
24079
|
const reportFilterOptionsAbortControllers = useRef({});
|
|
22100
24080
|
const [reports, reportsDispatch] = useReducer(reportsReducer, {});
|
|
22101
24081
|
const [reportsLoadingState, reportsLoadingStateDispatch] = useReducer(
|
|
@@ -22119,6 +24099,11 @@ var ContextProvider = ({
|
|
|
22119
24099
|
const viewerTenantsByOwnerRequests = useRef(/* @__PURE__ */ new Set());
|
|
22120
24100
|
const mappedTenantsRequests = useRef(/* @__PURE__ */ new Set());
|
|
22121
24101
|
const loadDashboardProcessId = useRef({});
|
|
24102
|
+
useEffect(() => {
|
|
24103
|
+
if (Object.keys(customReportFilters).length) {
|
|
24104
|
+
setCustomFiltersLoaded(true);
|
|
24105
|
+
}
|
|
24106
|
+
}, [customReportFilters]);
|
|
22122
24107
|
useEffect(() => {
|
|
22123
24108
|
if (!theme) {
|
|
22124
24109
|
const populatedTheme = {
|
|
@@ -22887,6 +24872,7 @@ var ContextProvider = ({
|
|
|
22887
24872
|
...dashboard2,
|
|
22888
24873
|
dateFilter: dashboard2.dateFilter ? {
|
|
22889
24874
|
...dashboard2.dateFilter,
|
|
24875
|
+
initialCacheDateRange: dashboard2.initialCacheDateRange ? { ...dashboard2.initialCacheDateRange } : void 0,
|
|
22890
24876
|
presetOptions: dashboard2.dateFilter.presetOptions?.map(
|
|
22891
24877
|
(preset) => ({
|
|
22892
24878
|
...preset,
|
|
@@ -23229,6 +25215,7 @@ var ContextProvider = ({
|
|
|
23229
25215
|
...dashboard2,
|
|
23230
25216
|
dateFilter: dashboard2.dateFilter ? {
|
|
23231
25217
|
...dashboard2.dateFilter,
|
|
25218
|
+
initialCacheDateRange: dashboard2.initialCacheDateRange ? { ...dashboard2.initialCacheDateRange } : void 0,
|
|
23232
25219
|
presetOptions: dashboard2.dateFilter.presetOptions?.map(
|
|
23233
25220
|
(preset) => ({
|
|
23234
25221
|
...preset,
|
|
@@ -23273,6 +25260,7 @@ var ContextProvider = ({
|
|
|
23273
25260
|
if (dashboard2.dateFilter) {
|
|
23274
25261
|
dashboard2.dateFilter = {
|
|
23275
25262
|
...dashboard2.dateFilter,
|
|
25263
|
+
initialCacheDateRange: dashboard2.initialCacheDateRange ? { ...dashboard2.initialCacheDateRange } : void 0,
|
|
23276
25264
|
startDate: presetOptions.find(
|
|
23277
25265
|
(elem) => elem.value === dashboard2.dateFilter.primaryRange?.value
|
|
23278
25266
|
)?.startDate,
|
|
@@ -23541,7 +25529,7 @@ var ContextProvider = ({
|
|
|
23541
25529
|
if (!theme) {
|
|
23542
25530
|
return null;
|
|
23543
25531
|
}
|
|
23544
|
-
return /* @__PURE__ */ jsx(
|
|
25532
|
+
return /* @__PURE__ */ jsx(CacheCabContext.Provider, { value: { getCacheCab }, children: /* @__PURE__ */ jsx(
|
|
23545
25533
|
ClientContext.Provider,
|
|
23546
25534
|
{
|
|
23547
25535
|
value: [
|
|
@@ -23582,7 +25570,9 @@ var ContextProvider = ({
|
|
|
23582
25570
|
reportFiltersDispatch,
|
|
23583
25571
|
customReportFiltersDispatch,
|
|
23584
25572
|
loadFiltersForReport,
|
|
23585
|
-
abortLoadingFilters
|
|
25573
|
+
abortLoadingFilters,
|
|
25574
|
+
customFiltersLoaded,
|
|
25575
|
+
setCustomFiltersLoaded
|
|
23586
25576
|
},
|
|
23587
25577
|
children: /* @__PURE__ */ jsx(
|
|
23588
25578
|
ReportsContext.Provider,
|
|
@@ -23625,7 +25615,7 @@ var ContextProvider = ({
|
|
|
23625
25615
|
}
|
|
23626
25616
|
) })
|
|
23627
25617
|
}
|
|
23628
|
-
);
|
|
25618
|
+
) });
|
|
23629
25619
|
};
|
|
23630
25620
|
|
|
23631
25621
|
// src/hooks/useExport.tsx
|
|
@@ -23644,12 +25634,12 @@ init_filterProcessing();
|
|
|
23644
25634
|
init_columnType();
|
|
23645
25635
|
import {
|
|
23646
25636
|
add,
|
|
23647
|
-
startOfDay as
|
|
23648
|
-
startOfMonth as
|
|
23649
|
-
startOfWeek as
|
|
23650
|
-
startOfYear
|
|
25637
|
+
startOfDay as startOfDay5,
|
|
25638
|
+
startOfMonth as startOfMonth3,
|
|
25639
|
+
startOfWeek as startOfWeek4,
|
|
25640
|
+
startOfYear as startOfYear2
|
|
23651
25641
|
} from "date-fns";
|
|
23652
|
-
import { utcToZonedTime as
|
|
25642
|
+
import { utcToZonedTime as utcToZonedTime3 } from "date-fns-tz";
|
|
23653
25643
|
function mergeComparisonRange(resp) {
|
|
23654
25644
|
if (resp.chartType === "table") return resp;
|
|
23655
25645
|
const compRows = resp.compareRows;
|
|
@@ -23692,6 +25682,18 @@ var useDashboardInternal = (dashboardName, customFilters) => {
|
|
|
23692
25682
|
(f) => f.filter
|
|
23693
25683
|
) : null;
|
|
23694
25684
|
}, [dashboardFilters, dashboardName]);
|
|
25685
|
+
const getExistingDateFilter = useMemo2(
|
|
25686
|
+
() => (name2) => {
|
|
25687
|
+
if (!name2) return void 0;
|
|
25688
|
+
const filtersForDashboard = dashboardFilters[name2];
|
|
25689
|
+
if (!filtersForDashboard) return void 0;
|
|
25690
|
+
const entry = Object.values(filtersForDashboard).find(
|
|
25691
|
+
(f) => f?.filter?.filterType === "date_range" /* Date */
|
|
25692
|
+
);
|
|
25693
|
+
return entry?.filter;
|
|
25694
|
+
},
|
|
25695
|
+
[dashboardFilters]
|
|
25696
|
+
);
|
|
23695
25697
|
useEffect2(() => {
|
|
23696
25698
|
if (!dashboardName) return;
|
|
23697
25699
|
if (backfilledDashboards.current.has(dashboardName)) return;
|
|
@@ -23729,7 +25731,7 @@ var useDashboardInternal = (dashboardName, customFilters) => {
|
|
|
23729
25731
|
customFilters
|
|
23730
25732
|
);
|
|
23731
25733
|
}, [dashboardName, loading, dashboardConfig, dashboardFilters]);
|
|
23732
|
-
const handleReload = async (overrideDashboardName, fetchFromServer = false, reportAction, overrideFilters) => {
|
|
25734
|
+
const handleReload = async (overrideDashboardName, fetchFromServer = false, reportAction, overrideFilters, options) => {
|
|
23733
25735
|
if (!dashboardName) return;
|
|
23734
25736
|
if (overrideFilters) {
|
|
23735
25737
|
const dateFilter2 = overrideFilters.filters.find(
|
|
@@ -23782,10 +25784,19 @@ var useDashboardInternal = (dashboardName, customFilters) => {
|
|
|
23782
25784
|
Object.values(dashboard?.sections ?? {}).flat(),
|
|
23783
25785
|
dashboardName
|
|
23784
25786
|
) : void 0;
|
|
25787
|
+
const existingDateFilter = options?.preserveExistingDateFilter ? getExistingDateFilter(dashboardName) : void 0;
|
|
25788
|
+
const mergedDateFilter = dateFilter && existingDateFilter ? {
|
|
25789
|
+
...dateFilter,
|
|
25790
|
+
startDate: existingDateFilter.startDate ?? dateFilter.startDate,
|
|
25791
|
+
endDate: existingDateFilter.endDate ?? dateFilter.endDate,
|
|
25792
|
+
preset: existingDateFilter.preset ?? dateFilter.preset,
|
|
25793
|
+
primaryRange: existingDateFilter.primaryRange ?? dateFilter.primaryRange,
|
|
25794
|
+
comparisonRange: existingDateFilter.comparisonRange ?? dateFilter.comparisonRange
|
|
25795
|
+
} : dateFilter ?? existingDateFilter;
|
|
23785
25796
|
loadFiltersForDashboard(
|
|
23786
25797
|
dashboardName,
|
|
23787
25798
|
[
|
|
23788
|
-
...
|
|
25799
|
+
...mergedDateFilter ? [mergedDateFilter] : [],
|
|
23789
25800
|
...updatedDashboard?.filters?.map((filter) => ({
|
|
23790
25801
|
...filter,
|
|
23791
25802
|
query: void 0
|
|
@@ -24070,7 +26081,8 @@ var useDashboards = () => {
|
|
|
24070
26081
|
tenantFilters,
|
|
24071
26082
|
dateFilter,
|
|
24072
26083
|
customFilters,
|
|
24073
|
-
tenantKeys
|
|
26084
|
+
tenantKeys,
|
|
26085
|
+
initialCacheDateRange
|
|
24074
26086
|
}) => {
|
|
24075
26087
|
if (!client) return;
|
|
24076
26088
|
if (tenantKeys?.some((key) => !key)) {
|
|
@@ -24091,6 +26103,7 @@ var useDashboards = () => {
|
|
|
24091
26103
|
filters,
|
|
24092
26104
|
tenantFilters,
|
|
24093
26105
|
dateFilter: dateFilter ?? null,
|
|
26106
|
+
initialCacheDateRange,
|
|
24094
26107
|
name: name2.trim(),
|
|
24095
26108
|
task: "edit-dashboard",
|
|
24096
26109
|
clientId: client.clientId,
|
|
@@ -24302,7 +26315,9 @@ var useDashboards = () => {
|
|
|
24302
26315
|
};
|
|
24303
26316
|
};
|
|
24304
26317
|
var useDashboard = (dashboardName, config) => {
|
|
26318
|
+
const logCacheStatistics = config?.showCacheLogs || false;
|
|
24305
26319
|
const { data, dashboardFilters, reload, isLoading } = useDashboardInternal(dashboardName);
|
|
26320
|
+
const [lastUpdated, setLastUpdated] = useState2(0);
|
|
24306
26321
|
const { customFilterDispatch } = useContext(DashboardFiltersContext);
|
|
24307
26322
|
const { reportsDispatch, reportsLoadingStateDispatch } = useContext(ReportsContext);
|
|
24308
26323
|
const initialLoad = useRef2(true);
|
|
@@ -24311,15 +26326,19 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24311
26326
|
const [client] = useContext(ClientContext);
|
|
24312
26327
|
const { tenants, flags } = useContext(TenantContext);
|
|
24313
26328
|
const { getToken } = useContext(FetchContext);
|
|
24314
|
-
const { customReportFilters } = useContext(ReportFiltersContext);
|
|
26329
|
+
const { customReportFilters, customFiltersLoaded, setCustomFiltersLoaded } = useContext(ReportFiltersContext);
|
|
24315
26330
|
const { eventTracking } = useContext(EventTrackingContext);
|
|
24316
|
-
const
|
|
26331
|
+
const { getCacheCab } = useContext(CacheCabContext);
|
|
24317
26332
|
const reportRequestIds = useRef2({});
|
|
24318
26333
|
const lastDashboardName = useRef2(null);
|
|
24319
26334
|
const pendingNameChangeReload = useRef2(false);
|
|
24320
|
-
|
|
24321
|
-
|
|
24322
|
-
|
|
26335
|
+
const [loadedDashes, setLoadedDashes] = useState2([]);
|
|
26336
|
+
const [lastUpdatedDict, setLastUpdatedDict] = useState2({});
|
|
26337
|
+
const cacheEnabled = config?.cacheEnabled ?? true;
|
|
26338
|
+
const cacheCab = useMemo2(
|
|
26339
|
+
() => getCacheCab(config?.cacheType),
|
|
26340
|
+
[getCacheCab, config?.cacheType]
|
|
26341
|
+
);
|
|
24323
26342
|
useEffect2(() => {
|
|
24324
26343
|
const nameChanged = dashboardName !== lastDashboardName.current;
|
|
24325
26344
|
if (nameChanged) {
|
|
@@ -24329,19 +26348,29 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24329
26348
|
backfilledDashboards.current = false;
|
|
24330
26349
|
reportRequestIds.current = {};
|
|
24331
26350
|
pendingNameChangeReload.current = true;
|
|
26351
|
+
if (customFiltersLoaded && !loadedDashes.includes(dashboardName)) {
|
|
26352
|
+
setCustomFiltersLoaded(false);
|
|
26353
|
+
}
|
|
26354
|
+
setLastUpdated(lastUpdatedDict[dashboardName] || 0);
|
|
24332
26355
|
}
|
|
24333
26356
|
if (!dashboardName) return;
|
|
24334
26357
|
if (pendingNameChangeReload.current && data) {
|
|
24335
26358
|
pendingNameChangeReload.current = false;
|
|
24336
26359
|
initialLoad.current = false;
|
|
26360
|
+
fetchedInitialReports.current = false;
|
|
24337
26361
|
return;
|
|
24338
26362
|
}
|
|
24339
26363
|
if (pendingNameChangeReload.current && !isLoading && !data && initialLoad.current) {
|
|
24340
26364
|
initialLoad.current = false;
|
|
24341
26365
|
pendingNameChangeReload.current = false;
|
|
24342
|
-
reload(
|
|
26366
|
+
reload(dashboardName, false, void 0, void 0, {
|
|
26367
|
+
preserveExistingDateFilter: true
|
|
26368
|
+
});
|
|
24343
26369
|
}
|
|
24344
26370
|
}, [isLoading, data, dashboardName]);
|
|
26371
|
+
useEffect2(() => {
|
|
26372
|
+
setLastUpdated(lastUpdatedDict[dashboardName] || 0);
|
|
26373
|
+
}, [lastUpdatedDict, dashboardName]);
|
|
24345
26374
|
useEffect2(() => {
|
|
24346
26375
|
if (backfilledDashboards.current) return;
|
|
24347
26376
|
if (isLoading || !data) return;
|
|
@@ -24350,7 +26379,9 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24350
26379
|
);
|
|
24351
26380
|
if (!needsBackfill) return;
|
|
24352
26381
|
backfilledDashboards.current = true;
|
|
24353
|
-
reload(dashboardName, false
|
|
26382
|
+
reload(dashboardName, false, void 0, void 0, {
|
|
26383
|
+
preserveExistingDateFilter: true
|
|
26384
|
+
});
|
|
24354
26385
|
}, [isLoading, data, dashboardFilters, dashboardName]);
|
|
24355
26386
|
const { allReportsById } = useAllReports();
|
|
24356
26387
|
const sections = useMemo2(() => {
|
|
@@ -24374,7 +26405,13 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24374
26405
|
fetchedInitialReports.current = true;
|
|
24375
26406
|
fetchReports([], dashboardFilters ?? [], config?.pageSize);
|
|
24376
26407
|
}
|
|
24377
|
-
}, [fetchedInitialReports, data, dashboardFilters]);
|
|
26408
|
+
}, [fetchedInitialReports, data, dashboardFilters, customFiltersLoaded]);
|
|
26409
|
+
useEffect2(() => {
|
|
26410
|
+
if (customFiltersLoaded && data && dashboardFilters !== null) {
|
|
26411
|
+
fetchedInitialReports.current = true;
|
|
26412
|
+
fetchReports([], dashboardFilters ?? [], config?.pageSize);
|
|
26413
|
+
}
|
|
26414
|
+
}, [customFiltersLoaded]);
|
|
24378
26415
|
const applyDashboardFilters = (filtersToUpdate) => {
|
|
24379
26416
|
const newFilters = (dashboardFilters ?? []).map((f) => {
|
|
24380
26417
|
const update = filtersToUpdate.find((u) => u.label === f.label);
|
|
@@ -24453,7 +26490,7 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24453
26490
|
});
|
|
24454
26491
|
return internalFilters;
|
|
24455
26492
|
};
|
|
24456
|
-
const
|
|
26493
|
+
const isFilter2 = (f) => {
|
|
24457
26494
|
return f && typeof f === "object" && "filterType" in f && !("id" in f);
|
|
24458
26495
|
};
|
|
24459
26496
|
const isDashboardFilter = (f) => {
|
|
@@ -24461,29 +26498,22 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24461
26498
|
};
|
|
24462
26499
|
const applyFilters = (filters2) => {
|
|
24463
26500
|
const dashboardFilters2 = filters2.filter(isDashboardFilter);
|
|
24464
|
-
const customFilters = filters2.filter(
|
|
26501
|
+
const customFilters = filters2.filter(isFilter2);
|
|
24465
26502
|
const newCustomFilters = applyCustomFilters(customFilters);
|
|
24466
26503
|
const newDashboardFilters = applyDashboardFilters(dashboardFilters2);
|
|
24467
26504
|
fetchReports(newCustomFilters, newDashboardFilters);
|
|
24468
26505
|
};
|
|
24469
|
-
const
|
|
24470
|
-
|
|
24471
|
-
|
|
24472
|
-
while (attempts < maxAttempts) {
|
|
24473
|
-
const filters2 = customFiltersRef.current[reportId];
|
|
24474
|
-
if (filters2 && filters2.length > 0) {
|
|
24475
|
-
return filters2;
|
|
24476
|
-
}
|
|
24477
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
24478
|
-
attempts++;
|
|
24479
|
-
}
|
|
24480
|
-
return [];
|
|
26506
|
+
const forceCacheRefresh = () => {
|
|
26507
|
+
if (!cacheEnabled) return;
|
|
26508
|
+
fetchReports([], dashboardFilters ?? [], config?.pageSize, true);
|
|
24481
26509
|
};
|
|
24482
|
-
const fetchReports = async (customFilters, dashboardFilters2, pageSize) => {
|
|
26510
|
+
const fetchReports = async (customFilters, dashboardFilters2, pageSize, forceCacheToRefresh = false) => {
|
|
24483
26511
|
if (!client || !sections) return;
|
|
24484
26512
|
const allReports = Object.values(sections).flat();
|
|
26513
|
+
const fetchStartTime = Date.now();
|
|
26514
|
+
let totalCached = 0;
|
|
24485
26515
|
await Promise.all(
|
|
24486
|
-
allReports.map(async (reportInfo) => {
|
|
26516
|
+
allReports.map(async (reportInfo, idx) => {
|
|
24487
26517
|
const reportId = reportInfo.id;
|
|
24488
26518
|
const requestId = (reportRequestIds.current[reportId] ?? 0) + 1;
|
|
24489
26519
|
reportRequestIds.current[reportId] = requestId;
|
|
@@ -24492,7 +26522,7 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24492
26522
|
id: reportId,
|
|
24493
26523
|
data: true
|
|
24494
26524
|
});
|
|
24495
|
-
const customReportFiltersArray =
|
|
26525
|
+
const customReportFiltersArray = customReportFilters[reportId] ?? [];
|
|
24496
26526
|
let rowsPerRequest = pageSize || 600;
|
|
24497
26527
|
if (!pageSize && (reportInfo.chartType === "table" || reportInfo.chartType === "metric")) {
|
|
24498
26528
|
rowsPerRequest = 10;
|
|
@@ -24504,17 +26534,162 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24504
26534
|
const additionalProcessing = {
|
|
24505
26535
|
page: pagination
|
|
24506
26536
|
};
|
|
24507
|
-
const usePivotTask = !!reportInfo.pivot;
|
|
26537
|
+
const usePivotTask = !cacheEnabled && !!reportInfo.pivot;
|
|
26538
|
+
const allFilters = dashboardFilters2.concat(customFilters).concat(customReportFiltersArray);
|
|
26539
|
+
const applyInMemoryPivotIfNeeded = (report2) => {
|
|
26540
|
+
const pivotToApply = reportInfo.pivot ?? report2.pivot;
|
|
26541
|
+
if (!pivotToApply || usePivotTask) {
|
|
26542
|
+
return report2;
|
|
26543
|
+
}
|
|
26544
|
+
const pivotRows = applyPivotInMemory(
|
|
26545
|
+
report2.rows ?? [],
|
|
26546
|
+
pivotToApply,
|
|
26547
|
+
allFilters
|
|
26548
|
+
);
|
|
26549
|
+
const pivotColumns = generatePivotColumnsInMemory({
|
|
26550
|
+
pivot: pivotToApply,
|
|
26551
|
+
pivotRows,
|
|
26552
|
+
sourceColumns: report2.columnInternal ?? report2.columns
|
|
26553
|
+
});
|
|
26554
|
+
return {
|
|
26555
|
+
...report2,
|
|
26556
|
+
pivot: pivotToApply,
|
|
26557
|
+
pivotRows,
|
|
26558
|
+
pivotColumns: pivotColumns ?? report2.pivotColumns,
|
|
26559
|
+
pivotRowCount: pivotRows.length
|
|
26560
|
+
};
|
|
26561
|
+
};
|
|
26562
|
+
if (cacheEnabled && cacheCab.isCacheable(reportId)) {
|
|
26563
|
+
const report2 = await cacheCab.get(reportId, dashboardFilters2, customFilters.concat(customReportFiltersArray), reportInfo.pivot, client, tenants, flags, pageSize, getToken, eventTracking, forceCacheToRefresh);
|
|
26564
|
+
if (reportRequestIds.current[reportId] !== requestId) {
|
|
26565
|
+
return null;
|
|
26566
|
+
}
|
|
26567
|
+
if (cacheCab.isCacheable(reportId)) {
|
|
26568
|
+
reportsDispatch({
|
|
26569
|
+
type: "UPDATE_REPORT",
|
|
26570
|
+
id: reportId,
|
|
26571
|
+
data: {
|
|
26572
|
+
...report2,
|
|
26573
|
+
pagination,
|
|
26574
|
+
triggerReload: false
|
|
26575
|
+
}
|
|
26576
|
+
});
|
|
26577
|
+
reportsLoadingStateDispatch({
|
|
26578
|
+
type: "SET_REPORT_LOADING",
|
|
26579
|
+
id: reportId,
|
|
26580
|
+
data: false
|
|
26581
|
+
});
|
|
26582
|
+
totalCached += 1;
|
|
26583
|
+
return report2;
|
|
26584
|
+
}
|
|
26585
|
+
}
|
|
26586
|
+
if (cacheEnabled && !cacheCab.isCacheable(reportId)) {
|
|
26587
|
+
try {
|
|
26588
|
+
const { report: uncacheableReport, fromCache } = await cacheCab.getOrFetchUncacheableResult(
|
|
26589
|
+
reportId,
|
|
26590
|
+
client,
|
|
26591
|
+
tenants,
|
|
26592
|
+
flags,
|
|
26593
|
+
allFilters,
|
|
26594
|
+
additionalProcessing,
|
|
26595
|
+
reportInfo.pivot,
|
|
26596
|
+
async () => {
|
|
26597
|
+
const { report: report2, error: error2 } = await fetchReport({
|
|
26598
|
+
reportId,
|
|
26599
|
+
client,
|
|
26600
|
+
tenants,
|
|
26601
|
+
flags,
|
|
26602
|
+
additionalProcessing,
|
|
26603
|
+
filters: allFilters,
|
|
26604
|
+
getToken,
|
|
26605
|
+
eventTracking,
|
|
26606
|
+
usePivotTask,
|
|
26607
|
+
overwriteCache: forceCacheToRefresh
|
|
26608
|
+
});
|
|
26609
|
+
if (error2 || !report2) {
|
|
26610
|
+
throw error2 ?? new Error("Failed to fetch uncacheable report");
|
|
26611
|
+
}
|
|
26612
|
+
return report2;
|
|
26613
|
+
},
|
|
26614
|
+
forceCacheToRefresh
|
|
26615
|
+
);
|
|
26616
|
+
if (reportRequestIds.current[reportId] !== requestId) {
|
|
26617
|
+
return null;
|
|
26618
|
+
}
|
|
26619
|
+
const uncacheableReportWithPivot = applyInMemoryPivotIfNeeded(uncacheableReport);
|
|
26620
|
+
reportsDispatch({
|
|
26621
|
+
type: "UPDATE_REPORT",
|
|
26622
|
+
id: reportId,
|
|
26623
|
+
data: {
|
|
26624
|
+
...uncacheableReportWithPivot,
|
|
26625
|
+
pagination,
|
|
26626
|
+
triggerReload: false
|
|
26627
|
+
}
|
|
26628
|
+
});
|
|
26629
|
+
reportsLoadingStateDispatch({
|
|
26630
|
+
type: "SET_REPORT_LOADING",
|
|
26631
|
+
id: reportId,
|
|
26632
|
+
data: false
|
|
26633
|
+
});
|
|
26634
|
+
if (fromCache) {
|
|
26635
|
+
totalCached += 1;
|
|
26636
|
+
}
|
|
26637
|
+
if (usePivotTask) {
|
|
26638
|
+
fetchReportRows({
|
|
26639
|
+
reportId,
|
|
26640
|
+
client,
|
|
26641
|
+
tenants,
|
|
26642
|
+
filters: allFilters,
|
|
26643
|
+
getToken,
|
|
26644
|
+
additionalProcessing,
|
|
26645
|
+
overwriteCache: forceCacheToRefresh
|
|
26646
|
+
}).then(({ rows, rowCount, columns, fields }) => {
|
|
26647
|
+
if (reportRequestIds.current[reportId] !== requestId) {
|
|
26648
|
+
return;
|
|
26649
|
+
}
|
|
26650
|
+
reportsDispatch({
|
|
26651
|
+
type: "UPDATE_REPORT",
|
|
26652
|
+
id: reportId,
|
|
26653
|
+
data: {
|
|
26654
|
+
rows,
|
|
26655
|
+
rowCount,
|
|
26656
|
+
columnInternal: columns,
|
|
26657
|
+
columns: columns.map((col) => ({
|
|
26658
|
+
field: col.field,
|
|
26659
|
+
format: col.format,
|
|
26660
|
+
label: col.label,
|
|
26661
|
+
inferFormat: col.inferFormat
|
|
26662
|
+
})),
|
|
26663
|
+
// @ts-ignore fields is not typed on QuillReportInternal
|
|
26664
|
+
fields,
|
|
26665
|
+
triggerReload: false
|
|
26666
|
+
}
|
|
26667
|
+
});
|
|
26668
|
+
}).catch((e) => {
|
|
26669
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
26670
|
+
return;
|
|
26671
|
+
}
|
|
26672
|
+
console.error("Failed to fetch background rows", e);
|
|
26673
|
+
});
|
|
26674
|
+
}
|
|
26675
|
+
return uncacheableReportWithPivot;
|
|
26676
|
+
} catch (error2) {
|
|
26677
|
+
console.error(error2);
|
|
26678
|
+
return null;
|
|
26679
|
+
}
|
|
26680
|
+
}
|
|
24508
26681
|
const { report, error } = await fetchReport({
|
|
24509
26682
|
reportId,
|
|
24510
26683
|
client,
|
|
24511
26684
|
tenants,
|
|
24512
26685
|
flags,
|
|
24513
26686
|
additionalProcessing,
|
|
24514
|
-
filters:
|
|
26687
|
+
filters: allFilters,
|
|
24515
26688
|
getToken,
|
|
24516
26689
|
eventTracking,
|
|
24517
|
-
usePivotTask
|
|
26690
|
+
usePivotTask,
|
|
26691
|
+
overwriteCache: forceCacheToRefresh
|
|
26692
|
+
// usePivotTask: false,
|
|
24518
26693
|
});
|
|
24519
26694
|
if (error) {
|
|
24520
26695
|
console.error(error);
|
|
@@ -24542,9 +26717,10 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24542
26717
|
reportId,
|
|
24543
26718
|
client,
|
|
24544
26719
|
tenants,
|
|
24545
|
-
filters:
|
|
26720
|
+
filters: allFilters,
|
|
24546
26721
|
getToken,
|
|
24547
|
-
additionalProcessing
|
|
26722
|
+
additionalProcessing,
|
|
26723
|
+
overwriteCache: forceCacheToRefresh
|
|
24548
26724
|
}).then(({ rows, rowCount, columns, fields }) => {
|
|
24549
26725
|
if (reportRequestIds.current[reportId] !== requestId) {
|
|
24550
26726
|
return;
|
|
@@ -24568,19 +26744,30 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24568
26744
|
}
|
|
24569
26745
|
});
|
|
24570
26746
|
}).catch((e) => {
|
|
24571
|
-
if (e instanceof Error && e.name === "AbortError")
|
|
26747
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
26748
|
+
return;
|
|
26749
|
+
}
|
|
24572
26750
|
console.error("Failed to fetch background rows", e);
|
|
24573
26751
|
});
|
|
24574
26752
|
}
|
|
24575
26753
|
return report;
|
|
24576
26754
|
})
|
|
24577
26755
|
);
|
|
26756
|
+
if (!loadedDashes.includes(dashboardName) || !cacheEnabled || forceCacheToRefresh) {
|
|
26757
|
+
setLoadedDashes((prev) => prev.includes(dashboardName) ? prev : [...prev, dashboardName]);
|
|
26758
|
+
setLastUpdatedDict((prev) => ({ ...prev, [dashboardName]: Date.now() }));
|
|
26759
|
+
}
|
|
26760
|
+
if (logCacheStatistics) {
|
|
26761
|
+
console.log(`Dashboard "${dashboardName}": Cache Rate: ${(100 * totalCached / allReports.length).toFixed(1)}%, load time: ${((Date.now() - fetchStartTime) / 1e3).toFixed(2)} secs`);
|
|
26762
|
+
}
|
|
24578
26763
|
};
|
|
24579
26764
|
return {
|
|
24580
26765
|
isLoading: !!isLoading || !sections,
|
|
24581
26766
|
sections: isLoading ? null : sections,
|
|
24582
26767
|
filters,
|
|
24583
|
-
applyFilters
|
|
26768
|
+
applyFilters,
|
|
26769
|
+
lastUpdated,
|
|
26770
|
+
forceCacheRefresh
|
|
24584
26771
|
};
|
|
24585
26772
|
};
|
|
24586
26773
|
var useDashboardReportInternal = (reportId, config) => {
|
|
@@ -24604,15 +26791,6 @@ var useDashboardReportInternal = (reportId, config) => {
|
|
|
24604
26791
|
} = useDashboardInternal(reports[reportId]?.dashboardName ?? null);
|
|
24605
26792
|
const [pageLoading, setPageLoading] = useState2(false);
|
|
24606
26793
|
const [maxPage, setMaxPage] = useState2(0);
|
|
24607
|
-
useEffect2(() => {
|
|
24608
|
-
if (config?.initialFilters) {
|
|
24609
|
-
customReportFiltersDispatch({
|
|
24610
|
-
type: "ADD_CUSTOM_REPORT_FILTERS",
|
|
24611
|
-
reportId,
|
|
24612
|
-
data: config.initialFilters.map(convertCustomFilter)
|
|
24613
|
-
});
|
|
24614
|
-
}
|
|
24615
|
-
}, []);
|
|
24616
26794
|
const processedReport = useMemo2(() => {
|
|
24617
26795
|
if (!reports[reportId]) return null;
|
|
24618
26796
|
const dashboardName = reports[reportId].dashboardName;
|
|
@@ -24817,6 +26995,7 @@ var useDashboardReportInternal = (reportId, config) => {
|
|
|
24817
26995
|
};
|
|
24818
26996
|
var useDashboardReport = (reportId, config) => {
|
|
24819
26997
|
const { report, loading, applyFilters, deleteReport, nextPage } = useDashboardReportInternal(reportId, config);
|
|
26998
|
+
const { customReportFiltersDispatch } = useContext(ReportFiltersContext);
|
|
24820
26999
|
const fetchingRef = useRef2(false);
|
|
24821
27000
|
const fetchNextPage = async () => {
|
|
24822
27001
|
if (fetchingRef.current) {
|
|
@@ -24831,6 +27010,15 @@ var useDashboardReport = (reportId, config) => {
|
|
|
24831
27010
|
fetchingRef.current = false;
|
|
24832
27011
|
}
|
|
24833
27012
|
};
|
|
27013
|
+
useEffect2(() => {
|
|
27014
|
+
if (config?.initialFilters) {
|
|
27015
|
+
customReportFiltersDispatch({
|
|
27016
|
+
type: "ADD_CUSTOM_REPORT_FILTERS",
|
|
27017
|
+
reportId,
|
|
27018
|
+
data: config.initialFilters.map(convertCustomFilter)
|
|
27019
|
+
});
|
|
27020
|
+
}
|
|
27021
|
+
}, []);
|
|
24834
27022
|
return {
|
|
24835
27023
|
report,
|
|
24836
27024
|
isLoading: loading || fetchingRef.current,
|
|
@@ -27995,19 +30183,23 @@ var RenderLegend = ({
|
|
|
27995
30183
|
const seeAllMeasureRef = useRef5(null);
|
|
27996
30184
|
const seeAllTriggerRef = useRef5(null);
|
|
27997
30185
|
const itemRefs = useRef5([]);
|
|
27998
|
-
|
|
27999
|
-
const maxItems = limit ??
|
|
30186
|
+
const safePayload = payload ?? [];
|
|
30187
|
+
const maxItems = limit ?? safePayload.length;
|
|
28000
30188
|
const measuredLimit = visibleCount ?? maxItems;
|
|
28001
|
-
const visiblePayload =
|
|
30189
|
+
const visiblePayload = safePayload.slice(0, Math.min(maxItems, measuredLimit));
|
|
28002
30190
|
const handleOpen = () => setIsOpen(true);
|
|
28003
30191
|
const handleClose = () => setIsOpen(false);
|
|
28004
30192
|
useLayoutEffect2(() => {
|
|
28005
30193
|
if (!containerRef.current) return;
|
|
28006
|
-
if (!
|
|
30194
|
+
if (!safePayload.length) {
|
|
30195
|
+
setShowSeeAll(false);
|
|
30196
|
+
setVisibleCount(null);
|
|
30197
|
+
return;
|
|
30198
|
+
}
|
|
28007
30199
|
const updateVisibleCount = () => {
|
|
28008
30200
|
const containerWidth = containerRef.current?.offsetWidth ?? 0;
|
|
28009
30201
|
if (!containerWidth) return;
|
|
28010
|
-
const maxCount = Math.min(maxItems,
|
|
30202
|
+
const maxCount = Math.min(maxItems, safePayload.length);
|
|
28011
30203
|
const seeAllWidth = getOuterWidth(seeAllMeasureRef.current);
|
|
28012
30204
|
const computeCount = (reserveSeeAll) => {
|
|
28013
30205
|
const availableWidth = containerWidth - (reserveSeeAll ? seeAllWidth : 0);
|
|
@@ -28023,7 +30215,7 @@ var RenderLegend = ({
|
|
|
28023
30215
|
return Math.max(1, nextCount);
|
|
28024
30216
|
};
|
|
28025
30217
|
const countWithSeeAll = computeCount(true);
|
|
28026
|
-
const shouldShowSeeAll =
|
|
30218
|
+
const shouldShowSeeAll = safePayload.length > countWithSeeAll;
|
|
28027
30219
|
const finalCount = shouldShowSeeAll ? countWithSeeAll : computeCount(false);
|
|
28028
30220
|
setShowSeeAll(shouldShowSeeAll);
|
|
28029
30221
|
setVisibleCount(finalCount);
|
|
@@ -28032,7 +30224,8 @@ var RenderLegend = ({
|
|
|
28032
30224
|
const observer = new ResizeObserver(updateVisibleCount);
|
|
28033
30225
|
observer.observe(containerRef.current);
|
|
28034
30226
|
return () => observer.disconnect();
|
|
28035
|
-
}, [
|
|
30227
|
+
}, [safePayload.length, maxItems]);
|
|
30228
|
+
if (!safePayload.length) return null;
|
|
28036
30229
|
return /* @__PURE__ */ jsxs19(
|
|
28037
30230
|
"div",
|
|
28038
30231
|
{
|
|
@@ -28072,7 +30265,7 @@ var RenderLegend = ({
|
|
|
28072
30265
|
justifyContent: "flex-start",
|
|
28073
30266
|
flexWrap: "nowrap"
|
|
28074
30267
|
},
|
|
28075
|
-
children:
|
|
30268
|
+
children: safePayload.slice(0, maxItems).map((entry, index) => /* @__PURE__ */ jsx27(
|
|
28076
30269
|
"div",
|
|
28077
30270
|
{
|
|
28078
30271
|
ref: (element) => {
|
|
@@ -28161,7 +30354,7 @@ var RenderLegend = ({
|
|
|
28161
30354
|
maxWidth: 520,
|
|
28162
30355
|
gap: "0.5rem"
|
|
28163
30356
|
},
|
|
28164
|
-
children:
|
|
30357
|
+
children: safePayload.map((entry, index) => /* @__PURE__ */ jsx27(
|
|
28165
30358
|
LegendItem,
|
|
28166
30359
|
{
|
|
28167
30360
|
entry,
|
|
@@ -28511,8 +30704,8 @@ var PieChartWrapper = React4.forwardRef(
|
|
|
28511
30704
|
cy: "50%",
|
|
28512
30705
|
startAngle: 90,
|
|
28513
30706
|
endAngle: -270,
|
|
28514
|
-
innerRadius: isDonut ?
|
|
28515
|
-
outerRadius:
|
|
30707
|
+
innerRadius: isDonut ? "70%" : "0%",
|
|
30708
|
+
outerRadius: "100%",
|
|
28516
30709
|
paddingAngle: 0,
|
|
28517
30710
|
dataKey: category,
|
|
28518
30711
|
nameKey: index,
|
|
@@ -29115,8 +31308,8 @@ import {
|
|
|
29115
31308
|
} from "recharts";
|
|
29116
31309
|
|
|
29117
31310
|
// src/utils/axisFormatter.ts
|
|
29118
|
-
import { endOfWeek as endOfWeek2, format as format5, getWeek as getWeek2, isValid as
|
|
29119
|
-
import { utcToZonedTime as
|
|
31311
|
+
import { endOfWeek as endOfWeek2, format as format5, getWeek as getWeek2, isValid as isValid5, startOfWeek as startOfWeek5 } from "date-fns";
|
|
31312
|
+
import { utcToZonedTime as utcToZonedTime4 } from "date-fns-tz";
|
|
29120
31313
|
var axisFormatter = ({ value, field, fields }) => {
|
|
29121
31314
|
if (field === void 0 || field === null) return "";
|
|
29122
31315
|
if (value === void 0 || value === null) return "";
|
|
@@ -29232,8 +31425,8 @@ var formatPercent2 = (value) => {
|
|
|
29232
31425
|
return formatter.format(Number(value));
|
|
29233
31426
|
};
|
|
29234
31427
|
var _getUTCDateHelper2 = (value, fmt) => {
|
|
29235
|
-
const utcDate =
|
|
29236
|
-
if (!
|
|
31428
|
+
const utcDate = utcToZonedTime4(new Date(value), "UTC");
|
|
31429
|
+
if (!isValid5(utcDate)) return "Invalid date";
|
|
29237
31430
|
return format5(utcDate, fmt);
|
|
29238
31431
|
};
|
|
29239
31432
|
var format_YYYY2 = (value) => _getUTCDateHelper2(value, "yyyy");
|
|
@@ -29242,9 +31435,9 @@ var format_MMM_yyyy2 = (value) => _getUTCDateHelper2(value, "MMM yyyy");
|
|
|
29242
31435
|
var format_hh_ap_pm2 = (value) => _getUTCDateHelper2(value, "hh:mm aa");
|
|
29243
31436
|
var format_MMM_dd_yyyy2 = (value) => _getUTCDateHelper2(value, "dd MMM yyyy");
|
|
29244
31437
|
var format_MMM_dd_MMM_dd = (value) => {
|
|
29245
|
-
const utcDate =
|
|
29246
|
-
if (!
|
|
29247
|
-
const monday =
|
|
31438
|
+
const utcDate = utcToZonedTime4(new Date(value), "UTC");
|
|
31439
|
+
if (!isValid5(utcDate)) return "Invalid date";
|
|
31440
|
+
const monday = startOfWeek5(utcDate, { weekStartsOn: 1 });
|
|
29248
31441
|
const sunday = endOfWeek2(utcDate, { weekStartsOn: 1 });
|
|
29249
31442
|
if (format5(monday, "MMM") === format5(sunday, "MMM")) {
|
|
29250
31443
|
return `${format5(monday, "MMM dd")} - ${format5(sunday, "dd")}`;
|
|
@@ -29253,20 +31446,20 @@ var format_MMM_dd_MMM_dd = (value) => {
|
|
|
29253
31446
|
}
|
|
29254
31447
|
};
|
|
29255
31448
|
var format_MMM_dd_hh_mm_ap_pm2 = (value) => {
|
|
29256
|
-
const utcDate =
|
|
29257
|
-
if (!
|
|
31449
|
+
const utcDate = utcToZonedTime4(new Date(value), "UTC");
|
|
31450
|
+
if (!isValid5(utcDate)) return "Invalid date";
|
|
29258
31451
|
const formatStr = utcDate.getMinutes() === 0 ? "MMM do h a" : "MMM do h:mm a";
|
|
29259
31452
|
const res = format5(utcDate, formatStr);
|
|
29260
31453
|
return res.slice(0, -2) + res.slice(-2).toLowerCase();
|
|
29261
31454
|
};
|
|
29262
31455
|
var format_wo_yyyy2 = (value) => {
|
|
29263
|
-
const utcDate =
|
|
29264
|
-
if (!
|
|
31456
|
+
const utcDate = utcToZonedTime4(new Date(value), "UTC");
|
|
31457
|
+
if (!isValid5(utcDate)) return "Invalid date";
|
|
29265
31458
|
return `${getWeek2(utcDate)},${utcDate.getFullYear()}`;
|
|
29266
31459
|
};
|
|
29267
31460
|
|
|
29268
31461
|
// src/components/Chart/ChartTooltip.tsx
|
|
29269
|
-
import { format as format6, subDays as
|
|
31462
|
+
import { format as format6, subDays as subDays3 } from "date-fns";
|
|
29270
31463
|
|
|
29271
31464
|
// src/components/Chart/ChartTooltipFrame.tsx
|
|
29272
31465
|
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
@@ -29510,7 +31703,7 @@ function reformatComparisonPayload(props, primaryLabel, comparisonLabel) {
|
|
|
29510
31703
|
const nameKey = isComparison ? `comparison_${props.xAxisField}` : props.xAxisField;
|
|
29511
31704
|
const days = LABEL_TO_DAYS[primaryLabel] ?? 0;
|
|
29512
31705
|
const primaryDate = item.payload[props.xAxisField] ?? 0;
|
|
29513
|
-
const compDate =
|
|
31706
|
+
const compDate = subDays3(new Date(primaryDate), days + 1);
|
|
29514
31707
|
const date = item.payload[nameKey] ?? format6(compDate, props.xAxisFormat);
|
|
29515
31708
|
const name2 = props.dateFormatter(date);
|
|
29516
31709
|
const color2 = item.color;
|
|
@@ -30576,16 +32769,16 @@ import {
|
|
|
30576
32769
|
useState as useState12
|
|
30577
32770
|
} from "react";
|
|
30578
32771
|
import {
|
|
30579
|
-
startOfMonth as
|
|
32772
|
+
startOfMonth as startOfMonth4,
|
|
30580
32773
|
endOfMonth as endOfMonth2,
|
|
30581
32774
|
format as format7,
|
|
30582
32775
|
eachDayOfInterval,
|
|
30583
|
-
subMonths as
|
|
30584
|
-
startOfWeek as
|
|
32776
|
+
subMonths as subMonths5,
|
|
32777
|
+
startOfWeek as startOfWeek6,
|
|
30585
32778
|
endOfWeek as endOfWeek3,
|
|
30586
32779
|
differenceInDays as differenceInDays3,
|
|
30587
|
-
startOfDay as
|
|
30588
|
-
addMonths,
|
|
32780
|
+
startOfDay as startOfDay6,
|
|
32781
|
+
addMonths as addMonths2,
|
|
30589
32782
|
isBefore as isBefore2,
|
|
30590
32783
|
isAfter as isAfter2
|
|
30591
32784
|
} from "date-fns";
|
|
@@ -31110,20 +33303,20 @@ function CalendarRow({
|
|
|
31110
33303
|
setLocalPreset
|
|
31111
33304
|
}) {
|
|
31112
33305
|
const firstMonthDisplayedDates = eachDayOfInterval({
|
|
31113
|
-
start:
|
|
33306
|
+
start: startOfWeek6(anchorStartDate),
|
|
31114
33307
|
end: endOfWeek3(endOfMonth2(anchorStartDate))
|
|
31115
33308
|
});
|
|
31116
33309
|
const secondMonthDisplayedDates = eachDayOfInterval({
|
|
31117
|
-
start:
|
|
33310
|
+
start: startOfWeek6(startOfMonth4(anchorEndDate)),
|
|
31118
33311
|
end: endOfWeek3(anchorEndDate)
|
|
31119
33312
|
});
|
|
31120
33313
|
const incrementAnchorDates = () => {
|
|
31121
|
-
setAnchorStartDate(
|
|
31122
|
-
setAnchorEndDate(endOfMonth2(
|
|
33314
|
+
setAnchorStartDate(startOfMonth4(addMonths2(anchorStartDate, 1)));
|
|
33315
|
+
setAnchorEndDate(endOfMonth2(addMonths2(anchorEndDate, 1)));
|
|
31123
33316
|
};
|
|
31124
33317
|
const decrementAnchorDates = () => {
|
|
31125
|
-
setAnchorStartDate(
|
|
31126
|
-
setAnchorEndDate(endOfMonth2(
|
|
33318
|
+
setAnchorStartDate(startOfMonth4(subMonths5(anchorStartDate, 1)));
|
|
33319
|
+
setAnchorEndDate(endOfMonth2(subMonths5(anchorEndDate, 1)));
|
|
31127
33320
|
};
|
|
31128
33321
|
return /* @__PURE__ */ jsx40("div", { style: { position: "absolute", zIndex: 100, marginTop: 12 }, children: /* @__PURE__ */ jsxs30(
|
|
31129
33322
|
"div",
|
|
@@ -31377,10 +33570,10 @@ function DayPicker({
|
|
|
31377
33570
|
setLocalPreset,
|
|
31378
33571
|
theme
|
|
31379
33572
|
}) {
|
|
31380
|
-
const isStartDate = differenceInDays3(
|
|
31381
|
-
const isEndDate = differenceInDays3(
|
|
33573
|
+
const isStartDate = differenceInDays3(startOfDay6(date), startOfDay6(localStartDate || 0)) === 0;
|
|
33574
|
+
const isEndDate = differenceInDays3(startOfDay6(date), startOfDay6(localEndDate || 0)) === 0;
|
|
31382
33575
|
const isBetweenStartAndEnd = isBefore2(date, localEndDate || 0) && isAfter2(date, localStartDate || 0);
|
|
31383
|
-
const isBeginningOfWeek = differenceInDays3(
|
|
33576
|
+
const isBeginningOfWeek = differenceInDays3(startOfWeek6(date), date) === 0;
|
|
31384
33577
|
const isEndOfWeek = differenceInDays3(endOfWeek3(date), date) === 0;
|
|
31385
33578
|
return /* @__PURE__ */ jsx40(
|
|
31386
33579
|
"button",
|
|
@@ -31429,7 +33622,7 @@ function DayPicker({
|
|
|
31429
33622
|
});
|
|
31430
33623
|
setLocalPreset("");
|
|
31431
33624
|
}
|
|
31432
|
-
if (localStartDate && localEndDate && differenceInDays3(
|
|
33625
|
+
if (localStartDate && localEndDate && differenceInDays3(startOfDay6(date), startOfDay6(localStartDate)) === 0) {
|
|
31433
33626
|
setLocalStartDate(void 0);
|
|
31434
33627
|
setLocalEndDate(void 0);
|
|
31435
33628
|
}
|
|
@@ -31440,16 +33633,16 @@ function DayPicker({
|
|
|
31440
33633
|
}
|
|
31441
33634
|
function getAnchorStartDate(startDate, endDate) {
|
|
31442
33635
|
if (!startDate && !endDate) {
|
|
31443
|
-
return
|
|
33636
|
+
return startOfMonth4(subMonths5(/* @__PURE__ */ new Date(), 1));
|
|
31444
33637
|
}
|
|
31445
33638
|
if (startDate && !endDate) {
|
|
31446
|
-
return
|
|
33639
|
+
return startOfMonth4(startDate);
|
|
31447
33640
|
}
|
|
31448
33641
|
if (!startDate && endDate) {
|
|
31449
|
-
return
|
|
33642
|
+
return startOfMonth4(subMonths5(endDate, 1));
|
|
31450
33643
|
}
|
|
31451
33644
|
if (startDate && endDate) {
|
|
31452
|
-
return
|
|
33645
|
+
return startOfMonth4(startDate);
|
|
31453
33646
|
}
|
|
31454
33647
|
return /* @__PURE__ */ new Date();
|
|
31455
33648
|
}
|
|
@@ -31458,13 +33651,13 @@ function getAnchorEndDate(startDate, endDate) {
|
|
|
31458
33651
|
return endOfMonth2(/* @__PURE__ */ new Date());
|
|
31459
33652
|
}
|
|
31460
33653
|
if (startDate && !endDate) {
|
|
31461
|
-
return endOfMonth2(
|
|
33654
|
+
return endOfMonth2(addMonths2(startDate, 1));
|
|
31462
33655
|
}
|
|
31463
33656
|
if (!startDate && endDate) {
|
|
31464
33657
|
return endOfMonth2(endDate);
|
|
31465
33658
|
}
|
|
31466
33659
|
if (startDate && endDate) {
|
|
31467
|
-
return endOfMonth2(
|
|
33660
|
+
return endOfMonth2(addMonths2(startDate, 1));
|
|
31468
33661
|
}
|
|
31469
33662
|
return /* @__PURE__ */ new Date();
|
|
31470
33663
|
}
|
|
@@ -32659,6 +34852,164 @@ function DashboardFilter2({
|
|
|
32659
34852
|
// src/Chart.tsx
|
|
32660
34853
|
init_paginationProcessing();
|
|
32661
34854
|
|
|
34855
|
+
// src/utils/cloudCacheValidation.ts
|
|
34856
|
+
var LIMIT_CLAUSE_REGEX = /^limit\b\s+(?:all|\d+|\$\d+|:[a-zA-Z_][a-zA-Z0-9_]*|\?)/i;
|
|
34857
|
+
var SQL_CONTENT_TO_IGNORE_REGEX = /'(?:''|[^'])*'|"(?:[^"]|"")*"|`[^`]*`|\[[^\]]*\]|--[^\n]*|\/\*[\s\S]*?\*\//g;
|
|
34858
|
+
function isWordChar(char) {
|
|
34859
|
+
if (!char) {
|
|
34860
|
+
return false;
|
|
34861
|
+
}
|
|
34862
|
+
return /[A-Za-z0-9_]/.test(char);
|
|
34863
|
+
}
|
|
34864
|
+
function getFinalSqlStatement(query) {
|
|
34865
|
+
const statements = query.split(";").map((statement) => statement.trim()).filter((statement) => statement.length > 0);
|
|
34866
|
+
return statements[statements.length - 1] ?? "";
|
|
34867
|
+
}
|
|
34868
|
+
function hasTopLevelLimitClause(statement) {
|
|
34869
|
+
let depth = 0;
|
|
34870
|
+
for (let i = 0; i < statement.length; i += 1) {
|
|
34871
|
+
const char = statement[i];
|
|
34872
|
+
if (char === "(") {
|
|
34873
|
+
depth += 1;
|
|
34874
|
+
continue;
|
|
34875
|
+
}
|
|
34876
|
+
if (char === ")") {
|
|
34877
|
+
depth = Math.max(0, depth - 1);
|
|
34878
|
+
continue;
|
|
34879
|
+
}
|
|
34880
|
+
if (depth !== 0) {
|
|
34881
|
+
continue;
|
|
34882
|
+
}
|
|
34883
|
+
const previousChar = i > 0 ? statement[i - 1] : void 0;
|
|
34884
|
+
if (isWordChar(previousChar)) {
|
|
34885
|
+
continue;
|
|
34886
|
+
}
|
|
34887
|
+
if (!LIMIT_CLAUSE_REGEX.test(statement.slice(i))) {
|
|
34888
|
+
continue;
|
|
34889
|
+
}
|
|
34890
|
+
return true;
|
|
34891
|
+
}
|
|
34892
|
+
return false;
|
|
34893
|
+
}
|
|
34894
|
+
function unwrapIdentifier(identifier) {
|
|
34895
|
+
if (!identifier) {
|
|
34896
|
+
return "";
|
|
34897
|
+
}
|
|
34898
|
+
const trimmed = identifier.trim();
|
|
34899
|
+
if (trimmed.length < 2) {
|
|
34900
|
+
return trimmed;
|
|
34901
|
+
}
|
|
34902
|
+
const startsAndEndsWithDoubleQuote = trimmed.startsWith('"') && trimmed.endsWith('"');
|
|
34903
|
+
const startsAndEndsWithSingleQuote = trimmed.startsWith("'") && trimmed.endsWith("'");
|
|
34904
|
+
const startsAndEndsWithBackticks = trimmed.startsWith("`") && trimmed.endsWith("`");
|
|
34905
|
+
const startsAndEndsWithBrackets = trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
34906
|
+
if (startsAndEndsWithDoubleQuote || startsAndEndsWithSingleQuote || startsAndEndsWithBackticks || startsAndEndsWithBrackets) {
|
|
34907
|
+
return trimmed.slice(1, -1);
|
|
34908
|
+
}
|
|
34909
|
+
return trimmed;
|
|
34910
|
+
}
|
|
34911
|
+
function normalizeIdentifier(identifier) {
|
|
34912
|
+
return unwrapIdentifier(identifier).toLowerCase();
|
|
34913
|
+
}
|
|
34914
|
+
function hasRowFieldWithIdentifier(row, normalizedField) {
|
|
34915
|
+
if (!row || !normalizedField) {
|
|
34916
|
+
return false;
|
|
34917
|
+
}
|
|
34918
|
+
return Object.keys(row).some(
|
|
34919
|
+
(fieldName) => normalizeIdentifier(fieldName) === normalizedField
|
|
34920
|
+
);
|
|
34921
|
+
}
|
|
34922
|
+
function reportReferencesField(report, field, table) {
|
|
34923
|
+
const normalizedField = normalizeIdentifier(field);
|
|
34924
|
+
if (!normalizedField) {
|
|
34925
|
+
return false;
|
|
34926
|
+
}
|
|
34927
|
+
const referencedColumns = report?.referencedColumns ?? {};
|
|
34928
|
+
let entries = Object.entries(referencedColumns);
|
|
34929
|
+
if (entries.length === 0) {
|
|
34930
|
+
return false;
|
|
34931
|
+
}
|
|
34932
|
+
const normalizedTable = normalizeIdentifier(table);
|
|
34933
|
+
if (normalizedTable) {
|
|
34934
|
+
entries = entries.filter(
|
|
34935
|
+
([tableName]) => normalizeIdentifier(tableName) === normalizedTable
|
|
34936
|
+
);
|
|
34937
|
+
}
|
|
34938
|
+
const referencedFields = entries.flatMap(([, fields]) => fields ?? []);
|
|
34939
|
+
if (referencedFields.length === 0) {
|
|
34940
|
+
return false;
|
|
34941
|
+
}
|
|
34942
|
+
return referencedFields.some((referencedField) => {
|
|
34943
|
+
const normalizedReferencedField = normalizeIdentifier(referencedField);
|
|
34944
|
+
return normalizedReferencedField === normalizedField || normalizedReferencedField === "*";
|
|
34945
|
+
});
|
|
34946
|
+
}
|
|
34947
|
+
function isDateFieldMissingInReport(report) {
|
|
34948
|
+
if (!report?.dateField?.field || !report.dateField.table) {
|
|
34949
|
+
return false;
|
|
34950
|
+
}
|
|
34951
|
+
const dateField = report.dateField;
|
|
34952
|
+
if (!reportReferencesField(report, dateField.field, dateField.table)) {
|
|
34953
|
+
return true;
|
|
34954
|
+
}
|
|
34955
|
+
const firstRow = report.rows?.[0];
|
|
34956
|
+
if (!firstRow) {
|
|
34957
|
+
return false;
|
|
34958
|
+
}
|
|
34959
|
+
const normalizedDateField = normalizeIdentifier(dateField.field);
|
|
34960
|
+
const dateFieldExistsInFirstRow = hasRowFieldWithIdentifier(
|
|
34961
|
+
firstRow,
|
|
34962
|
+
normalizedDateField
|
|
34963
|
+
);
|
|
34964
|
+
return !dateFieldExistsInFirstRow;
|
|
34965
|
+
}
|
|
34966
|
+
function hasLimitClause(query) {
|
|
34967
|
+
if (!query) {
|
|
34968
|
+
return false;
|
|
34969
|
+
}
|
|
34970
|
+
const sanitizedQuery = query.replace(SQL_CONTENT_TO_IGNORE_REGEX, " ");
|
|
34971
|
+
const finalStatement = getFinalSqlStatement(sanitizedQuery);
|
|
34972
|
+
if (!finalStatement) {
|
|
34973
|
+
return false;
|
|
34974
|
+
}
|
|
34975
|
+
return hasTopLevelLimitClause(finalStatement);
|
|
34976
|
+
}
|
|
34977
|
+
function reportUsesLimitClause(report) {
|
|
34978
|
+
const queriesToInspect = report?.itemQuery && report.itemQuery.length > 0 ? report.itemQuery : report?.queryString ? [report.queryString] : [];
|
|
34979
|
+
return queriesToInspect.some(hasLimitClause);
|
|
34980
|
+
}
|
|
34981
|
+
function getMissingDashboardFilterFields({
|
|
34982
|
+
rows = [],
|
|
34983
|
+
dashboardFilters = []
|
|
34984
|
+
}) {
|
|
34985
|
+
const dateIndex = dashboardFilters.findIndex(
|
|
34986
|
+
(filter) => filter.filterType === "date_range"
|
|
34987
|
+
);
|
|
34988
|
+
const requiredFields = dashboardFilters.flatMap((filter, index) => {
|
|
34989
|
+
if (index === dateIndex || !filter.field) {
|
|
34990
|
+
return [];
|
|
34991
|
+
}
|
|
34992
|
+
const normalizedField = normalizeIdentifier(filter.field);
|
|
34993
|
+
if (!normalizedField) {
|
|
34994
|
+
return [];
|
|
34995
|
+
}
|
|
34996
|
+
return [
|
|
34997
|
+
{
|
|
34998
|
+
displayField: unwrapIdentifier(filter.field),
|
|
34999
|
+
normalizedField
|
|
35000
|
+
}
|
|
35001
|
+
];
|
|
35002
|
+
});
|
|
35003
|
+
const dedupedRequiredFields = requiredFields.filter(
|
|
35004
|
+
(field, index, fields) => fields.findIndex(
|
|
35005
|
+
(candidate) => candidate.normalizedField === field.normalizedField
|
|
35006
|
+
) === index
|
|
35007
|
+
);
|
|
35008
|
+
return dedupedRequiredFields.filter(
|
|
35009
|
+
({ normalizedField }) => rows.some((row) => !hasRowFieldWithIdentifier(row, normalizedField))
|
|
35010
|
+
).map(({ displayField }) => displayField);
|
|
35011
|
+
}
|
|
35012
|
+
|
|
32662
35013
|
// src/components/Dashboard/MetricComponent.tsx
|
|
32663
35014
|
init_dateRangePickerUtils();
|
|
32664
35015
|
import { useContext as useContext12 } from "react";
|
|
@@ -32766,7 +35117,7 @@ function QuillMetricComponent({
|
|
|
32766
35117
|
width: "100%"
|
|
32767
35118
|
}
|
|
32768
35119
|
}
|
|
32769
|
-
) : !report?.rows || report?.rows?.length === 0
|
|
35120
|
+
) : !report?.rows || report?.rows?.length === 0 ? /* @__PURE__ */ jsx44(
|
|
32770
35121
|
"div",
|
|
32771
35122
|
{
|
|
32772
35123
|
style: {
|
|
@@ -36285,6 +38636,7 @@ function QuillTableDashboardComponent({
|
|
|
36285
38636
|
}
|
|
36286
38637
|
|
|
36287
38638
|
// src/Chart.tsx
|
|
38639
|
+
init_valueFormatter();
|
|
36288
38640
|
import { Fragment as Fragment5, jsx as jsx49, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
36289
38641
|
var MAX_ROWS_FOR_GENERIC_TABLE = 500;
|
|
36290
38642
|
function sumByKey(arr, key) {
|
|
@@ -36321,7 +38673,8 @@ function Chart({
|
|
|
36321
38673
|
filters,
|
|
36322
38674
|
onClickChartElement,
|
|
36323
38675
|
dateBucket,
|
|
36324
|
-
propagateChanges
|
|
38676
|
+
propagateChanges,
|
|
38677
|
+
isAdmin = false
|
|
36325
38678
|
}) {
|
|
36326
38679
|
const [schemaData] = useContext16(SchemaDataContext);
|
|
36327
38680
|
const { reload } = useReportInternal(reportId);
|
|
@@ -36443,6 +38796,25 @@ function Chart({
|
|
|
36443
38796
|
}
|
|
36444
38797
|
}, [report, theme]);
|
|
36445
38798
|
const [client, clientLoading] = useContext16(ClientContext);
|
|
38799
|
+
const cloudCacheEnabled = useMemo13(() => {
|
|
38800
|
+
return !!client?.features?.cloudCache;
|
|
38801
|
+
}, [client]);
|
|
38802
|
+
const shouldShowCloudCacheValidationErrors = isAdmin && cloudCacheEnabled;
|
|
38803
|
+
const isMissingDateField = useMemo13(() => {
|
|
38804
|
+
if (!shouldShowCloudCacheValidationErrors) return false;
|
|
38805
|
+
return isDateFieldMissingInReport(report);
|
|
38806
|
+
}, [report, shouldShowCloudCacheValidationErrors]);
|
|
38807
|
+
const usesLimitInQuery = useMemo13(() => {
|
|
38808
|
+
if (!shouldShowCloudCacheValidationErrors) return false;
|
|
38809
|
+
return reportUsesLimitClause(report);
|
|
38810
|
+
}, [report, shouldShowCloudCacheValidationErrors]);
|
|
38811
|
+
const missingDashboardFilterFields = useMemo13(() => {
|
|
38812
|
+
if (!shouldShowCloudCacheValidationErrors || !report) return [];
|
|
38813
|
+
return getMissingDashboardFilterFields({
|
|
38814
|
+
rows: report.rows,
|
|
38815
|
+
dashboardFilters
|
|
38816
|
+
});
|
|
38817
|
+
}, [report, dashboardFilters, shouldShowCloudCacheValidationErrors]);
|
|
36446
38818
|
const [error, setError] = useState19(void 0);
|
|
36447
38819
|
const updateFilter = (filter, value, comparison) => {
|
|
36448
38820
|
let filterValue = {};
|
|
@@ -36583,6 +38955,30 @@ function Chart({
|
|
|
36583
38955
|
if (report?.error || error) {
|
|
36584
38956
|
return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(ChartError, { errorMessage: report?.error ?? error }) });
|
|
36585
38957
|
}
|
|
38958
|
+
if (isMissingDateField) {
|
|
38959
|
+
return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(
|
|
38960
|
+
ChartError,
|
|
38961
|
+
{
|
|
38962
|
+
errorMessage: `The query for this report is missing dashboard date filter field ${report?.dateField?.field}, which is necessary for date filtering on this dashboard when the cache is enabled.`
|
|
38963
|
+
}
|
|
38964
|
+
) });
|
|
38965
|
+
}
|
|
38966
|
+
if (usesLimitInQuery) {
|
|
38967
|
+
return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(
|
|
38968
|
+
ChartError,
|
|
38969
|
+
{
|
|
38970
|
+
errorMessage: `The query for this report uses the LIMIT keyword, which is not supported when the cache is enabled.`
|
|
38971
|
+
}
|
|
38972
|
+
) });
|
|
38973
|
+
}
|
|
38974
|
+
if (missingDashboardFilterFields.length) {
|
|
38975
|
+
return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(
|
|
38976
|
+
ChartError,
|
|
38977
|
+
{
|
|
38978
|
+
errorMessage: `The query for this report is missing dashboard filter fields: ${missingDashboardFilterFields.join(", ")}`
|
|
38979
|
+
}
|
|
38980
|
+
) });
|
|
38981
|
+
}
|
|
36586
38982
|
return /* @__PURE__ */ jsxs37(
|
|
36587
38983
|
"div",
|
|
36588
38984
|
{
|
|
@@ -36913,7 +39309,7 @@ var ChartDisplay = ({
|
|
|
36913
39309
|
);
|
|
36914
39310
|
}
|
|
36915
39311
|
if (config?.chartType?.toLowerCase() === "metric") {
|
|
36916
|
-
if (!config?.rows || config?.rows?.length === 0
|
|
39312
|
+
if (!config?.rows || config?.rows?.length === 0) {
|
|
36917
39313
|
return /* @__PURE__ */ jsx49(
|
|
36918
39314
|
"div",
|
|
36919
39315
|
{
|
|
@@ -36951,6 +39347,36 @@ var ChartDisplay = ({
|
|
|
36951
39347
|
}
|
|
36952
39348
|
);
|
|
36953
39349
|
}
|
|
39350
|
+
if (config?.pivotRows && config?.pivotRows?.length > 0) {
|
|
39351
|
+
return /* @__PURE__ */ jsx49(
|
|
39352
|
+
"div",
|
|
39353
|
+
{
|
|
39354
|
+
style: {
|
|
39355
|
+
fontFamily: theme?.fontFamily,
|
|
39356
|
+
fontSize: 32,
|
|
39357
|
+
color: theme?.primaryTextColor,
|
|
39358
|
+
fontWeight: "600",
|
|
39359
|
+
textOverflow: "ellipsis",
|
|
39360
|
+
margin: 0,
|
|
39361
|
+
whiteSpace: "nowrap",
|
|
39362
|
+
boxSizing: "content-box",
|
|
39363
|
+
maxWidth: "100%",
|
|
39364
|
+
textAlign: "left",
|
|
39365
|
+
overflow: "hidden",
|
|
39366
|
+
height: containerStyle?.height || "100%",
|
|
39367
|
+
display: "flex",
|
|
39368
|
+
width: "100%",
|
|
39369
|
+
flexDirection: "row",
|
|
39370
|
+
...containerStyle
|
|
39371
|
+
},
|
|
39372
|
+
className,
|
|
39373
|
+
children: /* @__PURE__ */ jsx49(QuillMetricComponent, { report: config ?? EMPTY_REPORT, children: quillFormat({
|
|
39374
|
+
value: config?.pivotRows?.[0]?.[config?.xAxisField],
|
|
39375
|
+
format: config?.xAxisFormat
|
|
39376
|
+
}) ?? "No results" })
|
|
39377
|
+
}
|
|
39378
|
+
);
|
|
39379
|
+
}
|
|
36954
39380
|
return /* @__PURE__ */ jsx49(
|
|
36955
39381
|
"div",
|
|
36956
39382
|
{
|
|
@@ -37899,7 +40325,7 @@ init_Filter();
|
|
|
37899
40325
|
import { useState as useState22, useEffect as useEffect18, useMemo as useMemo15 } from "react";
|
|
37900
40326
|
init_textProcessing();
|
|
37901
40327
|
init_filterProcessing();
|
|
37902
|
-
import { format as format8, isValid as
|
|
40328
|
+
import { format as format8, isValid as isValid6, parse as parse4, startOfToday as startOfToday2 } from "date-fns";
|
|
37903
40329
|
import { Fragment as Fragment8, jsx as jsx55, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
37904
40330
|
function FilterModal({
|
|
37905
40331
|
schema,
|
|
@@ -38100,7 +40526,7 @@ function FilterModal({
|
|
|
38100
40526
|
DateOperator.LessThan,
|
|
38101
40527
|
DateOperator.LessThanOrEqualTo,
|
|
38102
40528
|
DateOperator.NotEqualTo
|
|
38103
|
-
].includes(operator2) && !
|
|
40529
|
+
].includes(operator2) && !isValid6(parse4(value, "yyyy-mm-dd", /* @__PURE__ */ new Date())) && (filterInitialized || !filter)) {
|
|
38104
40530
|
setValue(startOfToday2().toISOString().substring(0, 10));
|
|
38105
40531
|
} else if (type === FieldType.Date && [
|
|
38106
40532
|
DateOperator.InTheLast,
|
|
@@ -38290,7 +40716,7 @@ function FilterModal({
|
|
|
38290
40716
|
case DateOperator.GreaterThanOrEqualTo:
|
|
38291
40717
|
case DateOperator.LessThanOrEqualTo: {
|
|
38292
40718
|
const parsedDate = parse4(value, "yyyy-mm-dd", /* @__PURE__ */ new Date());
|
|
38293
|
-
if (!
|
|
40719
|
+
if (!isValid6(parsedDate)) {
|
|
38294
40720
|
alert("Please specify a valid date in yyyy-mm-dd");
|
|
38295
40721
|
return;
|
|
38296
40722
|
}
|
|
@@ -38818,6 +41244,9 @@ function validateTemplatesAgainstFilters(filters, templates) {
|
|
|
38818
41244
|
}
|
|
38819
41245
|
async function addTemplatesToDashboard(name2, newTemplates, client, dashboardData, getToken, eventTracking) {
|
|
38820
41246
|
try {
|
|
41247
|
+
if (!newTemplates?.length) {
|
|
41248
|
+
return null;
|
|
41249
|
+
}
|
|
38821
41250
|
const { publicKey, tenants } = client;
|
|
38822
41251
|
if (tenants) {
|
|
38823
41252
|
throw new Error("Adding from template not yet supported for tenants");
|
|
@@ -38870,6 +41299,7 @@ async function addTemplatesToDashboard(name2, newTemplates, client, dashboardDat
|
|
|
38870
41299
|
function: "addTemplatesToDashboard"
|
|
38871
41300
|
}
|
|
38872
41301
|
});
|
|
41302
|
+
return null;
|
|
38873
41303
|
}
|
|
38874
41304
|
}
|
|
38875
41305
|
|
|
@@ -40366,7 +42796,7 @@ import {
|
|
|
40366
42796
|
useEffect as useEffect25,
|
|
40367
42797
|
useRef as useRef20,
|
|
40368
42798
|
useMemo as useMemo22,
|
|
40369
|
-
useCallback as
|
|
42799
|
+
useCallback as useCallback5
|
|
40370
42800
|
} from "react";
|
|
40371
42801
|
import MonacoEditor from "@monaco-editor/react";
|
|
40372
42802
|
|
|
@@ -40377,7 +42807,7 @@ import {
|
|
|
40377
42807
|
useState as useState30,
|
|
40378
42808
|
useContext as useContext26,
|
|
40379
42809
|
useMemo as useMemo21,
|
|
40380
|
-
useCallback as
|
|
42810
|
+
useCallback as useCallback4
|
|
40381
42811
|
} from "react";
|
|
40382
42812
|
import {
|
|
40383
42813
|
closestCenter,
|
|
@@ -40398,7 +42828,7 @@ import { CSS as DND_CSS } from "@dnd-kit/utilities";
|
|
|
40398
42828
|
|
|
40399
42829
|
// src/internals/ReportBuilder/PivotModal.tsx
|
|
40400
42830
|
import {
|
|
40401
|
-
useCallback as
|
|
42831
|
+
useCallback as useCallback3,
|
|
40402
42832
|
useContext as useContext23,
|
|
40403
42833
|
useMemo as useMemo18,
|
|
40404
42834
|
useState as useState27,
|
|
@@ -40793,7 +43223,7 @@ import {
|
|
|
40793
43223
|
eachMonthOfInterval,
|
|
40794
43224
|
eachWeekOfInterval,
|
|
40795
43225
|
eachYearOfInterval,
|
|
40796
|
-
isValid as
|
|
43226
|
+
isValid as isValid7,
|
|
40797
43227
|
parseISO as parseISO3
|
|
40798
43228
|
} from "date-fns";
|
|
40799
43229
|
init_pivotProcessing();
|
|
@@ -41281,7 +43711,7 @@ var PivotModal = ({
|
|
|
41281
43711
|
setIsOpen(false);
|
|
41282
43712
|
setPopUpTitle("Add pivot");
|
|
41283
43713
|
};
|
|
41284
|
-
const onCommitPivot =
|
|
43714
|
+
const onCommitPivot = useCallback3(() => {
|
|
41285
43715
|
const errors2 = [];
|
|
41286
43716
|
if ((pivotAggregations?.length ?? 0) === 0) {
|
|
41287
43717
|
errors2.push("You must have at least one aggregation");
|
|
@@ -41423,7 +43853,7 @@ var PivotModal = ({
|
|
|
41423
43853
|
const onEditRecommendedPivot = (pivot) => {
|
|
41424
43854
|
onEditPivot(pivot, null);
|
|
41425
43855
|
};
|
|
41426
|
-
const refreshPivots =
|
|
43856
|
+
const refreshPivots = useCallback3(async () => {
|
|
41427
43857
|
if (!client) {
|
|
41428
43858
|
return;
|
|
41429
43859
|
}
|
|
@@ -44474,7 +46904,7 @@ function ChartBuilder({
|
|
|
44474
46904
|
template: true,
|
|
44475
46905
|
referenceLines: []
|
|
44476
46906
|
};
|
|
44477
|
-
const
|
|
46907
|
+
const updateDashboardFilters2 = async (dashboardName) => {
|
|
44478
46908
|
if (dashboardConfig && dashboardConfig[dashboardName]) {
|
|
44479
46909
|
return dashboardConfig[dashboardName];
|
|
44480
46910
|
}
|
|
@@ -44796,7 +47226,7 @@ function ChartBuilder({
|
|
|
44796
47226
|
if (destinationDashboardName) {
|
|
44797
47227
|
dashboardName = destinationDashboardName;
|
|
44798
47228
|
}
|
|
44799
|
-
const curDashboard = await
|
|
47229
|
+
const curDashboard = await updateDashboardFilters2(dashboardName);
|
|
44800
47230
|
setDashboardOptions(dashboardOptions2);
|
|
44801
47231
|
curFormData.dashboardName = dashboardName;
|
|
44802
47232
|
const curSchemaData = schemaData.schemaWithCustomFields;
|
|
@@ -44940,7 +47370,7 @@ function ChartBuilder({
|
|
|
44940
47370
|
) ?? {};
|
|
44941
47371
|
}, [client?.allTenantTypes]);
|
|
44942
47372
|
const [selectedPivotTable, setSelectedPivotTable] = useState30(pivotData);
|
|
44943
|
-
const getDefaultXAxisFormat =
|
|
47373
|
+
const getDefaultXAxisFormat = useCallback4(
|
|
44944
47374
|
(form) => {
|
|
44945
47375
|
if (form.pivot?.rowField) {
|
|
44946
47376
|
if (isDateField(form.pivot.rowFieldType ?? "")) {
|
|
@@ -46083,7 +48513,7 @@ function ChartBuilder({
|
|
|
46083
48513
|
value: formData.dashboardName || "",
|
|
46084
48514
|
onChange: async (e) => {
|
|
46085
48515
|
handleChange(e.target.value, "dashboardName");
|
|
46086
|
-
await
|
|
48516
|
+
await updateDashboardFilters2(e.target.value);
|
|
46087
48517
|
},
|
|
46088
48518
|
options: dashboardOptions.map((elem) => ({
|
|
46089
48519
|
label: elem.label,
|
|
@@ -48316,7 +50746,7 @@ function SQLEditor({
|
|
|
48316
50746
|
onCloseChartBuilder && onCloseChartBuilder();
|
|
48317
50747
|
}
|
|
48318
50748
|
}, [isChartBuilderOpen]);
|
|
48319
|
-
const handleRunSqlPrompt =
|
|
50749
|
+
const handleRunSqlPrompt = useCallback5(async () => {
|
|
48320
50750
|
if (!client || sqlResponseLoading) {
|
|
48321
50751
|
return;
|
|
48322
50752
|
}
|
|
@@ -48335,7 +50765,7 @@ function SQLEditor({
|
|
|
48335
50765
|
setQuery(resp.message);
|
|
48336
50766
|
setSqlResponseLoading(false);
|
|
48337
50767
|
}, [sqlPrompt, sqlResponseLoading]);
|
|
48338
|
-
const debounceRunSqlPrompt =
|
|
50768
|
+
const debounceRunSqlPrompt = useCallback5(
|
|
48339
50769
|
createDebounce(handleRunSqlPrompt, 500),
|
|
48340
50770
|
[handleRunSqlPrompt]
|
|
48341
50771
|
);
|
|
@@ -54450,7 +56880,7 @@ function StaticChart(props) {
|
|
|
54450
56880
|
pageLoading,
|
|
54451
56881
|
nextPage,
|
|
54452
56882
|
prevPage,
|
|
54453
|
-
sortRows
|
|
56883
|
+
sortRows: sortRows2
|
|
54454
56884
|
} = useDashboardReportInternal(reportId);
|
|
54455
56885
|
const baseStyle = report?.chartType && CHART_TYPE_STYLES[report.chartType] ? CHART_TYPE_STYLES[report.chartType] : DEFAULT_STYLE;
|
|
54456
56886
|
const mergedStyle = className ? { ...containerStyle ?? {} } : { ...baseStyle, ...containerStyle ?? {} };
|
|
@@ -54470,7 +56900,7 @@ function StaticChart(props) {
|
|
|
54470
56900
|
}
|
|
54471
56901
|
};
|
|
54472
56902
|
const onSortChange = (sort) => {
|
|
54473
|
-
|
|
56903
|
+
sortRows2({
|
|
54474
56904
|
field: sort.field,
|
|
54475
56905
|
direction: sort.direction
|
|
54476
56906
|
});
|