@zestl/zvolv-widgets 0.0.1 → 0.0.2
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/CHANGELOG.md +37 -0
- package/MIRROR_NOTES.md +146 -0
- package/README.md +153 -1
- package/SKILL.md +16 -1
- package/dist/index.cjs +787 -333
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +197 -16
- package/dist/index.d.ts +197 -16
- package/dist/index.js +582 -136
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React14, { createContext, useMemo, useContext, useState, useRef, useCallback, useEffect } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import
|
|
3
|
+
import dayjs4 from 'dayjs';
|
|
4
4
|
import utc from 'dayjs/plugin/utc.js';
|
|
5
5
|
import weekOfYear from 'dayjs/plugin/weekOfYear.js';
|
|
6
6
|
import _ from 'lodash';
|
|
7
|
+
import timezone2 from 'dayjs/plugin/timezone.js';
|
|
7
8
|
|
|
8
9
|
// src/core/ZvolvProvider.tsx
|
|
9
10
|
var RuntimeContext = createContext(null);
|
|
@@ -117,8 +118,8 @@ var TASK_DATE_FIELDS = [
|
|
|
117
118
|
"completeDate"
|
|
118
119
|
];
|
|
119
120
|
new Set(TASK_DATE_FIELDS.map((f) => f.toLowerCase()));
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
dayjs4.extend(utc);
|
|
122
|
+
dayjs4.extend(weekOfYear);
|
|
122
123
|
function humanizeDurationToMinutes(value) {
|
|
123
124
|
if (!value) return 0;
|
|
124
125
|
let total = 0;
|
|
@@ -163,7 +164,7 @@ function getDataType(elementType) {
|
|
|
163
164
|
function getDateRange(ops) {
|
|
164
165
|
const values = [];
|
|
165
166
|
const fmt2 = "YYYY-MM-DD";
|
|
166
|
-
const today =
|
|
167
|
+
const today = dayjs4();
|
|
167
168
|
switch (ops) {
|
|
168
169
|
case "TODAY":
|
|
169
170
|
values[0] = today.format(fmt2);
|
|
@@ -315,7 +316,7 @@ var resolveQueryUser = () => {
|
|
|
315
316
|
};
|
|
316
317
|
|
|
317
318
|
// src/runtime/queryGenerator.ts
|
|
318
|
-
|
|
319
|
+
dayjs4.extend(utc);
|
|
319
320
|
var mappingsCache = /* @__PURE__ */ new Map();
|
|
320
321
|
function getCachedAnalyticsMappings(indexKey) {
|
|
321
322
|
let pending2 = mappingsCache.get(indexKey);
|
|
@@ -467,7 +468,7 @@ function resolveDateMath(value) {
|
|
|
467
468
|
if (typeof value !== "string") return null;
|
|
468
469
|
const match = dateMathPattern.exec(value.trim());
|
|
469
470
|
if (!match) return null;
|
|
470
|
-
let d =
|
|
471
|
+
let d = dayjs4();
|
|
471
472
|
const [, amountStr, amountUnit, , roundUnit] = match;
|
|
472
473
|
if (amountStr && amountUnit) {
|
|
473
474
|
d = d.add(parseInt(amountStr, 10), dateMathUnit[amountUnit]);
|
|
@@ -482,7 +483,7 @@ function isDateMath(value) {
|
|
|
482
483
|
}
|
|
483
484
|
function getDate(dateFormula) {
|
|
484
485
|
const fmt2 = "YYYY-MM-DDTHH:mm:ssZ";
|
|
485
|
-
const d =
|
|
486
|
+
const d = dayjs4();
|
|
486
487
|
switch (dateFormula) {
|
|
487
488
|
case "{@[TODAY]}":
|
|
488
489
|
return d.startOf("day").format(fmt2);
|
|
@@ -679,7 +680,7 @@ function getFilters(field2, type, loggedInUser = null, isTask = false) {
|
|
|
679
680
|
field2.filter.operand = field2.filter.operand.map((oprd) => {
|
|
680
681
|
if (isDateMath(oprd)) return oprd;
|
|
681
682
|
const pattern = dateFieldPattern[field2.fieldFormat] ?? field2.fieldFormat;
|
|
682
|
-
return
|
|
683
|
+
return dayjs4(oprd, pattern).format("YYYY-MM-DD");
|
|
683
684
|
});
|
|
684
685
|
}
|
|
685
686
|
if (field2["taskfield"] && !field2["masterFieldDataType"]) {
|
|
@@ -964,6 +965,142 @@ function getTaskElementSort(dataSource, fieldMetaByName) {
|
|
|
964
965
|
}
|
|
965
966
|
return null;
|
|
966
967
|
}
|
|
968
|
+
function pivotEsField(entry) {
|
|
969
|
+
return entry?.masterField || entry?.title;
|
|
970
|
+
}
|
|
971
|
+
var HISTOGRAM_INTERVALS = {
|
|
972
|
+
day: "1d",
|
|
973
|
+
week: "1w",
|
|
974
|
+
month: "1M",
|
|
975
|
+
quarter: "1q",
|
|
976
|
+
year: "1y"
|
|
977
|
+
};
|
|
978
|
+
function getDateHistogramSource(row, esField, mfType, meta, sortOrder) {
|
|
979
|
+
const isTaskDate = taskDate.includes(esField) && !!(row.isTaskField || row.taskfield || meta?.isTaskField || meta?.taskfield);
|
|
980
|
+
if (!dateTypes.includes(mfType) && !isTaskDate) {
|
|
981
|
+
console.warn(`[@zestl/zvolv-widgets] groupBy "${row.title}": interval "${row.interval}" ignored \u2014 "${esField}" is not a date field.`);
|
|
982
|
+
return null;
|
|
983
|
+
}
|
|
984
|
+
const calendarInterval = HISTOGRAM_INTERVALS[row.interval];
|
|
985
|
+
if (!calendarInterval) {
|
|
986
|
+
console.warn(`[@zestl/zvolv-widgets] groupBy "${row.title}": unknown interval "${row.interval}" \u2014 use day | week | month | quarter | year.`);
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
const histogram = { field: esField, calendar_interval: calendarInterval, time_zone: row.timeZone || timezone };
|
|
990
|
+
if (sortOrder) histogram.order = sortOrder;
|
|
991
|
+
return { date_histogram: histogram };
|
|
992
|
+
}
|
|
993
|
+
var summaryFilterLists = /* @__PURE__ */ new Map();
|
|
994
|
+
var DATE_DIFF_DIVISOR = {
|
|
995
|
+
days: "86400000.0",
|
|
996
|
+
hours: "3600000.0",
|
|
997
|
+
minutes: "60000.0"
|
|
998
|
+
};
|
|
999
|
+
var LITERAL_DATE = /^\d{4}-\d{2}-\d{2}([T ][\d:.]+(Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
1000
|
+
function getDateDiffFixedEnd(end) {
|
|
1001
|
+
if (typeof end !== "string") return null;
|
|
1002
|
+
if (dateFormulas.includes(end)) return dayjs4(getDate(end)).valueOf();
|
|
1003
|
+
if (LITERAL_DATE.test(end.trim())) {
|
|
1004
|
+
const d = dayjs4(end.trim());
|
|
1005
|
+
if (d.isValid()) return d.valueOf();
|
|
1006
|
+
}
|
|
1007
|
+
if (/^\{@\[.*\]\}$/.test(end)) {
|
|
1008
|
+
console.warn(`[@zestl/zvolv-widgets] dateDiff end "${end}" is not a known date token (${dateFormulas.join(", ")}); it is being queried as a field name.`);
|
|
1009
|
+
}
|
|
1010
|
+
return null;
|
|
1011
|
+
}
|
|
1012
|
+
function getDateDiffScript(dd, fixedEnd) {
|
|
1013
|
+
const divisor = DATE_DIFF_DIVISOR[dd.unit] ?? DATE_DIFF_DIVISOR.days;
|
|
1014
|
+
if (fixedEnd != null) {
|
|
1015
|
+
return {
|
|
1016
|
+
source: `if(doc['${dd.start}'].size()==0) { return null; } return (params.now - doc['${dd.start}'].value.millis) / ${divisor};`,
|
|
1017
|
+
lang: "painless",
|
|
1018
|
+
params: { now: fixedEnd }
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
return {
|
|
1022
|
+
source: `if(doc['${dd.start}'].size()==0 || doc['${dd.end}'].size()==0) { return null; } return (doc['${dd.end}'].value.millis - doc['${dd.start}'].value.millis) / ${divisor};`,
|
|
1023
|
+
lang: "painless"
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
function getSummaryFilterClause(sumary, f, loggedInUser) {
|
|
1027
|
+
if (f.operator === "_ALL" || f.operator === "MULTIPLE") return null;
|
|
1028
|
+
const fb = {
|
|
1029
|
+
header: sumary.title,
|
|
1030
|
+
masterfield: f.operand ?? f.masterField,
|
|
1031
|
+
masterFieldDataType: f.masterFieldDataType,
|
|
1032
|
+
masterFieldType: f.masterFieldType,
|
|
1033
|
+
filter: { operator: f.operator, operand: Array.isArray(f.value) ? [...f.value] : f.value }
|
|
1034
|
+
};
|
|
1035
|
+
return getFilters(fb, "PIVOT", loggedInUser) ?? null;
|
|
1036
|
+
}
|
|
1037
|
+
function buildExtendedSummary(sumary, summaryAggs, loggedInUser, sortKeys = {}) {
|
|
1038
|
+
const name = sumary.value;
|
|
1039
|
+
const list = summaryFilterLists.get(name) ?? [];
|
|
1040
|
+
const andGroup = list.length > 1 && list.some((f) => f?.combine === "AND");
|
|
1041
|
+
const isPercentiles = sumary.type === "percentiles";
|
|
1042
|
+
if (!sumary.dateDiff && !andGroup && !(isPercentiles && sumary.percents?.length)) return false;
|
|
1043
|
+
const must = [];
|
|
1044
|
+
const mustNot = [];
|
|
1045
|
+
const conditions = andGroup ? list : list.slice(-1);
|
|
1046
|
+
for (const f of conditions) {
|
|
1047
|
+
const clause = getSummaryFilterClause(sumary, f, loggedInUser);
|
|
1048
|
+
if (!clause) continue;
|
|
1049
|
+
if (mustNotOp.includes(f.operator)) mustNot.push({ ...clause });
|
|
1050
|
+
else must.push(clause);
|
|
1051
|
+
}
|
|
1052
|
+
let metric;
|
|
1053
|
+
if (sumary.dateDiff) {
|
|
1054
|
+
const dd = sumary.dateDiff;
|
|
1055
|
+
const fixedEnd = getDateDiffFixedEnd(dd.end);
|
|
1056
|
+
must.push({ exists: { field: dd.start } });
|
|
1057
|
+
if (fixedEnd == null) must.push({ exists: { field: dd.end } });
|
|
1058
|
+
metric = { script: getDateDiffScript(dd, fixedEnd) };
|
|
1059
|
+
} else {
|
|
1060
|
+
const esField = pivotEsField(sumary);
|
|
1061
|
+
let aggType = sumary.type;
|
|
1062
|
+
let aggField = esField;
|
|
1063
|
+
const isTextField = sumary.masterFieldDataType === "STRING" && !dateTypes.includes(sumary.masterFieldType) && !isNumericTaskField(sumary);
|
|
1064
|
+
if (sumary.masterFieldType === "FORM_SEARCH" && (aggType === "value_count" || aggType === "cardinality")) {
|
|
1065
|
+
aggField = resolveFormSearchViewField(esField);
|
|
1066
|
+
} else if (sumary.masterFieldType === "FILE_UPLOAD_V2") {
|
|
1067
|
+
aggField = `${esField}.mediaKey.keyword`;
|
|
1068
|
+
} else if (isTextField) {
|
|
1069
|
+
if (["sum", "avg", "min", "max"].includes(aggType)) aggType = "value_count";
|
|
1070
|
+
aggField = `${esField}.keyword`;
|
|
1071
|
+
}
|
|
1072
|
+
metric = { field: aggField };
|
|
1073
|
+
finish(name, summaryAggs, must, mustNot, { [aggType]: metric });
|
|
1074
|
+
if (isPercentiles && sumary.percents?.length) metric.percents = sumary.percents;
|
|
1075
|
+
if (!isPercentiles && aggField === esField && sortKeys[esField]) {
|
|
1076
|
+
summaryAggs[`${name}_sort`] = { bucket_sort: { sort: [{ [name]: { order: sortKeys[esField] } }] } };
|
|
1077
|
+
}
|
|
1078
|
+
return true;
|
|
1079
|
+
}
|
|
1080
|
+
if (isPercentiles && sumary.percents?.length) metric.percents = sumary.percents;
|
|
1081
|
+
return finish(name, summaryAggs, must, mustNot, { [sumary.type]: metric });
|
|
1082
|
+
}
|
|
1083
|
+
function finish(name, summaryAggs, must, mustNot, metric) {
|
|
1084
|
+
if (must.length === 0 && mustNot.length === 0) {
|
|
1085
|
+
summaryAggs[name] = metric;
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
1088
|
+
const bool = {};
|
|
1089
|
+
if (must.length) bool.must = must;
|
|
1090
|
+
if (mustNot.length) bool.must_not = mustNot;
|
|
1091
|
+
summaryAggs[name] = { filter: { bool }, aggs: { [name]: metric } };
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
function groupPivotFilters(pivotFilters) {
|
|
1095
|
+
const out = /* @__PURE__ */ new Map();
|
|
1096
|
+
(pivotFilters || []).forEach((f) => {
|
|
1097
|
+
if (!f) return;
|
|
1098
|
+
const list = out.get(f.field) ?? [];
|
|
1099
|
+
list.push(f);
|
|
1100
|
+
out.set(f.field, list);
|
|
1101
|
+
});
|
|
1102
|
+
return out;
|
|
1103
|
+
}
|
|
967
1104
|
function getCompositeAggregations(pivotBody, filterMap, aggDataPoints, size = 5e4, scriptFields = {}, loggedInUser = null, sort = [], fieldMetaByName) {
|
|
968
1105
|
const composite = { size, sources: [] };
|
|
969
1106
|
pivotBody.rows.forEach((row) => {
|
|
@@ -985,17 +1122,21 @@ function getCompositeAggregations(pivotBody, filterMap, aggDataPoints, size = 5e
|
|
|
985
1122
|
const meta = fieldMetaByName?.get(row.title) || fieldMetaByName?.get(row.masterField) || {};
|
|
986
1123
|
const mfType = row.masterFieldType ?? meta.masterFieldType;
|
|
987
1124
|
const mfDataType = row.masterFieldDataType ?? meta.masterFieldDataType ?? (mfType ? getDataType(mfType) : void 0);
|
|
1125
|
+
const esField = pivotEsField(row);
|
|
988
1126
|
const sourceObj = {};
|
|
989
|
-
|
|
990
|
-
|
|
1127
|
+
const histogram = row.interval ? getDateHistogramSource(row, esField, mfType, meta, sortOrder) : null;
|
|
1128
|
+
if (histogram) {
|
|
1129
|
+
sourceObj[row.title] = histogram;
|
|
1130
|
+
} else if (mfType === "FORM_SEARCH" || mfType === "INPUT_TAG") {
|
|
1131
|
+
sourceObj[row.title] = { terms: { field: resolveFormSearchViewField(esField) } };
|
|
991
1132
|
} else if (mfType === "FILE_UPLOAD_V2") {
|
|
992
|
-
sourceObj[row.title] = { terms: { field: `${
|
|
1133
|
+
sourceObj[row.title] = { terms: { field: `${esField}.mediaKey.keyword` } };
|
|
993
1134
|
} else if (mfDataType === "STRING" && !dateTypes.includes(mfType) && !isNumericTaskField(row, fieldMetaByName)) {
|
|
994
|
-
sourceObj[row.title] = { terms: { field: `${
|
|
1135
|
+
sourceObj[row.title] = { terms: { field: `${esField}.keyword` } };
|
|
995
1136
|
} else if (!mfDataType && Object.keys(scriptFields).length > 0) {
|
|
996
1137
|
sourceObj[row.title] = { terms: scriptFields[row.title] };
|
|
997
1138
|
} else {
|
|
998
|
-
sourceObj[row.title] = { terms: { field:
|
|
1139
|
+
sourceObj[row.title] = { terms: { field: esField } };
|
|
999
1140
|
if (sortOrder) sourceObj[row.title]["terms"]["order"] = sortOrder;
|
|
1000
1141
|
}
|
|
1001
1142
|
composite.sources.push(sourceObj);
|
|
@@ -1013,7 +1154,7 @@ function getColumnAggregations(pivotBody, filterMap, aggDataPoints, loggedInUser
|
|
|
1013
1154
|
const colFilter = getFilters(fb, "PIVOT", loggedInUser);
|
|
1014
1155
|
if (colFilter) colFilters.push(colFilter);
|
|
1015
1156
|
}
|
|
1016
|
-
colAggs[col.title] = { terms: { field: col
|
|
1157
|
+
colAggs[col.title] = { terms: { field: pivotEsField(col) } };
|
|
1017
1158
|
if (i === pivotBody.columns.length - 1) {
|
|
1018
1159
|
const summaryResult = getSummaryAggregations(pivotBody, filterMap, aggDataPoints, loggedInUser, fMap);
|
|
1019
1160
|
colAggs[col.title]["aggs"] = summaryResult.summaryAggs;
|
|
@@ -1046,6 +1187,7 @@ function getSummaryAggregations(pivotBody, filterMap, aggDataPoints, loggedInUse
|
|
|
1046
1187
|
pivotBody.summary.forEach((sumary) => {
|
|
1047
1188
|
const filter = filterMap.get(sumary.value);
|
|
1048
1189
|
aggDataPoints["summary"].push(sumary.value);
|
|
1190
|
+
if (buildExtendedSummary(sumary, summaryAggs, loggedInUser, sortKeys)) return;
|
|
1049
1191
|
summaryAggs[sumary.value] = {};
|
|
1050
1192
|
const addBucketSort = (key) => {
|
|
1051
1193
|
if (sortKeys[key]) {
|
|
@@ -1053,17 +1195,18 @@ function getSummaryAggregations(pivotBody, filterMap, aggDataPoints, loggedInUse
|
|
|
1053
1195
|
}
|
|
1054
1196
|
};
|
|
1055
1197
|
const isTextField = sumary.masterFieldDataType === "STRING" && !dateTypes.includes(sumary.masterFieldType) && !isNumericTaskField(sumary, fMap);
|
|
1198
|
+
const esField = pivotEsField(sumary);
|
|
1056
1199
|
let aggType = sumary.type;
|
|
1057
|
-
let aggField =
|
|
1200
|
+
let aggField = esField;
|
|
1058
1201
|
if (sumary.masterFieldType === "FORM_SEARCH" && (sumary.type === "value_count" || sumary.type === "cardinality")) {
|
|
1059
|
-
aggField = resolveFormSearchViewField(
|
|
1202
|
+
aggField = resolveFormSearchViewField(esField);
|
|
1060
1203
|
} else if (sumary.masterFieldType === "FILE_UPLOAD_V2") {
|
|
1061
|
-
aggField = `${
|
|
1204
|
+
aggField = `${esField}.mediaKey.keyword`;
|
|
1062
1205
|
} else if (isTextField) {
|
|
1063
1206
|
if (["sum", "avg", "min", "max"].includes(sumary.type)) aggType = "value_count";
|
|
1064
|
-
aggField = `${
|
|
1207
|
+
aggField = `${esField}.keyword`;
|
|
1065
1208
|
}
|
|
1066
|
-
const usesRawField = aggField ===
|
|
1209
|
+
const usesRawField = aggField === esField;
|
|
1067
1210
|
if (filter) {
|
|
1068
1211
|
const fb = {
|
|
1069
1212
|
header: sumary.title,
|
|
@@ -1081,10 +1224,10 @@ function getSummaryAggregations(pivotBody, filterMap, aggDataPoints, loggedInUse
|
|
|
1081
1224
|
}
|
|
1082
1225
|
summaryAggs[sumary.value]["aggs"] = { [sumary.value]: {} };
|
|
1083
1226
|
summaryAggs[sumary.value]["aggs"][sumary.value][aggType] = { field: aggField };
|
|
1084
|
-
if (usesRawField) addBucketSort(
|
|
1227
|
+
if (usesRawField) addBucketSort(esField);
|
|
1085
1228
|
} else {
|
|
1086
1229
|
summaryAggs[sumary.value][aggType] = { field: aggField };
|
|
1087
|
-
if (usesRawField) addBucketSort(
|
|
1230
|
+
if (usesRawField) addBucketSort(esField);
|
|
1088
1231
|
}
|
|
1089
1232
|
});
|
|
1090
1233
|
return { summaryAggs, aggDataPoints };
|
|
@@ -1094,6 +1237,7 @@ function generateQuery(configuration, dataSource, formId, skip = null, limit = n
|
|
|
1094
1237
|
scriptFilters = [];
|
|
1095
1238
|
fieldMap = /* @__PURE__ */ new Map();
|
|
1096
1239
|
currentMappings = mappings;
|
|
1240
|
+
summaryFilterLists = /* @__PURE__ */ new Map();
|
|
1097
1241
|
let staticQueryClause = null;
|
|
1098
1242
|
const rawDataSourceQuery = dataSource?.query;
|
|
1099
1243
|
if (rawDataSourceQuery && typeof rawDataSourceQuery === "string") {
|
|
@@ -1186,6 +1330,7 @@ function generateQuery(configuration, dataSource, formId, skip = null, limit = n
|
|
|
1186
1330
|
if (dataSource?.pivot.filters?.length > 0) {
|
|
1187
1331
|
dataSource?.pivot.filters.forEach((f) => filterMap2.set(f.field, f));
|
|
1188
1332
|
}
|
|
1333
|
+
summaryFilterLists = groupPivotFilters(dataSource?.pivot.filters);
|
|
1189
1334
|
if (!isDrilldownView() && dataSource?.displayRowLimit && dataSource?.displayRowLimit !== "") {
|
|
1190
1335
|
size = dataSource?.displayRowLimit;
|
|
1191
1336
|
}
|
|
@@ -1763,16 +1908,29 @@ function taskField(header, masterFieldType = "INPUT_TEXT", options = {}) {
|
|
|
1763
1908
|
...options
|
|
1764
1909
|
};
|
|
1765
1910
|
}
|
|
1766
|
-
function groupBy(f, title = f.header) {
|
|
1911
|
+
function groupBy(f, title = f.header, options = {}) {
|
|
1767
1912
|
return {
|
|
1768
1913
|
title,
|
|
1769
1914
|
masterField: f.masterfield ?? f.taskfield ?? f.header,
|
|
1770
1915
|
masterFieldType: f.masterFieldType,
|
|
1771
|
-
masterFieldDataType: f.masterFieldDataType
|
|
1916
|
+
masterFieldDataType: f.masterFieldDataType,
|
|
1917
|
+
...options.interval ? { interval: options.interval } : {},
|
|
1918
|
+
...options.timeZone ? { timeZone: options.timeZone } : {}
|
|
1772
1919
|
};
|
|
1773
1920
|
}
|
|
1774
|
-
function
|
|
1921
|
+
function dateDiff(start, end, unit = "days") {
|
|
1922
|
+
const startField = start.masterfield ?? start.taskfield ?? start.header;
|
|
1923
|
+
const endField = typeof end === "string" ? end === "TODAY" ? "{@[TODAY]}" : end : end.masterfield ?? end.taskfield ?? end.header;
|
|
1924
|
+
const endLabel = typeof end === "string" ? end : end.header;
|
|
1775
1925
|
return {
|
|
1926
|
+
header: `${start.header} \u2192 ${endLabel} (${unit})`,
|
|
1927
|
+
masterfield: startField,
|
|
1928
|
+
masterFieldDataType: "FLOAT",
|
|
1929
|
+
dateDiff: { start: startField, end: endField, unit }
|
|
1930
|
+
};
|
|
1931
|
+
}
|
|
1932
|
+
function aggregate(f, type = "sum", outputName = f.header, options = {}) {
|
|
1933
|
+
const summary = {
|
|
1776
1934
|
title: f.header,
|
|
1777
1935
|
masterField: f.masterfield ?? f.taskfield ?? f.header,
|
|
1778
1936
|
masterFieldType: f.masterFieldType,
|
|
@@ -1780,6 +1938,36 @@ function aggregate(f, type = "sum", outputName = f.header) {
|
|
|
1780
1938
|
value: outputName,
|
|
1781
1939
|
type
|
|
1782
1940
|
};
|
|
1941
|
+
const dd = f.dateDiff;
|
|
1942
|
+
if (dd) summary.dateDiff = { ...dd };
|
|
1943
|
+
if (options.percents?.length) summary.percents = [...options.percents];
|
|
1944
|
+
if (options.where?.length) {
|
|
1945
|
+
summary.filters = options.where.map(([wf, cond]) => {
|
|
1946
|
+
const mf = wf.masterfield ?? wf.taskfield ?? wf.header;
|
|
1947
|
+
return {
|
|
1948
|
+
field: outputName,
|
|
1949
|
+
operand: mf,
|
|
1950
|
+
masterField: mf,
|
|
1951
|
+
masterFieldType: wf.masterFieldType,
|
|
1952
|
+
masterFieldDataType: wf.masterFieldDataType,
|
|
1953
|
+
operator: cond.operator,
|
|
1954
|
+
value: [...cond.operand],
|
|
1955
|
+
combine: "AND"
|
|
1956
|
+
};
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
return summary;
|
|
1960
|
+
}
|
|
1961
|
+
function hoistSummaryFilters(p) {
|
|
1962
|
+
if (!p?.summary?.some((s) => s.filters?.length)) return p;
|
|
1963
|
+
const hoisted = [];
|
|
1964
|
+
const summary = p.summary.map((s) => {
|
|
1965
|
+
if (!s.filters) return s;
|
|
1966
|
+
const { filters: filters2, ...rest } = s;
|
|
1967
|
+
hoisted.push(...filters2);
|
|
1968
|
+
return rest;
|
|
1969
|
+
});
|
|
1970
|
+
return { ...p, summary, filters: [...p.filters ?? [], ...hoisted] };
|
|
1783
1971
|
}
|
|
1784
1972
|
function derive(title, operator, operands) {
|
|
1785
1973
|
return { title, operator, operands };
|
|
@@ -1792,7 +1980,7 @@ function formSource(formId, fields, options = {}) {
|
|
|
1792
1980
|
formId,
|
|
1793
1981
|
newFormFramework: true,
|
|
1794
1982
|
fields: fields.map((f) => ({ ...f, formID: f.formID ?? formId })),
|
|
1795
|
-
...options.pivot ? { pivot: options.pivot } : {},
|
|
1983
|
+
...options.pivot ? { pivot: hoistSummaryFilters(options.pivot) } : {},
|
|
1796
1984
|
...options.displayRowLimit ? { displayRowLimit: options.displayRowLimit } : {}
|
|
1797
1985
|
};
|
|
1798
1986
|
}
|
|
@@ -1801,7 +1989,7 @@ function taskSource(fields, options = {}) {
|
|
|
1801
1989
|
isTask: true,
|
|
1802
1990
|
newFormFramework: true,
|
|
1803
1991
|
fields: fields.map((f) => ({ ...f, isTaskField: true })),
|
|
1804
|
-
...options.pivot ? { pivot: options.pivot } : {},
|
|
1992
|
+
...options.pivot ? { pivot: hoistSummaryFilters(options.pivot) } : {},
|
|
1805
1993
|
...options.displayRowLimit ? { displayRowLimit: options.displayRowLimit } : {}
|
|
1806
1994
|
};
|
|
1807
1995
|
}
|
|
@@ -1809,13 +1997,13 @@ function automationSource(automationId, fields = []) {
|
|
|
1809
1997
|
return { automation: { automationId, enabled: true }, fields };
|
|
1810
1998
|
}
|
|
1811
1999
|
function pivot(config) {
|
|
1812
|
-
return {
|
|
2000
|
+
return hoistSummaryFilters({
|
|
1813
2001
|
rows: config.rows ?? [],
|
|
1814
2002
|
columns: config.columns ?? [],
|
|
1815
2003
|
summary: config.summary ?? [],
|
|
1816
2004
|
filters: config.filters ?? [],
|
|
1817
2005
|
postOperations: config.postOperations ?? []
|
|
1818
|
-
};
|
|
2006
|
+
});
|
|
1819
2007
|
}
|
|
1820
2008
|
|
|
1821
2009
|
// src/core/config.ts
|
|
@@ -1913,7 +2101,7 @@ function coerceForField(field2, values) {
|
|
|
1913
2101
|
});
|
|
1914
2102
|
}
|
|
1915
2103
|
var FMT = "YYYY-MM-DD";
|
|
1916
|
-
function resolveDateToken(token, now =
|
|
2104
|
+
function resolveDateToken(token, now = dayjs4()) {
|
|
1917
2105
|
switch (String(token).toUpperCase()) {
|
|
1918
2106
|
case "TODAY":
|
|
1919
2107
|
return [now.format(FMT), now.format(FMT)];
|
|
@@ -1957,7 +2145,7 @@ function parseStrict(text2, fmt2) {
|
|
|
1957
2145
|
const y = map.YYYY, m = map.MM, d = map.DD;
|
|
1958
2146
|
if (!y || y.length !== 4 || !m || !d) return [null, null, null];
|
|
1959
2147
|
const mm = m.padStart(2, "0"), dd = d.padStart(2, "0");
|
|
1960
|
-
const parsed =
|
|
2148
|
+
const parsed = dayjs4(`${y}-${mm}-${dd}`);
|
|
1961
2149
|
if (!parsed.isValid() || parsed.format(FMT) !== `${y}-${mm}-${dd}`) return [null, null, null];
|
|
1962
2150
|
return [y, mm, dd];
|
|
1963
2151
|
}
|
|
@@ -2056,7 +2244,7 @@ function toComparable(v) {
|
|
|
2056
2244
|
if (typeof v === "number") return v;
|
|
2057
2245
|
const n = Number(v);
|
|
2058
2246
|
if (!isNaN(n)) return n;
|
|
2059
|
-
const d =
|
|
2247
|
+
const d = dayjs4(v);
|
|
2060
2248
|
return d.isValid() ? d.valueOf() : null;
|
|
2061
2249
|
}
|
|
2062
2250
|
function applyLocalSearch(rows, search, toLabel) {
|
|
@@ -2124,7 +2312,7 @@ function matchesWidgetFilter(row, f) {
|
|
|
2124
2312
|
case "DATE_IS": {
|
|
2125
2313
|
const range = resolveDateToken(String(values[0] ?? ""));
|
|
2126
2314
|
if (!range || raw2 == null || raw2 === "") return false;
|
|
2127
|
-
const d =
|
|
2315
|
+
const d = dayjs4(raw2).format(FMT);
|
|
2128
2316
|
return d >= range[0] && d <= range[1];
|
|
2129
2317
|
}
|
|
2130
2318
|
default:
|
|
@@ -2543,7 +2731,7 @@ var KPI_DEFAULT_TEMPLATES = {
|
|
|
2543
2731
|
hero_chart: HeroChart,
|
|
2544
2732
|
icon: Icon
|
|
2545
2733
|
};
|
|
2546
|
-
var WidgetStateSlot =
|
|
2734
|
+
var WidgetStateSlot = React14.createContext(null);
|
|
2547
2735
|
var WidgetShell = ({
|
|
2548
2736
|
widgetType,
|
|
2549
2737
|
title,
|
|
@@ -2561,7 +2749,7 @@ var WidgetShell = ({
|
|
|
2561
2749
|
}) => {
|
|
2562
2750
|
const t = useTokens();
|
|
2563
2751
|
const chrome = resolveChrome(t, widgetType);
|
|
2564
|
-
const renderState =
|
|
2752
|
+
const renderState = React14.useContext(WidgetStateSlot);
|
|
2565
2753
|
const frame = {
|
|
2566
2754
|
display: "flex",
|
|
2567
2755
|
flexDirection: "column",
|
|
@@ -2666,24 +2854,91 @@ function alignSummaryToSeries(dataSource, series) {
|
|
|
2666
2854
|
});
|
|
2667
2855
|
return { ...dataSource, pivot: { ...dataSource.pivot, summary: fixedSummary } };
|
|
2668
2856
|
}
|
|
2857
|
+
dayjs4.extend(utc);
|
|
2858
|
+
dayjs4.extend(timezone2);
|
|
2669
2859
|
function isLikelyTimestamp(v) {
|
|
2670
2860
|
if (typeof v !== "number" || !Number.isFinite(v)) return false;
|
|
2671
2861
|
return v > 946e9 && v < 41e11;
|
|
2672
2862
|
}
|
|
2673
|
-
function
|
|
2863
|
+
function wallStartOfPeriod(d, unit) {
|
|
2864
|
+
switch (unit) {
|
|
2865
|
+
case "week": {
|
|
2866
|
+
const day = d.startOf("day");
|
|
2867
|
+
return day.subtract((day.day() + 6) % 7, "day");
|
|
2868
|
+
}
|
|
2869
|
+
case "quarter": {
|
|
2870
|
+
const month = d.startOf("month");
|
|
2871
|
+
return month.month(Math.floor(month.month() / 3) * 3);
|
|
2872
|
+
}
|
|
2873
|
+
default:
|
|
2874
|
+
return d.startOf(unit);
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
function wallAddPeriod(d, unit) {
|
|
2878
|
+
return unit === "quarter" ? d.add(3, "month") : d.add(1, unit);
|
|
2879
|
+
}
|
|
2880
|
+
function inZone(wall, d, timeZone) {
|
|
2881
|
+
const date = wall(dayjs4.utc(d.tz(timeZone).format("YYYY-MM-DD"))).format("YYYY-MM-DD");
|
|
2882
|
+
return dayjs4.tz(date, timeZone);
|
|
2883
|
+
}
|
|
2884
|
+
function startOfPeriod(d, unit, timeZone) {
|
|
2885
|
+
return timeZone ? inZone((w) => wallStartOfPeriod(w, unit), d, timeZone) : wallStartOfPeriod(d, unit);
|
|
2886
|
+
}
|
|
2887
|
+
function addPeriod(d, unit, timeZone) {
|
|
2888
|
+
return timeZone ? inZone((w) => wallAddPeriod(w, unit), d, timeZone) : wallAddPeriod(d, unit);
|
|
2889
|
+
}
|
|
2890
|
+
var HAS_OFFSET = /(Z|[+-]\d{2}:?\d{2})$/i;
|
|
2891
|
+
function parseDateValue(v, timeZone) {
|
|
2892
|
+
if (timeZone && typeof v === "string" && !HAS_OFFSET.test(v.trim())) {
|
|
2893
|
+
try {
|
|
2894
|
+
return dayjs4.tz(v, timeZone);
|
|
2895
|
+
} catch {
|
|
2896
|
+
return dayjs4(NaN);
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
return dayjs4(v);
|
|
2900
|
+
}
|
|
2901
|
+
function sumInto(target, row, series) {
|
|
2902
|
+
series.forEach(({ valueField }) => {
|
|
2903
|
+
if (!(valueField in row) && !(valueField in target)) return;
|
|
2904
|
+
const a = Number(target[valueField]);
|
|
2905
|
+
const b = Number(row[valueField]);
|
|
2906
|
+
target[valueField] = (Number.isFinite(a) ? a : 0) + (Number.isFinite(b) ? b : 0);
|
|
2907
|
+
});
|
|
2908
|
+
}
|
|
2909
|
+
function fillDateGaps({
|
|
2910
|
+
rows,
|
|
2911
|
+
xKey,
|
|
2912
|
+
series,
|
|
2913
|
+
unit,
|
|
2914
|
+
range,
|
|
2915
|
+
merge = "sum",
|
|
2916
|
+
xFormat,
|
|
2917
|
+
timeZone
|
|
2918
|
+
}) {
|
|
2674
2919
|
if (!range) return rows;
|
|
2675
|
-
const keyFormat = unit === "month" ? "YYYY-MM" : "YYYY-MM-DD";
|
|
2676
2920
|
const byPeriod = /* @__PURE__ */ new Map();
|
|
2921
|
+
const copied = /* @__PURE__ */ new Set();
|
|
2677
2922
|
rows.forEach((row) => {
|
|
2678
|
-
const d =
|
|
2679
|
-
if (d.isValid())
|
|
2923
|
+
const d = parseDateValue(row[xKey], timeZone);
|
|
2924
|
+
if (!d.isValid()) return;
|
|
2925
|
+
const key = startOfPeriod(d, unit, timeZone).valueOf();
|
|
2926
|
+
const existing = byPeriod.get(key);
|
|
2927
|
+
if (!existing || merge === "last") {
|
|
2928
|
+
byPeriod.set(key, row);
|
|
2929
|
+
return;
|
|
2930
|
+
}
|
|
2931
|
+
const merged = copied.has(key) ? existing : { ...existing };
|
|
2932
|
+
copied.add(key);
|
|
2933
|
+
sumInto(merged, row, series);
|
|
2934
|
+
byPeriod.set(key, merged);
|
|
2680
2935
|
});
|
|
2681
2936
|
const filled = [];
|
|
2682
|
-
|
|
2683
|
-
const
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
const existing = byPeriod.get(
|
|
2937
|
+
const useTimestamp = rows.length ? isLikelyTimestamp(rows[0]?.[xKey]) : xFormat === "timestamp";
|
|
2938
|
+
const end = startOfPeriod(range.end, unit, timeZone);
|
|
2939
|
+
let cursor = startOfPeriod(range.start, unit, timeZone);
|
|
2940
|
+
while (!cursor.isAfter(end)) {
|
|
2941
|
+
const existing = byPeriod.get(cursor.valueOf());
|
|
2687
2942
|
if (existing) {
|
|
2688
2943
|
filled.push(existing);
|
|
2689
2944
|
} else {
|
|
@@ -2695,10 +2950,33 @@ function fillDateGaps({ rows, xKey, series, unit, range }) {
|
|
|
2695
2950
|
});
|
|
2696
2951
|
filled.push(zeroRow);
|
|
2697
2952
|
}
|
|
2698
|
-
cursor = cursor
|
|
2953
|
+
cursor = addPeriod(cursor, unit, timeZone);
|
|
2699
2954
|
}
|
|
2700
2955
|
return filled;
|
|
2701
2956
|
}
|
|
2957
|
+
function applyCumulative(rows, xKey, fields, baseline = {}) {
|
|
2958
|
+
if (!fields.length) return rows;
|
|
2959
|
+
const dated = rows.map((row, i) => ({ row, i, t: dayjs4(row?.[xKey]).valueOf() }));
|
|
2960
|
+
dated.sort((a, b) => {
|
|
2961
|
+
const at = Number.isFinite(a.t), bt = Number.isFinite(b.t);
|
|
2962
|
+
if (at && bt) return a.t - b.t || a.i - b.i;
|
|
2963
|
+
if (at !== bt) return at ? -1 : 1;
|
|
2964
|
+
return a.i - b.i;
|
|
2965
|
+
});
|
|
2966
|
+
const running = {};
|
|
2967
|
+
fields.forEach((f) => {
|
|
2968
|
+
running[f] = Number(baseline[f]) || 0;
|
|
2969
|
+
});
|
|
2970
|
+
return dated.map(({ row }) => {
|
|
2971
|
+
const next = { ...row };
|
|
2972
|
+
fields.forEach((f) => {
|
|
2973
|
+
const v = Number(row?.[f]);
|
|
2974
|
+
running[f] += Number.isFinite(v) ? v : 0;
|
|
2975
|
+
next[f] = running[f];
|
|
2976
|
+
});
|
|
2977
|
+
return next;
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2702
2980
|
function toNumber(v) {
|
|
2703
2981
|
if (typeof v === "number") return Number.isFinite(v) ? v : 0;
|
|
2704
2982
|
const n = Number(v);
|
|
@@ -2716,6 +2994,49 @@ function coerceSeriesNumbers(rows, series) {
|
|
|
2716
2994
|
});
|
|
2717
2995
|
}
|
|
2718
2996
|
|
|
2997
|
+
// src/transforms/percentiles.ts
|
|
2998
|
+
function percentileKey(name, percent) {
|
|
2999
|
+
return `${name}_p${String(Number(percent)).replace(".", "_")}`;
|
|
3000
|
+
}
|
|
3001
|
+
function percentileSummaries(summary) {
|
|
3002
|
+
return (summary || []).filter((s) => s?.type === "percentiles" && s.value).map((s) => s.value);
|
|
3003
|
+
}
|
|
3004
|
+
function readPercentiles(raw2) {
|
|
3005
|
+
if (raw2 == null || typeof raw2 !== "object") return null;
|
|
3006
|
+
const values = Array.isArray(raw2) ? raw2 : raw2.values ?? raw2;
|
|
3007
|
+
const out = {};
|
|
3008
|
+
if (Array.isArray(values)) {
|
|
3009
|
+
values.forEach((v) => {
|
|
3010
|
+
if (v && v.key != null) out[String(v.key)] = v.value;
|
|
3011
|
+
});
|
|
3012
|
+
} else if (typeof values === "object") {
|
|
3013
|
+
for (const [k, v] of Object.entries(values)) {
|
|
3014
|
+
if (k.endsWith("_as_string")) continue;
|
|
3015
|
+
if (Number.isFinite(Number(k))) out[k] = v;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
return Object.keys(out).length ? out : null;
|
|
3019
|
+
}
|
|
3020
|
+
function flattenPercentiles(rows, names) {
|
|
3021
|
+
if (!names.length) return rows;
|
|
3022
|
+
return rows.map((row) => {
|
|
3023
|
+
let next = row;
|
|
3024
|
+
for (const name of names) {
|
|
3025
|
+
const parsed = readPercentiles(row?.[name]);
|
|
3026
|
+
if (!parsed) continue;
|
|
3027
|
+
if (next === row) next = { ...row };
|
|
3028
|
+
let median;
|
|
3029
|
+
for (const [percent, value] of Object.entries(parsed)) {
|
|
3030
|
+
const n = value == null ? null : Number(value);
|
|
3031
|
+
next[percentileKey(name, percent)] = n;
|
|
3032
|
+
if (Number(percent) === 50 && n != null) median = n;
|
|
3033
|
+
}
|
|
3034
|
+
if (median !== void 0) next[name] = median;
|
|
3035
|
+
}
|
|
3036
|
+
return next;
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
3039
|
+
|
|
2719
3040
|
// src/react/useWidgetData.ts
|
|
2720
3041
|
var ALIGN_TYPES = /* @__PURE__ */ new Set(["BAR", "BAR_CHART", "PIE", "PIE_CHART", "DOUGHNUT", "DOUGHNUT_CHART"]);
|
|
2721
3042
|
var formCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -2736,6 +3057,27 @@ function getFormOnce(client, formId) {
|
|
|
2736
3057
|
}
|
|
2737
3058
|
return p;
|
|
2738
3059
|
}
|
|
3060
|
+
function baselineClause(source, start) {
|
|
3061
|
+
const f = (source.dataSource?.fields || []).find(
|
|
3062
|
+
(x) => x?.header === source.dateField || x?.masterfield === source.dateField
|
|
3063
|
+
);
|
|
3064
|
+
return {
|
|
3065
|
+
header: f?.header ?? source.dateField,
|
|
3066
|
+
masterfield: f?.masterfield ?? source.dateField,
|
|
3067
|
+
masterFieldType: f?.masterFieldType ?? "DATE_PICKER",
|
|
3068
|
+
masterFieldDataType: f?.masterFieldDataType ?? "STRING",
|
|
3069
|
+
// Date-only: the query generator keeps "YYYY-MM-DD" operands as dates.
|
|
3070
|
+
filter: { operator: "LESS_THAN", operand: [start.format("YYYY-MM-DD")] }
|
|
3071
|
+
};
|
|
3072
|
+
}
|
|
3073
|
+
function readBaseline(rows) {
|
|
3074
|
+
const out = {};
|
|
3075
|
+
for (const [k, v] of Object.entries(rows?.[0] ?? {})) {
|
|
3076
|
+
const n = Number(v);
|
|
3077
|
+
if (Number.isFinite(n)) out[k] = n;
|
|
3078
|
+
}
|
|
3079
|
+
return out;
|
|
3080
|
+
}
|
|
2739
3081
|
function useDebounced(value, ms, enabled) {
|
|
2740
3082
|
const [v, setV] = useState(value);
|
|
2741
3083
|
useEffect(() => {
|
|
@@ -2815,13 +3157,34 @@ function useWidgetData(args) {
|
|
|
2815
3157
|
const localKey = JSON.stringify(localFilters ?? {});
|
|
2816
3158
|
const dsKey = JSON.stringify(dataSource ?? {});
|
|
2817
3159
|
const remoteKey = JSON.stringify(remote);
|
|
2818
|
-
const
|
|
2819
|
-
|
|
3160
|
+
const dateGapKey = JSON.stringify(dateGap ?? null);
|
|
3161
|
+
const gapTimeZone = useMemo(() => {
|
|
3162
|
+
if (dateGap?.timeZone) return dateGap.timeZone;
|
|
3163
|
+
const row = (dataSource?.pivot?.rows || []).find((r) => r?.title === xKey && r?.interval);
|
|
3164
|
+
return row?.timeZone || void 0;
|
|
3165
|
+
}, [dateGap?.timeZone, dataSource, xKey]);
|
|
3166
|
+
const normalize = useCallback((incoming, fetchedBaseline) => {
|
|
3167
|
+
const percentiles = percentileSummaries(dataSource?.pivot?.summary);
|
|
3168
|
+
const flat = percentiles.length ? flattenPercentiles(incoming, percentiles) : incoming;
|
|
3169
|
+
const withPostOps = applyPostOperations(flat, dataSource?.pivot?.postOperations);
|
|
2820
3170
|
const numeric = coerceSeriesNumbers(withPostOps, series);
|
|
2821
3171
|
if (!dateGap) return numeric;
|
|
2822
|
-
const
|
|
2823
|
-
|
|
2824
|
-
|
|
3172
|
+
const tz = gapTimeZone;
|
|
3173
|
+
const period = (v) => startOfPeriod(parseDateValue(v, tz), dateGap.unit, tz);
|
|
3174
|
+
const range = dateGap.start && dateGap.end ? { start: period(dateGap.start), end: period(dateGap.end) } : null;
|
|
3175
|
+
const filled = fillDateGaps({ rows: numeric, xKey, series, unit: dateGap.unit, range, merge: dateGap.merge, timeZone: tz });
|
|
3176
|
+
if (!dateGap.cumulative) return filled;
|
|
3177
|
+
let inRange = filled;
|
|
3178
|
+
if (dateGap.start && !range) {
|
|
3179
|
+
const from = period(dateGap.start).valueOf();
|
|
3180
|
+
inRange = filled.filter((row) => {
|
|
3181
|
+
const d = parseDateValue(row?.[xKey], tz);
|
|
3182
|
+
return !d.isValid() || startOfPeriod(d, dateGap.unit, tz).valueOf() >= from;
|
|
3183
|
+
});
|
|
3184
|
+
}
|
|
3185
|
+
const fields = dateGap.cumulative === true ? series.map((s) => s.valueField) : dateGap.cumulative;
|
|
3186
|
+
return applyCumulative(inRange, xKey, fields, { ...fetchedBaseline || {}, ...dateGap.baseline || {} });
|
|
3187
|
+
}, [dataSource, series, xKey, dateGap, gapTimeZone]);
|
|
2825
3188
|
useEffect(() => {
|
|
2826
3189
|
if (automationRows) {
|
|
2827
3190
|
if (automationLoading) {
|
|
@@ -2843,53 +3206,67 @@ function useWidgetData(args) {
|
|
|
2843
3206
|
let cancelled = false;
|
|
2844
3207
|
setError(null);
|
|
2845
3208
|
setLoading(true);
|
|
3209
|
+
const queryForm = async (ds, mode, extraClauses = []) => {
|
|
3210
|
+
const formId = ds.formId ?? ds.fields?.[0]?.formID;
|
|
3211
|
+
const withFormId = formId ? { ...ds, formId } : ds;
|
|
3212
|
+
const merged = mergeHostFilters(localFilters, dashFilters);
|
|
3213
|
+
const cfgWithDates = { ...config, cdateFilters: mode === "main" ? cdateFilters : [] };
|
|
3214
|
+
const dashboardFilters = rt.formatDashboardFilters ? [...rt.formatDashboardFilters(cfgWithDates, withFormId, merged) || []] : [];
|
|
3215
|
+
if (remote.widgetFilters?.length) {
|
|
3216
|
+
dashboardFilters.push(...buildWidgetFilterClauses(withFormId, remote.widgetFilters));
|
|
3217
|
+
}
|
|
3218
|
+
if (mode === "main" && remote.columnFilters && Object.keys(remote.columnFilters).length) {
|
|
3219
|
+
dashboardFilters.push(...rt.formatHeaderFilters ? rt.formatHeaderFilters(withFormId, remote.columnFilters) || [] : buildColumnFilterClauses(withFormId, remote.columnFilters));
|
|
3220
|
+
}
|
|
3221
|
+
const searchClause = mode === "main" ? buildSearchClause(remote.search) : null;
|
|
3222
|
+
if (searchClause) dashboardFilters.push(searchClause);
|
|
3223
|
+
dashboardFilters.push(...extraClauses);
|
|
3224
|
+
const { dashboardSort, config: queryConfig } = buildRemoteSort(config, withFormId, mode === "main" ? remote.sort : null);
|
|
3225
|
+
if (formId && !ds.isTask && rt.client?.workflow?.getSingleForm) {
|
|
3226
|
+
const form = await getFormOnce(rt.client, formId).catch((e) => {
|
|
3227
|
+
console.warn(`[@zestl/zvolv-widgets] form lookup failed for ${formId}; querying anyway`, e);
|
|
3228
|
+
return true;
|
|
3229
|
+
});
|
|
3230
|
+
if (!form) throw new Error("You don't have access to this widget's form.");
|
|
3231
|
+
}
|
|
3232
|
+
const fixedDs = mode === "main" && ALIGN_TYPES.has(String(widgetType ?? "").toUpperCase()) && hasDeclaredSeries(config) ? alignSummaryToSeries(withFormId, series) : withFormId;
|
|
3233
|
+
const loggedInUser = rt.resolveQueryUser ? await rt.resolveQueryUser() : null;
|
|
3234
|
+
const mappings = rt.prefetchQueryMappings ? await rt.prefetchQueryMappings(fixedDs.formId) : void 0;
|
|
3235
|
+
if (!rt.generateQuery) throw new Error("runtime.generateQuery is not configured");
|
|
3236
|
+
const query = rt.generateQuery(
|
|
3237
|
+
queryConfig,
|
|
3238
|
+
fixedDs,
|
|
3239
|
+
fixedDs.formId,
|
|
3240
|
+
0,
|
|
3241
|
+
rowLimit,
|
|
3242
|
+
[],
|
|
3243
|
+
dashboardFilters,
|
|
3244
|
+
[],
|
|
3245
|
+
loggedInUser,
|
|
3246
|
+
dashboardSort,
|
|
3247
|
+
null,
|
|
3248
|
+
fixedDs.isTask,
|
|
3249
|
+
mappings
|
|
3250
|
+
);
|
|
3251
|
+
const res = await rt.client.workflow.elasticSearch(query);
|
|
3252
|
+
return Array.isArray(res) ? res : res?.elements ?? res?.data ?? [];
|
|
3253
|
+
};
|
|
2846
3254
|
(async () => {
|
|
2847
3255
|
try {
|
|
2848
3256
|
const ds = dataSource || {};
|
|
2849
3257
|
let fetched = [];
|
|
3258
|
+
let fetchedBaseline;
|
|
2850
3259
|
if (usesFormFramework(ds)) {
|
|
2851
|
-
const
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
}
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
}
|
|
2862
|
-
const searchClause = buildSearchClause(remote.search);
|
|
2863
|
-
if (searchClause) dashboardFilters.push(searchClause);
|
|
2864
|
-
const { dashboardSort, config: queryConfig } = buildRemoteSort(config, withFormId, remote.sort);
|
|
2865
|
-
if (formId && !ds.isTask && rt.client?.workflow?.getSingleForm) {
|
|
2866
|
-
const form = await getFormOnce(rt.client, formId).catch((e) => {
|
|
2867
|
-
console.warn(`[@zestl/zvolv-widgets] form lookup failed for ${formId}; querying anyway`, e);
|
|
2868
|
-
return true;
|
|
2869
|
-
});
|
|
2870
|
-
if (!form) throw new Error("You don't have access to this widget's form.");
|
|
2871
|
-
}
|
|
2872
|
-
const fixedDs = ALIGN_TYPES.has(String(widgetType ?? "").toUpperCase()) && hasDeclaredSeries(config) ? alignSummaryToSeries(withFormId, series) : withFormId;
|
|
2873
|
-
const loggedInUser = rt.resolveQueryUser ? await rt.resolveQueryUser() : null;
|
|
2874
|
-
const mappings = rt.prefetchQueryMappings ? await rt.prefetchQueryMappings(fixedDs.formId) : void 0;
|
|
2875
|
-
if (!rt.generateQuery) throw new Error("runtime.generateQuery is not configured");
|
|
2876
|
-
const query = rt.generateQuery(
|
|
2877
|
-
queryConfig,
|
|
2878
|
-
fixedDs,
|
|
2879
|
-
fixedDs.formId,
|
|
2880
|
-
0,
|
|
2881
|
-
rowLimit,
|
|
2882
|
-
[],
|
|
2883
|
-
dashboardFilters,
|
|
2884
|
-
[],
|
|
2885
|
-
loggedInUser,
|
|
2886
|
-
dashboardSort,
|
|
2887
|
-
null,
|
|
2888
|
-
fixedDs.isTask,
|
|
2889
|
-
mappings
|
|
2890
|
-
);
|
|
2891
|
-
const res = await rt.client.workflow.elasticSearch(query);
|
|
2892
|
-
fetched = Array.isArray(res) ? res : res?.elements ?? res?.data ?? [];
|
|
3260
|
+
const baselineReq = dateGap?.baselineSource && dateGap.start ? queryForm(
|
|
3261
|
+
dateGap.baselineSource.dataSource,
|
|
3262
|
+
"baseline",
|
|
3263
|
+
[baselineClause(dateGap.baselineSource, startOfPeriod(parseDateValue(dateGap.start, gapTimeZone), dateGap.unit, gapTimeZone))]
|
|
3264
|
+
).catch((e) => {
|
|
3265
|
+
console.warn("[@zestl/zvolv-widgets] dateGap baseline fetch failed; starting from 0", e);
|
|
3266
|
+
return [];
|
|
3267
|
+
}) : null;
|
|
3268
|
+
fetched = await queryForm(ds, "main");
|
|
3269
|
+
if (baselineReq) fetchedBaseline = readBaseline(await baselineReq);
|
|
2893
3270
|
} else {
|
|
2894
3271
|
const wftype = config?.dataConfs?.WorkflowTypeID ?? workflowTypeId;
|
|
2895
3272
|
const res = await rt.client.workflow.getDataSource(JSON.stringify({ widgetId, wftype }));
|
|
@@ -2897,7 +3274,7 @@ function useWidgetData(args) {
|
|
|
2897
3274
|
fetched = payload?.table ?? (Array.isArray(payload) ? payload : []);
|
|
2898
3275
|
}
|
|
2899
3276
|
if (cancelled || seq !== reqSeq.current) return;
|
|
2900
|
-
setSourceRows(normalize(fetched));
|
|
3277
|
+
setSourceRows(normalize(fetched, fetchedBaseline));
|
|
2901
3278
|
} catch (err) {
|
|
2902
3279
|
if (cancelled || seq !== reqSeq.current) return;
|
|
2903
3280
|
console.error(`[@zestl/zvolv-widgets] ${widgetType ?? "widget"} fetch failed:`, err);
|
|
@@ -2913,7 +3290,7 @@ function useWidgetData(args) {
|
|
|
2913
3290
|
return () => {
|
|
2914
3291
|
cancelled = true;
|
|
2915
3292
|
};
|
|
2916
|
-
}, [configKey, dashKey, cdateKey, localKey, dsKey, remoteKey, configured, nonce, automationRows, automationLoading]);
|
|
3293
|
+
}, [configKey, dashKey, cdateKey, localKey, dsKey, remoteKey, dateGapKey, configured, nonce, automationRows, automationLoading]);
|
|
2917
3294
|
const userKind = useMemo(() => {
|
|
2918
3295
|
if (!rt.getUserFieldKind) return null;
|
|
2919
3296
|
const field2 = (dataSource?.fields || []).find(
|
|
@@ -3265,7 +3642,7 @@ function useInteractiveWidgetData(props, options = {}) {
|
|
|
3265
3642
|
tokens: t
|
|
3266
3643
|
};
|
|
3267
3644
|
parts.push(
|
|
3268
|
-
/* @__PURE__ */ jsx(
|
|
3645
|
+
/* @__PURE__ */ jsx(React14.Fragment, { children: props.renderSortIndicator ? props.renderSortIndicator(args) : /* @__PURE__ */ jsx(DefaultSortIndicator, { ...args }) }, "sort")
|
|
3269
3646
|
);
|
|
3270
3647
|
}
|
|
3271
3648
|
if (flags.showColumnFilter) {
|
|
@@ -3279,7 +3656,7 @@ function useInteractiveWidgetData(props, options = {}) {
|
|
|
3279
3656
|
tokens: t
|
|
3280
3657
|
};
|
|
3281
3658
|
parts.push(
|
|
3282
|
-
/* @__PURE__ */ jsx(
|
|
3659
|
+
/* @__PURE__ */ jsx(React14.Fragment, { children: props.renderColumnFilter ? props.renderColumnFilter(args) : /* @__PURE__ */ jsx(DefaultColumnFilter, { ...args }) }, "filter")
|
|
3283
3660
|
);
|
|
3284
3661
|
}
|
|
3285
3662
|
return parts.length ? /* @__PURE__ */ jsx(Fragment, { children: parts }) : null;
|
|
@@ -3767,31 +4144,100 @@ function resolveDrillDown(config = {}) {
|
|
|
3767
4144
|
}
|
|
3768
4145
|
var WIDGET_TYPE = "KPI_CARD";
|
|
3769
4146
|
var KpiWidget = (props) => {
|
|
3770
|
-
const {
|
|
4147
|
+
const {
|
|
4148
|
+
title,
|
|
4149
|
+
description,
|
|
4150
|
+
emptyMessage,
|
|
4151
|
+
unconfiguredMessage,
|
|
4152
|
+
className,
|
|
4153
|
+
style,
|
|
4154
|
+
onItemClick,
|
|
4155
|
+
externalSeriesByIndex,
|
|
4156
|
+
...dataArgs
|
|
4157
|
+
} = props;
|
|
3771
4158
|
const ix = useInteractiveWidgetData({ ...dataArgs, widgetType: WIDGET_TYPE });
|
|
3772
4159
|
const { data, config, tokens: t } = ix;
|
|
3773
4160
|
const chrome = resolveChromeConfig(config);
|
|
3774
4161
|
const contents = config?.cardConfig?.contents ?? config?.contents ?? [];
|
|
3775
4162
|
const cardTemplate = config?.cardConfig?.template ?? config?.template ?? "standard";
|
|
3776
|
-
const
|
|
4163
|
+
const [fetchedSeries, setFetchedSeries] = useState({});
|
|
4164
|
+
const onSeries = useCallback((index, values) => {
|
|
4165
|
+
setFetchedSeries((prev) => {
|
|
4166
|
+
if (JSON.stringify(prev[index]) === JSON.stringify(values)) return prev;
|
|
4167
|
+
const next = { ...prev };
|
|
4168
|
+
if (values) next[index] = values;
|
|
4169
|
+
else delete next[index];
|
|
4170
|
+
return next;
|
|
4171
|
+
});
|
|
4172
|
+
}, []);
|
|
4173
|
+
const seriesByIndex = useMemo(
|
|
4174
|
+
() => externalSeriesByIndex ? { ...fetchedSeries, ...externalSeriesByIndex } : fetchedSeries,
|
|
4175
|
+
[fetchedSeries, externalSeriesByIndex]
|
|
4176
|
+
);
|
|
4177
|
+
const vms = useKpiContents({ contents, rows: data.rows, cardTemplate, externalSeriesByIndex: seriesByIndex });
|
|
3777
4178
|
const state = data.state === "empty" && contents.length > 0 ? "ready" : data.state;
|
|
3778
|
-
return /* @__PURE__ */
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
4179
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4180
|
+
contents.map(
|
|
4181
|
+
(content, i) => content?.seriesSource?.mode === "timeseries" && content.seriesSource.dataSource && !externalSeriesByIndex?.[i] ? /* @__PURE__ */ jsx(
|
|
4182
|
+
KpiSeriesFetcher,
|
|
4183
|
+
{
|
|
4184
|
+
index: i,
|
|
4185
|
+
source: content.seriesSource,
|
|
4186
|
+
onSeries,
|
|
4187
|
+
dashFilters: dataArgs.dashFilters,
|
|
4188
|
+
cdateFilters: dataArgs.cdateFilters,
|
|
4189
|
+
localFilters: dataArgs.localFilters,
|
|
4190
|
+
workflowTypeId: dataArgs.workflowTypeId
|
|
4191
|
+
},
|
|
4192
|
+
i
|
|
4193
|
+
) : null
|
|
4194
|
+
),
|
|
4195
|
+
/* @__PURE__ */ jsx(
|
|
4196
|
+
WidgetShell,
|
|
4197
|
+
{
|
|
4198
|
+
widgetType: WIDGET_TYPE,
|
|
4199
|
+
title: chrome.showHeader ? title ?? chrome.title : void 0,
|
|
4200
|
+
description: description ?? chrome.description,
|
|
4201
|
+
state,
|
|
4202
|
+
error: data.error,
|
|
4203
|
+
emptyMessage: emptyMessage ?? chrome.emptyMessage,
|
|
4204
|
+
unconfiguredMessage,
|
|
4205
|
+
className,
|
|
4206
|
+
style,
|
|
4207
|
+
actions: ix.toolbar,
|
|
4208
|
+
...ix.shell,
|
|
4209
|
+
children: /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 14, height: "100%" }, children: vms.map((vm, i) => /* @__PURE__ */ jsx(KpiItem, { vm, index: i, onClick: onItemClick }, i)) })
|
|
4210
|
+
}
|
|
4211
|
+
)
|
|
4212
|
+
] });
|
|
4213
|
+
};
|
|
4214
|
+
var KpiSeriesFetcher = ({ index, source, onSeries, dashFilters, cdateFilters, localFilters, workflowTypeId }) => {
|
|
4215
|
+
const { dataSource, xField, valueField, dateGap } = source;
|
|
4216
|
+
const configurations = useMemo(
|
|
4217
|
+
() => ({ series: [{ argumentField: xField, valueField }] }),
|
|
4218
|
+
[xField, valueField]
|
|
3794
4219
|
);
|
|
4220
|
+
const data = useWidgetData({
|
|
4221
|
+
widgetType: "KPI_SERIES",
|
|
4222
|
+
dataSource,
|
|
4223
|
+
configurations,
|
|
4224
|
+
dateGap: dateGap ?? null,
|
|
4225
|
+
dashFilters,
|
|
4226
|
+
cdateFilters,
|
|
4227
|
+
localFilters,
|
|
4228
|
+
workflowTypeId
|
|
4229
|
+
});
|
|
4230
|
+
const values = useMemo(
|
|
4231
|
+
() => data.rows.map((r) => toNum(r?.[valueField])).filter((n) => n != null),
|
|
4232
|
+
[data.rows, valueField]
|
|
4233
|
+
);
|
|
4234
|
+
const ready = data.state === "ready" || data.state === "empty";
|
|
4235
|
+
const key = ready ? JSON.stringify(values) : "";
|
|
4236
|
+
useEffect(() => {
|
|
4237
|
+
onSeries(index, ready ? values : void 0);
|
|
4238
|
+
}, [index, key, ready, onSeries]);
|
|
4239
|
+
useEffect(() => () => onSeries(index, void 0), [index, onSeries]);
|
|
4240
|
+
return null;
|
|
3795
4241
|
};
|
|
3796
4242
|
var KpiItem = ({
|
|
3797
4243
|
vm,
|
|
@@ -3848,7 +4294,7 @@ var ChartWidget = (props) => {
|
|
|
3848
4294
|
const renderer = render ?? children;
|
|
3849
4295
|
let body;
|
|
3850
4296
|
if (renderer) body = renderer(args);
|
|
3851
|
-
else if (override) body =
|
|
4297
|
+
else if (override) body = React14.createElement(override, args);
|
|
3852
4298
|
else body = /* @__PURE__ */ jsx(FallbackBars, { ...args });
|
|
3853
4299
|
return /* @__PURE__ */ jsx(
|
|
3854
4300
|
WidgetShell,
|
|
@@ -3958,7 +4404,7 @@ var RankingBarWidget = (props) => {
|
|
|
3958
4404
|
style,
|
|
3959
4405
|
actions: ix.toolbar,
|
|
3960
4406
|
...ix.shell,
|
|
3961
|
-
children: render ? render(args) : override ?
|
|
4407
|
+
children: render ? render(args) : override ? React14.createElement(override, args) : /* @__PURE__ */ jsx(DefaultRanking, { ...args })
|
|
3962
4408
|
}
|
|
3963
4409
|
);
|
|
3964
4410
|
};
|
|
@@ -4246,7 +4692,7 @@ var CollectionWidget = (props) => {
|
|
|
4246
4692
|
style,
|
|
4247
4693
|
actions: ix.toolbar,
|
|
4248
4694
|
...ix.shell,
|
|
4249
|
-
children: render ? render(args) : override ?
|
|
4695
|
+
children: render ? render(args) : override ? React14.createElement(override, args) : /* @__PURE__ */ jsx(DefaultList, { ...args })
|
|
4250
4696
|
}
|
|
4251
4697
|
);
|
|
4252
4698
|
};
|
|
@@ -4496,7 +4942,7 @@ var PivotGridWidget = (props) => {
|
|
|
4496
4942
|
};
|
|
4497
4943
|
function toDate(v) {
|
|
4498
4944
|
if (v === null || v === void 0 || v === "") return null;
|
|
4499
|
-
const d =
|
|
4945
|
+
const d = dayjs4(v);
|
|
4500
4946
|
return d.isValid() ? d.toDate() : null;
|
|
4501
4947
|
}
|
|
4502
4948
|
function useTemporalEvents(rows, mapping) {
|
|
@@ -4521,7 +4967,7 @@ function useTemporalEvents(rows, mapping) {
|
|
|
4521
4967
|
start,
|
|
4522
4968
|
end,
|
|
4523
4969
|
// With no time component on either bound, treat it as an all-day span.
|
|
4524
|
-
allDay: !!(start && !end) || !!start &&
|
|
4970
|
+
allDay: !!(start && !end) || !!start && dayjs4(start).startOf("day").isSame(start),
|
|
4525
4971
|
status: statusRaw !== void 0 ? { label: statusRaw, tone: statusTone(statusRaw) } : void 0,
|
|
4526
4972
|
progress: Number.isFinite(rawProgress) ? Math.max(0, Math.min(1, rawProgress > 1 ? rawProgress / 100 : rawProgress)) : void 0,
|
|
4527
4973
|
color: colorField ? row?.[colorField] : void 0,
|
|
@@ -4588,7 +5034,7 @@ var TemporalWidget = (props) => {
|
|
|
4588
5034
|
style,
|
|
4589
5035
|
actions: ix.toolbar,
|
|
4590
5036
|
...ix.shell,
|
|
4591
|
-
children: render ? render(args) : override ?
|
|
5037
|
+
children: render ? render(args) : override ? React14.createElement(override, args) : /* @__PURE__ */ jsx(DefaultTimeline, { ...args })
|
|
4592
5038
|
}
|
|
4593
5039
|
);
|
|
4594
5040
|
};
|
|
@@ -4615,8 +5061,8 @@ var DefaultTimeline = ({ events, tokens: t, onEventClick }) => /* @__PURE__ */ j
|
|
|
4615
5061
|
/* @__PURE__ */ jsxs("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
4616
5062
|
/* @__PURE__ */ jsx("div", { style: { fontSize: t.typography.body.fontSize, color: t.colors.textPrimary, fontWeight: 600 }, children: String(e.title ?? "") }),
|
|
4617
5063
|
/* @__PURE__ */ jsxs("div", { style: { fontSize: t.typography.caption.fontSize, color: t.colors.textTertiary }, children: [
|
|
4618
|
-
e.start ?
|
|
4619
|
-
e.end ? ` \u2192 ${
|
|
5064
|
+
e.start ? dayjs4(e.start).format("DD MMM YYYY") : "",
|
|
5065
|
+
e.end ? ` \u2192 ${dayjs4(e.end).format("DD MMM YYYY")}` : "",
|
|
4620
5066
|
e.group ? ` \xB7 ${String(e.group)}` : ""
|
|
4621
5067
|
] })
|
|
4622
5068
|
] }),
|
|
@@ -4711,7 +5157,7 @@ var StepperWidget = (props) => {
|
|
|
4711
5157
|
style,
|
|
4712
5158
|
actions: ix.toolbar,
|
|
4713
5159
|
...ix.shell,
|
|
4714
|
-
children: render ? render(args) : override ?
|
|
5160
|
+
children: render ? render(args) : override ? React14.createElement(override, args) : /* @__PURE__ */ jsx(DefaultStepper, { ...args })
|
|
4715
5161
|
}
|
|
4716
5162
|
);
|
|
4717
5163
|
};
|
|
@@ -4783,7 +5229,7 @@ function renderHtmlVariables(template, rows, variables) {
|
|
|
4783
5229
|
} else if (v.dataFormat === "AMOUNT" && typeof value === "number") {
|
|
4784
5230
|
value = formatAmountValue(value, v.amountSuffix || "Rupees", v.precision ?? 2);
|
|
4785
5231
|
} else if (v.dataFormat === "DATE" && value) {
|
|
4786
|
-
const d =
|
|
5232
|
+
const d = dayjs4(value);
|
|
4787
5233
|
if (d.isValid()) value = d.format(DATE_FORMAT_MAP[v.dateFormat] || "DD/MM/YYYY");
|
|
4788
5234
|
}
|
|
4789
5235
|
let text2;
|
|
@@ -5863,7 +6309,7 @@ function dynamicDefault(el2, user) {
|
|
|
5863
6309
|
const t = resolveFieldType(el2);
|
|
5864
6310
|
if ((dd.operator === "ADD" || dd.operator === "SUB") && (t === "DATE_PICKER" || t === "DATE_TIME_PICKER")) {
|
|
5865
6311
|
const sign = dd.operator === "SUB" ? -1 : 1;
|
|
5866
|
-
let d =
|
|
6312
|
+
let d = dayjs4();
|
|
5867
6313
|
const u = dd.units;
|
|
5868
6314
|
if (typeof u === "number" || typeof u === "string" && u.trim() !== "" && !isNaN(Number(u))) d = d.add(sign * Number(u), "day");
|
|
5869
6315
|
else Object.entries(u ?? {}).forEach(([k, n]) => {
|
|
@@ -5903,7 +6349,7 @@ function buildInitialValues(elements, opts = {}) {
|
|
|
5903
6349
|
}
|
|
5904
6350
|
function formatDateish(t, value) {
|
|
5905
6351
|
const isDayjs = (v) => v && typeof v === "object" && typeof v.isValid === "function" && typeof v.format === "function";
|
|
5906
|
-
const toD = (v) => isDayjs(v) ? v : v instanceof Date ?
|
|
6352
|
+
const toD = (v) => isDayjs(v) ? v : v instanceof Date ? dayjs4(v) : typeof v === "string" && v ? dayjs4(v) : null;
|
|
5907
6353
|
if (t === "DATE_PICKER") {
|
|
5908
6354
|
const d = toD(value);
|
|
5909
6355
|
return d?.isValid() ? d.format("YYYY-MM-DD") : value;
|
|
@@ -6018,9 +6464,9 @@ function formatFieldValue(el2, value) {
|
|
|
6018
6464
|
const t = resolveFieldType(el2);
|
|
6019
6465
|
if (t === "CHECK_BOX") return value ? "Yes" : "No";
|
|
6020
6466
|
if (RELATIONAL_TYPES.has(t)) return (Array.isArray(value) ? value : [value]).map((v) => v?.view ?? v?.select ?? String(v)).join(", ");
|
|
6021
|
-
if (t === "INPUT_DATE_RANGE" && Array.isArray(value)) return value.filter(Boolean).map((v) =>
|
|
6022
|
-
if (t === "DATE_PICKER") return
|
|
6023
|
-
if (t === "DATE_TIME_PICKER") return
|
|
6467
|
+
if (t === "INPUT_DATE_RANGE" && Array.isArray(value)) return value.filter(Boolean).map((v) => dayjs4(v).format("D MMM YYYY")).join(" \u2013 ");
|
|
6468
|
+
if (t === "DATE_PICKER") return dayjs4(value).isValid() ? dayjs4(value).format("D MMM YYYY") : String(value);
|
|
6469
|
+
if (t === "DATE_TIME_PICKER") return dayjs4(value).isValid() ? dayjs4(value).format("D MMM YYYY, HH:mm") : String(value);
|
|
6024
6470
|
if (t === "INPUT_PERCENT") return `${value}%`;
|
|
6025
6471
|
if (Array.isArray(value)) return value.map((v) => v?.media_name ?? v?.view ?? String(v)).join(", ");
|
|
6026
6472
|
return String(value);
|
|
@@ -6838,9 +7284,9 @@ function acceptOf(el2) {
|
|
|
6838
7284
|
if (!list.length) return el2.type === "UPLOAD_FILE_IMAGE" ? "image/*" : void 0;
|
|
6839
7285
|
return list.map((s) => s.includes("/") || s.startsWith(".") ? s : `.${s}`).join(",");
|
|
6840
7286
|
}
|
|
6841
|
-
var FormApiContext =
|
|
7287
|
+
var FormApiContext = React14.createContext(null);
|
|
6842
7288
|
function useFormApi() {
|
|
6843
|
-
const f =
|
|
7289
|
+
const f = React14.useContext(FormApiContext);
|
|
6844
7290
|
if (!f) throw new Error("@zestl/zvolv-widgets: useFormApi must be used inside <ZvolvForm> or FormApiContext");
|
|
6845
7291
|
return f;
|
|
6846
7292
|
}
|
|
@@ -7656,10 +8102,10 @@ function useTrialField(form, field2) {
|
|
|
7656
8102
|
chain
|
|
7657
8103
|
};
|
|
7658
8104
|
}
|
|
7659
|
-
var FormKitSlot =
|
|
8105
|
+
var FormKitSlot = React14.createContext(null);
|
|
7660
8106
|
function useKit(local) {
|
|
7661
|
-
const ctx =
|
|
7662
|
-
return
|
|
8107
|
+
const ctx = React14.useContext(FormKitSlot);
|
|
8108
|
+
return React14.useMemo(() => ({ ...ctx ?? {}, ...local ?? {} }), [ctx, local]);
|
|
7663
8109
|
}
|
|
7664
8110
|
var FormFields = ({ form, fields, kit: local }) => {
|
|
7665
8111
|
const kit = useKit(local);
|
|
@@ -8371,7 +8817,7 @@ function buildDashFilters(values = [], dateRange, operator = "AND") {
|
|
|
8371
8817
|
}
|
|
8372
8818
|
function dateRangeFor(token) {
|
|
8373
8819
|
const f = (d) => d.format("YYYY-MM-DD");
|
|
8374
|
-
const now =
|
|
8820
|
+
const now = dayjs4();
|
|
8375
8821
|
switch (token) {
|
|
8376
8822
|
case "TODAY":
|
|
8377
8823
|
return { start: f(now), end: f(now) };
|
|
@@ -8780,6 +9226,6 @@ function formWidget(o) {
|
|
|
8780
9226
|
};
|
|
8781
9227
|
}
|
|
8782
9228
|
|
|
8783
|
-
export { ActionCardWidget, ActivityFeedWidget, AreaChartWidget, BLOCKED_FILE_EXTENSIONS, BannerWidget, BarChartWidget, COLUMN_FILTER_BLANK, CONTAINER_KINDS, CalendarWidget, CardListWidget, CarouselWidget, ChartWidget, ChildTableWidget, CollectionWidget, DashboardTableWidget, DatabaseTableWidget, DefaultField, DoughnutChartWidget, EMPTY_INTERACTIONS, EntityGalleryWidget, FilterPanelWidget, FormApiContext, FormFields, FormKitSlot, FormWidget, GRID, GanttChartWidget, GaugeMeterWidget, GoogleMapWidget, GridCardWidget, HeatMapWidget, HtmlWidget, IframeWidget, KPI_DEFAULT_TEMPLATES, Delta as KpiDelta, Label as KpiLabel, Sparkline as KpiSparkline, Value as KpiValue, KpiWidget, LineChartWidget, MeetingSchedulerWidget, NON_INPUT_TYPES, NON_RENDERING_TYPES, PREFIX_UNITS, PieChartWidget, PivotGridWidget, RankingBarWidget, RawHtmlWidget, SAMPLE_ROWS, SUBMISSION_SKIP_TYPES, SUFFIX_UNITS, ScatterChartWidget, StepperWidget, TabWidget, TableWidget, TaskTrackerTableWidget, TemplateProvider, TemporalWidget, TimelineWidget, TreeWidget, WIDGET_REGISTRY, WidgetShell, WidgetStateSlot, ZaiChatWidget, ZvolvForm, ZvolvProvider, ZvolvThemeProvider, ZvolvWidget, aggregate, alignSummaryToSeries, applyLocalColumnFilters, applyLocalSearch, applyLocalSort, applyLocalWidgetFilters, applyPostOperations, applyRules, automationSource, buildColumnFilterClauses, buildDashFilters, buildDashboardTree, buildInitialValues, buildRemoteSort, buildSearchClause, buildSubmissionElements, buildTree, buildTriggerBody, buildWidgetFilterClauses, cascade, cdateFiltersFor, childIdsOf, cleanTitle, clearLookupCache, coerceSeriesNumbers, computeRowFormulas, createMockRuntime, createSubmission, createZvolvRuntime, dashboardDefaultDateToken, dashboardFilterDefs, dateRangeFor, defaultTokens, defineConfig, defineForm, derive, describeWidgetFilter, distinctColumnValues, eid, el, evaluateFormula, extractAgentFormData, fetchForm, fetchLookupOptions, fetchSubmission, field, fieldKind, fieldKindOf, fillDateGaps, filterableFields, formSource, formWidget, formatAmountValue, formatCompact, formatFieldValue, formulaLabels, getDataType2 as getDataType, getEmptyValue, getPostOpOperandSet, getPostOpResult, gridHeight, gridWidgets, groupBy, hasActiveInteractions, inspectForm, interpolate, invokeAgent, invokeTrigger, invokeZeno, isDataSourceConfigured, isLegacyId, isLikelyTimestamp, isServerSafeFormula, lookupConfigOf, mergeTokens, normaliseElement, normaliseForm, normalizeWidget, openFormRequest, operatorsForKind, optionFilterRules, parseConfig, parseDeep, pivot, renderHtmlVariables, resetQueryUser, resolveChrome, resolveChromeConfig, resolveCollectionMapping, resolveDashboardLayout, resolveDateToken, resolveDrillDown, resolveFieldType, resolveFilterMode, resolveFormWidget, resolveSeries, resolveTableMode, resolveWidget, resolveWidgetDefaults, resolveXKey, rowSubmissionIds, ruleMatches, rulesOf, searchPeople, serializeElementValue, statusTone, submissionIdOf, submissionToValues, submitElementsOf, taskField, taskSource, toBraceFormula, toNum, toRelational, toneColor, toneSurface, updateSubmission, uploadFile, useCollectionItems, useFieldOptions, useFileField, useFormApi, useFormInspector, useInteractiveWidgetData, useKpiContents, useSheetField, useTableColumns, useTemplateOverride, useTemporalEvents, useTokens, useTrialField, useWidgetData, useWidgetInteractions, useZvolvClient, useZvolvForm, useZvolvRuntime, usesFormFramework, validateField, validateForm, when, where };
|
|
9229
|
+
export { ActionCardWidget, ActivityFeedWidget, AreaChartWidget, BLOCKED_FILE_EXTENSIONS, BannerWidget, BarChartWidget, COLUMN_FILTER_BLANK, CONTAINER_KINDS, CalendarWidget, CardListWidget, CarouselWidget, ChartWidget, ChildTableWidget, CollectionWidget, DashboardTableWidget, DatabaseTableWidget, DefaultField, DoughnutChartWidget, EMPTY_INTERACTIONS, EntityGalleryWidget, FilterPanelWidget, FormApiContext, FormFields, FormKitSlot, FormWidget, GRID, GanttChartWidget, GaugeMeterWidget, GoogleMapWidget, GridCardWidget, HeatMapWidget, HtmlWidget, IframeWidget, KPI_DEFAULT_TEMPLATES, Delta as KpiDelta, Label as KpiLabel, Sparkline as KpiSparkline, Value as KpiValue, KpiWidget, LineChartWidget, MeetingSchedulerWidget, NON_INPUT_TYPES, NON_RENDERING_TYPES, PREFIX_UNITS, PieChartWidget, PivotGridWidget, RankingBarWidget, RawHtmlWidget, SAMPLE_ROWS, SUBMISSION_SKIP_TYPES, SUFFIX_UNITS, ScatterChartWidget, StepperWidget, TabWidget, TableWidget, TaskTrackerTableWidget, TemplateProvider, TemporalWidget, TimelineWidget, TreeWidget, WIDGET_REGISTRY, WidgetShell, WidgetStateSlot, ZaiChatWidget, ZvolvForm, ZvolvProvider, ZvolvThemeProvider, ZvolvWidget, addPeriod, aggregate, alignSummaryToSeries, applyCumulative, applyLocalColumnFilters, applyLocalSearch, applyLocalSort, applyLocalWidgetFilters, applyPostOperations, applyRules, automationSource, buildColumnFilterClauses, buildDashFilters, buildDashboardTree, buildInitialValues, buildRemoteSort, buildSearchClause, buildSubmissionElements, buildTree, buildTriggerBody, buildWidgetFilterClauses, cascade, cdateFiltersFor, childIdsOf, cleanTitle, clearLookupCache, coerceSeriesNumbers, computeRowFormulas, createMockRuntime, createSubmission, createZvolvRuntime, dashboardDefaultDateToken, dashboardFilterDefs, dateDiff, dateRangeFor, defaultTokens, defineConfig, defineForm, derive, describeWidgetFilter, distinctColumnValues, eid, el, evaluateFormula, extractAgentFormData, fetchForm, fetchLookupOptions, fetchSubmission, field, fieldKind, fieldKindOf, fillDateGaps, filterableFields, flattenPercentiles, formSource, formWidget, formatAmountValue, formatCompact, formatFieldValue, formulaLabels, getDataType2 as getDataType, getEmptyValue, getPostOpOperandSet, getPostOpResult, gridHeight, gridWidgets, groupBy, hasActiveInteractions, inspectForm, interpolate, invokeAgent, invokeTrigger, invokeZeno, isDataSourceConfigured, isLegacyId, isLikelyTimestamp, isServerSafeFormula, lookupConfigOf, mergeTokens, normaliseElement, normaliseForm, normalizeWidget, openFormRequest, operatorsForKind, optionFilterRules, parseConfig, parseDateValue, parseDeep, percentileKey, pivot, renderHtmlVariables, resetQueryUser, resolveChrome, resolveChromeConfig, resolveCollectionMapping, resolveDashboardLayout, resolveDateToken, resolveDrillDown, resolveFieldType, resolveFilterMode, resolveFormWidget, resolveSeries, resolveTableMode, resolveWidget, resolveWidgetDefaults, resolveXKey, rowSubmissionIds, ruleMatches, rulesOf, searchPeople, serializeElementValue, startOfPeriod, statusTone, submissionIdOf, submissionToValues, submitElementsOf, taskField, taskSource, toBraceFormula, toNum, toRelational, toneColor, toneSurface, updateSubmission, uploadFile, useCollectionItems, useFieldOptions, useFileField, useFormApi, useFormInspector, useInteractiveWidgetData, useKpiContents, useSheetField, useTableColumns, useTemplateOverride, useTemporalEvents, useTokens, useTrialField, useWidgetData, useWidgetInteractions, useZvolvClient, useZvolvForm, useZvolvRuntime, usesFormFramework, validateField, validateForm, when, where };
|
|
8784
9230
|
//# sourceMappingURL=index.js.map
|
|
8785
9231
|
//# sourceMappingURL=index.js.map
|