@olenbetong/appframe-core 2.15.2 → 2.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/mitt@3.0.1/node_modules/mitt/dist/mitt.mjs
1
+ // ../../node_modules/.pnpm/mitt@3.0.1/node_modules/mitt/dist/mitt.mjs
2
2
  function mitt_default(n) {
3
3
  return {
4
4
  all: n = n || /* @__PURE__ */ new Map(),
@@ -21,8 +21,7 @@ function mitt_default(n) {
21
21
  };
22
22
  }
23
23
 
24
- //#endregion
25
- //#region src/SessionHandler.ts
24
+ // src/SessionHandler.ts
26
25
  var SessionHandler = class {
27
26
  eventHandler = mitt_default();
28
27
  authenticated() {
@@ -67,8 +66,7 @@ var SessionHandler = class {
67
66
  }
68
67
  };
69
68
 
70
- //#endregion
71
- //#region src/UserSession.ts
69
+ // src/UserSession.ts
72
70
  var UserSession = class extends SessionHandler {
73
71
  amDesignator = "a.m.";
74
72
  dayNames = [
@@ -140,8 +138,7 @@ var UserSession = class extends SessionHandler {
140
138
  }
141
139
  };
142
140
 
143
- //#endregion
144
- //#region src/log.ts
141
+ // src/log.ts
145
142
  const article = window.af?.article?.id ?? window.window?.location.pathname.substring(1).split("/")[0];
146
143
  /**
147
144
  * Logs an activity to the website activity log
@@ -286,15 +283,13 @@ function getSessionData() {
286
283
  };
287
284
  }
288
285
 
289
- //#endregion
290
- //#region src/errorHandler.ts
286
+ // src/errorHandler.ts
291
287
  window.window?.addEventListener("error", (event) => {
292
288
  if (typeof event === "object" && "error" in event) logError(event.error);
293
289
  else if (typeof event === "object" && "message" in event) logError(event);
294
290
  });
295
291
 
296
- //#endregion
297
- //#region src/localStorage.ts
292
+ // src/localStorage.ts
298
293
  function getLocalKey(key) {
299
294
  return [
300
295
  af?.article?.id || "",
@@ -329,8 +324,7 @@ var LocalStorage = class {
329
324
  };
330
325
  var localStorage_default = new LocalStorage();
331
326
 
332
- //#endregion
333
- //#region src/date.ts
327
+ // src/date.ts
334
328
  function toLocalISODate(date) {
335
329
  return date ? toLocalISODateTime(date).substring(0, 10) : null;
336
330
  }
@@ -353,8 +347,7 @@ function toLocalDateTime(date) {
353
347
  return date ? date.toISOString().substring(0, 16) : "";
354
348
  }
355
349
 
356
- //#endregion
357
- //#region src/downloadBlob.ts
350
+ // src/downloadBlob.ts
358
351
  function downloadBlob(blob, fileName) {
359
352
  return new Promise((resolve, reject) => {
360
353
  try {
@@ -376,8 +369,7 @@ function downloadBlob(blob, fileName) {
376
369
  });
377
370
  }
378
371
 
379
- //#endregion
380
- //#region src/invariant.ts
372
+ // src/invariant.ts
381
373
  /**
382
374
  * Throws an error if the condition is falsy. The provided message is used as the error message.
383
375
  * A function can be provided to lazily generate the message.
@@ -392,8 +384,7 @@ function invariant(condition, message) {
392
384
  throw new Error(provided ?? "Invariant failed");
393
385
  }
394
386
 
395
- //#endregion
396
- //#region src/downloadRequest.ts
387
+ // src/downloadRequest.ts
397
388
  async function downloadRequest(request, { fileName, signal, onProgress }) {
398
389
  let bytesReceived = 0;
399
390
  onProgress?.({ status: "requested" });
@@ -447,8 +438,7 @@ async function downloadRequest(request, { fileName, signal, onProgress }) {
447
438
  }
448
439
  }
449
440
 
450
- //#endregion
451
- //#region src/parseFunc.ts
441
+ // src/parseFunc.ts
452
442
  const funcRegex = /^function(?:\s+([a-zA-Z$_][a-zA-Z0-9$_]*))?\s*\(((?:(?:\s*[a-zA-Z$_][a-zA-Z0-9$_]*)(?:\s*,\s*[a-zA-Z$_][a-zA-Z0-9$_]*)*)?)\s*\)\s*\{((?:.|\n|\r)*)\}$/;
453
443
  const arrowBlockRegex = /^(?:\(([^)]*)\)|([a-zA-Z$_][a-zA-Z0-9$_]*))\s*=>\s*\{([\s\S]*)\}$/;
454
444
  const arrowExpressionRegex = /^(?:\(([^)]*)\)|([a-zA-Z$_][a-zA-Z0-9$_]*))\s*=>\s*([\s\S]+)$/;
@@ -482,13 +472,11 @@ function parseFunc(func) {
482
472
  };
483
473
  }
484
474
 
485
- //#endregion
486
- //#region src/Namespace.ts
475
+ // src/Namespace.ts
487
476
  function Namespace() {}
488
477
  Namespace.prototype = Object.create(null);
489
478
 
490
- //#endregion
491
- //#region src/requireNamespace.ts
479
+ // src/requireNamespace.ts
492
480
  function requireNamespace(root, namespace) {
493
481
  if (typeof root === "object") {
494
482
  if (typeof namespace === "string") return requireNamespace(root, namespace.split("."));
@@ -500,8 +488,7 @@ function requireNamespace(root, namespace) {
500
488
  }
501
489
  }
502
490
 
503
- //#endregion
504
- //#region src/expose.ts
491
+ // src/expose.ts
505
492
  /**
506
493
  * Expose a value to a potentially deeply nested global variable
507
494
  * @param name {string | object} Either a dot-separated path to the global variable, or an object to expose the value on
@@ -531,8 +518,7 @@ function expose(name, value, options = {}) {
531
518
  }
532
519
  }
533
520
 
534
- //#endregion
535
- //#region src/getLocalizedString.ts
521
+ // src/getLocalizedString.ts
536
522
  async function fetchLocalizedString(text, project) {
537
523
  try {
538
524
  let response = await fetch(`/api/user/localize/new/${encodeURIComponent(project)}`, {
@@ -621,8 +607,7 @@ function createLocalizer(project) {
621
607
  };
622
608
  }
623
609
 
624
- //#endregion
625
- //#region src/filter/operators.ts
610
+ // src/filter/operators.ts
626
611
  /**
627
612
  * Operators that take no value at all.
628
613
  *
@@ -636,6 +621,26 @@ const PARAMETERLESS_OPERATORS = [
636
621
  "isblank",
637
622
  "isnotblank"
638
623
  ];
624
+ /**
625
+ * Whole-period checks for dates, such as "Is last week", in the order of the
626
+ * Windows filter editor. They take no value. The framework has no operator for
627
+ * them, so a filter using one is sent as a filter string (`needsFilterString`).
628
+ */
629
+ const PERIOD_OPERATORS = [
630
+ "isbeyondthisyear",
631
+ "islaterthisyear",
632
+ "islaterthismonth",
633
+ "isnextweek",
634
+ "islaterthisweek",
635
+ "istomorrow",
636
+ "istoday",
637
+ "isyesterday",
638
+ "isearlierthisweek",
639
+ "islastweek",
640
+ "isearlierthismonth",
641
+ "isearlierthisyear",
642
+ "ispriorthisyear"
643
+ ];
639
644
  /** Operators whose value is a two element `[from, to]` array. */
640
645
  const PAIR_OPERATORS = [
641
646
  "between",
@@ -646,7 +651,7 @@ const PAIR_OPERATORS = [
646
651
  /** Operators whose value is an array of values. */
647
652
  const LIST_OPERATORS = ["inlist", "notinlist"];
648
653
  function getOperatorArity(operator) {
649
- if (PARAMETERLESS_OPERATORS.includes(operator)) return "none";
654
+ if (PARAMETERLESS_OPERATORS.includes(operator) || PERIOD_OPERATORS.includes(operator)) return "none";
650
655
  if (PAIR_OPERATORS.includes(operator)) return "pair";
651
656
  if (LIST_OPERATORS.includes(operator)) return "list";
652
657
  return "single";
@@ -689,7 +694,20 @@ const OPERATOR_LABELS = {
689
694
  datelessthan: "Before",
690
695
  datelessthanorequal: "Up to",
691
696
  datebetween: "Between",
692
- datenotbetween: "Not between"
697
+ datenotbetween: "Not between",
698
+ isbeyondthisyear: "Is beyond this year",
699
+ islaterthisyear: "Is later this year",
700
+ islaterthismonth: "Is later this month",
701
+ isnextweek: "Is next week",
702
+ islaterthisweek: "Is later this week",
703
+ istomorrow: "Is tomorrow",
704
+ istoday: "Is today",
705
+ isyesterday: "Is yesterday",
706
+ isearlierthisweek: "Is earlier this week",
707
+ islastweek: "Is last week",
708
+ isearlierthismonth: "Is earlier this month",
709
+ isearlierthisyear: "Is earlier this year",
710
+ ispriorthisyear: "Is prior to this year"
693
711
  };
694
712
  /** Comparison operator labels used for date and time fields. */
695
713
  const DATE_OPERATOR_LABELS = {
@@ -734,13 +752,15 @@ const OPERATORS_BY_TYPE = {
734
752
  ...EQUALITY,
735
753
  ...LIST_CHECKS,
736
754
  ...RANGE,
737
- ...COMPARISONS
755
+ ...COMPARISONS,
756
+ ...PERIOD_OPERATORS
738
757
  ],
739
758
  datetime: [
740
759
  ...EQUALITY,
741
760
  ...LIST_CHECKS,
742
761
  ...RANGE,
743
- ...COMPARISONS
762
+ ...COMPARISONS,
763
+ ...PERIOD_OPERATORS
744
764
  ],
745
765
  number: [
746
766
  ...EQUALITY,
@@ -813,7 +833,10 @@ function getValueType(field, operator) {
813
833
  const RELATIVE_DATE_VALUES = [
814
834
  "Yesterday",
815
835
  "Today",
836
+ "Now",
816
837
  "Tomorrow",
838
+ "DayAfterTomorrow",
839
+ "TwoWeeksAway",
817
840
  "ThisWeek",
818
841
  "ThisMonth",
819
842
  "ThisYear",
@@ -828,7 +851,10 @@ const DYNAMIC_VALUE_LABELS = {
828
851
  CurrentUser: "Current user",
829
852
  Yesterday: "Yesterday",
830
853
  Today: "Today",
854
+ Now: "Now",
831
855
  Tomorrow: "Tomorrow",
856
+ DayAfterTomorrow: "Day after tomorrow",
857
+ TwoWeeksAway: "Two weeks away",
832
858
  ThisWeek: "This week",
833
859
  ThisMonth: "This month",
834
860
  ThisYear: "This year",
@@ -864,6 +890,30 @@ function getDynamicValuesForField(field) {
864
890
  if (field.type === "string") return ["CurrentUser"];
865
891
  return [];
866
892
  }
893
+ /** Operators that can compare a field with another column. */
894
+ const COLUMN_OPERATORS = [
895
+ ...EQUALITY,
896
+ ...RANGE,
897
+ ...COMPARISONS
898
+ ];
899
+ /** Whether an operator can take another column as its value. */
900
+ function supportsColumnValue(operator) {
901
+ return COLUMN_OPERATORS.includes(operator);
902
+ }
903
+ /** Dates and datetimes compare with each other; other types only with their own. */
904
+ function getComparableType(type) {
905
+ return type === "datetime" ? "date" : type;
906
+ }
907
+ /**
908
+ * The columns a field can be compared with: the other fields of the same type,
909
+ * as in the Windows filter editor. Booleans have only true and false checks,
910
+ * so they get none.
911
+ */
912
+ function getColumnsForField(field, fields) {
913
+ if (field.type === "boolean") return [];
914
+ let type = getComparableType(field.type);
915
+ return fields.filter((other) => other.name !== field.name && !other.excludeFromFilter && getComparableType(other.type) === type);
916
+ }
867
917
  /**
868
918
  * Aliases for names `eOperators.ToString()` can produce that are not operators
869
919
  * in their own right. `Not` is the bare negation flag (i.e. "not equal to"),
@@ -887,8 +937,7 @@ function normalizeOperator(operator) {
887
937
  return OPERATOR_ALIASES[normalized] ?? normalized;
888
938
  }
889
939
 
890
- //#endregion
891
- //#region src/filter/tree.ts
940
+ // src/filter/tree.ts
892
941
  /**
893
942
  * Creates the default empty filter: a single `and` group with no conditions.
894
943
  */
@@ -975,10 +1024,40 @@ function isCompleteExpression(item) {
975
1024
  let arity = getOperatorArity(normalizeOperator(item.operator));
976
1025
  if (arity === "none") return true;
977
1026
  if (item.value === null || item.value === void 0 || item.value === "") return false;
978
- if (arity === "pair") return Array.isArray(item.value) && item.value.length === 2 && item.value.every((v) => v !== "" && v != null);
1027
+ if (arity === "pair") return Array.isArray(item.value) && item.value.length === 2 && item.value.every((v) => {
1028
+ let end = isRangeEnd(v) ? v.value : v;
1029
+ return end !== "" && end != null;
1030
+ });
979
1031
  if (arity === "list") return Array.isArray(item.value) && item.value.length > 0;
980
1032
  return true;
981
1033
  }
1034
+ /** Whether a range value end is a `FilterRangeEnd` rather than a plain value. */
1035
+ function isRangeEnd(value) {
1036
+ return typeof value === "object" && value !== null && !(value instanceof Date) && "valueType" in value;
1037
+ }
1038
+ /** Dynamic values the framework has no `eDynamicValue` member for. */
1039
+ const DYNAMIC_VALUES_WITHOUT_FRAMEWORK_SUPPORT = /* @__PURE__ */ new Set([
1040
+ "Now",
1041
+ "DayAfterTomorrow",
1042
+ "TwoWeeksAway"
1043
+ ]);
1044
+ function needsConversion(valueType, value) {
1045
+ if (valueType === "column") return true;
1046
+ return valueType === "special" && typeof value === "string" && DYNAMIC_VALUES_WITHOUT_FRAMEWORK_SUPPORT.has(value);
1047
+ }
1048
+ /**
1049
+ * True when the filter holds something the framework's data API cannot read
1050
+ * from a filter object: another column, a range end that is not a plain value,
1051
+ * one of the dates only the Windows editor offers, or a whole-period check. Such a filter must be
1052
+ * converted with `convertFilter` and sent as a filter string.
1053
+ */
1054
+ function needsFilterString(filter) {
1055
+ if (!filter) return false;
1056
+ if (isGroup(filter)) return filter.items.some(needsFilterString);
1057
+ if (PERIOD_OPERATORS.includes(normalizeOperator(filter.operator))) return true;
1058
+ if (needsConversion(filter.valueType, filter.value)) return true;
1059
+ return Array.isArray(filter.value) && filter.value.some((item) => isRangeEnd(item));
1060
+ }
982
1061
  /**
983
1062
  * Creates an expression for a field, using the field's default operator and an
984
1063
  * empty value of the right shape.
@@ -1009,8 +1088,9 @@ function changeOperator(expression, operator, field) {
1009
1088
  let previousArity = getOperatorArity(normalizeOperator(expression.operator));
1010
1089
  let arity = getOperatorArity(operator);
1011
1090
  let value = expression.value;
1012
- if (arity !== previousArity) value = createEmptyValue(operator);
1013
- let valueType = expression.valueType === "special" && arity === previousArity ? "special" : getValueType(field, operator);
1091
+ let holdsColumn = expression.valueType === "column" || Array.isArray(value) && value.some((item) => isRangeEnd(item) && item.valueType === "column");
1092
+ if (arity !== previousArity || holdsColumn && !supportsColumnValue(operator)) value = createEmptyValue(operator);
1093
+ let valueType = (expression.valueType === "special" || expression.valueType === "column") && value === expression.value ? expression.valueType : getValueType(field, operator);
1014
1094
  return {
1015
1095
  ...expression,
1016
1096
  operator,
@@ -1076,8 +1156,7 @@ function addGroupAtPath(filter, path = []) {
1076
1156
  return insertNodeAtPath(filter, path, createEmptyGroup(parent && isGroup(parent) && parent.mode === "and" ? "or" : "and"));
1077
1157
  }
1078
1158
 
1079
- //#endregion
1080
- //#region src/filter/convertFilter.ts
1159
+ // src/filter/convertFilter.ts
1081
1160
  const CONVERT_URL = "/api/filter/convert";
1082
1161
  /**
1083
1162
  * Converts between a structured filter and a DevExpress filter string.
@@ -1102,8 +1181,7 @@ async function convertFilter(request, signal) {
1102
1181
  };
1103
1182
  }
1104
1183
 
1105
- //#endregion
1106
- //#region src/filter/describeFilter.ts
1184
+ // src/filter/describeFilter.ts
1107
1185
  /**
1108
1186
  * Builds a human-readable description of a filter, without contacting the
1109
1187
  * server. Use this for read-only summaries; the authoritative filter string is
@@ -1131,18 +1209,19 @@ function describeExpression(expression, fields) {
1131
1209
  let label = getOperatorLabel(operator, field?.type);
1132
1210
  let arity = getOperatorArity(operator);
1133
1211
  if (arity === "none") return `[${caption}] ${label}`;
1134
- return `[${caption}] ${label} ${formatValue(expression, arity)}`;
1212
+ return `[${caption}] ${label} ${formatValue(expression, arity, fields)}`;
1135
1213
  }
1136
- function formatValue(expression, arity) {
1214
+ function formatValue(expression, arity, fields) {
1137
1215
  let { value, valueType } = expression;
1138
- if (valueType === "special" && typeof value === "string") return getDynamicValueLabel(value);
1139
1216
  if (Array.isArray(value)) {
1140
- let formatted = value.map((item) => formatScalar(item, valueType));
1217
+ let formatted = value.map((item) => isRangeEnd(item) ? formatScalar(item.value, item.valueType, fields) : formatScalar(item, valueType, fields));
1141
1218
  return arity === "pair" ? formatted.join(" - ") : `(${formatted.join(", ")})`;
1142
1219
  }
1143
- return formatScalar(value, valueType);
1220
+ return formatScalar(value, valueType, fields);
1144
1221
  }
1145
- function formatScalar(value, valueType) {
1222
+ function formatScalar(value, valueType, fields) {
1223
+ if (valueType === "special" && typeof value === "string") return getDynamicValueLabel(value);
1224
+ if (valueType === "column" && typeof value === "string") return `[${fields.get(value.toLowerCase())?.caption ?? value}]`;
1146
1225
  if (value === null || value === void 0) return "";
1147
1226
  if (value instanceof Date) return value.toISOString().slice(0, 10);
1148
1227
  if (typeof value === "number" || typeof value === "boolean") return String(value);
@@ -1150,8 +1229,7 @@ function formatScalar(value, valueType) {
1150
1229
  return `'${String(value)}'`;
1151
1230
  }
1152
1231
 
1153
- //#endregion
1154
- //#region src/filter/fields.ts
1232
+ // src/filter/fields.ts
1155
1233
  const FIELD_TYPES = [
1156
1234
  "string",
1157
1235
  "number",
@@ -1186,8 +1264,7 @@ function toFieldMetadataList(records) {
1186
1264
  return records.map(toFieldMetadata).filter((field) => field.name !== "" && !field.excludeFromFilter).sort((a, b) => a.name.localeCompare(b.name));
1187
1265
  }
1188
1266
 
1189
- //#endregion
1190
- //#region src/filter/standardLayout.ts
1267
+ // src/filter/standardLayout.ts
1191
1268
  /**
1192
1269
  * The "standard layout" is the simplified shape the Windows filter editor can
1193
1270
  * render in its flow view: an outer `or` group whose items are `and` groups of
@@ -1269,8 +1346,7 @@ function collectExpressions(item, into) {
1269
1346
  for (let child of item.items) collectExpressions(child, into);
1270
1347
  }
1271
1348
 
1272
- //#endregion
1273
- //#region src/filter/savedFilters.ts
1349
+ // src/filter/savedFilters.ts
1274
1350
  /**
1275
1351
  * `sviw_Database_MyFilters` unions in a synthetic "No Filter" row so the Windows
1276
1352
  * tree can render a "no filter" entry. It is not a real filter and must be
@@ -1369,8 +1445,7 @@ const canDeleteSavedFilter = canRenameSavedFilter;
1369
1445
  */
1370
1446
  const canSetCrossDomain = canRenameSavedFilter;
1371
1447
 
1372
- //#endregion
1373
- //#region src/getUserImage.ts
1448
+ // src/getUserImage.ts
1374
1449
  const sizeMap = {
1375
1450
  xs: 64,
1376
1451
  sm: 128,
@@ -1385,8 +1460,7 @@ function getUserImage(primKeyOrOptions, login, hash, size = "xs") {
1385
1460
  return `/api/data/blob/EmployeesLookup/${primKeyOrOptions}/Image/${encodeURIComponent(login ?? "")}${login ? "." : ""}${encodeURIComponent(hash)}.jpg${sizePx ? `?width=${sizePx}` : ""}`;
1386
1461
  }
1387
1462
 
1388
- //#endregion
1389
- //#region src/localize.ts
1463
+ // src/localize.ts
1390
1464
  /**
1391
1465
  * Localization function for tagged templates. Replaces the arguments
1392
1466
  * with $n, where n is the index, before asking Appframe to translate
@@ -1410,8 +1484,7 @@ function localize(stringParts, ...args) {
1410
1484
  return localized;
1411
1485
  }
1412
1486
 
1413
- //#endregion
1414
- //#region src/report/recordSource.ts
1487
+ // src/report/recordSource.ts
1415
1488
  const XML_ENTITIES = {
1416
1489
  amp: "&",
1417
1490
  lt: "<",
@@ -1477,14 +1550,26 @@ function readSelectColumns(xml) {
1477
1550
  return columns;
1478
1551
  }
1479
1552
  /**
1553
+ * The record source a document holds. Parameter lookups store one `<afRecordSource>`; a report
1554
+ * stores its record sources as `<ArrayOfAfReportRecordSource>` with one `<afReportRecordSource>`
1555
+ * per data source, of which the one with the ID `Master` feeds the report (else the first).
1556
+ */
1557
+ function pickRecordSource(document) {
1558
+ if (!document) return null;
1559
+ let sources = [...document.matchAll(/<(afRecordSource|afReportRecordSource)(?:\s[^>]*)?>([\s\S]*?)<\/\1>/g)].map((match) => match[2]);
1560
+ if (sources.length === 0) return null;
1561
+ return sources.find((source) => readElement(source, "ID") === "Master") ?? sources[0];
1562
+ }
1563
+ /**
1480
1564
  * Reads the parts of an `afRecordSource` a web client can act on: the view, the
1481
1565
  * selected columns and the design-time filter.
1482
1566
  *
1483
1567
  * Returns `null` for anything that is not a record source, so a missing or
1484
1568
  * empty `RecordSource` column simply means "no lookup".
1485
1569
  */
1486
- function parseRecordSource(xml) {
1487
- if (!xml || !xml.includes("<afRecordSource")) return null;
1570
+ function parseRecordSource(document) {
1571
+ let xml = pickRecordSource(document);
1572
+ if (!xml) return null;
1488
1573
  let viewName = readElement(xml, "ViewName");
1489
1574
  if (!viewName) return null;
1490
1575
  let maxRecords = readElement(xml, "MaxRecords");
@@ -1497,8 +1582,7 @@ function parseRecordSource(xml) {
1497
1582
  };
1498
1583
  }
1499
1584
 
1500
- //#endregion
1501
- //#region src/report/parameters.ts
1585
+ // src/report/parameters.ts
1502
1586
  /**
1503
1587
  * Report parameters: mapping the metadata records onto something renderable,
1504
1588
  * and the XML the parameter values are stored as on a saved filter.
@@ -1651,8 +1735,7 @@ function restoreParameterValues(parameters, xml) {
1651
1735
  return values;
1652
1736
  }
1653
1737
 
1654
- //#endregion
1655
- //#region src/report/parameterDefaults.ts
1738
+ // src/report/parameterDefaults.ts
1656
1739
  /**
1657
1740
  * Resolving report parameter defaults that name a stored procedure.
1658
1741
  *
@@ -1714,8 +1797,7 @@ function firstValue(result) {
1714
1797
  return row;
1715
1798
  }
1716
1799
 
1717
- //#endregion
1718
- //#region src/report/render.ts
1800
+ // src/report/render.ts
1719
1801
  /**
1720
1802
  * Rendering a report through the framework's report route.
1721
1803
  *
@@ -1919,8 +2001,7 @@ function toParameterEntries(parameters) {
1919
2001
  }));
1920
2002
  }
1921
2003
 
1922
- //#endregion
1923
- //#region src/report/report.ts
2004
+ // src/report/report.ts
1924
2005
  /**
1925
2006
  * Mapping a `sviw_WinClient_MyReports` record onto the report model, including
1926
2007
  * which output formats the report offers.
@@ -1964,8 +2045,7 @@ function toReport(record) {
1964
2045
  };
1965
2046
  }
1966
2047
 
1967
- //#endregion
1968
- //#region src/alert.ts
2048
+ // src/alert.ts
1969
2049
  const template = `
1970
2050
  <dialog class="alert-dialog">
1971
2051
  <form method="dialog">
@@ -2076,8 +2156,7 @@ async function alert(prompt, options = {}) {
2076
2156
  });
2077
2157
  }
2078
2158
 
2079
- //#endregion
2080
- //#region src/settings.ts
2159
+ // src/settings.ts
2081
2160
  function getKey(article) {
2082
2161
  return `${article ?? window.af?.article?.id ?? window.window?.location.pathname.substring(1).split("/")[0]}.${window.af?.userSession.login ?? "anonymous"}`;
2083
2162
  }
@@ -2097,9 +2176,7 @@ function saveSettings(setting, value, article) {
2097
2176
  localStorage.setItem(key, JSON.stringify(userSettings));
2098
2177
  }
2099
2178
 
2100
- //#endregion
2101
- //#region src/index.ts
2102
- const version = "2.15.2";
2179
+ // src/index.ts
2180
+ const version = "2.16.1";
2103
2181
 
2104
- //#endregion
2105
- export { ConfirmButtons, NO_FILTER_ID, RELATIVE_DATE_VALUES, SessionHandler, UserSession, addGroupAtPath, alert, canDeleteSavedFilter, canEditSavedFilter, canRenameSavedFilter, canSetCrossDomain, canShareSavedFilter, changeOperator, coerceParameterValue, coerceToStandardLayout, confirm, convertFilter, countExpressions, createEmptyFilter, createEmptyGroup, createExpression, createLocalizer, decodeXml, describeFilter, downloadBlob, downloadReport, downloadRequest, encodeXml, expose, fetchParameterDefault, findSavedFilter, getDefaultOperator, getDefaultParameterValues, getDynamicValueLabel, getDynamicValuesForField, getLocalizedString, getNodeAtPath, getOperatorArity, getOperatorLabel, getOperatorsForField, getReportExtension, getReportFileName, getReportFormats, getReportMediaType, getReportRequest, getSessionData, getSettings, getUserImage, getValueType, insertNodeAtPath, invariant, isCompleteExpression, isEmptyFilter, isExpression, isGroup, isProcedureDefault, isStandardLayout, localStorage_default as localStorage, localize, logActivity, logError, mitt_default as mitt, normalizeOperator, openAlertDialog, openReport, parseParameterItems, parseParameters, parseRecordSource, partitionSavedFilters, printReport, pruneFilter, readElement, readElements, removeNodeAtPath, renderReport, resolveParameterDefaults, restoreParameterValues, saveSettings, serializeParameters, setGroupMode, startActivity, time, toFieldMetadata, toFieldMetadataList, toFilterFieldType, toFilterTree, toLocalDateTime, toLocalISODate, toLocalISODateTime, toReport, toReportParameter, toReportParameters, toSavedFilter, toSavedFilters, unwrapSingleAndGroup, updateNodeAtPath, version, waitForDialog };
2182
+ export { ConfirmButtons, NO_FILTER_ID, PERIOD_OPERATORS, RELATIVE_DATE_VALUES, SessionHandler, UserSession, addGroupAtPath, alert, canDeleteSavedFilter, canEditSavedFilter, canRenameSavedFilter, canSetCrossDomain, canShareSavedFilter, changeOperator, coerceParameterValue, coerceToStandardLayout, confirm, convertFilter, countExpressions, createEmptyFilter, createEmptyGroup, createExpression, createLocalizer, decodeXml, describeFilter, downloadBlob, downloadReport, downloadRequest, encodeXml, expose, fetchParameterDefault, findSavedFilter, getColumnsForField, getDefaultOperator, getDefaultParameterValues, getDynamicValueLabel, getDynamicValuesForField, getLocalizedString, getNodeAtPath, getOperatorArity, getOperatorLabel, getOperatorsForField, getReportExtension, getReportFileName, getReportFormats, getReportMediaType, getReportRequest, getSessionData, getSettings, getUserImage, getValueType, insertNodeAtPath, invariant, isCompleteExpression, isEmptyFilter, isExpression, isGroup, isProcedureDefault, isRangeEnd, isStandardLayout, localStorage_default as localStorage, localize, logActivity, logError, mitt_default as mitt, needsFilterString, normalizeOperator, openAlertDialog, openReport, parseParameterItems, parseParameters, parseRecordSource, partitionSavedFilters, printReport, pruneFilter, readElement, readElements, removeNodeAtPath, renderReport, resolveParameterDefaults, restoreParameterValues, saveSettings, serializeParameters, setGroupMode, startActivity, supportsColumnValue, time, toFieldMetadata, toFieldMetadataList, toFilterFieldType, toFilterTree, toLocalDateTime, toLocalISODate, toLocalISODateTime, toReport, toReportParameter, toReportParameters, toSavedFilter, toSavedFilters, unwrapSingleAndGroup, updateNodeAtPath, version, waitForDialog };