@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/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
- import React13, { createContext, useMemo, useContext, useState, useRef, useCallback, useEffect } from 'react';
1
+ import React14, { createContext, useMemo, useContext, useState, useRef, useCallback, useEffect } from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import dayjs8 from 'dayjs';
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
- dayjs8.extend(utc);
121
- dayjs8.extend(weekOfYear);
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 = dayjs8();
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
- dayjs8.extend(utc);
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 = dayjs8();
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 = dayjs8();
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 dayjs8(oprd, pattern).format("YYYY-MM-DD");
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
- if (mfType === "FORM_SEARCH" || mfType === "INPUT_TAG") {
990
- sourceObj[row.title] = { terms: { field: resolveFormSearchViewField(row.title) } };
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: `${row.title}.mediaKey.keyword` } };
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: `${row.title}.keyword` } };
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: row.title } };
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.title } };
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 = sumary.title;
1200
+ let aggField = esField;
1058
1201
  if (sumary.masterFieldType === "FORM_SEARCH" && (sumary.type === "value_count" || sumary.type === "cardinality")) {
1059
- aggField = resolveFormSearchViewField(sumary.title);
1202
+ aggField = resolveFormSearchViewField(esField);
1060
1203
  } else if (sumary.masterFieldType === "FILE_UPLOAD_V2") {
1061
- aggField = `${sumary.title}.mediaKey.keyword`;
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 = `${sumary.title}.keyword`;
1207
+ aggField = `${esField}.keyword`;
1065
1208
  }
1066
- const usesRawField = aggField === sumary.title;
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(sumary.title);
1227
+ if (usesRawField) addBucketSort(esField);
1085
1228
  } else {
1086
1229
  summaryAggs[sumary.value][aggType] = { field: aggField };
1087
- if (usesRawField) addBucketSort(sumary.title);
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 aggregate(f, type = "sum", outputName = f.header) {
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 = dayjs8()) {
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 = dayjs8(`${y}-${mm}-${dd}`);
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 = dayjs8(v);
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 = dayjs8(raw2).format(FMT);
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 = React13.createContext(null);
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 = React13.useContext(WidgetStateSlot);
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 fillDateGaps({ rows, xKey, series, unit, range }) {
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 = dayjs8(row[xKey]);
2679
- if (d.isValid()) byPeriod.set(d.startOf(unit).format(keyFormat), row);
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
- let cursor = range.start;
2683
- const useTimestamp = isLikelyTimestamp(rows[0]?.[xKey]);
2684
- while (cursor.isBefore(range.end) || cursor.isSame(range.end, unit)) {
2685
- const key = cursor.format(keyFormat);
2686
- const existing = byPeriod.get(key);
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.add(1, unit);
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 normalize = useCallback((incoming) => {
2819
- const withPostOps = applyPostOperations(incoming, dataSource?.pivot?.postOperations);
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 range = dateGap.start && dateGap.end ? { start: dayjs8(dateGap.start).startOf(dateGap.unit), end: dayjs8(dateGap.end).startOf(dateGap.unit) } : null;
2823
- return fillDateGaps({ rows: numeric, xKey, series, unit: dateGap.unit, range });
2824
- }, [dataSource, series, xKey, dateGap]);
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 formId = ds.formId ?? ds.fields?.[0]?.formID;
2852
- const withFormId = formId ? { ...ds, formId } : ds;
2853
- const merged = mergeHostFilters(localFilters, dashFilters);
2854
- const cfgWithDates = { ...config, cdateFilters };
2855
- const dashboardFilters = rt.formatDashboardFilters ? [...rt.formatDashboardFilters(cfgWithDates, withFormId, merged) || []] : [];
2856
- if (remote.widgetFilters?.length) {
2857
- dashboardFilters.push(...buildWidgetFilterClauses(withFormId, remote.widgetFilters));
2858
- }
2859
- if (remote.columnFilters && Object.keys(remote.columnFilters).length) {
2860
- dashboardFilters.push(...rt.formatHeaderFilters ? rt.formatHeaderFilters(withFormId, remote.columnFilters) || [] : buildColumnFilterClauses(withFormId, remote.columnFilters));
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(React13.Fragment, { children: props.renderSortIndicator ? props.renderSortIndicator(args) : /* @__PURE__ */ jsx(DefaultSortIndicator, { ...args }) }, "sort")
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(React13.Fragment, { children: props.renderColumnFilter ? props.renderColumnFilter(args) : /* @__PURE__ */ jsx(DefaultColumnFilter, { ...args }) }, "filter")
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 { title, description, emptyMessage, unconfiguredMessage, className, style, onItemClick, ...dataArgs } = props;
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 vms = useKpiContents({ contents, rows: data.rows, cardTemplate });
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__ */ jsx(
3779
- WidgetShell,
3780
- {
3781
- widgetType: WIDGET_TYPE,
3782
- title: chrome.showHeader ? title ?? chrome.title : void 0,
3783
- description: description ?? chrome.description,
3784
- state,
3785
- error: data.error,
3786
- emptyMessage: emptyMessage ?? chrome.emptyMessage,
3787
- unconfiguredMessage,
3788
- className,
3789
- style,
3790
- actions: ix.toolbar,
3791
- ...ix.shell,
3792
- 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)) })
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 = React13.createElement(override, args);
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 ? React13.createElement(override, args) : /* @__PURE__ */ jsx(DefaultRanking, { ...args })
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 ? React13.createElement(override, args) : /* @__PURE__ */ jsx(DefaultList, { ...args })
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 = dayjs8(v);
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 && dayjs8(start).startOf("day").isSame(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 ? React13.createElement(override, args) : /* @__PURE__ */ jsx(DefaultTimeline, { ...args })
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 ? dayjs8(e.start).format("DD MMM YYYY") : "",
4619
- e.end ? ` \u2192 ${dayjs8(e.end).format("DD MMM YYYY")}` : "",
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 ? React13.createElement(override, args) : /* @__PURE__ */ jsx(DefaultStepper, { ...args })
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 = dayjs8(value);
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 = dayjs8();
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 ? dayjs8(v) : typeof v === "string" && v ? dayjs8(v) : null;
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) => dayjs8(v).format("D MMM YYYY")).join(" \u2013 ");
6022
- if (t === "DATE_PICKER") return dayjs8(value).isValid() ? dayjs8(value).format("D MMM YYYY") : String(value);
6023
- if (t === "DATE_TIME_PICKER") return dayjs8(value).isValid() ? dayjs8(value).format("D MMM YYYY, HH:mm") : String(value);
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 = React13.createContext(null);
7287
+ var FormApiContext = React14.createContext(null);
6842
7288
  function useFormApi() {
6843
- const f = React13.useContext(FormApiContext);
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 = React13.createContext(null);
8105
+ var FormKitSlot = React14.createContext(null);
7660
8106
  function useKit(local) {
7661
- const ctx = React13.useContext(FormKitSlot);
7662
- return React13.useMemo(() => ({ ...ctx ?? {}, ...local ?? {} }), [ctx, local]);
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 = dayjs8();
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