@quillsql/react 2.16.20 → 2.16.21
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 +2413 -198
- package/dist/index.d.cts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +2410 -177
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -1537,6 +1537,7 @@ var init_dateRangePickerUtils = __esm({
|
|
|
1537
1537
|
}
|
|
1538
1538
|
});
|
|
1539
1539
|
const defaultCustomIntervals = defaultIntervals.flatMap((interval2) => {
|
|
1540
|
+
const normalizedLabel = interval2.label?.toLowerCase().trim();
|
|
1540
1541
|
let createdIntervals = [];
|
|
1541
1542
|
if (interval2.label === "This week") {
|
|
1542
1543
|
createdIntervals = [
|
|
@@ -1686,13 +1687,13 @@ var init_dateRangePickerUtils = __esm({
|
|
|
1686
1687
|
unit: "months"
|
|
1687
1688
|
}
|
|
1688
1689
|
];
|
|
1689
|
-
} else if (
|
|
1690
|
+
} else if (normalizedLabel === "last month") {
|
|
1690
1691
|
createdIntervals = [
|
|
1691
1692
|
{
|
|
1692
1693
|
type: "previous_month"
|
|
1693
1694
|
}
|
|
1694
1695
|
];
|
|
1695
|
-
} else if (
|
|
1696
|
+
} else if (normalizedLabel === "previous quarter" || normalizedLabel === "last quarter") {
|
|
1696
1697
|
createdIntervals = [
|
|
1697
1698
|
{
|
|
1698
1699
|
type: "previous_quarter"
|
|
@@ -2086,13 +2087,13 @@ var init_Filter = __esm({
|
|
|
2086
2087
|
TimeUnit2[TimeUnit2["Hour"] = HOUR] = "Hour";
|
|
2087
2088
|
return TimeUnit2;
|
|
2088
2089
|
})(TimeUnit || {});
|
|
2089
|
-
FieldType = /* @__PURE__ */ ((
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
return
|
|
2090
|
+
FieldType = /* @__PURE__ */ ((FieldType3) => {
|
|
2091
|
+
FieldType3[FieldType3["String"] = STRING] = "String";
|
|
2092
|
+
FieldType3[FieldType3["Number"] = NUMBER] = "Number";
|
|
2093
|
+
FieldType3[FieldType3["Date"] = DATE] = "Date";
|
|
2094
|
+
FieldType3[FieldType3["Null"] = NULL] = "Null";
|
|
2095
|
+
FieldType3[FieldType3["Boolean"] = BOOLEAN] = "Boolean";
|
|
2096
|
+
return FieldType3;
|
|
2096
2097
|
})(FieldType || {});
|
|
2097
2098
|
InternalFilterType = /* @__PURE__ */ ((InternalFilterType2) => {
|
|
2098
2099
|
InternalFilterType2["StringFilter"] = "string-filter";
|
|
@@ -2238,7 +2239,7 @@ var init_Filter = __esm({
|
|
|
2238
2239
|
fieldType = FieldType.Boolean;
|
|
2239
2240
|
operator = filter.operator;
|
|
2240
2241
|
field = filter.field;
|
|
2241
|
-
value =
|
|
2242
|
+
value = filter.value;
|
|
2242
2243
|
table = filter.table;
|
|
2243
2244
|
return {
|
|
2244
2245
|
filterType,
|
|
@@ -2249,7 +2250,7 @@ var init_Filter = __esm({
|
|
|
2249
2250
|
operator
|
|
2250
2251
|
};
|
|
2251
2252
|
case "date" /* Date */:
|
|
2252
|
-
if (typeof filter.value === "object" && filter.value && "
|
|
2253
|
+
if (typeof filter.value === "object" && filter.value && "unit" in filter.value) {
|
|
2253
2254
|
if (filter.value.value && typeof filter.value.value !== "number" || typeof filter.value.unit !== "string") {
|
|
2254
2255
|
throw new Error(
|
|
2255
2256
|
`Invalid value for DateFilter, expected { value: number, unit: string }, got ${filter.value}`
|
|
@@ -2305,7 +2306,7 @@ var init_Filter = __esm({
|
|
|
2305
2306
|
table = filter.table;
|
|
2306
2307
|
} else {
|
|
2307
2308
|
throw new Error(
|
|
2308
|
-
`Invalid value for DateFilter, expected { value
|
|
2309
|
+
`Invalid value for DateFilter, expected { value?: number, unit: string }, { startDate: string, endDate: string}, or string, got ${filter.value}`
|
|
2309
2310
|
);
|
|
2310
2311
|
}
|
|
2311
2312
|
return {
|
|
@@ -15908,7 +15909,7 @@ var init_dataProcessing = __esm({
|
|
|
15908
15909
|
} else {
|
|
15909
15910
|
if (data.dateField && data.dateField.field) {
|
|
15910
15911
|
const dateField = data.dateField.field.replaceAll('"', "");
|
|
15911
|
-
const
|
|
15912
|
+
const maxDate2 = new Date(
|
|
15912
15913
|
data.rows.reduce((acc, row) => {
|
|
15913
15914
|
const rowValue = row[dateField];
|
|
15914
15915
|
if (rowValue) {
|
|
@@ -15917,7 +15918,7 @@ var init_dataProcessing = __esm({
|
|
|
15917
15918
|
return Math.max(acc, 0);
|
|
15918
15919
|
}, 0)
|
|
15919
15920
|
);
|
|
15920
|
-
const
|
|
15921
|
+
const minDate2 = new Date(
|
|
15921
15922
|
data.rows.reduce((acc, row) => {
|
|
15922
15923
|
const rowValue = row[dateField];
|
|
15923
15924
|
if (rowValue) {
|
|
@@ -15927,16 +15928,16 @@ var init_dataProcessing = __esm({
|
|
|
15927
15928
|
}, (/* @__PURE__ */ new Date("3022-01-01")).getTime())
|
|
15928
15929
|
);
|
|
15929
15930
|
const dateBucket = getDateBucketFromRange({
|
|
15930
|
-
start:
|
|
15931
|
-
end:
|
|
15931
|
+
start: minDate2,
|
|
15932
|
+
end: maxDate2
|
|
15932
15933
|
});
|
|
15933
15934
|
const minDateBucket = getDateString(
|
|
15934
|
-
|
|
15935
|
+
minDate2.toISOString(),
|
|
15935
15936
|
void 0,
|
|
15936
15937
|
dateBucket
|
|
15937
15938
|
);
|
|
15938
15939
|
const maxDateBucket = getDateString(
|
|
15939
|
-
|
|
15940
|
+
maxDate2.toISOString(),
|
|
15940
15941
|
void 0,
|
|
15941
15942
|
dateBucket
|
|
15942
15943
|
);
|
|
@@ -16053,8 +16054,9 @@ async function generatePivotWithSQL({
|
|
|
16053
16054
|
getPivotRowCount = true,
|
|
16054
16055
|
caller,
|
|
16055
16056
|
getToken,
|
|
16056
|
-
reportBuilderState
|
|
16057
|
+
reportBuilderState,
|
|
16057
16058
|
// Add reportBuilderState parameter
|
|
16059
|
+
overwriteCache = false
|
|
16058
16060
|
}) {
|
|
16059
16061
|
const databaseType = client.databaseType || "postgresql";
|
|
16060
16062
|
if (!pivot.aggregations?.length && pivot.aggregationType) {
|
|
@@ -16103,7 +16105,8 @@ async function generatePivotWithSQL({
|
|
|
16103
16105
|
})),
|
|
16104
16106
|
// Only pass dashboard filters in Dashboard context, not ReportBuilder
|
|
16105
16107
|
tenants,
|
|
16106
|
-
additionalProcessing
|
|
16108
|
+
additionalProcessing,
|
|
16109
|
+
overwriteCache
|
|
16107
16110
|
},
|
|
16108
16111
|
getToken
|
|
16109
16112
|
});
|
|
@@ -16277,8 +16280,9 @@ async function generatePivotTable({
|
|
|
16277
16280
|
additionalProcessing,
|
|
16278
16281
|
caller,
|
|
16279
16282
|
pivotQuery,
|
|
16280
|
-
reportBuilderState
|
|
16283
|
+
reportBuilderState,
|
|
16281
16284
|
// Add reportBuilderState parameter
|
|
16285
|
+
overwriteCache
|
|
16282
16286
|
}) {
|
|
16283
16287
|
try {
|
|
16284
16288
|
if (report && client) {
|
|
@@ -16295,8 +16299,9 @@ async function generatePivotTable({
|
|
|
16295
16299
|
additionalProcessing,
|
|
16296
16300
|
caller,
|
|
16297
16301
|
getToken,
|
|
16298
|
-
reportBuilderState
|
|
16302
|
+
reportBuilderState,
|
|
16299
16303
|
// Pass reportBuilderState
|
|
16304
|
+
overwriteCache
|
|
16300
16305
|
});
|
|
16301
16306
|
return pivotTable;
|
|
16302
16307
|
}
|
|
@@ -18182,7 +18187,7 @@ var init_tableProcessing = __esm({
|
|
|
18182
18187
|
try {
|
|
18183
18188
|
let data;
|
|
18184
18189
|
if (reportBuilderState) {
|
|
18185
|
-
|
|
18190
|
+
({ data } = await quillFetch({
|
|
18186
18191
|
client,
|
|
18187
18192
|
task: "report-builder-counts",
|
|
18188
18193
|
metadata: {
|
|
@@ -18196,9 +18201,9 @@ var init_tableProcessing = __esm({
|
|
|
18196
18201
|
tenants
|
|
18197
18202
|
},
|
|
18198
18203
|
getToken
|
|
18199
|
-
});
|
|
18204
|
+
}));
|
|
18200
18205
|
} else {
|
|
18201
|
-
|
|
18206
|
+
({ data } = await quillFetch({
|
|
18202
18207
|
client,
|
|
18203
18208
|
task: "query",
|
|
18204
18209
|
metadata: {
|
|
@@ -18212,7 +18217,7 @@ var init_tableProcessing = __esm({
|
|
|
18212
18217
|
},
|
|
18213
18218
|
urlParameters: `caller=getCounts&task=query`,
|
|
18214
18219
|
getToken
|
|
18215
|
-
});
|
|
18220
|
+
}));
|
|
18216
18221
|
}
|
|
18217
18222
|
if (data.errorMessage) {
|
|
18218
18223
|
return { filteredColumns: columns, exceededColumns: void 0 };
|
|
@@ -19202,9 +19207,9 @@ var init_dataFetcher = __esm({
|
|
|
19202
19207
|
return { error: "Failed to fetch data" };
|
|
19203
19208
|
}
|
|
19204
19209
|
};
|
|
19205
|
-
parseFetchResponse = async (client, task, response, getToken) => {
|
|
19210
|
+
parseFetchResponse = async (client, task, response, getToken, useInMemory = false) => {
|
|
19206
19211
|
try {
|
|
19207
|
-
if (response.status === "error" || response.data?.error) {
|
|
19212
|
+
if (response.status === "error" || response.data?.error && !useInMemory) {
|
|
19208
19213
|
let errorPrefix = "Error: ";
|
|
19209
19214
|
let errorMessage = "Failed to fetch report: " + (response.error || response.data?.error);
|
|
19210
19215
|
if (task === "query" || task === "report-builder") {
|
|
@@ -19817,7 +19822,8 @@ async function cleanDashboardItem({
|
|
|
19817
19822
|
additionalProcessing,
|
|
19818
19823
|
customFields,
|
|
19819
19824
|
skipPivotFetch,
|
|
19820
|
-
tenants
|
|
19825
|
+
tenants,
|
|
19826
|
+
overwriteCache
|
|
19821
19827
|
}) {
|
|
19822
19828
|
if (!item) return defaultDashboardItem;
|
|
19823
19829
|
if (!item.rows) {
|
|
@@ -19921,7 +19927,8 @@ async function cleanDashboardItem({
|
|
|
19921
19927
|
dateBucket,
|
|
19922
19928
|
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
19923
19929
|
tenants,
|
|
19924
|
-
customFields
|
|
19930
|
+
customFields,
|
|
19931
|
+
overwriteCache
|
|
19925
19932
|
);
|
|
19926
19933
|
}
|
|
19927
19934
|
} catch (e) {
|
|
@@ -20026,7 +20033,7 @@ async function cleanDashboardItem({
|
|
|
20026
20033
|
referenceLines: item.referenceLines
|
|
20027
20034
|
};
|
|
20028
20035
|
}
|
|
20029
|
-
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
20036
|
+
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields, overwriteCache) {
|
|
20030
20037
|
if (!report) return void 0;
|
|
20031
20038
|
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
20032
20039
|
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
@@ -20094,7 +20101,8 @@ async function getPivotTable(report, dashboardFilters, dashboardName, getToken,
|
|
|
20094
20101
|
dashboardFilters,
|
|
20095
20102
|
tenants,
|
|
20096
20103
|
additionalProcessing,
|
|
20097
|
-
getToken
|
|
20104
|
+
getToken,
|
|
20105
|
+
overwriteCache
|
|
20098
20106
|
});
|
|
20099
20107
|
return pivotTable;
|
|
20100
20108
|
} catch (e) {
|
|
@@ -20342,7 +20350,8 @@ async function fetchReportRows({
|
|
|
20342
20350
|
filters = [],
|
|
20343
20351
|
getToken,
|
|
20344
20352
|
abortSignal,
|
|
20345
|
-
additionalProcessing
|
|
20353
|
+
additionalProcessing,
|
|
20354
|
+
overwriteCache = false
|
|
20346
20355
|
}) {
|
|
20347
20356
|
const fetchResp = await quillFetch({
|
|
20348
20357
|
client,
|
|
@@ -20354,7 +20363,8 @@ async function fetchReportRows({
|
|
|
20354
20363
|
filters: filters.map((filter) => ({ ...filter, options: void 0 })),
|
|
20355
20364
|
useNewNodeSql: true,
|
|
20356
20365
|
tenants,
|
|
20357
|
-
additionalProcessing
|
|
20366
|
+
additionalProcessing,
|
|
20367
|
+
overwriteCache
|
|
20358
20368
|
},
|
|
20359
20369
|
abortSignal,
|
|
20360
20370
|
getToken
|
|
@@ -20385,7 +20395,8 @@ async function fetchReport({
|
|
|
20385
20395
|
abortSignal,
|
|
20386
20396
|
getToken,
|
|
20387
20397
|
eventTracking,
|
|
20388
|
-
usePivotTask = false
|
|
20398
|
+
usePivotTask = false,
|
|
20399
|
+
overwriteCache = false
|
|
20389
20400
|
}) {
|
|
20390
20401
|
let reportInfo = void 0;
|
|
20391
20402
|
let errorMessage = void 0;
|
|
@@ -20405,7 +20416,8 @@ async function fetchReport({
|
|
|
20405
20416
|
rowsOnly,
|
|
20406
20417
|
rowCountOnly,
|
|
20407
20418
|
tenants,
|
|
20408
|
-
flags
|
|
20419
|
+
flags,
|
|
20420
|
+
overwriteCache
|
|
20409
20421
|
},
|
|
20410
20422
|
abortSignal,
|
|
20411
20423
|
getToken
|
|
@@ -20426,7 +20438,9 @@ async function fetchReport({
|
|
|
20426
20438
|
getToken,
|
|
20427
20439
|
eventTracking,
|
|
20428
20440
|
tenants,
|
|
20429
|
-
|
|
20441
|
+
// When not using pivot-template, avoid fallback pivot-template fetches.
|
|
20442
|
+
skipPivotFetch: !usePivotTask,
|
|
20443
|
+
overwriteCache
|
|
20430
20444
|
});
|
|
20431
20445
|
} catch (error) {
|
|
20432
20446
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -20476,7 +20490,8 @@ async function processReportResponse({
|
|
|
20476
20490
|
getToken,
|
|
20477
20491
|
eventTracking,
|
|
20478
20492
|
tenants,
|
|
20479
|
-
skipPivotFetch = false
|
|
20493
|
+
skipPivotFetch = false,
|
|
20494
|
+
overwriteCache
|
|
20480
20495
|
}) {
|
|
20481
20496
|
const shouldSkipPivotFetch = skipPivotFetch || !!resp?.pivotRows && !!resp?.fields;
|
|
20482
20497
|
const dashboardItem = {
|
|
@@ -20509,7 +20524,8 @@ async function processReportResponse({
|
|
|
20509
20524
|
getToken,
|
|
20510
20525
|
tenants,
|
|
20511
20526
|
eventTracking,
|
|
20512
|
-
skipPivotFetch: shouldSkipPivotFetch
|
|
20527
|
+
skipPivotFetch: shouldSkipPivotFetch,
|
|
20528
|
+
overwriteCache
|
|
20513
20529
|
});
|
|
20514
20530
|
if (additionalProcessing) {
|
|
20515
20531
|
reportInfo.pagination = additionalProcessing.page;
|
|
@@ -21586,6 +21602,1799 @@ async function getClientTenantIds({
|
|
|
21586
21602
|
|
|
21587
21603
|
// src/Context.tsx
|
|
21588
21604
|
init_columnProcessing();
|
|
21605
|
+
|
|
21606
|
+
// src/utils/cacheCab.ts
|
|
21607
|
+
init_dataFetcher();
|
|
21608
|
+
|
|
21609
|
+
// src/utils/inMemoryFilterEngine.ts
|
|
21610
|
+
init_Filter();
|
|
21611
|
+
var import_date_fns8 = require("date-fns");
|
|
21612
|
+
init_dateRangePickerUtils();
|
|
21613
|
+
var UNSET = Symbol("unset");
|
|
21614
|
+
var isFilter = (f) => {
|
|
21615
|
+
return f && typeof f === "object" && "filterType" in f && !("id" in f);
|
|
21616
|
+
};
|
|
21617
|
+
var isDashboardFilterUpdate = (f) => {
|
|
21618
|
+
return f && typeof f === "object" && "label" in f;
|
|
21619
|
+
};
|
|
21620
|
+
var normalizeFilterString = (value) => value.replaceAll("%", "").toLowerCase();
|
|
21621
|
+
var normalizeRowString = (value) => value.toLowerCase();
|
|
21622
|
+
var resolveFieldKeys = (field, table, resolver) => {
|
|
21623
|
+
if (!field) return [];
|
|
21624
|
+
const resolved = resolver?.(field, table);
|
|
21625
|
+
if (Array.isArray(resolved)) return resolved;
|
|
21626
|
+
if (typeof resolved === "string") return [resolved];
|
|
21627
|
+
return [field];
|
|
21628
|
+
};
|
|
21629
|
+
var getRowValue = (row, fieldKeys, cache) => {
|
|
21630
|
+
if (fieldKeys.length === 0) return void 0;
|
|
21631
|
+
const cacheKey = fieldKeys.join("|");
|
|
21632
|
+
if (Object.prototype.hasOwnProperty.call(cache, cacheKey)) {
|
|
21633
|
+
return cache[cacheKey];
|
|
21634
|
+
}
|
|
21635
|
+
for (const key of fieldKeys) {
|
|
21636
|
+
if (Object.prototype.hasOwnProperty.call(row, key)) {
|
|
21637
|
+
cache[cacheKey] = row[key];
|
|
21638
|
+
return row[key];
|
|
21639
|
+
}
|
|
21640
|
+
}
|
|
21641
|
+
cache[cacheKey] = void 0;
|
|
21642
|
+
return void 0;
|
|
21643
|
+
};
|
|
21644
|
+
var coerceNumber = (value) => {
|
|
21645
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
21646
|
+
if (typeof value === "string" && value !== "") {
|
|
21647
|
+
const parsed = Number(value);
|
|
21648
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
21649
|
+
}
|
|
21650
|
+
return null;
|
|
21651
|
+
};
|
|
21652
|
+
var coerceBoolean = (value) => {
|
|
21653
|
+
if (typeof value === "boolean") return value;
|
|
21654
|
+
if (typeof value === "number") return value !== 0;
|
|
21655
|
+
if (typeof value === "string") {
|
|
21656
|
+
const normalized = value.toLowerCase();
|
|
21657
|
+
if (normalized === "true" || normalized === "1") return true;
|
|
21658
|
+
if (normalized === "false" || normalized === "0") return false;
|
|
21659
|
+
}
|
|
21660
|
+
return null;
|
|
21661
|
+
};
|
|
21662
|
+
var toDateMs = (value) => {
|
|
21663
|
+
if (value instanceof Date) {
|
|
21664
|
+
return (0, import_date_fns8.isValid)(value) ? value.getTime() : null;
|
|
21665
|
+
}
|
|
21666
|
+
if (typeof value === "number") {
|
|
21667
|
+
const date = new Date(value);
|
|
21668
|
+
return (0, import_date_fns8.isValid)(date) ? date.getTime() : null;
|
|
21669
|
+
}
|
|
21670
|
+
if (typeof value === "string") {
|
|
21671
|
+
const date = new Date(value);
|
|
21672
|
+
return (0, import_date_fns8.isValid)(date) ? date.getTime() : null;
|
|
21673
|
+
}
|
|
21674
|
+
return null;
|
|
21675
|
+
};
|
|
21676
|
+
var buildColumnTypeMap = (columns) => {
|
|
21677
|
+
if (!columns?.length) return null;
|
|
21678
|
+
const map = /* @__PURE__ */ Object.create(null);
|
|
21679
|
+
for (const column of columns) {
|
|
21680
|
+
map[column.field] = column.jsType;
|
|
21681
|
+
}
|
|
21682
|
+
return map;
|
|
21683
|
+
};
|
|
21684
|
+
var resolveDashboardField = (filter, options) => {
|
|
21685
|
+
const mapped = options.filterMap?.[filter.label];
|
|
21686
|
+
if (mapped?.field) {
|
|
21687
|
+
return { field: mapped.field, table: mapped.table };
|
|
21688
|
+
}
|
|
21689
|
+
if (filter.filterType === "date_range" /* Date */ && options.dateField?.field) {
|
|
21690
|
+
return { field: options.dateField.field, table: options.dateField.table };
|
|
21691
|
+
}
|
|
21692
|
+
if (filter.field) {
|
|
21693
|
+
return { field: filter.field, table: filter.table };
|
|
21694
|
+
}
|
|
21695
|
+
return null;
|
|
21696
|
+
};
|
|
21697
|
+
var buildRelativeDateRange = (operator, value, now2, weekStartsOn) => {
|
|
21698
|
+
const amount = value.value || 1;
|
|
21699
|
+
const unit = value.unit;
|
|
21700
|
+
const currentStart = (() => {
|
|
21701
|
+
switch (unit) {
|
|
21702
|
+
case TimeUnit.Hour:
|
|
21703
|
+
return (0, import_date_fns8.startOfHour)(now2);
|
|
21704
|
+
case TimeUnit.Day:
|
|
21705
|
+
return (0, import_date_fns8.startOfDay)(now2);
|
|
21706
|
+
case TimeUnit.Week:
|
|
21707
|
+
return (0, import_date_fns8.startOfWeek)(now2, { weekStartsOn });
|
|
21708
|
+
case TimeUnit.Month:
|
|
21709
|
+
return (0, import_date_fns8.startOfMonth)(now2);
|
|
21710
|
+
case TimeUnit.Quarter:
|
|
21711
|
+
return (0, import_date_fns8.startOfQuarter)(now2);
|
|
21712
|
+
case TimeUnit.Year:
|
|
21713
|
+
return (0, import_date_fns8.startOfYear)(now2);
|
|
21714
|
+
default:
|
|
21715
|
+
return (0, import_date_fns8.startOfDay)(now2);
|
|
21716
|
+
}
|
|
21717
|
+
})();
|
|
21718
|
+
const addUnit = (base, multiplier) => {
|
|
21719
|
+
switch (unit) {
|
|
21720
|
+
case TimeUnit.Hour:
|
|
21721
|
+
return (0, import_date_fns8.addHours)(base, multiplier);
|
|
21722
|
+
case TimeUnit.Day:
|
|
21723
|
+
return (0, import_date_fns8.addDays)(base, multiplier);
|
|
21724
|
+
case TimeUnit.Week:
|
|
21725
|
+
return (0, import_date_fns8.addWeeks)(base, multiplier);
|
|
21726
|
+
case TimeUnit.Month:
|
|
21727
|
+
return (0, import_date_fns8.addMonths)(base, multiplier);
|
|
21728
|
+
case TimeUnit.Quarter:
|
|
21729
|
+
return (0, import_date_fns8.addMonths)(base, multiplier * 3);
|
|
21730
|
+
case TimeUnit.Year:
|
|
21731
|
+
return (0, import_date_fns8.addYears)(base, multiplier);
|
|
21732
|
+
default:
|
|
21733
|
+
return (0, import_date_fns8.addDays)(base, multiplier);
|
|
21734
|
+
}
|
|
21735
|
+
};
|
|
21736
|
+
const subUnit = (base, multiplier) => {
|
|
21737
|
+
switch (unit) {
|
|
21738
|
+
case TimeUnit.Hour:
|
|
21739
|
+
return (0, import_date_fns8.subHours)(base, multiplier);
|
|
21740
|
+
case TimeUnit.Day:
|
|
21741
|
+
return (0, import_date_fns8.subDays)(base, multiplier);
|
|
21742
|
+
case TimeUnit.Week:
|
|
21743
|
+
return (0, import_date_fns8.subWeeks)(base, multiplier);
|
|
21744
|
+
case TimeUnit.Month:
|
|
21745
|
+
return (0, import_date_fns8.subMonths)(base, multiplier);
|
|
21746
|
+
case TimeUnit.Quarter:
|
|
21747
|
+
return (0, import_date_fns8.subMonths)(base, multiplier * 3);
|
|
21748
|
+
case TimeUnit.Year:
|
|
21749
|
+
return (0, import_date_fns8.subYears)(base, multiplier);
|
|
21750
|
+
default:
|
|
21751
|
+
return (0, import_date_fns8.subDays)(base, multiplier);
|
|
21752
|
+
}
|
|
21753
|
+
};
|
|
21754
|
+
switch (operator) {
|
|
21755
|
+
case DateOperator.InTheLast: {
|
|
21756
|
+
const start2 = subUnit(now2, amount);
|
|
21757
|
+
return { start: start2.getTime() };
|
|
21758
|
+
}
|
|
21759
|
+
case DateOperator.InThePrevious: {
|
|
21760
|
+
const start2 = subUnit(currentStart, amount);
|
|
21761
|
+
return { start: start2.getTime(), end: currentStart.getTime(), endExclusive: true };
|
|
21762
|
+
}
|
|
21763
|
+
case DateOperator.InTheCurrent: {
|
|
21764
|
+
const end = addUnit(currentStart, 1);
|
|
21765
|
+
return {
|
|
21766
|
+
start: currentStart.getTime(),
|
|
21767
|
+
end: end.getTime(),
|
|
21768
|
+
endExclusive: true
|
|
21769
|
+
};
|
|
21770
|
+
}
|
|
21771
|
+
default:
|
|
21772
|
+
return null;
|
|
21773
|
+
}
|
|
21774
|
+
};
|
|
21775
|
+
var buildStringPredicate = (operator, value, fieldKeys) => {
|
|
21776
|
+
if (value === void 0 || value === null) return null;
|
|
21777
|
+
const normalizedValue = Array.isArray(value) ? value.map((v) => normalizeFilterString(String(v))) : normalizeFilterString(String(value));
|
|
21778
|
+
if (Array.isArray(normalizedValue)) {
|
|
21779
|
+
if (normalizedValue.length === 0) return null;
|
|
21780
|
+
} else if (normalizedValue === "") {
|
|
21781
|
+
return null;
|
|
21782
|
+
}
|
|
21783
|
+
if (operator === StringOperator.Is || operator === StringOperator.IsNot) {
|
|
21784
|
+
const values = Array.isArray(normalizedValue) ? normalizedValue : [normalizedValue];
|
|
21785
|
+
const valueSet = new Set(values);
|
|
21786
|
+
return (row, cache) => {
|
|
21787
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21788
|
+
if (rowValue === null || rowValue === void 0) return false;
|
|
21789
|
+
const normalized = normalizeRowString(String(rowValue));
|
|
21790
|
+
const hasValue = valueSet.has(normalized);
|
|
21791
|
+
return operator === StringOperator.Is ? hasValue : !hasValue;
|
|
21792
|
+
};
|
|
21793
|
+
}
|
|
21794
|
+
if (Array.isArray(normalizedValue)) {
|
|
21795
|
+
return null;
|
|
21796
|
+
}
|
|
21797
|
+
return (row, cache) => {
|
|
21798
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21799
|
+
if (rowValue === null || rowValue === void 0) return false;
|
|
21800
|
+
const normalizedRow = normalizeRowString(String(rowValue));
|
|
21801
|
+
switch (operator) {
|
|
21802
|
+
case StringOperator.IsExactly:
|
|
21803
|
+
return normalizedRow === normalizedValue;
|
|
21804
|
+
case StringOperator.IsNotExactly:
|
|
21805
|
+
return normalizedRow !== normalizedValue;
|
|
21806
|
+
case StringOperator.Contains:
|
|
21807
|
+
return normalizedRow.includes(normalizedValue);
|
|
21808
|
+
default:
|
|
21809
|
+
return false;
|
|
21810
|
+
}
|
|
21811
|
+
};
|
|
21812
|
+
};
|
|
21813
|
+
var buildNumericPredicate = (operator, value, fieldKeys) => {
|
|
21814
|
+
const filterValue = coerceNumber(value);
|
|
21815
|
+
if (filterValue === null) return null;
|
|
21816
|
+
return (row, cache) => {
|
|
21817
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21818
|
+
const parsed = coerceNumber(rowValue);
|
|
21819
|
+
if (parsed === null) return false;
|
|
21820
|
+
switch (operator) {
|
|
21821
|
+
case NumberOperator.EqualTo:
|
|
21822
|
+
return parsed === filterValue;
|
|
21823
|
+
case NumberOperator.NotEqualTo:
|
|
21824
|
+
return parsed !== filterValue;
|
|
21825
|
+
case NumberOperator.GreaterThan:
|
|
21826
|
+
return parsed > filterValue;
|
|
21827
|
+
case NumberOperator.LessThan:
|
|
21828
|
+
return parsed < filterValue;
|
|
21829
|
+
case NumberOperator.GreaterThanOrEqualTo:
|
|
21830
|
+
return parsed >= filterValue;
|
|
21831
|
+
case NumberOperator.LessThanOrEqualTo:
|
|
21832
|
+
return parsed <= filterValue;
|
|
21833
|
+
default:
|
|
21834
|
+
return false;
|
|
21835
|
+
}
|
|
21836
|
+
};
|
|
21837
|
+
};
|
|
21838
|
+
var buildNullPredicate = (operator, fieldKeys) => {
|
|
21839
|
+
return (row, cache) => {
|
|
21840
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21841
|
+
const isNullish = rowValue === null || rowValue === void 0;
|
|
21842
|
+
return operator === NullOperator.IsNull ? isNullish : !isNullish;
|
|
21843
|
+
};
|
|
21844
|
+
};
|
|
21845
|
+
var buildBooleanPredicate = (operator, value, fieldKeys) => {
|
|
21846
|
+
const filterValue = coerceBoolean(value);
|
|
21847
|
+
if (filterValue === null) return null;
|
|
21848
|
+
return (row, cache) => {
|
|
21849
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21850
|
+
const parsed = coerceBoolean(rowValue);
|
|
21851
|
+
if (parsed === null) return false;
|
|
21852
|
+
return operator === BoolOperator.EqualTo ? parsed === filterValue : parsed !== filterValue;
|
|
21853
|
+
};
|
|
21854
|
+
};
|
|
21855
|
+
var buildDateComparisonPredicate = (operator, value, fieldKeys) => {
|
|
21856
|
+
const filterDate = toDateMs(value);
|
|
21857
|
+
if (filterDate === null) return null;
|
|
21858
|
+
return (row, cache) => {
|
|
21859
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21860
|
+
const rowDate = toDateMs(rowValue);
|
|
21861
|
+
if (rowDate === null) return false;
|
|
21862
|
+
switch (operator) {
|
|
21863
|
+
case DateOperator.EqualTo:
|
|
21864
|
+
return rowDate === filterDate;
|
|
21865
|
+
case DateOperator.NotEqualTo:
|
|
21866
|
+
return rowDate !== filterDate;
|
|
21867
|
+
case DateOperator.GreaterThan:
|
|
21868
|
+
return rowDate > filterDate;
|
|
21869
|
+
case DateOperator.LessThan:
|
|
21870
|
+
return rowDate < filterDate;
|
|
21871
|
+
case DateOperator.GreaterThanOrEqualTo:
|
|
21872
|
+
return rowDate >= filterDate;
|
|
21873
|
+
case DateOperator.LessThanOrEqualTo:
|
|
21874
|
+
return rowDate <= filterDate;
|
|
21875
|
+
default:
|
|
21876
|
+
return false;
|
|
21877
|
+
}
|
|
21878
|
+
};
|
|
21879
|
+
};
|
|
21880
|
+
var buildDateRangePredicate = (range, fieldKeys) => {
|
|
21881
|
+
if (range.start === void 0 && range.end === void 0) return null;
|
|
21882
|
+
return (row, cache) => {
|
|
21883
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
21884
|
+
const rowDate = toDateMs(rowValue);
|
|
21885
|
+
if (rowDate === null) return false;
|
|
21886
|
+
if (range.start !== void 0 && rowDate < range.start) return false;
|
|
21887
|
+
if (range.end !== void 0) {
|
|
21888
|
+
if (range.endExclusive) {
|
|
21889
|
+
return rowDate < range.end;
|
|
21890
|
+
}
|
|
21891
|
+
return rowDate <= range.end;
|
|
21892
|
+
}
|
|
21893
|
+
return true;
|
|
21894
|
+
};
|
|
21895
|
+
};
|
|
21896
|
+
var buildCustomDatePredicate = (value, fieldKeys) => {
|
|
21897
|
+
const start2 = value.startDate ? toDateMs(value.startDate) : null;
|
|
21898
|
+
const end = value.endDate ? toDateMs(value.endDate) : null;
|
|
21899
|
+
if (start2 === null && end === null) return null;
|
|
21900
|
+
return buildDateRangePredicate(
|
|
21901
|
+
{
|
|
21902
|
+
start: start2 ?? void 0,
|
|
21903
|
+
end: end ?? void 0,
|
|
21904
|
+
endExclusive: false
|
|
21905
|
+
},
|
|
21906
|
+
fieldKeys
|
|
21907
|
+
);
|
|
21908
|
+
};
|
|
21909
|
+
var compileCustomFilter = (filter, options) => {
|
|
21910
|
+
const fieldKeys = resolveFieldKeys(
|
|
21911
|
+
filter.field,
|
|
21912
|
+
filter.table,
|
|
21913
|
+
options.fieldKeyResolver
|
|
21914
|
+
);
|
|
21915
|
+
if (fieldKeys.length === 0) return null;
|
|
21916
|
+
switch (filter.filterType) {
|
|
21917
|
+
case "string-filter" /* StringFilter */:
|
|
21918
|
+
case "string-in-filter" /* StringInFilter */:
|
|
21919
|
+
return buildStringPredicate(
|
|
21920
|
+
filter.operator,
|
|
21921
|
+
filter.value,
|
|
21922
|
+
fieldKeys
|
|
21923
|
+
);
|
|
21924
|
+
case "numeric-filter" /* NumericFilter */:
|
|
21925
|
+
return buildNumericPredicate(
|
|
21926
|
+
filter.operator,
|
|
21927
|
+
filter.value,
|
|
21928
|
+
fieldKeys
|
|
21929
|
+
);
|
|
21930
|
+
case "null-filter" /* NullFilter */:
|
|
21931
|
+
return buildNullPredicate(
|
|
21932
|
+
filter.operator,
|
|
21933
|
+
fieldKeys
|
|
21934
|
+
);
|
|
21935
|
+
case "boolean-filter" /* BooleanFilter */:
|
|
21936
|
+
return buildBooleanPredicate(
|
|
21937
|
+
filter.operator,
|
|
21938
|
+
filter.value,
|
|
21939
|
+
fieldKeys
|
|
21940
|
+
);
|
|
21941
|
+
case "date-custom-filter" /* DateCustomFilter */:
|
|
21942
|
+
return buildCustomDatePredicate(
|
|
21943
|
+
filter.value,
|
|
21944
|
+
fieldKeys
|
|
21945
|
+
);
|
|
21946
|
+
case "date-comparison-filter" /* DateComparisonFilter */:
|
|
21947
|
+
return buildDateComparisonPredicate(
|
|
21948
|
+
filter.operator,
|
|
21949
|
+
filter.value,
|
|
21950
|
+
fieldKeys
|
|
21951
|
+
);
|
|
21952
|
+
case "date-filter" /* DateFilter */: {
|
|
21953
|
+
const value = filter.value;
|
|
21954
|
+
if (!value?.unit) return null;
|
|
21955
|
+
const now2 = options.now ?? /* @__PURE__ */ new Date();
|
|
21956
|
+
const range = buildRelativeDateRange(
|
|
21957
|
+
filter.operator,
|
|
21958
|
+
value,
|
|
21959
|
+
now2,
|
|
21960
|
+
options.weekStartsOn ?? 0
|
|
21961
|
+
);
|
|
21962
|
+
if (!range) return null;
|
|
21963
|
+
return buildDateRangePredicate(range, fieldKeys);
|
|
21964
|
+
}
|
|
21965
|
+
default:
|
|
21966
|
+
return null;
|
|
21967
|
+
}
|
|
21968
|
+
};
|
|
21969
|
+
var compileDashboardFilter = (filter, options, columnTypeMap) => {
|
|
21970
|
+
const resolved = resolveDashboardField(filter, options);
|
|
21971
|
+
if (!resolved?.field) return null;
|
|
21972
|
+
const fieldKeys = resolveFieldKeys(
|
|
21973
|
+
resolved.field,
|
|
21974
|
+
resolved.table,
|
|
21975
|
+
options.fieldKeyResolver
|
|
21976
|
+
);
|
|
21977
|
+
if (fieldKeys.length === 0) return null;
|
|
21978
|
+
switch (filter.filterType) {
|
|
21979
|
+
case "string" /* String */: {
|
|
21980
|
+
const stringFilter = filter;
|
|
21981
|
+
if (stringFilter.stringFilterType === "multiselect" /* Multiselect */) {
|
|
21982
|
+
if (!stringFilter.values || stringFilter.values.length === 0) {
|
|
21983
|
+
return null;
|
|
21984
|
+
}
|
|
21985
|
+
return buildStringPredicate(
|
|
21986
|
+
StringOperator.Is,
|
|
21987
|
+
stringFilter.values,
|
|
21988
|
+
fieldKeys
|
|
21989
|
+
);
|
|
21990
|
+
}
|
|
21991
|
+
if (!stringFilter.selectedValue) return null;
|
|
21992
|
+
return buildStringPredicate(
|
|
21993
|
+
StringOperator.IsExactly,
|
|
21994
|
+
stringFilter.selectedValue,
|
|
21995
|
+
fieldKeys
|
|
21996
|
+
);
|
|
21997
|
+
}
|
|
21998
|
+
case "date_range" /* Date */: {
|
|
21999
|
+
const dateFilter = filter;
|
|
22000
|
+
const start2 = dateFilter.startDate ? dateFilter.startDate.getTime() : void 0;
|
|
22001
|
+
const end = dateFilter.endDate ? dateFilter.endDate.getTime() : void 0;
|
|
22002
|
+
return buildDateRangePredicate(
|
|
22003
|
+
{ start: start2, end, endExclusive: false },
|
|
22004
|
+
fieldKeys
|
|
22005
|
+
);
|
|
22006
|
+
}
|
|
22007
|
+
case "tenant" /* Tenant */: {
|
|
22008
|
+
const tenantFilter = filter;
|
|
22009
|
+
if (!tenantFilter.values || tenantFilter.values.length === 0) {
|
|
22010
|
+
return null;
|
|
22011
|
+
}
|
|
22012
|
+
const normalizedValues = tenantFilter.values.map(
|
|
22013
|
+
(v) => normalizeFilterString(String(v))
|
|
22014
|
+
);
|
|
22015
|
+
const valueSet = new Set(normalizedValues);
|
|
22016
|
+
const fieldType = columnTypeMap?.[resolved.field] ?? "string";
|
|
22017
|
+
return (row, cache) => {
|
|
22018
|
+
const rowValue = getRowValue(row, fieldKeys, cache);
|
|
22019
|
+
if (rowValue === null || rowValue === void 0) return false;
|
|
22020
|
+
if (fieldType === "number") {
|
|
22021
|
+
const numeric = coerceNumber(rowValue);
|
|
22022
|
+
return numeric !== null && valueSet.has(normalizeFilterString(String(numeric)));
|
|
22023
|
+
}
|
|
22024
|
+
return valueSet.has(normalizeRowString(String(rowValue)));
|
|
22025
|
+
};
|
|
22026
|
+
}
|
|
22027
|
+
default:
|
|
22028
|
+
return null;
|
|
22029
|
+
}
|
|
22030
|
+
};
|
|
22031
|
+
var updateDashboardFilters = (filtersToUpdate, dashboardFilters) => {
|
|
22032
|
+
return dashboardFilters.map((filter) => {
|
|
22033
|
+
const update = filtersToUpdate.find((u) => u.label === filter.label);
|
|
22034
|
+
if (!update) return filter;
|
|
22035
|
+
if (filter.filterType === "string" /* String */) {
|
|
22036
|
+
if (filter.stringFilterType === "multiselect" /* Multiselect */) {
|
|
22037
|
+
return {
|
|
22038
|
+
...filter,
|
|
22039
|
+
values: update.value
|
|
22040
|
+
};
|
|
22041
|
+
}
|
|
22042
|
+
return {
|
|
22043
|
+
...filter,
|
|
22044
|
+
selectedValue: update.value
|
|
22045
|
+
};
|
|
22046
|
+
}
|
|
22047
|
+
if (filter.filterType === "date_range" /* Date */) {
|
|
22048
|
+
const presetOptions = convertPresetOptionsToSelectableList(
|
|
22049
|
+
filter.presetOptions ?? [],
|
|
22050
|
+
filter.defaultPresetRanges ?? []
|
|
22051
|
+
);
|
|
22052
|
+
const value = update.value;
|
|
22053
|
+
const preset = presetOptions.find((p) => {
|
|
22054
|
+
const pStart = p.startDate ? new Date(p.startDate).toISOString() : void 0;
|
|
22055
|
+
const vStart = value.startDate ? new Date(value.startDate).toISOString() : void 0;
|
|
22056
|
+
const pEnd = p.endDate ? new Date(p.endDate).toISOString() : void 0;
|
|
22057
|
+
const vEnd = value.endDate ? new Date(value.endDate).toISOString() : void 0;
|
|
22058
|
+
return pStart === vStart && pEnd === vEnd;
|
|
22059
|
+
});
|
|
22060
|
+
if (!preset) {
|
|
22061
|
+
return { ...filter, startDate: value.startDate, endDate: value.endDate };
|
|
22062
|
+
}
|
|
22063
|
+
return {
|
|
22064
|
+
...filter,
|
|
22065
|
+
preset,
|
|
22066
|
+
startDate: value.startDate,
|
|
22067
|
+
endDate: value.endDate
|
|
22068
|
+
};
|
|
22069
|
+
}
|
|
22070
|
+
if (filter.filterType === "tenant" /* Tenant */) {
|
|
22071
|
+
const value = update.value;
|
|
22072
|
+
let values;
|
|
22073
|
+
if (Array.isArray(value)) {
|
|
22074
|
+
values = value;
|
|
22075
|
+
} else if (typeof value === "string") {
|
|
22076
|
+
values = [value];
|
|
22077
|
+
} else {
|
|
22078
|
+
values = [];
|
|
22079
|
+
}
|
|
22080
|
+
return {
|
|
22081
|
+
...filter,
|
|
22082
|
+
values
|
|
22083
|
+
};
|
|
22084
|
+
}
|
|
22085
|
+
return filter;
|
|
22086
|
+
});
|
|
22087
|
+
};
|
|
22088
|
+
var compileApplyFiltersPredicate = (filters, options) => {
|
|
22089
|
+
const dashboardUpdates = filters.filter(isDashboardFilterUpdate);
|
|
22090
|
+
const customFilters = filters.filter(isFilter);
|
|
22091
|
+
const internalCustomFilters = customFilters.map((filter) => {
|
|
22092
|
+
try {
|
|
22093
|
+
return convertCustomFilter(filter);
|
|
22094
|
+
} catch (error) {
|
|
22095
|
+
return null;
|
|
22096
|
+
}
|
|
22097
|
+
}).concat(options.customFilters ?? []).filter((filter) => filter !== null && filter !== void 0);
|
|
22098
|
+
const dashboardFilters = options.dashboardFilters ?? [];
|
|
22099
|
+
const updatedDashboardFilters = dashboardUpdates.length ? updateDashboardFilters(dashboardUpdates, dashboardFilters) : dashboardFilters;
|
|
22100
|
+
const columnTypeMap = buildColumnTypeMap(options.columns);
|
|
22101
|
+
const predicates = [];
|
|
22102
|
+
for (const filter of internalCustomFilters) {
|
|
22103
|
+
const predicate = compileCustomFilter(filter, options);
|
|
22104
|
+
if (predicate) predicates.push(predicate);
|
|
22105
|
+
}
|
|
22106
|
+
for (const filter of updatedDashboardFilters) {
|
|
22107
|
+
const predicate = compileDashboardFilter(
|
|
22108
|
+
filter,
|
|
22109
|
+
options,
|
|
22110
|
+
columnTypeMap
|
|
22111
|
+
);
|
|
22112
|
+
if (predicate) predicates.push(predicate);
|
|
22113
|
+
}
|
|
22114
|
+
if (predicates.length === 0) {
|
|
22115
|
+
return { predicate: () => true, hasPredicates: false };
|
|
22116
|
+
}
|
|
22117
|
+
return {
|
|
22118
|
+
predicate: (row) => {
|
|
22119
|
+
const cache = /* @__PURE__ */ Object.create(null);
|
|
22120
|
+
for (const predicate of predicates) {
|
|
22121
|
+
if (!predicate(row, cache)) return false;
|
|
22122
|
+
}
|
|
22123
|
+
return true;
|
|
22124
|
+
},
|
|
22125
|
+
hasPredicates: true
|
|
22126
|
+
};
|
|
22127
|
+
};
|
|
22128
|
+
var applyFiltersInMemory = (rows, filters, options) => {
|
|
22129
|
+
if (!rows.length) return rows;
|
|
22130
|
+
const { predicate, hasPredicates } = compileApplyFiltersPredicate(
|
|
22131
|
+
filters,
|
|
22132
|
+
options
|
|
22133
|
+
);
|
|
22134
|
+
if (!hasPredicates) return rows;
|
|
22135
|
+
const results = [];
|
|
22136
|
+
for (let i = 0; i < rows.length; i += 1) {
|
|
22137
|
+
const row = rows[i];
|
|
22138
|
+
if (predicate(row)) {
|
|
22139
|
+
results.push(row);
|
|
22140
|
+
}
|
|
22141
|
+
}
|
|
22142
|
+
return results;
|
|
22143
|
+
};
|
|
22144
|
+
|
|
22145
|
+
// src/utils/inMemoryPivotEngine.ts
|
|
22146
|
+
init_columnType();
|
|
22147
|
+
var MS_IN_DAY = 24 * 60 * 60 * 1e3;
|
|
22148
|
+
var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
22149
|
+
var INVALID_DATE_KEY = "-2026";
|
|
22150
|
+
function singleAggToMultiAgg(pivot) {
|
|
22151
|
+
if (pivot.aggregations) {
|
|
22152
|
+
return pivot;
|
|
22153
|
+
}
|
|
22154
|
+
const newPivot = { ...pivot };
|
|
22155
|
+
const newAgg = { aggregationType: pivot.aggregationType };
|
|
22156
|
+
const fieldsToCopy = ["valueField", "valueFieldType", "valueField2", "valueField2Type"];
|
|
22157
|
+
fieldsToCopy.forEach((x) => {
|
|
22158
|
+
if (pivot[x]) {
|
|
22159
|
+
newAgg[x] = pivot[x];
|
|
22160
|
+
delete newPivot[x];
|
|
22161
|
+
}
|
|
22162
|
+
});
|
|
22163
|
+
newPivot.aggregations = [newAgg];
|
|
22164
|
+
return newPivot;
|
|
22165
|
+
}
|
|
22166
|
+
function isDateFormat2(xAxisFormat) {
|
|
22167
|
+
const DATE_FORMATS = [
|
|
22168
|
+
"yyyy",
|
|
22169
|
+
"mmm_dd",
|
|
22170
|
+
"mmm_yyyy",
|
|
22171
|
+
"mmm_dd_yyyy",
|
|
22172
|
+
"hh_ap_pm",
|
|
22173
|
+
"mmm_dd-mmm_dd",
|
|
22174
|
+
"mmm_dd_hh:mm_ap_pm",
|
|
22175
|
+
"wo, yyyy"
|
|
22176
|
+
];
|
|
22177
|
+
const isDate = DATE_FORMATS.includes(xAxisFormat.toLowerCase());
|
|
22178
|
+
return isDate;
|
|
22179
|
+
}
|
|
22180
|
+
function isValidDate3(date) {
|
|
22181
|
+
try {
|
|
22182
|
+
return date instanceof Date && !isNaN(date.getTime());
|
|
22183
|
+
} catch {
|
|
22184
|
+
return false;
|
|
22185
|
+
}
|
|
22186
|
+
}
|
|
22187
|
+
function inferDateBucketFromFilters(pivot, filters) {
|
|
22188
|
+
if (!pivot?.rowFieldType) {
|
|
22189
|
+
return void 0;
|
|
22190
|
+
}
|
|
22191
|
+
const normalizedType = String(pivot.rowFieldType).toLowerCase();
|
|
22192
|
+
if (isDateFormat2(normalizedType)) {
|
|
22193
|
+
switch (normalizedType) {
|
|
22194
|
+
case "mmm_dd-mmm_dd":
|
|
22195
|
+
return "week";
|
|
22196
|
+
case "yyyy":
|
|
22197
|
+
case "wo, yyyy":
|
|
22198
|
+
return "year";
|
|
22199
|
+
case "mmm_dd_hh:mm_ap_pm":
|
|
22200
|
+
case "hh_ap_pm":
|
|
22201
|
+
return "day";
|
|
22202
|
+
default:
|
|
22203
|
+
return "month";
|
|
22204
|
+
}
|
|
22205
|
+
}
|
|
22206
|
+
const isDateLike = isDateType(normalizedType);
|
|
22207
|
+
if (!isDateLike) {
|
|
22208
|
+
return void 0;
|
|
22209
|
+
}
|
|
22210
|
+
let earliest;
|
|
22211
|
+
let latest;
|
|
22212
|
+
const extractTimestamp = (value) => {
|
|
22213
|
+
if (!value) {
|
|
22214
|
+
return void 0;
|
|
22215
|
+
}
|
|
22216
|
+
if (value instanceof Date) {
|
|
22217
|
+
return value.getTime();
|
|
22218
|
+
}
|
|
22219
|
+
const parsed = Date.parse(value);
|
|
22220
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
22221
|
+
};
|
|
22222
|
+
(Array.isArray(filters) ? filters : []).forEach((filter) => {
|
|
22223
|
+
if (!filter || filter.filterType !== "date_range") {
|
|
22224
|
+
return;
|
|
22225
|
+
}
|
|
22226
|
+
if (filter.primaryRange?.value === "ALL_TIME") {
|
|
22227
|
+
earliest = -1;
|
|
22228
|
+
return;
|
|
22229
|
+
}
|
|
22230
|
+
const possibleStarts = [
|
|
22231
|
+
filter.startDate,
|
|
22232
|
+
filter.start,
|
|
22233
|
+
filter.primaryRange?.startDate,
|
|
22234
|
+
filter.primaryRange?.start,
|
|
22235
|
+
filter.range?.startDate,
|
|
22236
|
+
filter.range?.start
|
|
22237
|
+
];
|
|
22238
|
+
const possibleEnds = [
|
|
22239
|
+
filter.endDate,
|
|
22240
|
+
filter.end,
|
|
22241
|
+
filter.primaryRange?.endDate,
|
|
22242
|
+
filter.primaryRange?.end,
|
|
22243
|
+
filter.range?.endDate,
|
|
22244
|
+
filter.range?.end
|
|
22245
|
+
];
|
|
22246
|
+
possibleStarts.forEach((value) => {
|
|
22247
|
+
const timestamp = extractTimestamp(value);
|
|
22248
|
+
if (timestamp === void 0) {
|
|
22249
|
+
return;
|
|
22250
|
+
}
|
|
22251
|
+
earliest = earliest === void 0 ? timestamp : Math.min(earliest, timestamp);
|
|
22252
|
+
});
|
|
22253
|
+
possibleEnds.forEach((value) => {
|
|
22254
|
+
const timestamp = extractTimestamp(value);
|
|
22255
|
+
if (timestamp === void 0) {
|
|
22256
|
+
return;
|
|
22257
|
+
}
|
|
22258
|
+
latest = latest === void 0 ? timestamp : Math.max(latest, timestamp);
|
|
22259
|
+
});
|
|
22260
|
+
});
|
|
22261
|
+
if (earliest === -1) {
|
|
22262
|
+
return "month";
|
|
22263
|
+
}
|
|
22264
|
+
if (earliest === void 0 || latest === void 0) {
|
|
22265
|
+
return void 0;
|
|
22266
|
+
}
|
|
22267
|
+
if (latest < earliest) {
|
|
22268
|
+
[earliest, latest] = [latest, earliest];
|
|
22269
|
+
}
|
|
22270
|
+
const diffInDays = Math.max(1, Math.round((latest - earliest) / MS_IN_DAY));
|
|
22271
|
+
if (diffInDays < 20) {
|
|
22272
|
+
return "day";
|
|
22273
|
+
}
|
|
22274
|
+
if (diffInDays <= 59) {
|
|
22275
|
+
return "week";
|
|
22276
|
+
}
|
|
22277
|
+
if (diffInDays <= 400) {
|
|
22278
|
+
return "month";
|
|
22279
|
+
}
|
|
22280
|
+
return "year";
|
|
22281
|
+
}
|
|
22282
|
+
function getDateRangeFromFilters(filters) {
|
|
22283
|
+
let earliest;
|
|
22284
|
+
let latest;
|
|
22285
|
+
const extractTimestamp = (value) => {
|
|
22286
|
+
if (!value) return void 0;
|
|
22287
|
+
if (value instanceof Date) return value.getTime();
|
|
22288
|
+
const parsed = Date.parse(value);
|
|
22289
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
22290
|
+
};
|
|
22291
|
+
(Array.isArray(filters) ? filters : []).forEach((filter) => {
|
|
22292
|
+
if (!filter || filter.filterType !== "date_range") return;
|
|
22293
|
+
if (filter.primaryRange?.value === "ALL_TIME") return;
|
|
22294
|
+
const possibleStarts = [
|
|
22295
|
+
filter.startDate,
|
|
22296
|
+
filter.start,
|
|
22297
|
+
filter.primaryRange?.startDate,
|
|
22298
|
+
filter.primaryRange?.start,
|
|
22299
|
+
filter.range?.startDate,
|
|
22300
|
+
filter.range?.start
|
|
22301
|
+
];
|
|
22302
|
+
const possibleEnds = [
|
|
22303
|
+
filter.endDate,
|
|
22304
|
+
filter.end,
|
|
22305
|
+
filter.primaryRange?.endDate,
|
|
22306
|
+
filter.primaryRange?.end,
|
|
22307
|
+
filter.range?.endDate,
|
|
22308
|
+
filter.range?.end
|
|
22309
|
+
];
|
|
22310
|
+
possibleStarts.forEach((v) => {
|
|
22311
|
+
const ts = extractTimestamp(v);
|
|
22312
|
+
if (ts === void 0) return;
|
|
22313
|
+
earliest = earliest === void 0 ? ts : Math.min(earliest, ts);
|
|
22314
|
+
});
|
|
22315
|
+
possibleEnds.forEach((v) => {
|
|
22316
|
+
const ts = extractTimestamp(v);
|
|
22317
|
+
if (ts === void 0) return;
|
|
22318
|
+
latest = latest === void 0 ? ts : Math.max(latest, ts);
|
|
22319
|
+
});
|
|
22320
|
+
});
|
|
22321
|
+
if (earliest === void 0 || latest === void 0) return void 0;
|
|
22322
|
+
if (latest < earliest) [earliest, latest] = [latest, earliest];
|
|
22323
|
+
return {
|
|
22324
|
+
start: new Date(earliest),
|
|
22325
|
+
end: new Date(latest)
|
|
22326
|
+
};
|
|
22327
|
+
}
|
|
22328
|
+
function generateBucketKeys(start2, end, bucket) {
|
|
22329
|
+
const keys = /* @__PURE__ */ new Set();
|
|
22330
|
+
const startDay = new Date(Date.UTC(start2.getUTCFullYear(), start2.getUTCMonth(), start2.getUTCDate()));
|
|
22331
|
+
const endDay = new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate()));
|
|
22332
|
+
const cur = new Date(startDay);
|
|
22333
|
+
while (cur <= endDay) {
|
|
22334
|
+
keys.add(getDateKey(cur, bucket));
|
|
22335
|
+
cur.setUTCDate(cur.getUTCDate() + 1);
|
|
22336
|
+
}
|
|
22337
|
+
return Array.from(keys).sort((a, b) => parseInt(a) - parseInt(b));
|
|
22338
|
+
}
|
|
22339
|
+
function buildEmptyAggRow(aggregations) {
|
|
22340
|
+
const multiAgg = aggregations.length > 1;
|
|
22341
|
+
const empty = {};
|
|
22342
|
+
aggregations.forEach((agg) => {
|
|
22343
|
+
const { aggregationType: type, valueField } = agg;
|
|
22344
|
+
const key = !valueField ? `${type}` + (multiAgg ? `_${type}` : "") : `${valueField}` + (multiAgg ? `_${type}` : "");
|
|
22345
|
+
empty[key] = 0;
|
|
22346
|
+
});
|
|
22347
|
+
return empty;
|
|
22348
|
+
}
|
|
22349
|
+
function getBucketRange(dateKey, bucket) {
|
|
22350
|
+
const d = new Date(parseInt(dateKey, 10));
|
|
22351
|
+
let start2 = new Date(d);
|
|
22352
|
+
let end = new Date(d);
|
|
22353
|
+
switch (bucket) {
|
|
22354
|
+
case "day":
|
|
22355
|
+
start2 = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
|
|
22356
|
+
end = new Date(start2);
|
|
22357
|
+
break;
|
|
22358
|
+
case "week":
|
|
22359
|
+
start2 = new Date(d);
|
|
22360
|
+
end = new Date(start2);
|
|
22361
|
+
end.setUTCDate(start2.getUTCDate() + 6);
|
|
22362
|
+
break;
|
|
22363
|
+
case "month":
|
|
22364
|
+
start2 = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1));
|
|
22365
|
+
end = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0));
|
|
22366
|
+
break;
|
|
22367
|
+
case "year":
|
|
22368
|
+
start2 = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
22369
|
+
end = new Date(Date.UTC(d.getUTCFullYear(), 11, 31));
|
|
22370
|
+
break;
|
|
22371
|
+
}
|
|
22372
|
+
return { start: start2, end };
|
|
22373
|
+
}
|
|
22374
|
+
function formatBucketNameFromRange(start2, end, bucket) {
|
|
22375
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
22376
|
+
switch (bucket) {
|
|
22377
|
+
case "day":
|
|
22378
|
+
return `${pad(start2.getUTCDate())} ${MONTHS[start2.getUTCMonth()]} ${start2.getUTCFullYear()}`;
|
|
22379
|
+
case "week": {
|
|
22380
|
+
const sameMonth = start2.getUTCMonth() === end.getUTCMonth();
|
|
22381
|
+
return sameMonth ? `${MONTHS[start2.getUTCMonth()]} ${start2.getUTCDate()} - ${end.getUTCDate()}` : `${MONTHS[start2.getUTCMonth()]} ${start2.getUTCDate()} - ${MONTHS[end.getUTCMonth()]} ${end.getUTCDate()}`;
|
|
22382
|
+
}
|
|
22383
|
+
case "month":
|
|
22384
|
+
return `${MONTHS[start2.getUTCMonth()]} ${start2.getUTCFullYear()}`;
|
|
22385
|
+
case "year":
|
|
22386
|
+
return `${start2.getUTCFullYear()}`;
|
|
22387
|
+
default:
|
|
22388
|
+
return "";
|
|
22389
|
+
}
|
|
22390
|
+
}
|
|
22391
|
+
function getDateKey(date, bucket) {
|
|
22392
|
+
if (!isValidDate3(date)) {
|
|
22393
|
+
return INVALID_DATE_KEY;
|
|
22394
|
+
}
|
|
22395
|
+
switch (bucket) {
|
|
22396
|
+
case "day":
|
|
22397
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()).toString();
|
|
22398
|
+
case "week": {
|
|
22399
|
+
const day = date.getUTCDay();
|
|
22400
|
+
const mondayUtc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() - (day + 6) % 7);
|
|
22401
|
+
return mondayUtc.toString();
|
|
22402
|
+
}
|
|
22403
|
+
case "month":
|
|
22404
|
+
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString();
|
|
22405
|
+
case "year":
|
|
22406
|
+
return Date.UTC(date.getUTCFullYear(), 0, 1).toString();
|
|
22407
|
+
default:
|
|
22408
|
+
return INVALID_DATE_KEY;
|
|
22409
|
+
}
|
|
22410
|
+
}
|
|
22411
|
+
function sortRows(rows, pivot) {
|
|
22412
|
+
try {
|
|
22413
|
+
const { sort, sortField, sortFieldType, sortDirection } = pivot;
|
|
22414
|
+
if (!sort || sortField == null || sortFieldType == null) return rows;
|
|
22415
|
+
const sortFunc = isBoolType(sortFieldType) ? (a, b) => a === b ? 0 : a ? 1 : -1 : isDateType(sortFieldType) ? (a, b) => {
|
|
22416
|
+
const ta = new Date(a), tb = new Date(b);
|
|
22417
|
+
const aValid = isValidDate3(ta), bValid = isValidDate3(tb);
|
|
22418
|
+
if (!aValid && !bValid) return 0;
|
|
22419
|
+
if (!aValid) return 1;
|
|
22420
|
+
if (!bValid) return -1;
|
|
22421
|
+
return ta.getTime() - tb.getTime();
|
|
22422
|
+
} : isStringType(sortFieldType) ? (a, b) => a.localeCompare(b) : (a, b) => a - b;
|
|
22423
|
+
const dir = sortDirection === "ASC" ? 1 : -1;
|
|
22424
|
+
rows.sort((a, b) => {
|
|
22425
|
+
const av = a[sortField], bv = b[sortField];
|
|
22426
|
+
if (av == null && bv == null) return 0;
|
|
22427
|
+
if (av == null) return 1;
|
|
22428
|
+
if (bv == null) return -1;
|
|
22429
|
+
return dir * sortFunc(av, bv);
|
|
22430
|
+
});
|
|
22431
|
+
} catch {
|
|
22432
|
+
console.warn(`Sorting failed.`);
|
|
22433
|
+
}
|
|
22434
|
+
return rows;
|
|
22435
|
+
}
|
|
22436
|
+
function assembleFinalRows(seen, rowKey, dateBucket, dateRange) {
|
|
22437
|
+
const allColumns = /* @__PURE__ */ new Set();
|
|
22438
|
+
Object.keys(seen).forEach((rowKeyVal) => {
|
|
22439
|
+
Object.keys(seen[rowKeyVal]).forEach((col) => {
|
|
22440
|
+
allColumns.add(col);
|
|
22441
|
+
});
|
|
22442
|
+
});
|
|
22443
|
+
const filled = {};
|
|
22444
|
+
Object.keys(seen).forEach((rowKeyVal) => {
|
|
22445
|
+
filled[rowKeyVal] = {};
|
|
22446
|
+
allColumns.forEach((col) => {
|
|
22447
|
+
const value = seen[rowKeyVal][col];
|
|
22448
|
+
filled[rowKeyVal][col] = value ?? 0;
|
|
22449
|
+
});
|
|
22450
|
+
});
|
|
22451
|
+
if (dateBucket) {
|
|
22452
|
+
return Object.keys(filled).sort((a, b) => parseInt(a) - parseInt(b)).map((k) => {
|
|
22453
|
+
if (k === INVALID_DATE_KEY) {
|
|
22454
|
+
return { [rowKey]: "Invalid Date", ...filled[k], __quillRawDate: 0 };
|
|
22455
|
+
}
|
|
22456
|
+
const { start: start2, end } = getBucketRange(k, dateBucket);
|
|
22457
|
+
let bucketStart = start2;
|
|
22458
|
+
let bucketEnd = end;
|
|
22459
|
+
if (dateRange) {
|
|
22460
|
+
if (bucketStart < dateRange.start) bucketStart = dateRange.start;
|
|
22461
|
+
if (bucketEnd > dateRange.end) bucketEnd = dateRange.end;
|
|
22462
|
+
}
|
|
22463
|
+
return {
|
|
22464
|
+
[rowKey]: formatBucketNameFromRange(bucketStart, bucketEnd, dateBucket),
|
|
22465
|
+
...filled[k],
|
|
22466
|
+
__quillRawDate: bucketStart.toISOString()
|
|
22467
|
+
};
|
|
22468
|
+
});
|
|
22469
|
+
}
|
|
22470
|
+
return Object.keys(filled).sort().map((k) => ({ [rowKey]: k, ...filled[k] }));
|
|
22471
|
+
}
|
|
22472
|
+
function anyToNum(valueFieldType, obj) {
|
|
22473
|
+
if (!valueFieldType) {
|
|
22474
|
+
if (typeof obj === "number") return obj;
|
|
22475
|
+
if (typeof obj === "string" && !isNaN(Number(obj))) return Number(obj);
|
|
22476
|
+
return obj ? 1 : 0;
|
|
22477
|
+
}
|
|
22478
|
+
if (isNumberType(valueFieldType)) {
|
|
22479
|
+
return Number(obj);
|
|
22480
|
+
}
|
|
22481
|
+
return obj ? 1 : 0;
|
|
22482
|
+
}
|
|
22483
|
+
function updateAccumulator(acc, row, agg, isOneRow) {
|
|
22484
|
+
const {
|
|
22485
|
+
aggregationType: type,
|
|
22486
|
+
valueField,
|
|
22487
|
+
valueFieldType,
|
|
22488
|
+
valueField2,
|
|
22489
|
+
valueField2Type
|
|
22490
|
+
} = agg;
|
|
22491
|
+
if (!valueField) return;
|
|
22492
|
+
const distinctDenom = !!valueField2 && !!valueField2Type && valueField !== valueField2;
|
|
22493
|
+
const rawVal = row[valueField];
|
|
22494
|
+
if (valueFieldType && (type === "min" || type === "max") && (isDateType(valueFieldType) || isDateFormat2(valueFieldType))) {
|
|
22495
|
+
const dateVal = rawVal instanceof Date ? rawVal : new Date(rawVal);
|
|
22496
|
+
if (!isNaN(dateVal.getTime())) {
|
|
22497
|
+
if (type === "min") {
|
|
22498
|
+
acc.minDate = acc.minDate && acc.minDate.getTime() < dateVal.getTime() ? acc.minDate : dateVal;
|
|
22499
|
+
} else {
|
|
22500
|
+
acc.maxDate = acc.maxDate && acc.maxDate.getTime() > dateVal.getTime() ? acc.maxDate : dateVal;
|
|
22501
|
+
}
|
|
22502
|
+
}
|
|
22503
|
+
return;
|
|
22504
|
+
}
|
|
22505
|
+
const numVal = anyToNum(valueFieldType, rawVal);
|
|
22506
|
+
switch (type) {
|
|
22507
|
+
case "sum":
|
|
22508
|
+
acc.sum += numVal;
|
|
22509
|
+
break;
|
|
22510
|
+
case "average":
|
|
22511
|
+
case "avg":
|
|
22512
|
+
acc.sum += numVal;
|
|
22513
|
+
acc.count++;
|
|
22514
|
+
break;
|
|
22515
|
+
case "min":
|
|
22516
|
+
acc.min = acc.hasVal ? Math.min(acc.min, numVal) : numVal;
|
|
22517
|
+
acc.hasVal = true;
|
|
22518
|
+
break;
|
|
22519
|
+
case "max":
|
|
22520
|
+
acc.max = acc.hasVal ? Math.max(acc.max, numVal) : numVal;
|
|
22521
|
+
acc.hasVal = true;
|
|
22522
|
+
break;
|
|
22523
|
+
case "count":
|
|
22524
|
+
acc.count += numVal;
|
|
22525
|
+
break;
|
|
22526
|
+
case "percentage":
|
|
22527
|
+
acc.sum += numVal;
|
|
22528
|
+
acc.count += distinctDenom ? anyToNum(valueField2Type, row[valueField2]) : isOneRow ? 1 : numVal;
|
|
22529
|
+
break;
|
|
22530
|
+
}
|
|
22531
|
+
}
|
|
22532
|
+
function getFinalAggregationValue({
|
|
22533
|
+
type,
|
|
22534
|
+
valueFieldType,
|
|
22535
|
+
valueField,
|
|
22536
|
+
acc,
|
|
22537
|
+
distinctDenom = false,
|
|
22538
|
+
sumOfDenom,
|
|
22539
|
+
rowsLength,
|
|
22540
|
+
totalRowsForCount
|
|
22541
|
+
}) {
|
|
22542
|
+
if (valueFieldType && (type === "min" || type === "max") && (isDateType(valueFieldType) || isDateFormat2(valueFieldType))) {
|
|
22543
|
+
const dateVal = type === "min" ? acc.minDate : acc.maxDate;
|
|
22544
|
+
return dateVal?.toISOString() ?? "";
|
|
22545
|
+
}
|
|
22546
|
+
if (type === "count") {
|
|
22547
|
+
return totalRowsForCount ?? acc.count;
|
|
22548
|
+
}
|
|
22549
|
+
let final;
|
|
22550
|
+
if (!valueField && type === "percentage" && rowsLength !== void 0) {
|
|
22551
|
+
final = rowsLength ? (totalRowsForCount ?? 0) / rowsLength : 0;
|
|
22552
|
+
} else {
|
|
22553
|
+
switch (type) {
|
|
22554
|
+
case "sum":
|
|
22555
|
+
final = acc.sum;
|
|
22556
|
+
break;
|
|
22557
|
+
case "average":
|
|
22558
|
+
case "avg":
|
|
22559
|
+
final = acc.count ? acc.sum / acc.count : 0;
|
|
22560
|
+
break;
|
|
22561
|
+
case "min":
|
|
22562
|
+
final = acc.hasVal ? acc.min : 0;
|
|
22563
|
+
break;
|
|
22564
|
+
case "max":
|
|
22565
|
+
final = acc.hasVal ? acc.max : 0;
|
|
22566
|
+
break;
|
|
22567
|
+
case "percentage": {
|
|
22568
|
+
const denom = distinctDenom ? acc.count : sumOfDenom ?? acc.count;
|
|
22569
|
+
final = denom ? acc.sum / denom : 0;
|
|
22570
|
+
break;
|
|
22571
|
+
}
|
|
22572
|
+
default:
|
|
22573
|
+
final = 0;
|
|
22574
|
+
}
|
|
22575
|
+
}
|
|
22576
|
+
return final;
|
|
22577
|
+
}
|
|
22578
|
+
function aggregateToOneRow(rows, aggregations) {
|
|
22579
|
+
const multiAgg = aggregations.length > 1;
|
|
22580
|
+
const resultArray = aggregations.map((agg) => {
|
|
22581
|
+
const { aggregationType: type, valueField, valueFieldType } = agg;
|
|
22582
|
+
if (!valueField) {
|
|
22583
|
+
if (type !== "count") {
|
|
22584
|
+
return {};
|
|
22585
|
+
}
|
|
22586
|
+
const finalKey2 = "count" + (multiAgg ? "_count" : "");
|
|
22587
|
+
return { [finalKey2]: rows.length };
|
|
22588
|
+
}
|
|
22589
|
+
const finalKey = `${valueField}` + (multiAgg ? `_${type}` : "");
|
|
22590
|
+
const acc = {
|
|
22591
|
+
sum: 0,
|
|
22592
|
+
count: 0,
|
|
22593
|
+
min: Infinity,
|
|
22594
|
+
max: -Infinity,
|
|
22595
|
+
hasVal: false,
|
|
22596
|
+
minDate: null,
|
|
22597
|
+
maxDate: null
|
|
22598
|
+
};
|
|
22599
|
+
for (const row of rows) {
|
|
22600
|
+
updateAccumulator(acc, row, agg, true);
|
|
22601
|
+
}
|
|
22602
|
+
return {
|
|
22603
|
+
[finalKey]: getFinalAggregationValue({
|
|
22604
|
+
type,
|
|
22605
|
+
valueFieldType,
|
|
22606
|
+
valueField,
|
|
22607
|
+
acc,
|
|
22608
|
+
totalRowsForCount: acc.count
|
|
22609
|
+
})
|
|
22610
|
+
};
|
|
22611
|
+
});
|
|
22612
|
+
return [
|
|
22613
|
+
resultArray.reduce((acc, current) => {
|
|
22614
|
+
return { ...acc, ...current };
|
|
22615
|
+
}, {})
|
|
22616
|
+
];
|
|
22617
|
+
}
|
|
22618
|
+
function aggregateWithColumn(rows, colKey, aggregations, getGroupKey) {
|
|
22619
|
+
if (!colKey) return;
|
|
22620
|
+
const seen = {};
|
|
22621
|
+
const multiAgg = aggregations.length > 1;
|
|
22622
|
+
aggregations.forEach((agg) => {
|
|
22623
|
+
const { aggregationType: type, valueField, valueFieldType, valueField2, valueField2Type } = agg;
|
|
22624
|
+
if (!valueField) {
|
|
22625
|
+
if (type !== "count" && type !== "percentage") return;
|
|
22626
|
+
}
|
|
22627
|
+
const distinctDenom = !!valueField2 && !!valueField2Type && valueField !== valueField2;
|
|
22628
|
+
const accs = {};
|
|
22629
|
+
rows.forEach((row) => {
|
|
22630
|
+
const groupKey = getGroupKey(row);
|
|
22631
|
+
const colVal = row[colKey];
|
|
22632
|
+
if (!accs[groupKey]) accs[groupKey] = {};
|
|
22633
|
+
if (!accs[groupKey][colVal]) {
|
|
22634
|
+
accs[groupKey][colVal] = {
|
|
22635
|
+
sum: 0,
|
|
22636
|
+
count: 0,
|
|
22637
|
+
min: Infinity,
|
|
22638
|
+
max: -Infinity,
|
|
22639
|
+
hasVal: false,
|
|
22640
|
+
minDate: null,
|
|
22641
|
+
maxDate: null,
|
|
22642
|
+
totalRows: 0
|
|
22643
|
+
};
|
|
22644
|
+
}
|
|
22645
|
+
const acc = accs[groupKey][colVal];
|
|
22646
|
+
acc.totalRows += 1;
|
|
22647
|
+
if (!valueField) {
|
|
22648
|
+
if (type === "count") acc.count += 1;
|
|
22649
|
+
else if (type === "percentage") acc.sum += 1;
|
|
22650
|
+
return;
|
|
22651
|
+
}
|
|
22652
|
+
updateAccumulator(acc, row, agg, false);
|
|
22653
|
+
});
|
|
22654
|
+
Object.keys(accs).forEach((groupKey) => {
|
|
22655
|
+
if (!seen[groupKey]) seen[groupKey] = {};
|
|
22656
|
+
const sumOfDenom = Object.values(accs[groupKey]).reduce((t, a) => t + a.count, 0);
|
|
22657
|
+
Object.keys(accs[groupKey]).forEach((colVal) => {
|
|
22658
|
+
const acc = accs[groupKey][colVal];
|
|
22659
|
+
const finalKey = `${colVal}` + (multiAgg ? `_${type}` : "");
|
|
22660
|
+
seen[groupKey][finalKey] = getFinalAggregationValue({
|
|
22661
|
+
type,
|
|
22662
|
+
valueFieldType,
|
|
22663
|
+
valueField,
|
|
22664
|
+
acc,
|
|
22665
|
+
distinctDenom,
|
|
22666
|
+
sumOfDenom,
|
|
22667
|
+
totalRowsForCount: acc.totalRows
|
|
22668
|
+
});
|
|
22669
|
+
});
|
|
22670
|
+
});
|
|
22671
|
+
});
|
|
22672
|
+
return seen;
|
|
22673
|
+
}
|
|
22674
|
+
function aggregateWithoutColumn(rows, aggregations, getGroupKey) {
|
|
22675
|
+
const seen = {};
|
|
22676
|
+
const multiAgg = aggregations.length > 1;
|
|
22677
|
+
aggregations.forEach((agg) => {
|
|
22678
|
+
const { aggregationType: type, valueField, valueFieldType, valueField2, valueField2Type } = agg;
|
|
22679
|
+
if (!valueField) {
|
|
22680
|
+
if (type !== "count" && type !== "percentage") return;
|
|
22681
|
+
}
|
|
22682
|
+
const finalKey = !valueField ? `${type}` + (multiAgg ? `_${type}` : "") : `${valueField}` + (multiAgg ? `_${type}` : "");
|
|
22683
|
+
const distinctDenom = !!valueField2 && !!valueField2Type && valueField !== valueField2;
|
|
22684
|
+
const accs = {};
|
|
22685
|
+
rows.forEach((row) => {
|
|
22686
|
+
const key = getGroupKey(row);
|
|
22687
|
+
if (!seen[key]) seen[key] = {};
|
|
22688
|
+
if (!accs[key]) {
|
|
22689
|
+
accs[key] = {
|
|
22690
|
+
sum: 0,
|
|
22691
|
+
count: 0,
|
|
22692
|
+
min: Infinity,
|
|
22693
|
+
max: -Infinity,
|
|
22694
|
+
hasVal: false,
|
|
22695
|
+
minDate: null,
|
|
22696
|
+
maxDate: null,
|
|
22697
|
+
totalRows: 0
|
|
22698
|
+
};
|
|
22699
|
+
}
|
|
22700
|
+
const acc = accs[key];
|
|
22701
|
+
acc.totalRows += 1;
|
|
22702
|
+
if (!valueField) {
|
|
22703
|
+
if (type === "count") acc.count += 1;
|
|
22704
|
+
else if (type === "percentage") acc.sum += 1;
|
|
22705
|
+
return;
|
|
22706
|
+
}
|
|
22707
|
+
updateAccumulator(acc, row, agg, false);
|
|
22708
|
+
});
|
|
22709
|
+
const sumOfDenom = Object.values(accs).reduce((t, a) => t + a.count, 0);
|
|
22710
|
+
Object.keys(accs).forEach((k) => {
|
|
22711
|
+
const acc = accs[k];
|
|
22712
|
+
seen[k][finalKey] = getFinalAggregationValue({
|
|
22713
|
+
type,
|
|
22714
|
+
valueFieldType,
|
|
22715
|
+
valueField,
|
|
22716
|
+
acc,
|
|
22717
|
+
distinctDenom,
|
|
22718
|
+
sumOfDenom,
|
|
22719
|
+
rowsLength: rows.length,
|
|
22720
|
+
totalRowsForCount: acc.totalRows
|
|
22721
|
+
});
|
|
22722
|
+
});
|
|
22723
|
+
});
|
|
22724
|
+
return seen;
|
|
22725
|
+
}
|
|
22726
|
+
function applyPivotInMemory(rows, pivot, filters) {
|
|
22727
|
+
if (!pivot) return rows;
|
|
22728
|
+
const multiAggPivot = pivot.aggregations ? pivot : singleAggToMultiAgg(pivot);
|
|
22729
|
+
if (multiAggPivot.rowField === void 0) {
|
|
22730
|
+
return aggregateToOneRow(rows, multiAggPivot.aggregations);
|
|
22731
|
+
}
|
|
22732
|
+
const { rowField, columnField, aggregations } = multiAggPivot;
|
|
22733
|
+
const dateBucket = inferDateBucketFromFilters(pivot, filters);
|
|
22734
|
+
const dateRange = dateBucket ? getDateRangeFromFilters(filters) : void 0;
|
|
22735
|
+
const getRowKey = dateBucket ? (row) => {
|
|
22736
|
+
const rawValue = row[rowField];
|
|
22737
|
+
const rawDateValue = rawValue !== null && typeof rawValue === "object" && rawValue.value ? rawValue.value : rawValue;
|
|
22738
|
+
return getDateKey(new Date(rawDateValue), dateBucket);
|
|
22739
|
+
} : (row) => row[rowField];
|
|
22740
|
+
const aggregated = columnField ? aggregateWithColumn(rows, columnField, aggregations, getRowKey) : aggregateWithoutColumn(rows, aggregations, getRowKey);
|
|
22741
|
+
const aggregatedRows = aggregated || {};
|
|
22742
|
+
if (rows.length === 0 && dateBucket && dateRange && !columnField) {
|
|
22743
|
+
const bucketKeys = generateBucketKeys(dateRange.start, dateRange.end, dateBucket);
|
|
22744
|
+
const emptyAgg = buildEmptyAggRow(aggregations);
|
|
22745
|
+
bucketKeys.forEach((k) => {
|
|
22746
|
+
aggregatedRows[k] = { ...emptyAgg };
|
|
22747
|
+
});
|
|
22748
|
+
}
|
|
22749
|
+
const finalRows = assembleFinalRows(
|
|
22750
|
+
aggregatedRows,
|
|
22751
|
+
rowField,
|
|
22752
|
+
dateBucket,
|
|
22753
|
+
rows.length === 0 ? dateRange : void 0
|
|
22754
|
+
);
|
|
22755
|
+
const sorted = sortRows(finalRows, pivot);
|
|
22756
|
+
if (pivot.rowLimit) {
|
|
22757
|
+
return sorted.slice(0, pivot.rowLimit);
|
|
22758
|
+
}
|
|
22759
|
+
return sorted;
|
|
22760
|
+
}
|
|
22761
|
+
|
|
22762
|
+
// src/utils/cacheCab.ts
|
|
22763
|
+
var import_idb = require("idb");
|
|
22764
|
+
var import_date_fns9 = require("date-fns");
|
|
22765
|
+
var import_date_fns_tz2 = require("date-fns-tz");
|
|
22766
|
+
var TZ = "America/Los_Angeles";
|
|
22767
|
+
var CacheCab = class {
|
|
22768
|
+
fetchedRange = {};
|
|
22769
|
+
cachedReportIds = [];
|
|
22770
|
+
uncacheableReportIDs = [];
|
|
22771
|
+
uncacheableInFlight = /* @__PURE__ */ new Map();
|
|
22772
|
+
storage;
|
|
22773
|
+
META_KEY = "cachecab:meta";
|
|
22774
|
+
DATA_PREFIX = "cachecab:data:";
|
|
22775
|
+
UNCACHEABLE_PREFIX = "cachecab:uncacheable:";
|
|
22776
|
+
constructor({
|
|
22777
|
+
storageType = "memory"
|
|
22778
|
+
} = {}) {
|
|
22779
|
+
this.storage = storageType !== "idb" ? new MemoryStorage() : new IdbStorage();
|
|
22780
|
+
void this.loadMetaFromStorage();
|
|
22781
|
+
}
|
|
22782
|
+
async get(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, pageSize, getToken, eventTracking, forceRefresh) {
|
|
22783
|
+
if (this.isCached(reportId, tenants) && !forceRefresh) {
|
|
22784
|
+
return this.getFromCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking);
|
|
22785
|
+
} else {
|
|
22786
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, true, forceRefresh);
|
|
22787
|
+
}
|
|
22788
|
+
}
|
|
22789
|
+
isCached(reportId, tenants) {
|
|
22790
|
+
return this.cachedReportIds.includes(this.getCacheKey(reportId, tenants));
|
|
22791
|
+
}
|
|
22792
|
+
isCacheable(reportId) {
|
|
22793
|
+
return !this.uncacheableReportIDs.includes(reportId);
|
|
22794
|
+
}
|
|
22795
|
+
async getUncacheableResult(reportId, client, tenants, flags, filters, additionalProcessing, pivot) {
|
|
22796
|
+
const key = this.getUncacheableRequestKey(
|
|
22797
|
+
reportId,
|
|
22798
|
+
client,
|
|
22799
|
+
tenants,
|
|
22800
|
+
flags,
|
|
22801
|
+
filters,
|
|
22802
|
+
additionalProcessing,
|
|
22803
|
+
pivot
|
|
22804
|
+
);
|
|
22805
|
+
try {
|
|
22806
|
+
const raw = await this.storage.getItem(key);
|
|
22807
|
+
return raw ? JSON.parse(raw) : null;
|
|
22808
|
+
} catch {
|
|
22809
|
+
return null;
|
|
22810
|
+
}
|
|
22811
|
+
}
|
|
22812
|
+
async setUncacheableResult(reportId, client, tenants, flags, filters, additionalProcessing, pivot, report) {
|
|
22813
|
+
const key = this.getUncacheableRequestKey(
|
|
22814
|
+
reportId,
|
|
22815
|
+
client,
|
|
22816
|
+
tenants,
|
|
22817
|
+
flags,
|
|
22818
|
+
filters,
|
|
22819
|
+
additionalProcessing,
|
|
22820
|
+
pivot
|
|
22821
|
+
);
|
|
22822
|
+
try {
|
|
22823
|
+
await this.storage.setItem(key, JSON.stringify(report));
|
|
22824
|
+
} catch {
|
|
22825
|
+
}
|
|
22826
|
+
}
|
|
22827
|
+
async getOrFetchUncacheableResult(reportId, client, tenants, flags, filters, additionalProcessing, pivot, fetcher, forceRefresh = false) {
|
|
22828
|
+
const key = this.getUncacheableRequestKey(
|
|
22829
|
+
reportId,
|
|
22830
|
+
client,
|
|
22831
|
+
tenants,
|
|
22832
|
+
flags,
|
|
22833
|
+
filters,
|
|
22834
|
+
additionalProcessing,
|
|
22835
|
+
pivot
|
|
22836
|
+
);
|
|
22837
|
+
if (!forceRefresh) {
|
|
22838
|
+
const raw = await this.storage.getItem(key);
|
|
22839
|
+
if (raw) {
|
|
22840
|
+
return { report: JSON.parse(raw), fromCache: true };
|
|
22841
|
+
}
|
|
22842
|
+
const inFlight = this.uncacheableInFlight.get(key);
|
|
22843
|
+
if (inFlight) {
|
|
22844
|
+
const report = await inFlight;
|
|
22845
|
+
return { report, fromCache: false };
|
|
22846
|
+
}
|
|
22847
|
+
}
|
|
22848
|
+
const requestPromise = (async () => {
|
|
22849
|
+
const report = await fetcher();
|
|
22850
|
+
try {
|
|
22851
|
+
await this.storage.setItem(key, JSON.stringify(report));
|
|
22852
|
+
} catch {
|
|
22853
|
+
}
|
|
22854
|
+
return report;
|
|
22855
|
+
})();
|
|
22856
|
+
this.uncacheableInFlight.set(key, requestPromise);
|
|
22857
|
+
try {
|
|
22858
|
+
const report = await requestPromise;
|
|
22859
|
+
return { report, fromCache: false };
|
|
22860
|
+
} finally {
|
|
22861
|
+
this.uncacheableInFlight.delete(key);
|
|
22862
|
+
}
|
|
22863
|
+
}
|
|
22864
|
+
async addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, firstTime = true, forceRefresh = false) {
|
|
22865
|
+
const tenantPart = tenants ? JSON.stringify(tenants) : "";
|
|
22866
|
+
const cacheKey = this.getCacheKey(reportId, tenants);
|
|
22867
|
+
if (firstTime) {
|
|
22868
|
+
const result = await this.fetchInitialReport({ reportId, client, tenants, flags, filters: dashboardFilters, getToken, eventTracking, forceRefresh });
|
|
22869
|
+
try {
|
|
22870
|
+
await this.storage.setItem(this.DATA_PREFIX + cacheKey, JSON.stringify(result));
|
|
22871
|
+
this.cachedReportIds.push(cacheKey);
|
|
22872
|
+
await this.persistMetaToStorage();
|
|
22873
|
+
} catch {
|
|
22874
|
+
console.warn(`Failed to cache report: ${reportId}. Cache full?`);
|
|
22875
|
+
}
|
|
22876
|
+
const newRows = await this.applyPivotsAndFilters(result, dashboardFilters, customFilters, pivot, tenantPart, false);
|
|
22877
|
+
if (pivot) {
|
|
22878
|
+
return { ...result, pivotRows: newRows, pivotRowCount: newRows.length };
|
|
22879
|
+
}
|
|
22880
|
+
return { ...result, rows: newRows, rowCount: newRows.length };
|
|
22881
|
+
} else {
|
|
22882
|
+
const dbDateFilter = dashboardFilters.find((x) => x.filterType === "date_range");
|
|
22883
|
+
const { start: requestedStart, end: requestedEnd } = normalizePSTRanges(
|
|
22884
|
+
dbDateFilter?.startDate ? new Date(dbDateFilter.startDate) : void 0,
|
|
22885
|
+
dbDateFilter?.endDate ? new Date(dbDateFilter.endDate) : void 0
|
|
22886
|
+
);
|
|
22887
|
+
if (!requestedStart || !requestedEnd) {
|
|
22888
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, true);
|
|
22889
|
+
}
|
|
22890
|
+
const currentRange = this.fetchedRange[cacheKey];
|
|
22891
|
+
const rangeStart = currentRange?.start ?? requestedStart;
|
|
22892
|
+
const rangeEnd = currentRange?.end ?? endOfDayPST(/* @__PURE__ */ new Date());
|
|
22893
|
+
const existingRaw = await this.storage.getItem(this.DATA_PREFIX + cacheKey);
|
|
22894
|
+
let existing;
|
|
22895
|
+
let fetchedRows = [];
|
|
22896
|
+
try {
|
|
22897
|
+
existing = JSON.parse(existingRaw);
|
|
22898
|
+
if (!existing.rows) {
|
|
22899
|
+
throw new Error("Invalid Cache!");
|
|
22900
|
+
}
|
|
22901
|
+
if (requestedStart < rangeStart) {
|
|
22902
|
+
const olderReport = await this.fetchReport({
|
|
22903
|
+
reportId,
|
|
22904
|
+
client,
|
|
22905
|
+
tenants,
|
|
22906
|
+
flags,
|
|
22907
|
+
filters: dashboardFilters,
|
|
22908
|
+
getToken,
|
|
22909
|
+
eventTracking,
|
|
22910
|
+
start: requestedStart,
|
|
22911
|
+
end: rangeStart
|
|
22912
|
+
});
|
|
22913
|
+
fetchedRows = olderReport.rows;
|
|
22914
|
+
}
|
|
22915
|
+
if (requestedEnd && requestedEnd > rangeEnd) {
|
|
22916
|
+
const newerReport = await this.fetchReport({
|
|
22917
|
+
reportId,
|
|
22918
|
+
client,
|
|
22919
|
+
tenants,
|
|
22920
|
+
flags,
|
|
22921
|
+
filters: dashboardFilters,
|
|
22922
|
+
getToken,
|
|
22923
|
+
eventTracking,
|
|
22924
|
+
start: rangeEnd,
|
|
22925
|
+
end: requestedEnd
|
|
22926
|
+
});
|
|
22927
|
+
fetchedRows = fetchedRows.concat(newerReport.rows);
|
|
22928
|
+
}
|
|
22929
|
+
} catch {
|
|
22930
|
+
existing = await this.fetchReport({
|
|
22931
|
+
reportId,
|
|
22932
|
+
client,
|
|
22933
|
+
tenants,
|
|
22934
|
+
flags,
|
|
22935
|
+
filters: dashboardFilters,
|
|
22936
|
+
getToken,
|
|
22937
|
+
eventTracking,
|
|
22938
|
+
start: requestedStart,
|
|
22939
|
+
end: requestedEnd
|
|
22940
|
+
});
|
|
22941
|
+
fetchedRows = existing.rows;
|
|
22942
|
+
}
|
|
22943
|
+
const dateKey = existing.dateField?.field ? removeQuotes(existing.dateField.field) : void 0;
|
|
22944
|
+
let mergedRows;
|
|
22945
|
+
if (dateKey) {
|
|
22946
|
+
const startMs = rangeStart.getTime();
|
|
22947
|
+
const endMs = rangeEnd.getTime();
|
|
22948
|
+
const boundaryRows = existing.rows.filter((row) => {
|
|
22949
|
+
const raw = row[dateKey];
|
|
22950
|
+
if (!raw) return false;
|
|
22951
|
+
const t = new Date(raw).getTime();
|
|
22952
|
+
return Math.abs(t - startMs) <= MS_IN_DAY || Math.abs(t - endMs) <= MS_IN_DAY;
|
|
22953
|
+
});
|
|
22954
|
+
const filteredNew = filterNewRows(boundaryRows, fetchedRows);
|
|
22955
|
+
mergedRows = filteredNew.concat(existing.rows);
|
|
22956
|
+
} else {
|
|
22957
|
+
mergedRows = filterNewRows(existing.rows, fetchedRows).concat(existing.rows);
|
|
22958
|
+
}
|
|
22959
|
+
const merged = { ...existing, rows: mergedRows };
|
|
22960
|
+
await this.storage.setItem(this.DATA_PREFIX + cacheKey, JSON.stringify(merged));
|
|
22961
|
+
await this.persistMetaToStorage();
|
|
22962
|
+
const newRows = await this.applyPivotsAndFilters(merged, dashboardFilters, customFilters, pivot, tenantPart, false);
|
|
22963
|
+
if (pivot) {
|
|
22964
|
+
return { ...merged, pivotRows: newRows, pivotRowCount: newRows.length };
|
|
22965
|
+
}
|
|
22966
|
+
return { ...merged, rows: newRows, rowCount: newRows.length };
|
|
22967
|
+
}
|
|
22968
|
+
}
|
|
22969
|
+
/**
|
|
22970
|
+
* Returns cache entry (or re-queries if stale)
|
|
22971
|
+
*/
|
|
22972
|
+
async getFromCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking) {
|
|
22973
|
+
const dateRangeFilter = dashboardFilters.find((x) => x.filterType === "date_range");
|
|
22974
|
+
const cacheKey = this.getCacheKey(reportId, tenants);
|
|
22975
|
+
if (!dateRangeFilter || dateRangeFilter?.primaryRange.value === "ALL_TIME") {
|
|
22976
|
+
const fetchInfo = this.fetchedRange[cacheKey];
|
|
22977
|
+
if (!fetchInfo || fetchInfo?.allTimeDoneBefore === false || Date.now() - fetchInfo.fetchedAtUTCMS >= MS_IN_DAY) {
|
|
22978
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, true);
|
|
22979
|
+
}
|
|
22980
|
+
} else if (this.weShouldReQuery(cacheKey, dateRangeFilter)) {
|
|
22981
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, false);
|
|
22982
|
+
}
|
|
22983
|
+
try {
|
|
22984
|
+
const raw = await this.storage.getItem(this.DATA_PREFIX + cacheKey);
|
|
22985
|
+
if (!raw) {
|
|
22986
|
+
throw new Error("Invalid Cache!");
|
|
22987
|
+
}
|
|
22988
|
+
const parsed = JSON.parse(raw);
|
|
22989
|
+
const tenantPart = tenants ? JSON.stringify(tenants) : "";
|
|
22990
|
+
const newRows = await this.applyPivotsAndFilters(parsed, dashboardFilters, customFilters, pivot, tenantPart);
|
|
22991
|
+
if (pivot) {
|
|
22992
|
+
return { ...parsed, pivotRows: newRows, pivotRowCount: newRows.length };
|
|
22993
|
+
}
|
|
22994
|
+
return { ...parsed, rows: newRows, rowCount: newRows.length };
|
|
22995
|
+
} catch (err) {
|
|
22996
|
+
console.error(err);
|
|
22997
|
+
return this.addToCache(reportId, dashboardFilters, customFilters, pivot, client, tenants, flags, getToken, eventTracking, false);
|
|
22998
|
+
}
|
|
22999
|
+
}
|
|
23000
|
+
weShouldReQuery(cacheKey, dateRangeFilter) {
|
|
23001
|
+
const start2 = dateRangeFilter.startDate;
|
|
23002
|
+
const end = dateRangeFilter.endDate;
|
|
23003
|
+
const range = this.fetchedRange[cacheKey];
|
|
23004
|
+
const { start: s, end: e } = normalizePSTRanges(
|
|
23005
|
+
start2 ? new Date(start2) : void 0,
|
|
23006
|
+
end ? new Date(end) : void 0
|
|
23007
|
+
);
|
|
23008
|
+
return !range || !s || !e || range.start > s || range.end < e;
|
|
23009
|
+
}
|
|
23010
|
+
async fetchInitialReport({
|
|
23011
|
+
reportId,
|
|
23012
|
+
client,
|
|
23013
|
+
tenants,
|
|
23014
|
+
flags,
|
|
23015
|
+
filters = [],
|
|
23016
|
+
getToken,
|
|
23017
|
+
eventTracking,
|
|
23018
|
+
forceRefresh
|
|
23019
|
+
}) {
|
|
23020
|
+
let start2;
|
|
23021
|
+
let end;
|
|
23022
|
+
const dateRangeFilter = filters.find((x) => x.filterType === "date_range");
|
|
23023
|
+
const cacheRange = dateRangeFilter?.initialCacheDateRange;
|
|
23024
|
+
if (cacheRange && cacheRange.startDate) {
|
|
23025
|
+
const startDate = dateRangeFilter?.startDate;
|
|
23026
|
+
start2 = startDate ? (0, import_date_fns9.min)([new Date(cacheRange.startDate), new Date(startDate)]) : new Date(cacheRange.startDate);
|
|
23027
|
+
end = endOfDayPST(/* @__PURE__ */ new Date());
|
|
23028
|
+
} else {
|
|
23029
|
+
const endDate = dateRangeFilter?.endDate ? new Date(dateRangeFilter.endDate) : void 0;
|
|
23030
|
+
const currentDay = endOfDayPST(/* @__PURE__ */ new Date());
|
|
23031
|
+
end = endDate ? (0, import_date_fns9.max)([currentDay, endDate]) : currentDay;
|
|
23032
|
+
start2 = (0, import_date_fns9.subMonths)(end, 7);
|
|
23033
|
+
}
|
|
23034
|
+
const normalized = normalizePSTRanges(start2, end);
|
|
23035
|
+
return this.fetchReport({
|
|
23036
|
+
reportId,
|
|
23037
|
+
client,
|
|
23038
|
+
tenants,
|
|
23039
|
+
flags,
|
|
23040
|
+
filters,
|
|
23041
|
+
getToken,
|
|
23042
|
+
eventTracking,
|
|
23043
|
+
start: normalized.start,
|
|
23044
|
+
end: normalized.end,
|
|
23045
|
+
forceRefresh
|
|
23046
|
+
});
|
|
23047
|
+
}
|
|
23048
|
+
async fetchReport({
|
|
23049
|
+
reportId,
|
|
23050
|
+
client,
|
|
23051
|
+
tenants,
|
|
23052
|
+
flags,
|
|
23053
|
+
filters = [],
|
|
23054
|
+
getToken,
|
|
23055
|
+
eventTracking,
|
|
23056
|
+
start: start2,
|
|
23057
|
+
end,
|
|
23058
|
+
forceRefresh
|
|
23059
|
+
}) {
|
|
23060
|
+
let reportInfo = void 0;
|
|
23061
|
+
try {
|
|
23062
|
+
const { start: s, end: e } = normalizePSTRanges(start2, end);
|
|
23063
|
+
const adjusted = [...filters].map((x) => {
|
|
23064
|
+
return { ...x, options: void 0 };
|
|
23065
|
+
});
|
|
23066
|
+
const dateFilterIndex = adjusted.findIndex((x) => x.filterType === "date_range");
|
|
23067
|
+
const isAllTime = dateFilterIndex !== -1 && adjusted[dateFilterIndex].primaryRange?.value === "ALL_TIME";
|
|
23068
|
+
if (!isAllTime) {
|
|
23069
|
+
const dateFilter = adjusted[dateFilterIndex];
|
|
23070
|
+
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
23071
|
+
adjusted[dateFilterIndex] = { ...dateFilter, startDate: s, endDate: e };
|
|
23072
|
+
}
|
|
23073
|
+
}
|
|
23074
|
+
const fetchResp = await quillFetch({
|
|
23075
|
+
client,
|
|
23076
|
+
task: "report",
|
|
23077
|
+
metadata: {
|
|
23078
|
+
reportId,
|
|
23079
|
+
clientId: client.publicKey,
|
|
23080
|
+
databaseType: client.databaseType,
|
|
23081
|
+
filters: adjusted,
|
|
23082
|
+
additionalProcessing: { page: { rowsPerPage: 1e3, rowsPerRequest: 1e5 } },
|
|
23083
|
+
useNewNodeSql: true,
|
|
23084
|
+
tenants,
|
|
23085
|
+
flags,
|
|
23086
|
+
overwriteCache: forceRefresh ?? false
|
|
23087
|
+
},
|
|
23088
|
+
getToken
|
|
23089
|
+
});
|
|
23090
|
+
const resp = await parseFetchResponse(
|
|
23091
|
+
client,
|
|
23092
|
+
"report",
|
|
23093
|
+
fetchResp,
|
|
23094
|
+
getToken,
|
|
23095
|
+
true
|
|
23096
|
+
);
|
|
23097
|
+
reportInfo = await processReportResponse({
|
|
23098
|
+
resp,
|
|
23099
|
+
client,
|
|
23100
|
+
filters: adjusted,
|
|
23101
|
+
dateBucket: resp?.dateBucket,
|
|
23102
|
+
additionalProcessing: { page: { rowsPerPage: 1e3, rowsPerRequest: 1e5 } },
|
|
23103
|
+
getToken,
|
|
23104
|
+
eventTracking,
|
|
23105
|
+
tenants,
|
|
23106
|
+
// CacheCab fetches with task: 'report'; keep pivot processing local.
|
|
23107
|
+
skipPivotFetch: true,
|
|
23108
|
+
overwriteCache: forceRefresh ?? false
|
|
23109
|
+
});
|
|
23110
|
+
const dateField = reportInfo.dateField?.field;
|
|
23111
|
+
if (!isAllTime && dateField !== void 0 && reportInfo.rows.length > 0) {
|
|
23112
|
+
const cleanedDateField = removeQuotes(dateField);
|
|
23113
|
+
const missingDateFieldCount = reportInfo.rows.some((row) => row[cleanedDateField] === void 0);
|
|
23114
|
+
if (missingDateFieldCount) {
|
|
23115
|
+
this.uncacheableReportIDs.push(reportId);
|
|
23116
|
+
return EMPTY_INTERNAL_REPORT;
|
|
23117
|
+
}
|
|
23118
|
+
}
|
|
23119
|
+
const requiredFilterFields = adjusted.flatMap((x, idx) => {
|
|
23120
|
+
if (idx === dateFilterIndex || !x.values && !x.selectedValue) return [];
|
|
23121
|
+
return removeQuotes(x.field);
|
|
23122
|
+
});
|
|
23123
|
+
const missingFields = [...new Set(requiredFilterFields.filter(
|
|
23124
|
+
(field) => reportInfo?.rows.some((row) => row[field] === void 0)
|
|
23125
|
+
))];
|
|
23126
|
+
if (missingFields.length > 0) {
|
|
23127
|
+
this.uncacheableReportIDs.push(reportId);
|
|
23128
|
+
return EMPTY_INTERNAL_REPORT;
|
|
23129
|
+
}
|
|
23130
|
+
const cacheKey = this.getCacheKey(reportId, tenants);
|
|
23131
|
+
if (isAllTime) {
|
|
23132
|
+
this.fetchedRange[cacheKey] = { start: /* @__PURE__ */ new Date(0), end: /* @__PURE__ */ new Date(), fetchedAtUTCMS: Date.now(), allTimeDoneBefore: true };
|
|
23133
|
+
} else {
|
|
23134
|
+
const existing = this.fetchedRange[cacheKey];
|
|
23135
|
+
if (existing && !forceRefresh) {
|
|
23136
|
+
const oldStart = existing.start;
|
|
23137
|
+
const oldEnd = existing.end;
|
|
23138
|
+
this.fetchedRange[cacheKey] = { start: getMinDate(oldStart, s), end: getMaxDate(oldEnd, e), fetchedAtUTCMS: Date.now(), allTimeDoneBefore: false };
|
|
23139
|
+
} else {
|
|
23140
|
+
this.fetchedRange[cacheKey] = { start: s, end: e, fetchedAtUTCMS: Date.now(), allTimeDoneBefore: false };
|
|
23141
|
+
}
|
|
23142
|
+
}
|
|
23143
|
+
} catch (error) {
|
|
23144
|
+
console.warn(error);
|
|
23145
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
23146
|
+
throw error;
|
|
23147
|
+
}
|
|
23148
|
+
}
|
|
23149
|
+
return reportInfo || EMPTY_INTERNAL_REPORT;
|
|
23150
|
+
}
|
|
23151
|
+
async applyPivotsAndFilters(report, dashboardFilters, customFilters, pivot, tenantPart, useCache = true) {
|
|
23152
|
+
const datasetVersion = this.fetchedRange[report.id + tenantPart]?.fetchedAtUTCMS ?? 0;
|
|
23153
|
+
const keyParts = [
|
|
23154
|
+
report.queryString,
|
|
23155
|
+
tenantPart,
|
|
23156
|
+
datasetVersion,
|
|
23157
|
+
// prevents fetching stale filters on hard refresh
|
|
23158
|
+
hashString(stableStringify(dashboardFilters)),
|
|
23159
|
+
hashString(stableStringify(customFilters))
|
|
23160
|
+
];
|
|
23161
|
+
const queryKey = this.DATA_PREFIX + keyParts.join("|");
|
|
23162
|
+
let filtersApplied;
|
|
23163
|
+
if (useCache) {
|
|
23164
|
+
try {
|
|
23165
|
+
const cache = await this.storage.getItem(queryKey);
|
|
23166
|
+
if (cache) {
|
|
23167
|
+
filtersApplied = JSON.parse(cache);
|
|
23168
|
+
}
|
|
23169
|
+
} catch {
|
|
23170
|
+
}
|
|
23171
|
+
}
|
|
23172
|
+
if (!filtersApplied) {
|
|
23173
|
+
const dateIndex = dashboardFilters.findIndex((x) => x.filterType === "date_range");
|
|
23174
|
+
const requiredFilterFields = dashboardFilters.flatMap((x, idx) => {
|
|
23175
|
+
if (idx === dateIndex || !x.values?.length && !x.selectedValue) return [];
|
|
23176
|
+
return removeQuotes(x.field);
|
|
23177
|
+
});
|
|
23178
|
+
const missingFields = [...new Set(requiredFilterFields.filter(
|
|
23179
|
+
(field) => report.rows.some((row) => row[field] === void 0)
|
|
23180
|
+
))];
|
|
23181
|
+
if (missingFields.length > 0) {
|
|
23182
|
+
this.uncacheableReportIDs.push(report.id);
|
|
23183
|
+
return [];
|
|
23184
|
+
}
|
|
23185
|
+
const dbDateFilter = dashboardFilters.find((x) => x.filterType === "date_range");
|
|
23186
|
+
if (report.dateField && dbDateFilter?.startDate) {
|
|
23187
|
+
const { start: startDate, end: endDate } = normalizePSTRanges(
|
|
23188
|
+
new Date(dbDateFilter.startDate),
|
|
23189
|
+
dbDateFilter.endDate ? new Date(dbDateFilter.endDate) : void 0
|
|
23190
|
+
);
|
|
23191
|
+
const fieldToUse = report.rows[0] && report.rows[0]["__quillRawDate"] ? "__quillRawDate" : removeQuotes(report.dateField.field);
|
|
23192
|
+
const dateFilteredRows = report.rows.filter((x) => {
|
|
23193
|
+
const rowDate = new Date(x[fieldToUse]);
|
|
23194
|
+
return startDate <= rowDate && (endDate ? rowDate <= endDate : true);
|
|
23195
|
+
});
|
|
23196
|
+
filtersApplied = applyFiltersInMemory(dateFilteredRows, [], { dashboardFilters, customFilters });
|
|
23197
|
+
} else {
|
|
23198
|
+
filtersApplied = applyFiltersInMemory(report.rows, [], { dashboardFilters, customFilters });
|
|
23199
|
+
}
|
|
23200
|
+
}
|
|
23201
|
+
try {
|
|
23202
|
+
await this.storage.setItem(queryKey, JSON.stringify(filtersApplied));
|
|
23203
|
+
} catch {
|
|
23204
|
+
}
|
|
23205
|
+
const withPivot = applyPivotInMemory(filtersApplied, pivot, dashboardFilters.concat(customFilters));
|
|
23206
|
+
return withPivot;
|
|
23207
|
+
}
|
|
23208
|
+
getCacheKey(reportId, tenants) {
|
|
23209
|
+
const tenantPart = tenants ? JSON.stringify(tenants) : "";
|
|
23210
|
+
return reportId + tenantPart;
|
|
23211
|
+
}
|
|
23212
|
+
getUncacheableRequestKey(reportId, client, tenants, flags, filters, additionalProcessing, pivot) {
|
|
23213
|
+
const canonicalFilters = filters.map(
|
|
23214
|
+
(f) => canonicalizeFilterForUncacheableKey(f)
|
|
23215
|
+
);
|
|
23216
|
+
const keyParts = [
|
|
23217
|
+
reportId,
|
|
23218
|
+
client.publicKey,
|
|
23219
|
+
client.databaseType,
|
|
23220
|
+
hashString(stableStringify(canonicalizeForKey(tenants ?? null))),
|
|
23221
|
+
hashString(stableStringify(canonicalizeForKey(flags ?? null))),
|
|
23222
|
+
hashString(stableStringify(canonicalFilters)),
|
|
23223
|
+
hashString(stableStringify(canonicalizeForKey(additionalProcessing ?? null))),
|
|
23224
|
+
hashString(stableStringify(canonicalizeForKey(pivot ?? null)))
|
|
23225
|
+
];
|
|
23226
|
+
return this.UNCACHEABLE_PREFIX + keyParts.join("|");
|
|
23227
|
+
}
|
|
23228
|
+
async loadMetaFromStorage() {
|
|
23229
|
+
const meta = await this.storage.getItem(this.META_KEY);
|
|
23230
|
+
if (!meta) return;
|
|
23231
|
+
try {
|
|
23232
|
+
const parsed = JSON.parse(meta);
|
|
23233
|
+
this.cachedReportIds = parsed.cached || [];
|
|
23234
|
+
this.uncacheableReportIDs = parsed.cannotBeCached;
|
|
23235
|
+
this.fetchedRange = Object.fromEntries(
|
|
23236
|
+
Object.entries(parsed.fetchedRange || {}).map(([id2, range]) => [
|
|
23237
|
+
id2,
|
|
23238
|
+
{ ...range, start: new Date(range.start), end: new Date(range.end) }
|
|
23239
|
+
])
|
|
23240
|
+
);
|
|
23241
|
+
} catch (err) {
|
|
23242
|
+
console.warn("CacheCab: could not parse meta from storage", err);
|
|
23243
|
+
}
|
|
23244
|
+
}
|
|
23245
|
+
async persistMetaToStorage() {
|
|
23246
|
+
const serializableRange = Object.fromEntries(
|
|
23247
|
+
Object.entries(this.fetchedRange).map(([id2, range]) => [
|
|
23248
|
+
id2,
|
|
23249
|
+
{ ...range }
|
|
23250
|
+
])
|
|
23251
|
+
);
|
|
23252
|
+
await this.storage.setItem(
|
|
23253
|
+
this.META_KEY,
|
|
23254
|
+
JSON.stringify({
|
|
23255
|
+
fetchedRange: serializableRange,
|
|
23256
|
+
cached: this.cachedReportIds,
|
|
23257
|
+
cannotBeCached: this.uncacheableReportIDs
|
|
23258
|
+
})
|
|
23259
|
+
);
|
|
23260
|
+
}
|
|
23261
|
+
};
|
|
23262
|
+
var MemoryStorage = class {
|
|
23263
|
+
store = /* @__PURE__ */ new Map();
|
|
23264
|
+
async getItem(key) {
|
|
23265
|
+
return this.store.get(key) ?? null;
|
|
23266
|
+
}
|
|
23267
|
+
async setItem(key, value) {
|
|
23268
|
+
this.store.set(key, value);
|
|
23269
|
+
}
|
|
23270
|
+
};
|
|
23271
|
+
var DB_NAME = "quill.cachecab";
|
|
23272
|
+
var STORE_NAME = "kv";
|
|
23273
|
+
var IdbStorage = class {
|
|
23274
|
+
dbPromise;
|
|
23275
|
+
constructor() {
|
|
23276
|
+
this.dbPromise = (0, import_idb.openDB)(DB_NAME, 1, {
|
|
23277
|
+
upgrade(db) {
|
|
23278
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
23279
|
+
db.createObjectStore(STORE_NAME);
|
|
23280
|
+
}
|
|
23281
|
+
}
|
|
23282
|
+
});
|
|
23283
|
+
}
|
|
23284
|
+
async getItem(key) {
|
|
23285
|
+
const db = await this.dbPromise;
|
|
23286
|
+
return await db.get(STORE_NAME, key) ?? null;
|
|
23287
|
+
}
|
|
23288
|
+
async setItem(key, value) {
|
|
23289
|
+
const db = await this.dbPromise;
|
|
23290
|
+
await db.put(STORE_NAME, value, key);
|
|
23291
|
+
}
|
|
23292
|
+
};
|
|
23293
|
+
function removeQuotes(str) {
|
|
23294
|
+
return str.replace(/^['"]|['"]$/g, "");
|
|
23295
|
+
}
|
|
23296
|
+
function getMaxDate(d1, d2) {
|
|
23297
|
+
return d1 > d2 ? d1 : d2;
|
|
23298
|
+
}
|
|
23299
|
+
function getMinDate(d1, d2) {
|
|
23300
|
+
return d2 > d1 ? d1 : d2;
|
|
23301
|
+
}
|
|
23302
|
+
function hashString(str) {
|
|
23303
|
+
let h1 = 3735928559 ^ 0, h2 = 1103547991 ^ 0;
|
|
23304
|
+
for (let i = 0, ch; i < str.length; i++) {
|
|
23305
|
+
ch = str.charCodeAt(i);
|
|
23306
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
23307
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
23308
|
+
}
|
|
23309
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
23310
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
23311
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
|
|
23312
|
+
}
|
|
23313
|
+
function filterNewRows(existingRows, newRows) {
|
|
23314
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23315
|
+
const getKey = (row) => stableStringify(row);
|
|
23316
|
+
existingRows.forEach((row) => seen.add(getKey(row)));
|
|
23317
|
+
return newRows.filter((row) => {
|
|
23318
|
+
const k = getKey(row);
|
|
23319
|
+
if (seen.has(k)) return false;
|
|
23320
|
+
seen.add(k);
|
|
23321
|
+
return true;
|
|
23322
|
+
});
|
|
23323
|
+
}
|
|
23324
|
+
function stableStringify(obj) {
|
|
23325
|
+
if (obj === null || typeof obj !== "object") return JSON.stringify(obj);
|
|
23326
|
+
if (Array.isArray(obj)) {
|
|
23327
|
+
return `[${obj.map(stableStringify).join(",")}]`;
|
|
23328
|
+
}
|
|
23329
|
+
const keys = Object.keys(obj).sort();
|
|
23330
|
+
return `{${keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",")}}`;
|
|
23331
|
+
}
|
|
23332
|
+
function canonicalizeForKey(value) {
|
|
23333
|
+
if (value instanceof Date) {
|
|
23334
|
+
return value.toISOString();
|
|
23335
|
+
}
|
|
23336
|
+
if (Array.isArray(value)) {
|
|
23337
|
+
return value.map(canonicalizeForKey);
|
|
23338
|
+
}
|
|
23339
|
+
if (value && typeof value === "object") {
|
|
23340
|
+
const out = {};
|
|
23341
|
+
Object.keys(value).sort().forEach((key) => {
|
|
23342
|
+
if (value[key] !== void 0) {
|
|
23343
|
+
out[key] = canonicalizeForKey(value[key]);
|
|
23344
|
+
}
|
|
23345
|
+
});
|
|
23346
|
+
return out;
|
|
23347
|
+
}
|
|
23348
|
+
return value;
|
|
23349
|
+
}
|
|
23350
|
+
function canonicalizeFilterForUncacheableKey(filter) {
|
|
23351
|
+
const raw = canonicalizeForKey(filter) ?? {};
|
|
23352
|
+
const base = {
|
|
23353
|
+
filterType: raw.filterType,
|
|
23354
|
+
field: raw.field,
|
|
23355
|
+
table: raw.table,
|
|
23356
|
+
label: raw.label,
|
|
23357
|
+
operator: raw.operator
|
|
23358
|
+
};
|
|
23359
|
+
if (raw.selectedValue !== void 0) {
|
|
23360
|
+
base.selectedValue = raw.selectedValue;
|
|
23361
|
+
}
|
|
23362
|
+
if (Array.isArray(raw.values)) {
|
|
23363
|
+
base.values = [...raw.values].map(canonicalizeForKey).sort();
|
|
23364
|
+
}
|
|
23365
|
+
if (raw.value !== void 0) {
|
|
23366
|
+
base.value = canonicalizeForKey(raw.value);
|
|
23367
|
+
}
|
|
23368
|
+
if (raw.filterType === "date_range") {
|
|
23369
|
+
const { start: start2, end } = normalizePSTRanges(
|
|
23370
|
+
raw.startDate ? new Date(raw.startDate) : void 0,
|
|
23371
|
+
raw.endDate ? new Date(raw.endDate) : void 0
|
|
23372
|
+
);
|
|
23373
|
+
base.startDate = start2 ? start2.toISOString() : void 0;
|
|
23374
|
+
base.endDate = end ? end.toISOString() : void 0;
|
|
23375
|
+
base.primaryRange = raw.primaryRange?.value;
|
|
23376
|
+
base.comparisonRange = raw.comparisonRange?.value;
|
|
23377
|
+
}
|
|
23378
|
+
return canonicalizeForKey(base);
|
|
23379
|
+
}
|
|
23380
|
+
function startOfDayPST(date) {
|
|
23381
|
+
const pstDate = (0, import_date_fns_tz2.utcToZonedTime)(date, TZ);
|
|
23382
|
+
const startPst = (0, import_date_fns9.startOfDay)(pstDate);
|
|
23383
|
+
return (0, import_date_fns_tz2.zonedTimeToUtc)(startPst, TZ);
|
|
23384
|
+
}
|
|
23385
|
+
function endOfDayPST(date) {
|
|
23386
|
+
const pstDate = (0, import_date_fns_tz2.utcToZonedTime)(date, TZ);
|
|
23387
|
+
const endPst = (0, import_date_fns9.endOfDay)(pstDate);
|
|
23388
|
+
return (0, import_date_fns_tz2.zonedTimeToUtc)(endPst, TZ);
|
|
23389
|
+
}
|
|
23390
|
+
function normalizePSTRanges(start2, end) {
|
|
23391
|
+
return {
|
|
23392
|
+
start: start2 ? startOfDayPST(start2) : void 0,
|
|
23393
|
+
end: end ? endOfDayPST(end) : void 0
|
|
23394
|
+
};
|
|
23395
|
+
}
|
|
23396
|
+
|
|
23397
|
+
// src/Context.tsx
|
|
21589
23398
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
21590
23399
|
var dummySetter = () => {
|
|
21591
23400
|
};
|
|
@@ -21917,7 +23726,9 @@ var ReportFiltersContext = (0, import_react.createContext)({
|
|
|
21917
23726
|
loadFiltersForReport: async () => {
|
|
21918
23727
|
},
|
|
21919
23728
|
abortLoadingFilters: () => {
|
|
21920
|
-
}
|
|
23729
|
+
},
|
|
23730
|
+
customFiltersLoaded: false,
|
|
23731
|
+
setCustomFiltersLoaded: dummySetter
|
|
21921
23732
|
});
|
|
21922
23733
|
var customDashboardFiltersReducer = (state, action) => {
|
|
21923
23734
|
switch (action.type) {
|
|
@@ -22007,6 +23818,9 @@ var FetchContext = (0, import_react.createContext)({
|
|
|
22007
23818
|
var EventTrackingContext = (0, import_react.createContext)({
|
|
22008
23819
|
eventTracking: null
|
|
22009
23820
|
});
|
|
23821
|
+
var CacheCabContext = (0, import_react.createContext)({
|
|
23822
|
+
getCacheCab: (storageType) => new CacheCab({ storageType })
|
|
23823
|
+
});
|
|
22010
23824
|
var ContextProvider = ({
|
|
22011
23825
|
children,
|
|
22012
23826
|
initialTheme,
|
|
@@ -22020,6 +23834,14 @@ var ContextProvider = ({
|
|
|
22020
23834
|
getAuthorizationToken = async () => "",
|
|
22021
23835
|
eventTracking = null
|
|
22022
23836
|
}) => {
|
|
23837
|
+
const cacheCabByTypeRef = (0, import_react.useRef)({});
|
|
23838
|
+
const getCacheCab = (0, import_react.useCallback)((storageType) => {
|
|
23839
|
+
const key = storageType === "idb" ? "idb" : "memory";
|
|
23840
|
+
if (!cacheCabByTypeRef.current[key]) {
|
|
23841
|
+
cacheCabByTypeRef.current[key] = new CacheCab({ storageType: key });
|
|
23842
|
+
}
|
|
23843
|
+
return cacheCabByTypeRef.current[key];
|
|
23844
|
+
}, []);
|
|
22023
23845
|
const [client, setClient] = (0, import_react.useState)(
|
|
22024
23846
|
typeof window !== "undefined" && sessionStorage ? JSON.parse(sessionStorage.getItem("quill-client") ?? "null") : null
|
|
22025
23847
|
);
|
|
@@ -22082,6 +23904,7 @@ var ContextProvider = ({
|
|
|
22082
23904
|
reportFiltersReducer,
|
|
22083
23905
|
{}
|
|
22084
23906
|
);
|
|
23907
|
+
const [customFiltersLoaded, setCustomFiltersLoaded] = (0, import_react.useState)(false);
|
|
22085
23908
|
const reportFilterOptionsAbortControllers = (0, import_react.useRef)({});
|
|
22086
23909
|
const [reports, reportsDispatch] = (0, import_react.useReducer)(reportsReducer, {});
|
|
22087
23910
|
const [reportsLoadingState, reportsLoadingStateDispatch] = (0, import_react.useReducer)(
|
|
@@ -22105,6 +23928,11 @@ var ContextProvider = ({
|
|
|
22105
23928
|
const viewerTenantsByOwnerRequests = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
22106
23929
|
const mappedTenantsRequests = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
22107
23930
|
const loadDashboardProcessId = (0, import_react.useRef)({});
|
|
23931
|
+
(0, import_react.useEffect)(() => {
|
|
23932
|
+
if (Object.keys(customReportFilters).length) {
|
|
23933
|
+
setCustomFiltersLoaded(true);
|
|
23934
|
+
}
|
|
23935
|
+
}, [customReportFilters]);
|
|
22108
23936
|
(0, import_react.useEffect)(() => {
|
|
22109
23937
|
if (!theme) {
|
|
22110
23938
|
const populatedTheme = {
|
|
@@ -22873,6 +24701,7 @@ var ContextProvider = ({
|
|
|
22873
24701
|
...dashboard2,
|
|
22874
24702
|
dateFilter: dashboard2.dateFilter ? {
|
|
22875
24703
|
...dashboard2.dateFilter,
|
|
24704
|
+
initialCacheDateRange: dashboard2.initialCacheDateRange ? { ...dashboard2.initialCacheDateRange } : void 0,
|
|
22876
24705
|
presetOptions: dashboard2.dateFilter.presetOptions?.map(
|
|
22877
24706
|
(preset) => ({
|
|
22878
24707
|
...preset,
|
|
@@ -23215,6 +25044,7 @@ var ContextProvider = ({
|
|
|
23215
25044
|
...dashboard2,
|
|
23216
25045
|
dateFilter: dashboard2.dateFilter ? {
|
|
23217
25046
|
...dashboard2.dateFilter,
|
|
25047
|
+
initialCacheDateRange: dashboard2.initialCacheDateRange ? { ...dashboard2.initialCacheDateRange } : void 0,
|
|
23218
25048
|
presetOptions: dashboard2.dateFilter.presetOptions?.map(
|
|
23219
25049
|
(preset) => ({
|
|
23220
25050
|
...preset,
|
|
@@ -23259,6 +25089,7 @@ var ContextProvider = ({
|
|
|
23259
25089
|
if (dashboard2.dateFilter) {
|
|
23260
25090
|
dashboard2.dateFilter = {
|
|
23261
25091
|
...dashboard2.dateFilter,
|
|
25092
|
+
initialCacheDateRange: dashboard2.initialCacheDateRange ? { ...dashboard2.initialCacheDateRange } : void 0,
|
|
23262
25093
|
startDate: presetOptions.find(
|
|
23263
25094
|
(elem) => elem.value === dashboard2.dateFilter.primaryRange?.value
|
|
23264
25095
|
)?.startDate,
|
|
@@ -23527,7 +25358,7 @@ var ContextProvider = ({
|
|
|
23527
25358
|
if (!theme) {
|
|
23528
25359
|
return null;
|
|
23529
25360
|
}
|
|
23530
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
25361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CacheCabContext.Provider, { value: { getCacheCab }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
23531
25362
|
ClientContext.Provider,
|
|
23532
25363
|
{
|
|
23533
25364
|
value: [
|
|
@@ -23568,7 +25399,9 @@ var ContextProvider = ({
|
|
|
23568
25399
|
reportFiltersDispatch,
|
|
23569
25400
|
customReportFiltersDispatch,
|
|
23570
25401
|
loadFiltersForReport,
|
|
23571
|
-
abortLoadingFilters
|
|
25402
|
+
abortLoadingFilters,
|
|
25403
|
+
customFiltersLoaded,
|
|
25404
|
+
setCustomFiltersLoaded
|
|
23572
25405
|
},
|
|
23573
25406
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
23574
25407
|
ReportsContext.Provider,
|
|
@@ -23611,7 +25444,7 @@ var ContextProvider = ({
|
|
|
23611
25444
|
}
|
|
23612
25445
|
) })
|
|
23613
25446
|
}
|
|
23614
|
-
);
|
|
25447
|
+
) });
|
|
23615
25448
|
};
|
|
23616
25449
|
|
|
23617
25450
|
// src/hooks/useExport.tsx
|
|
@@ -23627,9 +25460,9 @@ init_Filter();
|
|
|
23627
25460
|
init_filterProcessing();
|
|
23628
25461
|
|
|
23629
25462
|
// src/utils/merge.ts
|
|
23630
|
-
var
|
|
25463
|
+
var import_date_fns10 = require("date-fns");
|
|
23631
25464
|
init_columnType();
|
|
23632
|
-
var
|
|
25465
|
+
var import_date_fns_tz3 = require("date-fns-tz");
|
|
23633
25466
|
function mergeComparisonRange(resp) {
|
|
23634
25467
|
if (resp.chartType === "table") return resp;
|
|
23635
25468
|
const compRows = resp.compareRows;
|
|
@@ -23672,6 +25505,18 @@ var useDashboardInternal = (dashboardName, customFilters) => {
|
|
|
23672
25505
|
(f) => f.filter
|
|
23673
25506
|
) : null;
|
|
23674
25507
|
}, [dashboardFilters, dashboardName]);
|
|
25508
|
+
const getExistingDateFilter = (0, import_react2.useMemo)(
|
|
25509
|
+
() => (name2) => {
|
|
25510
|
+
if (!name2) return void 0;
|
|
25511
|
+
const filtersForDashboard = dashboardFilters[name2];
|
|
25512
|
+
if (!filtersForDashboard) return void 0;
|
|
25513
|
+
const entry = Object.values(filtersForDashboard).find(
|
|
25514
|
+
(f) => f?.filter?.filterType === "date_range" /* Date */
|
|
25515
|
+
);
|
|
25516
|
+
return entry?.filter;
|
|
25517
|
+
},
|
|
25518
|
+
[dashboardFilters]
|
|
25519
|
+
);
|
|
23675
25520
|
(0, import_react2.useEffect)(() => {
|
|
23676
25521
|
if (!dashboardName) return;
|
|
23677
25522
|
if (backfilledDashboards.current.has(dashboardName)) return;
|
|
@@ -23709,7 +25554,7 @@ var useDashboardInternal = (dashboardName, customFilters) => {
|
|
|
23709
25554
|
customFilters
|
|
23710
25555
|
);
|
|
23711
25556
|
}, [dashboardName, loading, dashboardConfig, dashboardFilters]);
|
|
23712
|
-
const handleReload = async (overrideDashboardName, fetchFromServer = false, reportAction, overrideFilters) => {
|
|
25557
|
+
const handleReload = async (overrideDashboardName, fetchFromServer = false, reportAction, overrideFilters, options) => {
|
|
23713
25558
|
if (!dashboardName) return;
|
|
23714
25559
|
if (overrideFilters) {
|
|
23715
25560
|
const dateFilter2 = overrideFilters.filters.find(
|
|
@@ -23762,10 +25607,19 @@ var useDashboardInternal = (dashboardName, customFilters) => {
|
|
|
23762
25607
|
Object.values(dashboard?.sections ?? {}).flat(),
|
|
23763
25608
|
dashboardName
|
|
23764
25609
|
) : void 0;
|
|
25610
|
+
const existingDateFilter = options?.preserveExistingDateFilter ? getExistingDateFilter(dashboardName) : void 0;
|
|
25611
|
+
const mergedDateFilter = dateFilter && existingDateFilter ? {
|
|
25612
|
+
...dateFilter,
|
|
25613
|
+
startDate: existingDateFilter.startDate ?? dateFilter.startDate,
|
|
25614
|
+
endDate: existingDateFilter.endDate ?? dateFilter.endDate,
|
|
25615
|
+
preset: existingDateFilter.preset ?? dateFilter.preset,
|
|
25616
|
+
primaryRange: existingDateFilter.primaryRange ?? dateFilter.primaryRange,
|
|
25617
|
+
comparisonRange: existingDateFilter.comparisonRange ?? dateFilter.comparisonRange
|
|
25618
|
+
} : dateFilter ?? existingDateFilter;
|
|
23765
25619
|
loadFiltersForDashboard(
|
|
23766
25620
|
dashboardName,
|
|
23767
25621
|
[
|
|
23768
|
-
...
|
|
25622
|
+
...mergedDateFilter ? [mergedDateFilter] : [],
|
|
23769
25623
|
...updatedDashboard?.filters?.map((filter) => ({
|
|
23770
25624
|
...filter,
|
|
23771
25625
|
query: void 0
|
|
@@ -24050,7 +25904,8 @@ var useDashboards = () => {
|
|
|
24050
25904
|
tenantFilters,
|
|
24051
25905
|
dateFilter,
|
|
24052
25906
|
customFilters,
|
|
24053
|
-
tenantKeys
|
|
25907
|
+
tenantKeys,
|
|
25908
|
+
initialCacheDateRange
|
|
24054
25909
|
}) => {
|
|
24055
25910
|
if (!client) return;
|
|
24056
25911
|
if (tenantKeys?.some((key) => !key)) {
|
|
@@ -24071,6 +25926,7 @@ var useDashboards = () => {
|
|
|
24071
25926
|
filters,
|
|
24072
25927
|
tenantFilters,
|
|
24073
25928
|
dateFilter: dateFilter ?? null,
|
|
25929
|
+
initialCacheDateRange,
|
|
24074
25930
|
name: name2.trim(),
|
|
24075
25931
|
task: "edit-dashboard",
|
|
24076
25932
|
clientId: client.clientId,
|
|
@@ -24282,7 +26138,9 @@ var useDashboards = () => {
|
|
|
24282
26138
|
};
|
|
24283
26139
|
};
|
|
24284
26140
|
var useDashboard = (dashboardName, config) => {
|
|
26141
|
+
const logCacheStatistics = config?.showCacheLogs || false;
|
|
24285
26142
|
const { data, dashboardFilters, reload, isLoading } = useDashboardInternal(dashboardName);
|
|
26143
|
+
const [lastUpdated, setLastUpdated] = (0, import_react2.useState)(0);
|
|
24286
26144
|
const { customFilterDispatch } = (0, import_react2.useContext)(DashboardFiltersContext);
|
|
24287
26145
|
const { reportsDispatch, reportsLoadingStateDispatch } = (0, import_react2.useContext)(ReportsContext);
|
|
24288
26146
|
const initialLoad = (0, import_react2.useRef)(true);
|
|
@@ -24291,15 +26149,19 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24291
26149
|
const [client] = (0, import_react2.useContext)(ClientContext);
|
|
24292
26150
|
const { tenants, flags } = (0, import_react2.useContext)(TenantContext);
|
|
24293
26151
|
const { getToken } = (0, import_react2.useContext)(FetchContext);
|
|
24294
|
-
const { customReportFilters } = (0, import_react2.useContext)(ReportFiltersContext);
|
|
26152
|
+
const { customReportFilters, customFiltersLoaded, setCustomFiltersLoaded } = (0, import_react2.useContext)(ReportFiltersContext);
|
|
24295
26153
|
const { eventTracking } = (0, import_react2.useContext)(EventTrackingContext);
|
|
24296
|
-
const
|
|
26154
|
+
const { getCacheCab } = (0, import_react2.useContext)(CacheCabContext);
|
|
24297
26155
|
const reportRequestIds = (0, import_react2.useRef)({});
|
|
24298
26156
|
const lastDashboardName = (0, import_react2.useRef)(null);
|
|
24299
26157
|
const pendingNameChangeReload = (0, import_react2.useRef)(false);
|
|
24300
|
-
(0, import_react2.
|
|
24301
|
-
|
|
24302
|
-
|
|
26158
|
+
const [loadedDashes, setLoadedDashes] = (0, import_react2.useState)([]);
|
|
26159
|
+
const [lastUpdatedDict, setLastUpdatedDict] = (0, import_react2.useState)({});
|
|
26160
|
+
const cacheEnabled = config?.cacheEnabled ?? true;
|
|
26161
|
+
const cacheCab = (0, import_react2.useMemo)(
|
|
26162
|
+
() => getCacheCab(config?.cacheType),
|
|
26163
|
+
[getCacheCab, config?.cacheType]
|
|
26164
|
+
);
|
|
24303
26165
|
(0, import_react2.useEffect)(() => {
|
|
24304
26166
|
const nameChanged = dashboardName !== lastDashboardName.current;
|
|
24305
26167
|
if (nameChanged) {
|
|
@@ -24309,19 +26171,29 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24309
26171
|
backfilledDashboards.current = false;
|
|
24310
26172
|
reportRequestIds.current = {};
|
|
24311
26173
|
pendingNameChangeReload.current = true;
|
|
26174
|
+
if (customFiltersLoaded && !loadedDashes.includes(dashboardName)) {
|
|
26175
|
+
setCustomFiltersLoaded(false);
|
|
26176
|
+
}
|
|
26177
|
+
setLastUpdated(lastUpdatedDict[dashboardName] || 0);
|
|
24312
26178
|
}
|
|
24313
26179
|
if (!dashboardName) return;
|
|
24314
26180
|
if (pendingNameChangeReload.current && data) {
|
|
24315
26181
|
pendingNameChangeReload.current = false;
|
|
24316
26182
|
initialLoad.current = false;
|
|
26183
|
+
fetchedInitialReports.current = false;
|
|
24317
26184
|
return;
|
|
24318
26185
|
}
|
|
24319
26186
|
if (pendingNameChangeReload.current && !isLoading && !data && initialLoad.current) {
|
|
24320
26187
|
initialLoad.current = false;
|
|
24321
26188
|
pendingNameChangeReload.current = false;
|
|
24322
|
-
reload(
|
|
26189
|
+
reload(dashboardName, false, void 0, void 0, {
|
|
26190
|
+
preserveExistingDateFilter: true
|
|
26191
|
+
});
|
|
24323
26192
|
}
|
|
24324
26193
|
}, [isLoading, data, dashboardName]);
|
|
26194
|
+
(0, import_react2.useEffect)(() => {
|
|
26195
|
+
setLastUpdated(lastUpdatedDict[dashboardName] || 0);
|
|
26196
|
+
}, [lastUpdatedDict, dashboardName]);
|
|
24325
26197
|
(0, import_react2.useEffect)(() => {
|
|
24326
26198
|
if (backfilledDashboards.current) return;
|
|
24327
26199
|
if (isLoading || !data) return;
|
|
@@ -24330,7 +26202,9 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24330
26202
|
);
|
|
24331
26203
|
if (!needsBackfill) return;
|
|
24332
26204
|
backfilledDashboards.current = true;
|
|
24333
|
-
reload(dashboardName, false
|
|
26205
|
+
reload(dashboardName, false, void 0, void 0, {
|
|
26206
|
+
preserveExistingDateFilter: true
|
|
26207
|
+
});
|
|
24334
26208
|
}, [isLoading, data, dashboardFilters, dashboardName]);
|
|
24335
26209
|
const { allReportsById } = useAllReports();
|
|
24336
26210
|
const sections = (0, import_react2.useMemo)(() => {
|
|
@@ -24354,7 +26228,13 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24354
26228
|
fetchedInitialReports.current = true;
|
|
24355
26229
|
fetchReports([], dashboardFilters ?? [], config?.pageSize);
|
|
24356
26230
|
}
|
|
24357
|
-
}, [fetchedInitialReports, data, dashboardFilters]);
|
|
26231
|
+
}, [fetchedInitialReports, data, dashboardFilters, customFiltersLoaded]);
|
|
26232
|
+
(0, import_react2.useEffect)(() => {
|
|
26233
|
+
if (customFiltersLoaded && data && dashboardFilters !== null) {
|
|
26234
|
+
fetchedInitialReports.current = true;
|
|
26235
|
+
fetchReports([], dashboardFilters ?? [], config?.pageSize);
|
|
26236
|
+
}
|
|
26237
|
+
}, [customFiltersLoaded]);
|
|
24358
26238
|
const applyDashboardFilters = (filtersToUpdate) => {
|
|
24359
26239
|
const newFilters = (dashboardFilters ?? []).map((f) => {
|
|
24360
26240
|
const update = filtersToUpdate.find((u) => u.label === f.label);
|
|
@@ -24433,7 +26313,7 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24433
26313
|
});
|
|
24434
26314
|
return internalFilters;
|
|
24435
26315
|
};
|
|
24436
|
-
const
|
|
26316
|
+
const isFilter2 = (f) => {
|
|
24437
26317
|
return f && typeof f === "object" && "filterType" in f && !("id" in f);
|
|
24438
26318
|
};
|
|
24439
26319
|
const isDashboardFilter = (f) => {
|
|
@@ -24441,29 +26321,22 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24441
26321
|
};
|
|
24442
26322
|
const applyFilters = (filters2) => {
|
|
24443
26323
|
const dashboardFilters2 = filters2.filter(isDashboardFilter);
|
|
24444
|
-
const customFilters = filters2.filter(
|
|
26324
|
+
const customFilters = filters2.filter(isFilter2);
|
|
24445
26325
|
const newCustomFilters = applyCustomFilters(customFilters);
|
|
24446
26326
|
const newDashboardFilters = applyDashboardFilters(dashboardFilters2);
|
|
24447
26327
|
fetchReports(newCustomFilters, newDashboardFilters);
|
|
24448
26328
|
};
|
|
24449
|
-
const
|
|
24450
|
-
|
|
24451
|
-
|
|
24452
|
-
while (attempts < maxAttempts) {
|
|
24453
|
-
const filters2 = customFiltersRef.current[reportId];
|
|
24454
|
-
if (filters2 && filters2.length > 0) {
|
|
24455
|
-
return filters2;
|
|
24456
|
-
}
|
|
24457
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
24458
|
-
attempts++;
|
|
24459
|
-
}
|
|
24460
|
-
return [];
|
|
26329
|
+
const forceCacheRefresh = () => {
|
|
26330
|
+
if (!cacheEnabled) return;
|
|
26331
|
+
fetchReports([], dashboardFilters ?? [], config?.pageSize, true);
|
|
24461
26332
|
};
|
|
24462
|
-
const fetchReports = async (customFilters, dashboardFilters2, pageSize) => {
|
|
26333
|
+
const fetchReports = async (customFilters, dashboardFilters2, pageSize, forceCacheToRefresh = false) => {
|
|
24463
26334
|
if (!client || !sections) return;
|
|
24464
26335
|
const allReports = Object.values(sections).flat();
|
|
26336
|
+
const fetchStartTime = Date.now();
|
|
26337
|
+
let totalCached = 0;
|
|
24465
26338
|
await Promise.all(
|
|
24466
|
-
allReports.map(async (reportInfo) => {
|
|
26339
|
+
allReports.map(async (reportInfo, idx) => {
|
|
24467
26340
|
const reportId = reportInfo.id;
|
|
24468
26341
|
const requestId = (reportRequestIds.current[reportId] ?? 0) + 1;
|
|
24469
26342
|
reportRequestIds.current[reportId] = requestId;
|
|
@@ -24472,7 +26345,7 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24472
26345
|
id: reportId,
|
|
24473
26346
|
data: true
|
|
24474
26347
|
});
|
|
24475
|
-
const customReportFiltersArray =
|
|
26348
|
+
const customReportFiltersArray = customReportFilters[reportId] ?? [];
|
|
24476
26349
|
let rowsPerRequest = pageSize || 600;
|
|
24477
26350
|
if (!pageSize && (reportInfo.chartType === "table" || reportInfo.chartType === "metric")) {
|
|
24478
26351
|
rowsPerRequest = 10;
|
|
@@ -24484,17 +26357,138 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24484
26357
|
const additionalProcessing = {
|
|
24485
26358
|
page: pagination
|
|
24486
26359
|
};
|
|
24487
|
-
const usePivotTask = !!reportInfo.pivot;
|
|
26360
|
+
const usePivotTask = !cacheEnabled && !!reportInfo.pivot;
|
|
26361
|
+
const allFilters = dashboardFilters2.concat(customFilters).concat(customReportFiltersArray);
|
|
26362
|
+
if (cacheEnabled && cacheCab.isCacheable(reportId)) {
|
|
26363
|
+
const report2 = await cacheCab.get(reportId, dashboardFilters2, customFilters.concat(customReportFiltersArray), reportInfo.pivot, client, tenants, flags, pageSize, getToken, eventTracking, forceCacheToRefresh);
|
|
26364
|
+
if (reportRequestIds.current[reportId] !== requestId) {
|
|
26365
|
+
return null;
|
|
26366
|
+
}
|
|
26367
|
+
if (cacheCab.isCacheable(reportId)) {
|
|
26368
|
+
reportsDispatch({
|
|
26369
|
+
type: "UPDATE_REPORT",
|
|
26370
|
+
id: reportId,
|
|
26371
|
+
data: {
|
|
26372
|
+
...report2,
|
|
26373
|
+
pagination,
|
|
26374
|
+
triggerReload: false
|
|
26375
|
+
}
|
|
26376
|
+
});
|
|
26377
|
+
reportsLoadingStateDispatch({
|
|
26378
|
+
type: "SET_REPORT_LOADING",
|
|
26379
|
+
id: reportId,
|
|
26380
|
+
data: false
|
|
26381
|
+
});
|
|
26382
|
+
totalCached += 1;
|
|
26383
|
+
return report2;
|
|
26384
|
+
}
|
|
26385
|
+
}
|
|
26386
|
+
if (cacheEnabled && !cacheCab.isCacheable(reportId)) {
|
|
26387
|
+
try {
|
|
26388
|
+
const { report: uncacheableReport, fromCache } = await cacheCab.getOrFetchUncacheableResult(
|
|
26389
|
+
reportId,
|
|
26390
|
+
client,
|
|
26391
|
+
tenants,
|
|
26392
|
+
flags,
|
|
26393
|
+
allFilters,
|
|
26394
|
+
additionalProcessing,
|
|
26395
|
+
reportInfo.pivot,
|
|
26396
|
+
async () => {
|
|
26397
|
+
const { report: report2, error: error2 } = await fetchReport({
|
|
26398
|
+
reportId,
|
|
26399
|
+
client,
|
|
26400
|
+
tenants,
|
|
26401
|
+
flags,
|
|
26402
|
+
additionalProcessing,
|
|
26403
|
+
filters: allFilters,
|
|
26404
|
+
getToken,
|
|
26405
|
+
eventTracking,
|
|
26406
|
+
usePivotTask,
|
|
26407
|
+
overwriteCache: forceCacheToRefresh
|
|
26408
|
+
});
|
|
26409
|
+
if (error2 || !report2) {
|
|
26410
|
+
throw error2 ?? new Error("Failed to fetch uncacheable report");
|
|
26411
|
+
}
|
|
26412
|
+
return report2;
|
|
26413
|
+
},
|
|
26414
|
+
forceCacheToRefresh
|
|
26415
|
+
);
|
|
26416
|
+
if (reportRequestIds.current[reportId] !== requestId) {
|
|
26417
|
+
return null;
|
|
26418
|
+
}
|
|
26419
|
+
reportsDispatch({
|
|
26420
|
+
type: "UPDATE_REPORT",
|
|
26421
|
+
id: reportId,
|
|
26422
|
+
data: {
|
|
26423
|
+
...uncacheableReport,
|
|
26424
|
+
pagination,
|
|
26425
|
+
triggerReload: false
|
|
26426
|
+
}
|
|
26427
|
+
});
|
|
26428
|
+
reportsLoadingStateDispatch({
|
|
26429
|
+
type: "SET_REPORT_LOADING",
|
|
26430
|
+
id: reportId,
|
|
26431
|
+
data: false
|
|
26432
|
+
});
|
|
26433
|
+
if (fromCache) {
|
|
26434
|
+
totalCached += 1;
|
|
26435
|
+
}
|
|
26436
|
+
if (usePivotTask) {
|
|
26437
|
+
fetchReportRows({
|
|
26438
|
+
reportId,
|
|
26439
|
+
client,
|
|
26440
|
+
tenants,
|
|
26441
|
+
filters: allFilters,
|
|
26442
|
+
getToken,
|
|
26443
|
+
additionalProcessing,
|
|
26444
|
+
overwriteCache: forceCacheToRefresh
|
|
26445
|
+
}).then(({ rows, rowCount, columns, fields }) => {
|
|
26446
|
+
if (reportRequestIds.current[reportId] !== requestId) {
|
|
26447
|
+
return;
|
|
26448
|
+
}
|
|
26449
|
+
reportsDispatch({
|
|
26450
|
+
type: "UPDATE_REPORT",
|
|
26451
|
+
id: reportId,
|
|
26452
|
+
data: {
|
|
26453
|
+
rows,
|
|
26454
|
+
rowCount,
|
|
26455
|
+
columnInternal: columns,
|
|
26456
|
+
columns: columns.map((col) => ({
|
|
26457
|
+
field: col.field,
|
|
26458
|
+
format: col.format,
|
|
26459
|
+
label: col.label,
|
|
26460
|
+
inferFormat: col.inferFormat
|
|
26461
|
+
})),
|
|
26462
|
+
// @ts-ignore fields is not typed on QuillReportInternal
|
|
26463
|
+
fields,
|
|
26464
|
+
triggerReload: false
|
|
26465
|
+
}
|
|
26466
|
+
});
|
|
26467
|
+
}).catch((e) => {
|
|
26468
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
26469
|
+
return;
|
|
26470
|
+
}
|
|
26471
|
+
console.error("Failed to fetch background rows", e);
|
|
26472
|
+
});
|
|
26473
|
+
}
|
|
26474
|
+
return uncacheableReport;
|
|
26475
|
+
} catch (error2) {
|
|
26476
|
+
console.error(error2);
|
|
26477
|
+
return null;
|
|
26478
|
+
}
|
|
26479
|
+
}
|
|
24488
26480
|
const { report, error } = await fetchReport({
|
|
24489
26481
|
reportId,
|
|
24490
26482
|
client,
|
|
24491
26483
|
tenants,
|
|
24492
26484
|
flags,
|
|
24493
26485
|
additionalProcessing,
|
|
24494
|
-
filters:
|
|
26486
|
+
filters: allFilters,
|
|
24495
26487
|
getToken,
|
|
24496
26488
|
eventTracking,
|
|
24497
|
-
usePivotTask
|
|
26489
|
+
usePivotTask,
|
|
26490
|
+
overwriteCache: forceCacheToRefresh
|
|
26491
|
+
// usePivotTask: false,
|
|
24498
26492
|
});
|
|
24499
26493
|
if (error) {
|
|
24500
26494
|
console.error(error);
|
|
@@ -24522,9 +26516,10 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24522
26516
|
reportId,
|
|
24523
26517
|
client,
|
|
24524
26518
|
tenants,
|
|
24525
|
-
filters:
|
|
26519
|
+
filters: allFilters,
|
|
24526
26520
|
getToken,
|
|
24527
|
-
additionalProcessing
|
|
26521
|
+
additionalProcessing,
|
|
26522
|
+
overwriteCache: forceCacheToRefresh
|
|
24528
26523
|
}).then(({ rows, rowCount, columns, fields }) => {
|
|
24529
26524
|
if (reportRequestIds.current[reportId] !== requestId) {
|
|
24530
26525
|
return;
|
|
@@ -24548,19 +26543,30 @@ var useDashboard = (dashboardName, config) => {
|
|
|
24548
26543
|
}
|
|
24549
26544
|
});
|
|
24550
26545
|
}).catch((e) => {
|
|
24551
|
-
if (e instanceof Error && e.name === "AbortError")
|
|
26546
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
26547
|
+
return;
|
|
26548
|
+
}
|
|
24552
26549
|
console.error("Failed to fetch background rows", e);
|
|
24553
26550
|
});
|
|
24554
26551
|
}
|
|
24555
26552
|
return report;
|
|
24556
26553
|
})
|
|
24557
26554
|
);
|
|
26555
|
+
if (!loadedDashes.includes(dashboardName) || !cacheEnabled || forceCacheToRefresh) {
|
|
26556
|
+
setLoadedDashes((prev) => prev.includes(dashboardName) ? prev : [...prev, dashboardName]);
|
|
26557
|
+
setLastUpdatedDict((prev) => ({ ...prev, [dashboardName]: Date.now() }));
|
|
26558
|
+
}
|
|
26559
|
+
if (logCacheStatistics) {
|
|
26560
|
+
console.log(`Dashboard "${dashboardName}": Cache Rate: ${(100 * totalCached / allReports.length).toFixed(1)}%, load time: ${((Date.now() - fetchStartTime) / 1e3).toFixed(2)} secs`);
|
|
26561
|
+
}
|
|
24558
26562
|
};
|
|
24559
26563
|
return {
|
|
24560
26564
|
isLoading: !!isLoading || !sections,
|
|
24561
26565
|
sections: isLoading ? null : sections,
|
|
24562
26566
|
filters,
|
|
24563
|
-
applyFilters
|
|
26567
|
+
applyFilters,
|
|
26568
|
+
lastUpdated,
|
|
26569
|
+
forceCacheRefresh
|
|
24564
26570
|
};
|
|
24565
26571
|
};
|
|
24566
26572
|
var useDashboardReportInternal = (reportId, config) => {
|
|
@@ -24584,15 +26590,6 @@ var useDashboardReportInternal = (reportId, config) => {
|
|
|
24584
26590
|
} = useDashboardInternal(reports[reportId]?.dashboardName ?? null);
|
|
24585
26591
|
const [pageLoading, setPageLoading] = (0, import_react2.useState)(false);
|
|
24586
26592
|
const [maxPage, setMaxPage] = (0, import_react2.useState)(0);
|
|
24587
|
-
(0, import_react2.useEffect)(() => {
|
|
24588
|
-
if (config?.initialFilters) {
|
|
24589
|
-
customReportFiltersDispatch({
|
|
24590
|
-
type: "ADD_CUSTOM_REPORT_FILTERS",
|
|
24591
|
-
reportId,
|
|
24592
|
-
data: config.initialFilters.map(convertCustomFilter)
|
|
24593
|
-
});
|
|
24594
|
-
}
|
|
24595
|
-
}, []);
|
|
24596
26593
|
const processedReport = (0, import_react2.useMemo)(() => {
|
|
24597
26594
|
if (!reports[reportId]) return null;
|
|
24598
26595
|
const dashboardName = reports[reportId].dashboardName;
|
|
@@ -24797,6 +26794,7 @@ var useDashboardReportInternal = (reportId, config) => {
|
|
|
24797
26794
|
};
|
|
24798
26795
|
var useDashboardReport = (reportId, config) => {
|
|
24799
26796
|
const { report, loading, applyFilters, deleteReport, nextPage } = useDashboardReportInternal(reportId, config);
|
|
26797
|
+
const { customReportFiltersDispatch } = (0, import_react2.useContext)(ReportFiltersContext);
|
|
24800
26798
|
const fetchingRef = (0, import_react2.useRef)(false);
|
|
24801
26799
|
const fetchNextPage = async () => {
|
|
24802
26800
|
if (fetchingRef.current) {
|
|
@@ -24811,6 +26809,15 @@ var useDashboardReport = (reportId, config) => {
|
|
|
24811
26809
|
fetchingRef.current = false;
|
|
24812
26810
|
}
|
|
24813
26811
|
};
|
|
26812
|
+
(0, import_react2.useEffect)(() => {
|
|
26813
|
+
if (config?.initialFilters) {
|
|
26814
|
+
customReportFiltersDispatch({
|
|
26815
|
+
type: "ADD_CUSTOM_REPORT_FILTERS",
|
|
26816
|
+
reportId,
|
|
26817
|
+
data: config.initialFilters.map(convertCustomFilter)
|
|
26818
|
+
});
|
|
26819
|
+
}
|
|
26820
|
+
}, []);
|
|
24814
26821
|
return {
|
|
24815
26822
|
report,
|
|
24816
26823
|
isLoading: loading || fetchingRef.current,
|
|
@@ -25275,7 +27282,7 @@ function QuillCustomDocumentComponent({
|
|
|
25275
27282
|
}
|
|
25276
27283
|
|
|
25277
27284
|
// src/Chart.tsx
|
|
25278
|
-
var
|
|
27285
|
+
var import_date_fns14 = require("date-fns");
|
|
25279
27286
|
|
|
25280
27287
|
// src/components/Chart/BarList.tsx
|
|
25281
27288
|
var import_react4 = __toESM(require("react"), 1);
|
|
@@ -27964,19 +29971,23 @@ var RenderLegend = ({
|
|
|
27964
29971
|
const seeAllMeasureRef = (0, import_react12.useRef)(null);
|
|
27965
29972
|
const seeAllTriggerRef = (0, import_react12.useRef)(null);
|
|
27966
29973
|
const itemRefs = (0, import_react12.useRef)([]);
|
|
27967
|
-
|
|
27968
|
-
const maxItems = limit ??
|
|
29974
|
+
const safePayload = payload ?? [];
|
|
29975
|
+
const maxItems = limit ?? safePayload.length;
|
|
27969
29976
|
const measuredLimit = visibleCount ?? maxItems;
|
|
27970
|
-
const visiblePayload =
|
|
29977
|
+
const visiblePayload = safePayload.slice(0, Math.min(maxItems, measuredLimit));
|
|
27971
29978
|
const handleOpen = () => setIsOpen(true);
|
|
27972
29979
|
const handleClose = () => setIsOpen(false);
|
|
27973
29980
|
(0, import_react12.useLayoutEffect)(() => {
|
|
27974
29981
|
if (!containerRef.current) return;
|
|
27975
|
-
if (!
|
|
29982
|
+
if (!safePayload.length) {
|
|
29983
|
+
setShowSeeAll(false);
|
|
29984
|
+
setVisibleCount(null);
|
|
29985
|
+
return;
|
|
29986
|
+
}
|
|
27976
29987
|
const updateVisibleCount = () => {
|
|
27977
29988
|
const containerWidth = containerRef.current?.offsetWidth ?? 0;
|
|
27978
29989
|
if (!containerWidth) return;
|
|
27979
|
-
const maxCount = Math.min(maxItems,
|
|
29990
|
+
const maxCount = Math.min(maxItems, safePayload.length);
|
|
27980
29991
|
const seeAllWidth = getOuterWidth(seeAllMeasureRef.current);
|
|
27981
29992
|
const computeCount = (reserveSeeAll) => {
|
|
27982
29993
|
const availableWidth = containerWidth - (reserveSeeAll ? seeAllWidth : 0);
|
|
@@ -27992,7 +30003,7 @@ var RenderLegend = ({
|
|
|
27992
30003
|
return Math.max(1, nextCount);
|
|
27993
30004
|
};
|
|
27994
30005
|
const countWithSeeAll = computeCount(true);
|
|
27995
|
-
const shouldShowSeeAll =
|
|
30006
|
+
const shouldShowSeeAll = safePayload.length > countWithSeeAll;
|
|
27996
30007
|
const finalCount = shouldShowSeeAll ? countWithSeeAll : computeCount(false);
|
|
27997
30008
|
setShowSeeAll(shouldShowSeeAll);
|
|
27998
30009
|
setVisibleCount(finalCount);
|
|
@@ -28001,7 +30012,8 @@ var RenderLegend = ({
|
|
|
28001
30012
|
const observer = new ResizeObserver(updateVisibleCount);
|
|
28002
30013
|
observer.observe(containerRef.current);
|
|
28003
30014
|
return () => observer.disconnect();
|
|
28004
|
-
}, [
|
|
30015
|
+
}, [safePayload.length, maxItems]);
|
|
30016
|
+
if (!safePayload.length) return null;
|
|
28005
30017
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
28006
30018
|
"div",
|
|
28007
30019
|
{
|
|
@@ -28041,7 +30053,7 @@ var RenderLegend = ({
|
|
|
28041
30053
|
justifyContent: "flex-start",
|
|
28042
30054
|
flexWrap: "nowrap"
|
|
28043
30055
|
},
|
|
28044
|
-
children:
|
|
30056
|
+
children: safePayload.slice(0, maxItems).map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
28045
30057
|
"div",
|
|
28046
30058
|
{
|
|
28047
30059
|
ref: (element) => {
|
|
@@ -28130,7 +30142,7 @@ var RenderLegend = ({
|
|
|
28130
30142
|
maxWidth: 520,
|
|
28131
30143
|
gap: "0.5rem"
|
|
28132
30144
|
},
|
|
28133
|
-
children:
|
|
30145
|
+
children: safePayload.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
28134
30146
|
LegendItem,
|
|
28135
30147
|
{
|
|
28136
30148
|
entry,
|
|
@@ -28480,8 +30492,8 @@ var PieChartWrapper = import_react13.default.forwardRef(
|
|
|
28480
30492
|
cy: "50%",
|
|
28481
30493
|
startAngle: 90,
|
|
28482
30494
|
endAngle: -270,
|
|
28483
|
-
innerRadius: isDonut ?
|
|
28484
|
-
outerRadius:
|
|
30495
|
+
innerRadius: isDonut ? "70%" : "0%",
|
|
30496
|
+
outerRadius: "100%",
|
|
28485
30497
|
paddingAngle: 0,
|
|
28486
30498
|
dataKey: category,
|
|
28487
30499
|
nameKey: index,
|
|
@@ -29074,8 +31086,8 @@ var import_recharts2 = require("recharts");
|
|
|
29074
31086
|
init_valueFormatter();
|
|
29075
31087
|
|
|
29076
31088
|
// src/utils/axisFormatter.ts
|
|
29077
|
-
var
|
|
29078
|
-
var
|
|
31089
|
+
var import_date_fns11 = require("date-fns");
|
|
31090
|
+
var import_date_fns_tz4 = require("date-fns-tz");
|
|
29079
31091
|
var axisFormatter = ({ value, field, fields }) => {
|
|
29080
31092
|
if (field === void 0 || field === null) return "";
|
|
29081
31093
|
if (value === void 0 || value === null) return "";
|
|
@@ -29191,9 +31203,9 @@ var formatPercent2 = (value) => {
|
|
|
29191
31203
|
return formatter.format(Number(value));
|
|
29192
31204
|
};
|
|
29193
31205
|
var _getUTCDateHelper2 = (value, fmt) => {
|
|
29194
|
-
const utcDate = (0,
|
|
29195
|
-
if (!(0,
|
|
29196
|
-
return (0,
|
|
31206
|
+
const utcDate = (0, import_date_fns_tz4.utcToZonedTime)(new Date(value), "UTC");
|
|
31207
|
+
if (!(0, import_date_fns11.isValid)(utcDate)) return "Invalid date";
|
|
31208
|
+
return (0, import_date_fns11.format)(utcDate, fmt);
|
|
29197
31209
|
};
|
|
29198
31210
|
var format_YYYY2 = (value) => _getUTCDateHelper2(value, "yyyy");
|
|
29199
31211
|
var format_MMM_dd = (value) => _getUTCDateHelper2(value, "dd MMM");
|
|
@@ -29201,31 +31213,31 @@ var format_MMM_yyyy2 = (value) => _getUTCDateHelper2(value, "MMM yyyy");
|
|
|
29201
31213
|
var format_hh_ap_pm2 = (value) => _getUTCDateHelper2(value, "hh:mm aa");
|
|
29202
31214
|
var format_MMM_dd_yyyy2 = (value) => _getUTCDateHelper2(value, "dd MMM yyyy");
|
|
29203
31215
|
var format_MMM_dd_MMM_dd = (value) => {
|
|
29204
|
-
const utcDate = (0,
|
|
29205
|
-
if (!(0,
|
|
29206
|
-
const monday = (0,
|
|
29207
|
-
const sunday = (0,
|
|
29208
|
-
if ((0,
|
|
29209
|
-
return `${(0,
|
|
31216
|
+
const utcDate = (0, import_date_fns_tz4.utcToZonedTime)(new Date(value), "UTC");
|
|
31217
|
+
if (!(0, import_date_fns11.isValid)(utcDate)) return "Invalid date";
|
|
31218
|
+
const monday = (0, import_date_fns11.startOfWeek)(utcDate, { weekStartsOn: 1 });
|
|
31219
|
+
const sunday = (0, import_date_fns11.endOfWeek)(utcDate, { weekStartsOn: 1 });
|
|
31220
|
+
if ((0, import_date_fns11.format)(monday, "MMM") === (0, import_date_fns11.format)(sunday, "MMM")) {
|
|
31221
|
+
return `${(0, import_date_fns11.format)(monday, "MMM dd")} - ${(0, import_date_fns11.format)(sunday, "dd")}`;
|
|
29210
31222
|
} else {
|
|
29211
|
-
return `${(0,
|
|
31223
|
+
return `${(0, import_date_fns11.format)(monday, "MMM dd")} - ${(0, import_date_fns11.format)(sunday, "MMM dd")}`;
|
|
29212
31224
|
}
|
|
29213
31225
|
};
|
|
29214
31226
|
var format_MMM_dd_hh_mm_ap_pm2 = (value) => {
|
|
29215
|
-
const utcDate = (0,
|
|
29216
|
-
if (!(0,
|
|
31227
|
+
const utcDate = (0, import_date_fns_tz4.utcToZonedTime)(new Date(value), "UTC");
|
|
31228
|
+
if (!(0, import_date_fns11.isValid)(utcDate)) return "Invalid date";
|
|
29217
31229
|
const formatStr = utcDate.getMinutes() === 0 ? "MMM do h a" : "MMM do h:mm a";
|
|
29218
|
-
const res = (0,
|
|
31230
|
+
const res = (0, import_date_fns11.format)(utcDate, formatStr);
|
|
29219
31231
|
return res.slice(0, -2) + res.slice(-2).toLowerCase();
|
|
29220
31232
|
};
|
|
29221
31233
|
var format_wo_yyyy2 = (value) => {
|
|
29222
|
-
const utcDate = (0,
|
|
29223
|
-
if (!(0,
|
|
29224
|
-
return `${(0,
|
|
31234
|
+
const utcDate = (0, import_date_fns_tz4.utcToZonedTime)(new Date(value), "UTC");
|
|
31235
|
+
if (!(0, import_date_fns11.isValid)(utcDate)) return "Invalid date";
|
|
31236
|
+
return `${(0, import_date_fns11.getWeek)(utcDate)},${utcDate.getFullYear()}`;
|
|
29225
31237
|
};
|
|
29226
31238
|
|
|
29227
31239
|
// src/components/Chart/ChartTooltip.tsx
|
|
29228
|
-
var
|
|
31240
|
+
var import_date_fns12 = require("date-fns");
|
|
29229
31241
|
|
|
29230
31242
|
// src/components/Chart/ChartTooltipFrame.tsx
|
|
29231
31243
|
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
@@ -29420,7 +31432,7 @@ var ChartTooltipPrimary = (props) => /* @__PURE__ */ (0, import_jsx_runtime33.js
|
|
|
29420
31432
|
paddingTop: 2,
|
|
29421
31433
|
paddingBottom: 2
|
|
29422
31434
|
},
|
|
29423
|
-
children: !isNaN(new Date(props.label)) && props.dateFormatter ? props.dateFormatter(props.label) : !isNaN(new Date(props.label)) ? (0,
|
|
31435
|
+
children: !isNaN(new Date(props.label)) && props.dateFormatter ? props.dateFormatter(props.label) : !isNaN(new Date(props.label)) ? (0, import_date_fns12.format)(new Date(props.label), "MMM yyyy") : props.label
|
|
29424
31436
|
}
|
|
29425
31437
|
)
|
|
29426
31438
|
}
|
|
@@ -29469,8 +31481,8 @@ function reformatComparisonPayload(props, primaryLabel, comparisonLabel) {
|
|
|
29469
31481
|
const nameKey = isComparison ? `comparison_${props.xAxisField}` : props.xAxisField;
|
|
29470
31482
|
const days = LABEL_TO_DAYS[primaryLabel] ?? 0;
|
|
29471
31483
|
const primaryDate = item.payload[props.xAxisField] ?? 0;
|
|
29472
|
-
const compDate = (0,
|
|
29473
|
-
const date = item.payload[nameKey] ?? (0,
|
|
31484
|
+
const compDate = (0, import_date_fns12.subDays)(new Date(primaryDate), days + 1);
|
|
31485
|
+
const date = item.payload[nameKey] ?? (0, import_date_fns12.format)(compDate, props.xAxisFormat);
|
|
29474
31486
|
const name2 = props.dateFormatter(date);
|
|
29475
31487
|
const color2 = item.color;
|
|
29476
31488
|
const value = props.valueFormatter(item.value, item.name);
|
|
@@ -29503,7 +31515,7 @@ function reformatComparisonPayload(props, primaryLabel, comparisonLabel) {
|
|
|
29503
31515
|
return columnsByKey;
|
|
29504
31516
|
}
|
|
29505
31517
|
function getTooltipLabel(props, altTooltipLabel, isDateXAxis) {
|
|
29506
|
-
return props.payload.length <= 2 && altTooltipLabel && isDateXAxis ? !isNaN(new Date(altTooltipLabel)) && props.dateFormatter ? props.dateFormatter(altTooltipLabel) : !isNaN(new Date(altTooltipLabel)) ? (0,
|
|
31518
|
+
return props.payload.length <= 2 && altTooltipLabel && isDateXAxis ? !isNaN(new Date(altTooltipLabel)) && props.dateFormatter ? props.dateFormatter(altTooltipLabel) : !isNaN(new Date(altTooltipLabel)) ? (0, import_date_fns12.format)(new Date(altTooltipLabel), "MMM yyyy") : altTooltipLabel : !isNaN(new Date(props.label)) && props.dateFormatter ? props.dateFormatter(props.label) : !isNaN(new Date(props.label)) ? (0, import_date_fns12.format)(new Date(props.label), "MMM yyyy") : props.label;
|
|
29507
31519
|
}
|
|
29508
31520
|
function ChartTooltipComparison(props) {
|
|
29509
31521
|
const isDateXAxis = isDateFormat(props.xAxisFormat);
|
|
@@ -30519,7 +32531,7 @@ init_dateRangePickerUtils();
|
|
|
30519
32531
|
|
|
30520
32532
|
// src/DateRangePicker/QuillDateRangePicker.tsx
|
|
30521
32533
|
var import_react20 = require("react");
|
|
30522
|
-
var
|
|
32534
|
+
var import_date_fns13 = require("date-fns");
|
|
30523
32535
|
|
|
30524
32536
|
// src/components/QuillSelect.tsx
|
|
30525
32537
|
var import_react19 = require("react");
|
|
@@ -30965,9 +32977,9 @@ function QuillDateRangePicker({
|
|
|
30965
32977
|
]
|
|
30966
32978
|
}
|
|
30967
32979
|
),
|
|
30968
|
-
localStartDate && (0,
|
|
32980
|
+
localStartDate && (0, import_date_fns13.format)(localStartDate, "MMM dd, yyyy"),
|
|
30969
32981
|
localStartDate ? " - " : "Pick a date",
|
|
30970
|
-
localEndDate && (0,
|
|
32982
|
+
localEndDate && (0, import_date_fns13.format)(localEndDate, "MMM dd, yyyy")
|
|
30971
32983
|
]
|
|
30972
32984
|
}
|
|
30973
32985
|
),
|
|
@@ -31034,21 +33046,21 @@ function CalendarRow({
|
|
|
31034
33046
|
updateDateFilter,
|
|
31035
33047
|
setLocalPreset
|
|
31036
33048
|
}) {
|
|
31037
|
-
const firstMonthDisplayedDates = (0,
|
|
31038
|
-
start: (0,
|
|
31039
|
-
end: (0,
|
|
33049
|
+
const firstMonthDisplayedDates = (0, import_date_fns13.eachDayOfInterval)({
|
|
33050
|
+
start: (0, import_date_fns13.startOfWeek)(anchorStartDate),
|
|
33051
|
+
end: (0, import_date_fns13.endOfWeek)((0, import_date_fns13.endOfMonth)(anchorStartDate))
|
|
31040
33052
|
});
|
|
31041
|
-
const secondMonthDisplayedDates = (0,
|
|
31042
|
-
start: (0,
|
|
31043
|
-
end: (0,
|
|
33053
|
+
const secondMonthDisplayedDates = (0, import_date_fns13.eachDayOfInterval)({
|
|
33054
|
+
start: (0, import_date_fns13.startOfWeek)((0, import_date_fns13.startOfMonth)(anchorEndDate)),
|
|
33055
|
+
end: (0, import_date_fns13.endOfWeek)(anchorEndDate)
|
|
31044
33056
|
});
|
|
31045
33057
|
const incrementAnchorDates = () => {
|
|
31046
|
-
setAnchorStartDate((0,
|
|
31047
|
-
setAnchorEndDate((0,
|
|
33058
|
+
setAnchorStartDate((0, import_date_fns13.startOfMonth)((0, import_date_fns13.addMonths)(anchorStartDate, 1)));
|
|
33059
|
+
setAnchorEndDate((0, import_date_fns13.endOfMonth)((0, import_date_fns13.addMonths)(anchorEndDate, 1)));
|
|
31048
33060
|
};
|
|
31049
33061
|
const decrementAnchorDates = () => {
|
|
31050
|
-
setAnchorStartDate((0,
|
|
31051
|
-
setAnchorEndDate((0,
|
|
33062
|
+
setAnchorStartDate((0, import_date_fns13.startOfMonth)((0, import_date_fns13.subMonths)(anchorStartDate, 1)));
|
|
33063
|
+
setAnchorEndDate((0, import_date_fns13.endOfMonth)((0, import_date_fns13.subMonths)(anchorEndDate, 1)));
|
|
31052
33064
|
};
|
|
31053
33065
|
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { style: { position: "absolute", zIndex: 100, marginTop: 12 }, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
31054
33066
|
"div",
|
|
@@ -31144,7 +33156,7 @@ function CalendarRow({
|
|
|
31144
33156
|
color: theme.primaryTextColor,
|
|
31145
33157
|
fontWeight: 600
|
|
31146
33158
|
},
|
|
31147
|
-
children: (0,
|
|
33159
|
+
children: (0, import_date_fns13.format)(anchorStartDate, "MMM yyyy")
|
|
31148
33160
|
}
|
|
31149
33161
|
)
|
|
31150
33162
|
]
|
|
@@ -31208,7 +33220,7 @@ function CalendarRow({
|
|
|
31208
33220
|
color: theme.primaryTextColor,
|
|
31209
33221
|
fontWeight: 600
|
|
31210
33222
|
},
|
|
31211
|
-
children: (0,
|
|
33223
|
+
children: (0, import_date_fns13.format)(anchorEndDate, "MMM yyyy")
|
|
31212
33224
|
}
|
|
31213
33225
|
),
|
|
31214
33226
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
@@ -31302,11 +33314,11 @@ function DayPicker({
|
|
|
31302
33314
|
setLocalPreset,
|
|
31303
33315
|
theme
|
|
31304
33316
|
}) {
|
|
31305
|
-
const isStartDate = (0,
|
|
31306
|
-
const isEndDate = (0,
|
|
31307
|
-
const isBetweenStartAndEnd = (0,
|
|
31308
|
-
const isBeginningOfWeek = (0,
|
|
31309
|
-
const isEndOfWeek = (0,
|
|
33317
|
+
const isStartDate = (0, import_date_fns13.differenceInDays)((0, import_date_fns13.startOfDay)(date), (0, import_date_fns13.startOfDay)(localStartDate || 0)) === 0;
|
|
33318
|
+
const isEndDate = (0, import_date_fns13.differenceInDays)((0, import_date_fns13.startOfDay)(date), (0, import_date_fns13.startOfDay)(localEndDate || 0)) === 0;
|
|
33319
|
+
const isBetweenStartAndEnd = (0, import_date_fns13.isBefore)(date, localEndDate || 0) && (0, import_date_fns13.isAfter)(date, localStartDate || 0);
|
|
33320
|
+
const isBeginningOfWeek = (0, import_date_fns13.differenceInDays)((0, import_date_fns13.startOfWeek)(date), date) === 0;
|
|
33321
|
+
const isEndOfWeek = (0, import_date_fns13.differenceInDays)((0, import_date_fns13.endOfWeek)(date), date) === 0;
|
|
31310
33322
|
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
31311
33323
|
"button",
|
|
31312
33324
|
{
|
|
@@ -31338,7 +33350,7 @@ function DayPicker({
|
|
|
31338
33350
|
});
|
|
31339
33351
|
setLocalPreset("");
|
|
31340
33352
|
}
|
|
31341
|
-
if (localStartDate && localEndDate && (0,
|
|
33353
|
+
if (localStartDate && localEndDate && (0, import_date_fns13.isAfter)(date, localStartDate)) {
|
|
31342
33354
|
setLocalEndDate(date);
|
|
31343
33355
|
updateDateFilter({
|
|
31344
33356
|
startDate: localStartDate,
|
|
@@ -31346,7 +33358,7 @@ function DayPicker({
|
|
|
31346
33358
|
});
|
|
31347
33359
|
setLocalPreset("");
|
|
31348
33360
|
}
|
|
31349
|
-
if (localStartDate && localEndDate && (0,
|
|
33361
|
+
if (localStartDate && localEndDate && (0, import_date_fns13.isBefore)(date, localStartDate)) {
|
|
31350
33362
|
setLocalStartDate(date);
|
|
31351
33363
|
updateDateFilter({
|
|
31352
33364
|
startDate: date,
|
|
@@ -31354,42 +33366,42 @@ function DayPicker({
|
|
|
31354
33366
|
});
|
|
31355
33367
|
setLocalPreset("");
|
|
31356
33368
|
}
|
|
31357
|
-
if (localStartDate && localEndDate && (0,
|
|
33369
|
+
if (localStartDate && localEndDate && (0, import_date_fns13.differenceInDays)((0, import_date_fns13.startOfDay)(date), (0, import_date_fns13.startOfDay)(localStartDate)) === 0) {
|
|
31358
33370
|
setLocalStartDate(void 0);
|
|
31359
33371
|
setLocalEndDate(void 0);
|
|
31360
33372
|
}
|
|
31361
33373
|
},
|
|
31362
|
-
children: (0,
|
|
33374
|
+
children: (0, import_date_fns13.format)(date, "d")
|
|
31363
33375
|
}
|
|
31364
33376
|
);
|
|
31365
33377
|
}
|
|
31366
33378
|
function getAnchorStartDate(startDate, endDate) {
|
|
31367
33379
|
if (!startDate && !endDate) {
|
|
31368
|
-
return (0,
|
|
33380
|
+
return (0, import_date_fns13.startOfMonth)((0, import_date_fns13.subMonths)(/* @__PURE__ */ new Date(), 1));
|
|
31369
33381
|
}
|
|
31370
33382
|
if (startDate && !endDate) {
|
|
31371
|
-
return (0,
|
|
33383
|
+
return (0, import_date_fns13.startOfMonth)(startDate);
|
|
31372
33384
|
}
|
|
31373
33385
|
if (!startDate && endDate) {
|
|
31374
|
-
return (0,
|
|
33386
|
+
return (0, import_date_fns13.startOfMonth)((0, import_date_fns13.subMonths)(endDate, 1));
|
|
31375
33387
|
}
|
|
31376
33388
|
if (startDate && endDate) {
|
|
31377
|
-
return (0,
|
|
33389
|
+
return (0, import_date_fns13.startOfMonth)(startDate);
|
|
31378
33390
|
}
|
|
31379
33391
|
return /* @__PURE__ */ new Date();
|
|
31380
33392
|
}
|
|
31381
33393
|
function getAnchorEndDate(startDate, endDate) {
|
|
31382
33394
|
if (!startDate && !endDate) {
|
|
31383
|
-
return (0,
|
|
33395
|
+
return (0, import_date_fns13.endOfMonth)(/* @__PURE__ */ new Date());
|
|
31384
33396
|
}
|
|
31385
33397
|
if (startDate && !endDate) {
|
|
31386
|
-
return (0,
|
|
33398
|
+
return (0, import_date_fns13.endOfMonth)((0, import_date_fns13.addMonths)(startDate, 1));
|
|
31387
33399
|
}
|
|
31388
33400
|
if (!startDate && endDate) {
|
|
31389
|
-
return (0,
|
|
33401
|
+
return (0, import_date_fns13.endOfMonth)(endDate);
|
|
31390
33402
|
}
|
|
31391
33403
|
if (startDate && endDate) {
|
|
31392
|
-
return (0,
|
|
33404
|
+
return (0, import_date_fns13.endOfMonth)((0, import_date_fns13.addMonths)(startDate, 1));
|
|
31393
33405
|
}
|
|
31394
33406
|
return /* @__PURE__ */ new Date();
|
|
31395
33407
|
}
|
|
@@ -32573,6 +34585,164 @@ function DashboardFilter2({
|
|
|
32573
34585
|
// src/Chart.tsx
|
|
32574
34586
|
init_paginationProcessing();
|
|
32575
34587
|
|
|
34588
|
+
// src/utils/cloudCacheValidation.ts
|
|
34589
|
+
var LIMIT_CLAUSE_REGEX = /^limit\b\s+(?:all|\d+|\$\d+|:[a-zA-Z_][a-zA-Z0-9_]*|\?)/i;
|
|
34590
|
+
var SQL_CONTENT_TO_IGNORE_REGEX = /'(?:''|[^'])*'|"(?:[^"]|"")*"|`[^`]*`|\[[^\]]*\]|--[^\n]*|\/\*[\s\S]*?\*\//g;
|
|
34591
|
+
function isWordChar(char) {
|
|
34592
|
+
if (!char) {
|
|
34593
|
+
return false;
|
|
34594
|
+
}
|
|
34595
|
+
return /[A-Za-z0-9_]/.test(char);
|
|
34596
|
+
}
|
|
34597
|
+
function getFinalSqlStatement(query) {
|
|
34598
|
+
const statements = query.split(";").map((statement) => statement.trim()).filter((statement) => statement.length > 0);
|
|
34599
|
+
return statements[statements.length - 1] ?? "";
|
|
34600
|
+
}
|
|
34601
|
+
function hasTopLevelLimitClause(statement) {
|
|
34602
|
+
let depth = 0;
|
|
34603
|
+
for (let i = 0; i < statement.length; i += 1) {
|
|
34604
|
+
const char = statement[i];
|
|
34605
|
+
if (char === "(") {
|
|
34606
|
+
depth += 1;
|
|
34607
|
+
continue;
|
|
34608
|
+
}
|
|
34609
|
+
if (char === ")") {
|
|
34610
|
+
depth = Math.max(0, depth - 1);
|
|
34611
|
+
continue;
|
|
34612
|
+
}
|
|
34613
|
+
if (depth !== 0) {
|
|
34614
|
+
continue;
|
|
34615
|
+
}
|
|
34616
|
+
const previousChar = i > 0 ? statement[i - 1] : void 0;
|
|
34617
|
+
if (isWordChar(previousChar)) {
|
|
34618
|
+
continue;
|
|
34619
|
+
}
|
|
34620
|
+
if (!LIMIT_CLAUSE_REGEX.test(statement.slice(i))) {
|
|
34621
|
+
continue;
|
|
34622
|
+
}
|
|
34623
|
+
return true;
|
|
34624
|
+
}
|
|
34625
|
+
return false;
|
|
34626
|
+
}
|
|
34627
|
+
function unwrapIdentifier(identifier) {
|
|
34628
|
+
if (!identifier) {
|
|
34629
|
+
return "";
|
|
34630
|
+
}
|
|
34631
|
+
const trimmed = identifier.trim();
|
|
34632
|
+
if (trimmed.length < 2) {
|
|
34633
|
+
return trimmed;
|
|
34634
|
+
}
|
|
34635
|
+
const startsAndEndsWithDoubleQuote = trimmed.startsWith('"') && trimmed.endsWith('"');
|
|
34636
|
+
const startsAndEndsWithSingleQuote = trimmed.startsWith("'") && trimmed.endsWith("'");
|
|
34637
|
+
const startsAndEndsWithBackticks = trimmed.startsWith("`") && trimmed.endsWith("`");
|
|
34638
|
+
const startsAndEndsWithBrackets = trimmed.startsWith("[") && trimmed.endsWith("]");
|
|
34639
|
+
if (startsAndEndsWithDoubleQuote || startsAndEndsWithSingleQuote || startsAndEndsWithBackticks || startsAndEndsWithBrackets) {
|
|
34640
|
+
return trimmed.slice(1, -1);
|
|
34641
|
+
}
|
|
34642
|
+
return trimmed;
|
|
34643
|
+
}
|
|
34644
|
+
function normalizeIdentifier(identifier) {
|
|
34645
|
+
return unwrapIdentifier(identifier).toLowerCase();
|
|
34646
|
+
}
|
|
34647
|
+
function hasRowFieldWithIdentifier(row, normalizedField) {
|
|
34648
|
+
if (!row || !normalizedField) {
|
|
34649
|
+
return false;
|
|
34650
|
+
}
|
|
34651
|
+
return Object.keys(row).some(
|
|
34652
|
+
(fieldName) => normalizeIdentifier(fieldName) === normalizedField
|
|
34653
|
+
);
|
|
34654
|
+
}
|
|
34655
|
+
function reportReferencesField(report, field, table) {
|
|
34656
|
+
const normalizedField = normalizeIdentifier(field);
|
|
34657
|
+
if (!normalizedField) {
|
|
34658
|
+
return false;
|
|
34659
|
+
}
|
|
34660
|
+
const referencedColumns = report?.referencedColumns ?? {};
|
|
34661
|
+
let entries = Object.entries(referencedColumns);
|
|
34662
|
+
if (entries.length === 0) {
|
|
34663
|
+
return false;
|
|
34664
|
+
}
|
|
34665
|
+
const normalizedTable = normalizeIdentifier(table);
|
|
34666
|
+
if (normalizedTable) {
|
|
34667
|
+
entries = entries.filter(
|
|
34668
|
+
([tableName]) => normalizeIdentifier(tableName) === normalizedTable
|
|
34669
|
+
);
|
|
34670
|
+
}
|
|
34671
|
+
const referencedFields = entries.flatMap(([, fields]) => fields ?? []);
|
|
34672
|
+
if (referencedFields.length === 0) {
|
|
34673
|
+
return false;
|
|
34674
|
+
}
|
|
34675
|
+
return referencedFields.some((referencedField) => {
|
|
34676
|
+
const normalizedReferencedField = normalizeIdentifier(referencedField);
|
|
34677
|
+
return normalizedReferencedField === normalizedField || normalizedReferencedField === "*";
|
|
34678
|
+
});
|
|
34679
|
+
}
|
|
34680
|
+
function isDateFieldMissingInReport(report) {
|
|
34681
|
+
if (!report?.dateField?.field || !report.dateField.table) {
|
|
34682
|
+
return false;
|
|
34683
|
+
}
|
|
34684
|
+
const dateField = report.dateField;
|
|
34685
|
+
if (!reportReferencesField(report, dateField.field, dateField.table)) {
|
|
34686
|
+
return true;
|
|
34687
|
+
}
|
|
34688
|
+
const firstRow = report.rows?.[0];
|
|
34689
|
+
if (!firstRow) {
|
|
34690
|
+
return false;
|
|
34691
|
+
}
|
|
34692
|
+
const normalizedDateField = normalizeIdentifier(dateField.field);
|
|
34693
|
+
const dateFieldExistsInFirstRow = hasRowFieldWithIdentifier(
|
|
34694
|
+
firstRow,
|
|
34695
|
+
normalizedDateField
|
|
34696
|
+
);
|
|
34697
|
+
return !dateFieldExistsInFirstRow;
|
|
34698
|
+
}
|
|
34699
|
+
function hasLimitClause(query) {
|
|
34700
|
+
if (!query) {
|
|
34701
|
+
return false;
|
|
34702
|
+
}
|
|
34703
|
+
const sanitizedQuery = query.replace(SQL_CONTENT_TO_IGNORE_REGEX, " ");
|
|
34704
|
+
const finalStatement = getFinalSqlStatement(sanitizedQuery);
|
|
34705
|
+
if (!finalStatement) {
|
|
34706
|
+
return false;
|
|
34707
|
+
}
|
|
34708
|
+
return hasTopLevelLimitClause(finalStatement);
|
|
34709
|
+
}
|
|
34710
|
+
function reportUsesLimitClause(report) {
|
|
34711
|
+
const queriesToInspect = report?.itemQuery && report.itemQuery.length > 0 ? report.itemQuery : report?.queryString ? [report.queryString] : [];
|
|
34712
|
+
return queriesToInspect.some(hasLimitClause);
|
|
34713
|
+
}
|
|
34714
|
+
function getMissingDashboardFilterFields({
|
|
34715
|
+
rows = [],
|
|
34716
|
+
dashboardFilters = []
|
|
34717
|
+
}) {
|
|
34718
|
+
const dateIndex = dashboardFilters.findIndex(
|
|
34719
|
+
(filter) => filter.filterType === "date_range"
|
|
34720
|
+
);
|
|
34721
|
+
const requiredFields = dashboardFilters.flatMap((filter, index) => {
|
|
34722
|
+
if (index === dateIndex || !filter.field) {
|
|
34723
|
+
return [];
|
|
34724
|
+
}
|
|
34725
|
+
const normalizedField = normalizeIdentifier(filter.field);
|
|
34726
|
+
if (!normalizedField) {
|
|
34727
|
+
return [];
|
|
34728
|
+
}
|
|
34729
|
+
return [
|
|
34730
|
+
{
|
|
34731
|
+
displayField: unwrapIdentifier(filter.field),
|
|
34732
|
+
normalizedField
|
|
34733
|
+
}
|
|
34734
|
+
];
|
|
34735
|
+
});
|
|
34736
|
+
const dedupedRequiredFields = requiredFields.filter(
|
|
34737
|
+
(field, index, fields) => fields.findIndex(
|
|
34738
|
+
(candidate) => candidate.normalizedField === field.normalizedField
|
|
34739
|
+
) === index
|
|
34740
|
+
);
|
|
34741
|
+
return dedupedRequiredFields.filter(
|
|
34742
|
+
({ normalizedField }) => rows.some((row) => !hasRowFieldWithIdentifier(row, normalizedField))
|
|
34743
|
+
).map(({ displayField }) => displayField);
|
|
34744
|
+
}
|
|
34745
|
+
|
|
32576
34746
|
// src/components/Dashboard/MetricComponent.tsx
|
|
32577
34747
|
var import_react24 = require("react");
|
|
32578
34748
|
init_dateRangePickerUtils();
|
|
@@ -32680,7 +34850,7 @@ function QuillMetricComponent({
|
|
|
32680
34850
|
width: "100%"
|
|
32681
34851
|
}
|
|
32682
34852
|
}
|
|
32683
|
-
) : !report?.rows || report?.rows?.length === 0
|
|
34853
|
+
) : !report?.rows || report?.rows?.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
32684
34854
|
"div",
|
|
32685
34855
|
{
|
|
32686
34856
|
style: {
|
|
@@ -36194,6 +38364,7 @@ function QuillTableDashboardComponent({
|
|
|
36194
38364
|
}
|
|
36195
38365
|
|
|
36196
38366
|
// src/Chart.tsx
|
|
38367
|
+
init_valueFormatter();
|
|
36197
38368
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
36198
38369
|
var MAX_ROWS_FOR_GENERIC_TABLE = 500;
|
|
36199
38370
|
function sumByKey(arr, key) {
|
|
@@ -36230,7 +38401,8 @@ function Chart({
|
|
|
36230
38401
|
filters,
|
|
36231
38402
|
onClickChartElement,
|
|
36232
38403
|
dateBucket,
|
|
36233
|
-
propagateChanges
|
|
38404
|
+
propagateChanges,
|
|
38405
|
+
isAdmin = false
|
|
36234
38406
|
}) {
|
|
36235
38407
|
const [schemaData] = (0, import_react30.useContext)(SchemaDataContext);
|
|
36236
38408
|
const { reload } = useReportInternal(reportId);
|
|
@@ -36352,6 +38524,25 @@ function Chart({
|
|
|
36352
38524
|
}
|
|
36353
38525
|
}, [report, theme]);
|
|
36354
38526
|
const [client, clientLoading] = (0, import_react30.useContext)(ClientContext);
|
|
38527
|
+
const cloudCacheEnabled = (0, import_react30.useMemo)(() => {
|
|
38528
|
+
return !!client?.features?.cloudCache;
|
|
38529
|
+
}, [client]);
|
|
38530
|
+
const shouldShowCloudCacheValidationErrors = isAdmin && cloudCacheEnabled;
|
|
38531
|
+
const isMissingDateField = (0, import_react30.useMemo)(() => {
|
|
38532
|
+
if (!shouldShowCloudCacheValidationErrors) return false;
|
|
38533
|
+
return isDateFieldMissingInReport(report);
|
|
38534
|
+
}, [report, shouldShowCloudCacheValidationErrors]);
|
|
38535
|
+
const usesLimitInQuery = (0, import_react30.useMemo)(() => {
|
|
38536
|
+
if (!shouldShowCloudCacheValidationErrors) return false;
|
|
38537
|
+
return reportUsesLimitClause(report);
|
|
38538
|
+
}, [report, shouldShowCloudCacheValidationErrors]);
|
|
38539
|
+
const missingDashboardFilterFields = (0, import_react30.useMemo)(() => {
|
|
38540
|
+
if (!shouldShowCloudCacheValidationErrors || !report) return [];
|
|
38541
|
+
return getMissingDashboardFilterFields({
|
|
38542
|
+
rows: report.rows,
|
|
38543
|
+
dashboardFilters
|
|
38544
|
+
});
|
|
38545
|
+
}, [report, dashboardFilters, shouldShowCloudCacheValidationErrors]);
|
|
36355
38546
|
const [error, setError] = (0, import_react30.useState)(void 0);
|
|
36356
38547
|
const updateFilter = (filter, value, comparison) => {
|
|
36357
38548
|
let filterValue = {};
|
|
@@ -36492,6 +38683,15 @@ function Chart({
|
|
|
36492
38683
|
if (report?.error || error) {
|
|
36493
38684
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { errorMessage: report?.error ?? error }) });
|
|
36494
38685
|
}
|
|
38686
|
+
if (isMissingDateField) {
|
|
38687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { 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.` }) });
|
|
38688
|
+
}
|
|
38689
|
+
if (usesLimitInQuery) {
|
|
38690
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { errorMessage: `The query for this report uses the LIMIT keyword, which is not supported when the cache is enabled.` }) });
|
|
38691
|
+
}
|
|
38692
|
+
if (missingDashboardFilterFields.length) {
|
|
38693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { errorMessage: `The query for this report is missing dashboard filter fields: ${missingDashboardFilterFields.join(", ")}` }) });
|
|
38694
|
+
}
|
|
36495
38695
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
36496
38696
|
"div",
|
|
36497
38697
|
{
|
|
@@ -36822,7 +39022,7 @@ var ChartDisplay = ({
|
|
|
36822
39022
|
);
|
|
36823
39023
|
}
|
|
36824
39024
|
if (config?.chartType?.toLowerCase() === "metric") {
|
|
36825
|
-
if (!config?.rows || config?.rows?.length === 0
|
|
39025
|
+
if (!config?.rows || config?.rows?.length === 0) {
|
|
36826
39026
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
36827
39027
|
"div",
|
|
36828
39028
|
{
|
|
@@ -36860,6 +39060,36 @@ var ChartDisplay = ({
|
|
|
36860
39060
|
}
|
|
36861
39061
|
);
|
|
36862
39062
|
}
|
|
39063
|
+
if (config?.pivotRows && config?.pivotRows?.length > 0) {
|
|
39064
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
39065
|
+
"div",
|
|
39066
|
+
{
|
|
39067
|
+
style: {
|
|
39068
|
+
fontFamily: theme?.fontFamily,
|
|
39069
|
+
fontSize: 32,
|
|
39070
|
+
color: theme?.primaryTextColor,
|
|
39071
|
+
fontWeight: "600",
|
|
39072
|
+
textOverflow: "ellipsis",
|
|
39073
|
+
margin: 0,
|
|
39074
|
+
whiteSpace: "nowrap",
|
|
39075
|
+
boxSizing: "content-box",
|
|
39076
|
+
maxWidth: "100%",
|
|
39077
|
+
textAlign: "left",
|
|
39078
|
+
overflow: "hidden",
|
|
39079
|
+
height: containerStyle?.height || "100%",
|
|
39080
|
+
display: "flex",
|
|
39081
|
+
width: "100%",
|
|
39082
|
+
flexDirection: "row",
|
|
39083
|
+
...containerStyle
|
|
39084
|
+
},
|
|
39085
|
+
className,
|
|
39086
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(QuillMetricComponent, { report: config ?? EMPTY_REPORT, children: quillFormat({
|
|
39087
|
+
value: config?.pivotRows?.[0]?.[config?.xAxisField],
|
|
39088
|
+
format: config?.xAxisFormat
|
|
39089
|
+
}) ?? "No results" })
|
|
39090
|
+
}
|
|
39091
|
+
);
|
|
39092
|
+
}
|
|
36863
39093
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
36864
39094
|
"div",
|
|
36865
39095
|
{
|
|
@@ -37799,7 +40029,7 @@ var FilterPopoverWrapper = ({
|
|
|
37799
40029
|
// src/components/ReportBuilder/FilterModal.tsx
|
|
37800
40030
|
var import_react35 = require("react");
|
|
37801
40031
|
init_Filter();
|
|
37802
|
-
var
|
|
40032
|
+
var import_date_fns15 = require("date-fns");
|
|
37803
40033
|
init_textProcessing();
|
|
37804
40034
|
init_filterProcessing();
|
|
37805
40035
|
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
@@ -37833,10 +40063,10 @@ function FilterModal({
|
|
|
37833
40063
|
const [unit, setUnit] = (0, import_react35.useState)("");
|
|
37834
40064
|
const [unitOptions, setUnitOptions] = (0, import_react35.useState)([]);
|
|
37835
40065
|
const [startDate, setStartDate] = (0, import_react35.useState)(
|
|
37836
|
-
(0,
|
|
40066
|
+
(0, import_date_fns15.startOfToday)().toISOString().substring(0, 10)
|
|
37837
40067
|
);
|
|
37838
40068
|
const [endDate, setEndDate] = (0, import_react35.useState)(
|
|
37839
|
-
(0,
|
|
40069
|
+
(0, import_date_fns15.startOfToday)().toISOString().substring(0, 10)
|
|
37840
40070
|
);
|
|
37841
40071
|
const [filterInitialized, setFilterInitialized] = (0, import_react35.useState)(false);
|
|
37842
40072
|
const [table, setTable] = (0, import_react35.useState)(void 0);
|
|
@@ -37904,10 +40134,10 @@ function FilterModal({
|
|
|
37904
40134
|
onOperatorChange(filter.operator);
|
|
37905
40135
|
setUnit(filter.filterType === "date-filter" ? filter.value.unit : "");
|
|
37906
40136
|
setStartDate(
|
|
37907
|
-
filter.value?.startDate ? filter.value.startDate.substring(0, 10) : (0,
|
|
40137
|
+
filter.value?.startDate ? filter.value.startDate.substring(0, 10) : (0, import_date_fns15.startOfToday)().toISOString().substring(0, 10)
|
|
37908
40138
|
);
|
|
37909
40139
|
setEndDate(
|
|
37910
|
-
filter.value?.endDate ? filter.value.endDate.substring(0, 10) : (0,
|
|
40140
|
+
filter.value?.endDate ? filter.value.endDate.substring(0, 10) : (0, import_date_fns15.startOfToday)().toISOString().substring(0, 10)
|
|
37911
40141
|
);
|
|
37912
40142
|
if (filter.filterType === "string-in-filter") {
|
|
37913
40143
|
setSelectedOptions(
|
|
@@ -38002,8 +40232,8 @@ function FilterModal({
|
|
|
38002
40232
|
DateOperator.LessThan,
|
|
38003
40233
|
DateOperator.LessThanOrEqualTo,
|
|
38004
40234
|
DateOperator.NotEqualTo
|
|
38005
|
-
].includes(operator2) && !(0,
|
|
38006
|
-
setValue((0,
|
|
40235
|
+
].includes(operator2) && !(0, import_date_fns15.isValid)((0, import_date_fns15.parse)(value, "yyyy-mm-dd", /* @__PURE__ */ new Date())) && (filterInitialized || !filter)) {
|
|
40236
|
+
setValue((0, import_date_fns15.startOfToday)().toISOString().substring(0, 10));
|
|
38007
40237
|
} else if (type === FieldType.Date && [
|
|
38008
40238
|
DateOperator.InTheLast,
|
|
38009
40239
|
DateOperator.InTheCurrent,
|
|
@@ -38191,12 +40421,12 @@ function FilterModal({
|
|
|
38191
40421
|
case DateOperator.LessThan:
|
|
38192
40422
|
case DateOperator.GreaterThanOrEqualTo:
|
|
38193
40423
|
case DateOperator.LessThanOrEqualTo: {
|
|
38194
|
-
const parsedDate = (0,
|
|
38195
|
-
if (!(0,
|
|
40424
|
+
const parsedDate = (0, import_date_fns15.parse)(value, "yyyy-mm-dd", /* @__PURE__ */ new Date());
|
|
40425
|
+
if (!(0, import_date_fns15.isValid)(parsedDate)) {
|
|
38196
40426
|
alert("Please specify a valid date in yyyy-mm-dd");
|
|
38197
40427
|
return;
|
|
38198
40428
|
}
|
|
38199
|
-
const normalizedDate = (0,
|
|
40429
|
+
const normalizedDate = (0, import_date_fns15.format)(parsedDate, "yyyy-mm-dd");
|
|
38200
40430
|
onSubmitFilter({
|
|
38201
40431
|
field,
|
|
38202
40432
|
filterType: "date-comparison-filter" /* DateComparisonFilter */,
|
|
@@ -38492,8 +40722,8 @@ function FilterModal({
|
|
|
38492
40722
|
QuillDateRangePicker,
|
|
38493
40723
|
{
|
|
38494
40724
|
dateRange: {
|
|
38495
|
-
startDate: startDate ? /* @__PURE__ */ new Date(startDate + "T00:00:00") : (0,
|
|
38496
|
-
endDate: endDate ? /* @__PURE__ */ new Date(endDate + "T00:00:00") : (0,
|
|
40725
|
+
startDate: startDate ? /* @__PURE__ */ new Date(startDate + "T00:00:00") : (0, import_date_fns15.startOfToday)(),
|
|
40726
|
+
endDate: endDate ? /* @__PURE__ */ new Date(endDate + "T00:00:00") : (0, import_date_fns15.startOfToday)()
|
|
38497
40727
|
},
|
|
38498
40728
|
preset: "",
|
|
38499
40729
|
presetOptions: [],
|
|
@@ -38720,6 +40950,9 @@ function validateTemplatesAgainstFilters(filters, templates) {
|
|
|
38720
40950
|
}
|
|
38721
40951
|
async function addTemplatesToDashboard(name2, newTemplates, client, dashboardData, getToken, eventTracking) {
|
|
38722
40952
|
try {
|
|
40953
|
+
if (!newTemplates?.length) {
|
|
40954
|
+
return null;
|
|
40955
|
+
}
|
|
38723
40956
|
const { publicKey, tenants } = client;
|
|
38724
40957
|
if (tenants) {
|
|
38725
40958
|
throw new Error("Adding from template not yet supported for tenants");
|
|
@@ -38772,6 +41005,7 @@ async function addTemplatesToDashboard(name2, newTemplates, client, dashboardDat
|
|
|
38772
41005
|
function: "addTemplatesToDashboard"
|
|
38773
41006
|
}
|
|
38774
41007
|
});
|
|
41008
|
+
return null;
|
|
38775
41009
|
}
|
|
38776
41010
|
}
|
|
38777
41011
|
|
|
@@ -40649,7 +42883,7 @@ var PivotList = ({
|
|
|
40649
42883
|
};
|
|
40650
42884
|
|
|
40651
42885
|
// src/internals/ReportBuilder/PivotModal.tsx
|
|
40652
|
-
var
|
|
42886
|
+
var import_date_fns16 = require("date-fns");
|
|
40653
42887
|
init_textProcessing();
|
|
40654
42888
|
init_pivotProcessing();
|
|
40655
42889
|
init_tableProcessing();
|
|
@@ -42477,7 +44711,7 @@ var validateReport = (formData, dashboardData, defaultDateFilter, allTables) =>
|
|
|
42477
44711
|
|
|
42478
44712
|
// src/components/Chart/InternalChart.tsx
|
|
42479
44713
|
var import_react42 = require("react");
|
|
42480
|
-
var
|
|
44714
|
+
var import_date_fns17 = require("date-fns");
|
|
42481
44715
|
init_Filter();
|
|
42482
44716
|
init_filterProcessing();
|
|
42483
44717
|
init_dateRangePickerUtils();
|
|
@@ -44317,7 +46551,7 @@ function ChartBuilder({
|
|
|
44317
46551
|
template: true,
|
|
44318
46552
|
referenceLines: []
|
|
44319
46553
|
};
|
|
44320
|
-
const
|
|
46554
|
+
const updateDashboardFilters2 = async (dashboardName) => {
|
|
44321
46555
|
if (dashboardConfig && dashboardConfig[dashboardName]) {
|
|
44322
46556
|
return dashboardConfig[dashboardName];
|
|
44323
46557
|
}
|
|
@@ -44639,7 +46873,7 @@ function ChartBuilder({
|
|
|
44639
46873
|
if (destinationDashboardName) {
|
|
44640
46874
|
dashboardName = destinationDashboardName;
|
|
44641
46875
|
}
|
|
44642
|
-
const curDashboard = await
|
|
46876
|
+
const curDashboard = await updateDashboardFilters2(dashboardName);
|
|
44643
46877
|
setDashboardOptions(dashboardOptions2);
|
|
44644
46878
|
curFormData.dashboardName = dashboardName;
|
|
44645
46879
|
const curSchemaData = schemaData.schemaWithCustomFields;
|
|
@@ -45926,7 +48160,7 @@ function ChartBuilder({
|
|
|
45926
48160
|
value: formData.dashboardName || "",
|
|
45927
48161
|
onChange: async (e) => {
|
|
45928
48162
|
handleChange(e.target.value, "dashboardName");
|
|
45929
|
-
await
|
|
48163
|
+
await updateDashboardFilters2(e.target.value);
|
|
45930
48164
|
},
|
|
45931
48165
|
options: dashboardOptions.map((elem) => ({
|
|
45932
48166
|
label: elem.label,
|
|
@@ -54257,7 +56491,7 @@ function StaticChart(props) {
|
|
|
54257
56491
|
pageLoading,
|
|
54258
56492
|
nextPage,
|
|
54259
56493
|
prevPage,
|
|
54260
|
-
sortRows
|
|
56494
|
+
sortRows: sortRows2
|
|
54261
56495
|
} = useDashboardReportInternal(reportId);
|
|
54262
56496
|
const baseStyle = report?.chartType && CHART_TYPE_STYLES[report.chartType] ? CHART_TYPE_STYLES[report.chartType] : DEFAULT_STYLE;
|
|
54263
56497
|
const mergedStyle = className ? { ...containerStyle ?? {} } : { ...baseStyle, ...containerStyle ?? {} };
|
|
@@ -54277,7 +56511,7 @@ function StaticChart(props) {
|
|
|
54277
56511
|
}
|
|
54278
56512
|
};
|
|
54279
56513
|
const onSortChange = (sort) => {
|
|
54280
|
-
|
|
56514
|
+
sortRows2({
|
|
54281
56515
|
field: sort.field,
|
|
54282
56516
|
direction: sort.direction
|
|
54283
56517
|
});
|
|
@@ -54286,29 +56520,10 @@ function StaticChart(props) {
|
|
|
54286
56520
|
...report,
|
|
54287
56521
|
...report.pivot ? formattedPivotRowsAndColumns(report) : {}
|
|
54288
56522
|
} : void 0;
|
|
54289
|
-
const patchedConfig = config && config.pivot ? {
|
|
54290
|
-
...config,
|
|
54291
|
-
yAxisFields: config.columns?.slice(1).map((col) => ({
|
|
54292
|
-
field: col.field,
|
|
54293
|
-
label: col.label ?? col.field,
|
|
54294
|
-
format: col.format ?? "number"
|
|
54295
|
-
})) ?? config.yAxisFields
|
|
54296
|
-
} : config;
|
|
54297
|
-
if (patchedConfig) {
|
|
54298
|
-
const sample = (patchedConfig.pivotRows ?? patchedConfig.rows ?? []).slice(0, 1).map((row) => {
|
|
54299
|
-
const field = patchedConfig.yAxisFields?.[0]?.field;
|
|
54300
|
-
return {
|
|
54301
|
-
...row,
|
|
54302
|
-
_firstField: field,
|
|
54303
|
-
_firstFieldType: field ? typeof row[field] : void 0
|
|
54304
|
-
};
|
|
54305
|
-
});
|
|
54306
|
-
}
|
|
54307
56523
|
return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
|
|
54308
56524
|
ChartDisplay,
|
|
54309
56525
|
{
|
|
54310
|
-
|
|
54311
|
-
config: patchedConfig,
|
|
56526
|
+
config,
|
|
54312
56527
|
onClickChartElement,
|
|
54313
56528
|
loading,
|
|
54314
56529
|
className,
|