@odoo/o-spreadsheet 18.1.12 → 18.1.13

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.1.12
6
- * @date 2025-03-19T08:23:50.676Z
7
- * @hash 32f788f
5
+ * @version 18.1.13
6
+ * @date 2025-03-26T12:48:31.680Z
7
+ * @hash 45ec54c
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -1120,7 +1120,10 @@ function rgbaStringToHex(color) {
1120
1120
  }
1121
1121
  else if (stringVals.length === 4) {
1122
1122
  const alpha = parseFloat(stringVals.pop() || "1");
1123
- alphaHex = Math.round((alpha || 1) * 255);
1123
+ if (isNaN(alpha)) {
1124
+ throw new Error("invalid alpha value");
1125
+ }
1126
+ alphaHex = Math.round(alpha * 255);
1124
1127
  }
1125
1128
  const vals = stringVals.map((val) => parseInt(val, 10));
1126
1129
  if (alphaHex !== 255) {
@@ -6990,7 +6993,7 @@ function isValidLocale(locale) {
6990
6993
  */
6991
6994
  function canonicalizeNumberContent(content, locale) {
6992
6995
  return content.startsWith("=")
6993
- ? canonicalizeFormula$1(content, locale)
6996
+ ? canonicalizeFormula(content, locale)
6994
6997
  : canonicalizeNumberLiteral(content, locale);
6995
6998
  }
6996
6999
  /**
@@ -7005,7 +7008,7 @@ function canonicalizeNumberContent(content, locale) {
7005
7008
  */
7006
7009
  function canonicalizeContent(content, locale) {
7007
7010
  return content.startsWith("=")
7008
- ? canonicalizeFormula$1(content, locale)
7011
+ ? canonicalizeFormula(content, locale)
7009
7012
  : canonicalizeLiteral(content, locale);
7010
7013
  }
7011
7014
  /**
@@ -7021,15 +7024,21 @@ function localizeContent(content, locale) {
7021
7024
  ? localizeFormula(content, locale)
7022
7025
  : localizeLiteral(content, locale);
7023
7026
  }
7027
+ /** Change a number string to its canonical form (en_US locale) */
7028
+ function canonicalizeNumberValue(content, locale) {
7029
+ return content.startsWith("=")
7030
+ ? canonicalizeFormula(content, locale)
7031
+ : canonicalizeNumberLiteral(content, locale);
7032
+ }
7024
7033
  /** Change a formula to its canonical form (en_US locale) */
7025
- function canonicalizeFormula$1(formula, locale) {
7026
- return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
7034
+ function canonicalizeFormula(formula, locale) {
7035
+ return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7027
7036
  }
7028
7037
  /** Change a formula from the canonical form to the given locale */
7029
7038
  function localizeFormula(formula, locale) {
7030
- return _localizeFormula$1(formula, DEFAULT_LOCALE, locale);
7039
+ return _localizeFormula(formula, DEFAULT_LOCALE, locale);
7031
7040
  }
7032
- function _localizeFormula$1(formula, fromLocale, toLocale) {
7041
+ function _localizeFormula(formula, fromLocale, toLocale) {
7033
7042
  if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7034
7043
  fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7035
7044
  return formula;
@@ -7184,37 +7193,6 @@ function getDateTimeFormat(locale) {
7184
7193
  return locale.dateFormat + " " + locale.timeFormat;
7185
7194
  }
7186
7195
 
7187
- /** Change a number string to its canonical form (en_US locale) */
7188
- function canonicalizeNumberValue(content, locale) {
7189
- return content.startsWith("=")
7190
- ? canonicalizeFormula(content, locale)
7191
- : canonicalizeNumberLiteral(content, locale);
7192
- }
7193
- /** Change a formula to its canonical form (en_US locale) */
7194
- function canonicalizeFormula(formula, locale) {
7195
- return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7196
- }
7197
- function _localizeFormula(formula, fromLocale, toLocale) {
7198
- if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7199
- fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7200
- return formula;
7201
- }
7202
- const tokens = tokenize(formula, fromLocale);
7203
- let localizedFormula = "";
7204
- for (const token of tokens) {
7205
- if (token.type === "NUMBER") {
7206
- localizedFormula += token.value.replace(fromLocale.decimalSeparator, toLocale.decimalSeparator);
7207
- }
7208
- else if (token.type === "ARG_SEPARATOR") {
7209
- localizedFormula += toLocale.formulaArgSeparator;
7210
- }
7211
- else {
7212
- localizedFormula += token.value;
7213
- }
7214
- }
7215
- return localizedFormula;
7216
- }
7217
-
7218
7196
  function boolAnd(args) {
7219
7197
  let foundBoolean = false;
7220
7198
  let acc = true;
@@ -9589,6 +9567,7 @@ class ComposerFocusStore extends SpreadsheetStore {
9589
9567
  }
9590
9568
 
9591
9569
  const TREND_LINE_XAXIS_ID = "x1";
9570
+ const MOVING_AVERAGE_TREND_LINE_XAXIS_ID = "xMovingAverage";
9592
9571
  /**
9593
9572
  * This file contains helpers that are common to different charts (mainly
9594
9573
  * line, bar and pie charts)
@@ -9929,6 +9908,9 @@ function getPieColors(colors, dataSetsValues) {
9929
9908
  }
9930
9909
  return pieColors;
9931
9910
  }
9911
+ function isTrendLineAxis(axisID) {
9912
+ return axisID === TREND_LINE_XAXIS_ID || axisID === MOVING_AVERAGE_TREND_LINE_XAXIS_ID;
9913
+ }
9932
9914
 
9933
9915
  /** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
9934
9916
  const chartShowValuesPlugin = {
@@ -9973,7 +9955,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
9973
9955
  const yMin = chart.chartArea.top;
9974
9956
  const textsPositions = {};
9975
9957
  for (const dataset of chart._metasets) {
9976
- if (dataset.xAxisID === TREND_LINE_XAXIS_ID || dataset.hidden) {
9958
+ if (isTrendLineAxis(dataset.axisID) || dataset.hidden) {
9977
9959
  continue;
9978
9960
  }
9979
9961
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10016,7 +9998,7 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
10016
9998
  const xMin = chart.chartArea.left;
10017
9999
  const textsPositions = {};
10018
10000
  for (const dataset of chart._metasets) {
10019
- if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
10001
+ if (isTrendLineAxis(dataset.axisID)) {
10020
10002
  return; // ignore trend lines
10021
10003
  }
10022
10004
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -20380,11 +20362,26 @@ const SEARCH = {
20380
20362
  const _searchFor = toString(searchFor).toLowerCase();
20381
20363
  const _textToSearch = toString(textToSearch).toLowerCase();
20382
20364
  const _startingAt = toNumber(startingAt, this.locale);
20383
- assert(() => _textToSearch !== "", _t("The text_to_search must be non-empty."));
20384
- assert(() => _startingAt >= 1, _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt.toString()));
20365
+ if (_textToSearch === "") {
20366
+ return {
20367
+ value: CellErrorType.GenericError,
20368
+ message: _t("The text_to_search must be non-empty."),
20369
+ };
20370
+ }
20371
+ if (_startingAt < 1) {
20372
+ return {
20373
+ value: CellErrorType.GenericError,
20374
+ message: _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt),
20375
+ };
20376
+ }
20385
20377
  const result = _textToSearch.indexOf(_searchFor, _startingAt - 1);
20386
- assert(() => result >= 0, _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch));
20387
- return result + 1;
20378
+ if (result === -1) {
20379
+ return {
20380
+ value: CellErrorType.GenericError,
20381
+ message: _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch),
20382
+ };
20383
+ }
20384
+ return { value: result + 1 };
20388
20385
  },
20389
20386
  isExported: true,
20390
20387
  };
@@ -21719,11 +21716,14 @@ function compileTokens(tokens) {
21719
21716
  }
21720
21717
  }
21721
21718
  function compileTokensOrThrow(tokens) {
21722
- const { dependencies, constantValues, symbols } = formulaArguments(tokens);
21723
- const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
21719
+ const { dependencies, literalValues, symbols } = formulaArguments(tokens);
21720
+ const cacheKey = compilationCacheKey(tokens);
21724
21721
  if (!functionCache[cacheKey]) {
21725
21722
  const ast = parseTokens([...tokens]);
21726
21723
  const scope = new Scope();
21724
+ let stringCount = 0;
21725
+ let numberCount = 0;
21726
+ let dependencyCount = 0;
21727
21727
  if (ast.type === "BIN_OPERATION" && ast.value === ":") {
21728
21728
  throw new BadExpressionError(_t("Invalid formula"));
21729
21729
  }
@@ -21797,16 +21797,15 @@ function compileTokensOrThrow(tokens) {
21797
21797
  case "BOOLEAN":
21798
21798
  return code.return(`{ value: ${ast.value} }`);
21799
21799
  case "NUMBER":
21800
- return code.return(`{ value: this.constantValues.numbers[${constantValues.numbers.indexOf(ast.value)}] }`);
21800
+ return code.return(`this.literalValues.numbers[${numberCount++}]`);
21801
21801
  case "STRING":
21802
- return code.return(`{ value: this.constantValues.strings[${constantValues.strings.indexOf(ast.value)}] }`);
21802
+ return code.return(`this.literalValues.strings[${stringCount++}]`);
21803
21803
  case "REFERENCE":
21804
- const referenceIndex = dependencies.indexOf(ast.value);
21805
21804
  if ((!isMeta && ast.value.includes(":")) || hasRange) {
21806
- return code.return(`range(deps[${referenceIndex}])`);
21805
+ return code.return(`range(deps[${dependencyCount++}])`);
21807
21806
  }
21808
21807
  else {
21809
- return code.return(`ref(deps[${referenceIndex}], ${isMeta ? "true" : "false"})`);
21808
+ return code.return(`ref(deps[${dependencyCount++}], ${isMeta ? "true" : "false"})`);
21810
21809
  }
21811
21810
  case "FUNCALL":
21812
21811
  const args = compileFunctionArgs(ast).map((arg) => arg.assignResultToVariable());
@@ -21838,7 +21837,7 @@ function compileTokensOrThrow(tokens) {
21838
21837
  const compiledFormula = {
21839
21838
  execute: functionCache[cacheKey],
21840
21839
  dependencies,
21841
- constantValues,
21840
+ literalValues,
21842
21841
  symbols,
21843
21842
  tokens,
21844
21843
  isBadExpression: false,
@@ -21851,33 +21850,31 @@ function compileTokensOrThrow(tokens) {
21851
21850
  * References, numbers and strings are replaced with placeholders because
21852
21851
  * the compiled formula does not depend on their actual value.
21853
21852
  * Both `=A1+1+"2"` and `=A2+2+"3"` are compiled to the exact same function.
21854
- *
21855
21853
  * Spaces are also ignored to compute the cache key.
21856
21854
  *
21857
- * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|0|+|1|+SUM(|N0|,|N0|,|S0|)`
21855
+ * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|C|+|C|+SUM(|N|,|N|,|S|)`
21858
21856
  */
21859
- function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
21857
+ function compilationCacheKey(tokens) {
21860
21858
  let cacheKey = "";
21861
21859
  for (const token of tokens) {
21862
21860
  switch (token.type) {
21863
21861
  case "STRING":
21864
- const value = removeStringQuotes(token.value);
21865
- cacheKey += `|S${constantValues.strings.indexOf(value)}|`;
21862
+ cacheKey += "|S|";
21866
21863
  break;
21867
21864
  case "NUMBER":
21868
- cacheKey += `|N${constantValues.numbers.indexOf(parseNumber(token.value, DEFAULT_LOCALE))}|`;
21865
+ cacheKey += "|N|";
21869
21866
  break;
21870
21867
  case "REFERENCE":
21871
21868
  case "INVALID_REFERENCE":
21872
21869
  if (token.value.includes(":")) {
21873
- cacheKey += `R|${dependencies.indexOf(token.value)}|`;
21870
+ cacheKey += "|R|";
21874
21871
  }
21875
21872
  else {
21876
- cacheKey += `C|${dependencies.indexOf(token.value)}|`;
21873
+ cacheKey += "|C|";
21877
21874
  }
21878
21875
  break;
21879
21876
  case "SPACE":
21880
- cacheKey += "";
21877
+ // ignore spaces
21881
21878
  break;
21882
21879
  default:
21883
21880
  cacheKey += token.value;
@@ -21890,7 +21887,7 @@ function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
21890
21887
  * Return formula arguments which are references, strings and numbers.
21891
21888
  */
21892
21889
  function formulaArguments(tokens) {
21893
- const constantValues = {
21890
+ const literalValues = {
21894
21891
  numbers: [],
21895
21892
  strings: [],
21896
21893
  };
@@ -21904,15 +21901,11 @@ function formulaArguments(tokens) {
21904
21901
  break;
21905
21902
  case "STRING":
21906
21903
  const value = removeStringQuotes(token.value);
21907
- if (!constantValues.strings.includes(value)) {
21908
- constantValues.strings.push(value);
21909
- }
21904
+ literalValues.strings.push({ value });
21910
21905
  break;
21911
21906
  case "NUMBER": {
21912
21907
  const value = parseNumber(token.value, DEFAULT_LOCALE);
21913
- if (!constantValues.numbers.includes(value)) {
21914
- constantValues.numbers.push(value);
21915
- }
21908
+ literalValues.numbers.push({ value });
21916
21909
  break;
21917
21910
  }
21918
21911
  case "SYMBOL": {
@@ -21923,7 +21916,7 @@ function formulaArguments(tokens) {
21923
21916
  }
21924
21917
  return {
21925
21918
  dependencies,
21926
- constantValues,
21919
+ literalValues,
21927
21920
  symbols,
21928
21921
  };
21929
21922
  }
@@ -22844,9 +22837,9 @@ const XLSX_CHART_TYPES = [
22844
22837
  /** In XLSX color format (no #) */
22845
22838
  const AUTO_COLOR = "000000";
22846
22839
  const XLSX_ICONSET_MAP = {
22847
- arrow: "3Arrows",
22840
+ arrows: "3Arrows",
22848
22841
  smiley: "3Symbols",
22849
- dot: "3TrafficLights1",
22842
+ dots: "3TrafficLights1",
22850
22843
  };
22851
22844
  const NAMESPACE = {
22852
22845
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -23517,6 +23510,7 @@ const ICON_SET_CONVERSION_MAP = {
23517
23510
  };
23518
23511
  /** Map between legend position in XLSX file and human readable position */
23519
23512
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
23513
+ none: "none",
23520
23514
  b: "bottom",
23521
23515
  t: "top",
23522
23516
  l: "left",
@@ -26279,7 +26273,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26279
26273
  default: "ffffff",
26280
26274
  }).asString(),
26281
26275
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
26282
- default: "b",
26276
+ default: "none",
26283
26277
  }).asString()],
26284
26278
  stacked: barChartGrouping === "stacked",
26285
26279
  fontColor: "000000",
@@ -26313,7 +26307,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26313
26307
  default: "ffffff",
26314
26308
  }).asString(),
26315
26309
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
26316
- default: "b",
26310
+ default: "none",
26317
26311
  }).asString()],
26318
26312
  stacked: barChartGrouping === "stacked",
26319
26313
  fontColor: "000000",
@@ -28925,7 +28919,8 @@ function getChartLabelValues(getters, dataSets, labelRange) {
28925
28919
  }
28926
28920
  }
28927
28921
  else if (dataSets.length === 1) {
28928
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
28922
+ const dataLength = getData(getters, dataSets[0]).length;
28923
+ for (let i = 0; i < dataLength; i++) {
28929
28924
  labels.formattedValues.push("");
28930
28925
  labels.values.push("");
28931
28926
  }
@@ -29108,7 +29103,7 @@ function getLineChartDatasets(definition, args) {
29108
29103
  function getScatterChartDatasets(definition, args) {
29109
29104
  const dataSets = getLineChartDatasets(definition, args);
29110
29105
  for (const dataSet of dataSets) {
29111
- if (dataSet.xAxisID !== TREND_LINE_XAXIS_ID) {
29106
+ if (!isTrendLineAxis(dataSet.xAxisID)) {
29112
29107
  dataSet.showLine = false;
29113
29108
  }
29114
29109
  }
@@ -29235,7 +29230,9 @@ function getTrendingLineDataSet(dataset, config, data) {
29235
29230
  const borderColor = config.color || lightenColor(rgbaToHex(defaultBorderColor), 0.5);
29236
29231
  return {
29237
29232
  type: "line",
29238
- xAxisID: TREND_LINE_XAXIS_ID,
29233
+ xAxisID: config.type === "trailingMovingAverage"
29234
+ ? MOVING_AVERAGE_TREND_LINE_XAXIS_ID
29235
+ : TREND_LINE_XAXIS_ID,
29239
29236
  yAxisID: dataset.yAxisID,
29240
29237
  label: dataset.label ? _t("Trend line for %s", dataset.label) : "",
29241
29238
  data,
@@ -29310,22 +29307,19 @@ function getPieChartLegend(definition, args) {
29310
29307
  const { dataSetsValues } = args;
29311
29308
  const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
29312
29309
  const colors = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
29310
+ const fontColor = chartFontColor(definition.background);
29313
29311
  return {
29314
29312
  ...getLegendDisplayOptions(definition),
29315
29313
  labels: {
29316
- color: chartFontColor(definition.background),
29317
29314
  usePointStyle: true,
29318
- //@ts-ignore
29319
- generateLabels: (c) =>
29320
- //@ts-ignore
29321
- c.data.labels.map((label, index) => ({
29322
- text: label,
29315
+ generateLabels: (c) => c.data.labels?.map((label, index) => ({
29316
+ text: String(label),
29323
29317
  strokeStyle: colors[index],
29324
29318
  fillStyle: colors[index],
29325
29319
  pointStyle: "rect",
29326
- hidden: false,
29327
29320
  lineWidth: 2,
29328
- })),
29321
+ fontColor,
29322
+ })) || [],
29329
29323
  filter: (legendItem, data) => {
29330
29324
  return "datasetIndex" in legendItem
29331
29325
  ? !data.datasets[legendItem.datasetIndex].hidden
@@ -29458,7 +29452,7 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
29458
29452
  color: fontColor,
29459
29453
  usePointStyle: true,
29460
29454
  generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
29461
- if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
29455
+ if (isTrendLineAxis(dataset["xAxisID"])) {
29462
29456
  return {
29463
29457
  text: dataset.label ?? "",
29464
29458
  fontColor,
@@ -29516,6 +29510,11 @@ function getBarChartScales(definition, args) {
29516
29510
  offset: false,
29517
29511
  display: false,
29518
29512
  };
29513
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29514
+ ...scales.x,
29515
+ offset: false,
29516
+ display: false,
29517
+ };
29519
29518
  }
29520
29519
  return scales;
29521
29520
  }
@@ -29549,6 +29548,10 @@ function getLineChartScales(definition, args) {
29549
29548
  ...scales.x,
29550
29549
  display: false,
29551
29550
  };
29551
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29552
+ ...scales.x,
29553
+ display: false,
29554
+ };
29552
29555
  if (axisType === "category" || axisType === "time") {
29553
29556
  /* We add a second x axis here to draw the trend lines, with the labels length being
29554
29557
  * set so that the second axis points match the classical x axis
@@ -29557,6 +29560,8 @@ function getLineChartScales(definition, args) {
29557
29560
  scales[TREND_LINE_XAXIS_ID]["type"] = "category";
29558
29561
  scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
29559
29562
  scales[TREND_LINE_XAXIS_ID]["offset"] = false;
29563
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["type"] = "category";
29564
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["offset"] = false;
29560
29565
  }
29561
29566
  }
29562
29567
  return scales;
@@ -29802,9 +29807,7 @@ function getBarChartTooltip(definition, args) {
29802
29807
  return {
29803
29808
  callbacks: {
29804
29809
  title: function (tooltipItems) {
29805
- return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
29806
- ? undefined
29807
- : "";
29810
+ return tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID)) ? undefined : "";
29808
29811
  },
29809
29812
  label: function (tooltipItem) {
29810
29813
  const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
@@ -29827,7 +29830,7 @@ function getLineChartTooltip(definition, args) {
29827
29830
  if (axisType === "linear") {
29828
29831
  tooltip.callbacks.label = (tooltipItem) => {
29829
29832
  const dataSetPoint = tooltipItem.parsed.y;
29830
- let label = tooltipItem.dataset.xAxisID === TREND_LINE_XAXIS_ID
29833
+ let label = isTrendLineAxis(tooltipItem.dataset.xAxisID)
29831
29834
  ? ""
29832
29835
  : tooltipItem.parsed.x;
29833
29836
  if (typeof label === "string" && isNumber(label, locale)) {
@@ -29852,8 +29855,7 @@ function getLineChartTooltip(definition, args) {
29852
29855
  };
29853
29856
  }
29854
29857
  tooltip.callbacks.title = function (tooltipItems) {
29855
- const displayTooltipTitle = axisType !== "linear" &&
29856
- tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
29858
+ const displayTooltipTitle = axisType !== "linear" && tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID));
29857
29859
  return displayTooltipTitle ? undefined : "";
29858
29860
  };
29859
29861
  return tooltip;
@@ -34010,6 +34012,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
34010
34012
  CHART_COMMON_OPTIONS: CHART_COMMON_OPTIONS,
34011
34013
  GaugeChart: GaugeChart,
34012
34014
  LineChart: LineChart,
34015
+ MOVING_AVERAGE_TREND_LINE_XAXIS_ID: MOVING_AVERAGE_TREND_LINE_XAXIS_ID,
34013
34016
  PieChart: PieChart,
34014
34017
  ScorecardChart: ScorecardChart$1,
34015
34018
  TREND_LINE_XAXIS_ID: TREND_LINE_XAXIS_ID,
@@ -34039,6 +34042,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
34039
34042
  getDefinedAxis: getDefinedAxis,
34040
34043
  getPieColors: getPieColors,
34041
34044
  getSmartChartDefinition: getSmartChartDefinition,
34045
+ isTrendLineAxis: isTrendLineAxis,
34042
34046
  shouldRemoveFirstLabel: shouldRemoveFirstLabel,
34043
34047
  toExcelDataset: toExcelDataset,
34044
34048
  toExcelLabelRange: toExcelLabelRange,
@@ -36086,9 +36090,7 @@ class FormulaFingerprintStore extends SpreadsheetStore {
36086
36090
  }
36087
36091
  }
36088
36092
  }
36089
- // removes the index placeholders from the normalized formula
36090
- // =|N0|+|N1|+|N0| -> =|N|+|N|+|N|
36091
- const normalizedFormula = cell.compiledFormula.normalizedFormula.replace(/(|\w)(\d)(|)/g, "$1$3");
36093
+ const normalizedFormula = cell.compiledFormula.normalizedFormula;
36092
36094
  return hash(fingerprintVector) + normalizedFormula;
36093
36095
  }
36094
36096
  getLiteralFingerprint(position) {
@@ -39079,9 +39081,11 @@ class SeriesDesignEditor extends Component {
39079
39081
  if (!runtime || !("chartJsConfig" in runtime)) {
39080
39082
  return [];
39081
39083
  }
39082
- return runtime.chartJsConfig.data.datasets.map((d) => d.label);
39084
+ return runtime.chartJsConfig.data.datasets
39085
+ .filter((d) => !isTrendLineAxis(d["xAxisID"] ?? ""))
39086
+ .map((d) => d.label);
39083
39087
  }
39084
- updateSerieEditor(ev) {
39088
+ updateEditedSeries(ev) {
39085
39089
  this.state.index = ev.target.selectedIndex;
39086
39090
  }
39087
39091
  updateDataSeriesColor(color) {
@@ -39094,7 +39098,7 @@ class SeriesDesignEditor extends Component {
39094
39098
  };
39095
39099
  this.props.updateChart(this.props.figureId, { dataSets });
39096
39100
  }
39097
- getDataSerieColor() {
39101
+ getDataSeriesColor() {
39098
39102
  const dataSets = this.props.definition.dataSets;
39099
39103
  if (!dataSets?.[this.state.index])
39100
39104
  return "";
@@ -39114,7 +39118,7 @@ class SeriesDesignEditor extends Component {
39114
39118
  };
39115
39119
  this.props.updateChart(this.props.figureId, { dataSets });
39116
39120
  }
39117
- getDataSerieLabel() {
39121
+ getDataSeriesLabel() {
39118
39122
  const dataSets = this.props.definition.dataSets;
39119
39123
  return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
39120
39124
  }
@@ -39227,7 +39231,7 @@ class SeriesWithAxisDesignEditor extends Component {
39227
39231
  }
39228
39232
  this.updateTrendLineValue(index, { window });
39229
39233
  }
39230
- getDataSerieColor(index) {
39234
+ getDataSeriesColor(index) {
39231
39235
  const dataSets = this.props.definition.dataSets;
39232
39236
  if (!dataSets?.[index])
39233
39237
  return "";
@@ -39238,7 +39242,7 @@ class SeriesWithAxisDesignEditor extends Component {
39238
39242
  }
39239
39243
  getTrendLineColor(index) {
39240
39244
  return (this.getTrendLineConfiguration(index)?.color ??
39241
- setColorAlpha(this.getDataSerieColor(index), 0.5));
39245
+ setColorAlpha(this.getDataSeriesColor(index), 0.5));
39242
39246
  }
39243
39247
  updateTrendLineColor(index, color) {
39244
39248
  this.updateTrendLineValue(index, { color });
@@ -70321,7 +70325,9 @@ css /* scss */ `
70321
70325
  border: 1px solid;
70322
70326
  font-family: ${DEFAULT_FONT};
70323
70327
 
70324
- .o-composer:empty:not(:focus):not(.active)::before {
70328
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
70329
+ .o-composer:empty:not(:focus):not(.active)::before,
70330
+ &.o-topbar-composer-readonly .o-composer:empty::before {
70325
70331
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
70326
70332
  position: relative;
70327
70333
  top: 20%;
@@ -73662,10 +73668,14 @@ function addIconSetRule(cf, rule) {
73662
73668
  continue;
73663
73669
  }
73664
73670
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
73671
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
73672
+ if (isIconSetReversed(rule.icons)) {
73673
+ iconSetAttrs.push(["reverse", "1"]);
73674
+ }
73665
73675
  conditionalFormats.push(escapeXml /*xml*/ `
73666
73676
  <conditionalFormatting sqref="${range}">
73667
73677
  <cfRule ${formatAttributes(ruleAttributes)}>
73668
- <iconSet iconSet="${getIconSet(rule.icons)}">
73678
+ <iconSet ${formatAttributes(iconSetAttrs)}>
73669
73679
  ${joinXmlNodes(cfValueObjectNodes)}
73670
73680
  </iconSet>
73671
73681
  </cfRule>
@@ -73683,9 +73693,21 @@ function commonCfAttributes(cf) {
73683
73693
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
73684
73694
  ];
73685
73695
  }
73696
+ function isIconSetReversed(iconSet) {
73697
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
73698
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
73699
+ }
73686
73700
  function getIconSet(iconSet) {
73687
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
73688
- "dots"];
73701
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
73702
+ }
73703
+ /**
73704
+ * Partial detection based on "upper" point only.
73705
+ * We support any arbitrary icon in the set, while excel doesn't allow
73706
+ * mixing icons from different types.
73707
+ */
73708
+ function detectIconsType(iconSet) {
73709
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
73710
+ return type;
73689
73711
  }
73690
73712
  function thresholdAttributes(threshold, position) {
73691
73713
  const type = getExcelThresholdType(threshold.type, position);
@@ -75558,6 +75580,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
75558
75580
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
75559
75581
 
75560
75582
 
75561
- __info__.version = "18.1.12";
75562
- __info__.date = "2025-03-19T08:23:50.676Z";
75563
- __info__.hash = "32f788f";
75583
+ __info__.version = "18.1.13";
75584
+ __info__.date = "2025-03-26T12:48:31.680Z";
75585
+ __info__.hash = "45ec54c";