@odoo/o-spreadsheet 18.2.4 → 18.2.5

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.2.4
6
- * @date 2025-03-19T08:20:57.717Z
7
- * @hash 958936a
5
+ * @version 18.2.5
6
+ * @date 2025-03-26T12:47:44.113Z
7
+ * @hash 4675edd
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -1131,7 +1131,10 @@ function rgbaStringToHex(color) {
1131
1131
  }
1132
1132
  else if (stringVals.length === 4) {
1133
1133
  const alpha = parseFloat(stringVals.pop() || "1");
1134
- alphaHex = Math.round((alpha || 1) * 255);
1134
+ if (isNaN(alpha)) {
1135
+ throw new Error("invalid alpha value");
1136
+ }
1137
+ alphaHex = Math.round(alpha * 255);
1135
1138
  }
1136
1139
  const vals = stringVals.map((val) => parseInt(val, 10));
1137
1140
  if (alphaHex !== 255) {
@@ -6999,7 +7002,7 @@ function isValidLocale(locale) {
6999
7002
  */
7000
7003
  function canonicalizeNumberContent(content, locale) {
7001
7004
  return content.startsWith("=")
7002
- ? canonicalizeFormula$1(content, locale)
7005
+ ? canonicalizeFormula(content, locale)
7003
7006
  : canonicalizeNumberLiteral(content, locale);
7004
7007
  }
7005
7008
  /**
@@ -7014,7 +7017,7 @@ function canonicalizeNumberContent(content, locale) {
7014
7017
  */
7015
7018
  function canonicalizeContent(content, locale) {
7016
7019
  return content.startsWith("=")
7017
- ? canonicalizeFormula$1(content, locale)
7020
+ ? canonicalizeFormula(content, locale)
7018
7021
  : canonicalizeLiteral(content, locale);
7019
7022
  }
7020
7023
  /**
@@ -7030,15 +7033,21 @@ function localizeContent(content, locale) {
7030
7033
  ? localizeFormula(content, locale)
7031
7034
  : localizeLiteral(content, locale);
7032
7035
  }
7036
+ /** Change a number string to its canonical form (en_US locale) */
7037
+ function canonicalizeNumberValue(content, locale) {
7038
+ return content.startsWith("=")
7039
+ ? canonicalizeFormula(content, locale)
7040
+ : canonicalizeNumberLiteral(content, locale);
7041
+ }
7033
7042
  /** Change a formula to its canonical form (en_US locale) */
7034
- function canonicalizeFormula$1(formula, locale) {
7035
- return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
7043
+ function canonicalizeFormula(formula, locale) {
7044
+ return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7036
7045
  }
7037
7046
  /** Change a formula from the canonical form to the given locale */
7038
7047
  function localizeFormula(formula, locale) {
7039
- return _localizeFormula$1(formula, DEFAULT_LOCALE, locale);
7048
+ return _localizeFormula(formula, DEFAULT_LOCALE, locale);
7040
7049
  }
7041
- function _localizeFormula$1(formula, fromLocale, toLocale) {
7050
+ function _localizeFormula(formula, fromLocale, toLocale) {
7042
7051
  if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7043
7052
  fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7044
7053
  return formula;
@@ -7193,37 +7202,6 @@ function getDateTimeFormat(locale) {
7193
7202
  return locale.dateFormat + " " + locale.timeFormat;
7194
7203
  }
7195
7204
 
7196
- /** Change a number string to its canonical form (en_US locale) */
7197
- function canonicalizeNumberValue(content, locale) {
7198
- return content.startsWith("=")
7199
- ? canonicalizeFormula(content, locale)
7200
- : canonicalizeNumberLiteral(content, locale);
7201
- }
7202
- /** Change a formula to its canonical form (en_US locale) */
7203
- function canonicalizeFormula(formula, locale) {
7204
- return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7205
- }
7206
- function _localizeFormula(formula, fromLocale, toLocale) {
7207
- if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7208
- fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7209
- return formula;
7210
- }
7211
- const tokens = tokenize(formula, fromLocale);
7212
- let localizedFormula = "";
7213
- for (const token of tokens) {
7214
- if (token.type === "NUMBER") {
7215
- localizedFormula += token.value.replace(fromLocale.decimalSeparator, toLocale.decimalSeparator);
7216
- }
7217
- else if (token.type === "ARG_SEPARATOR") {
7218
- localizedFormula += toLocale.formulaArgSeparator;
7219
- }
7220
- else {
7221
- localizedFormula += token.value;
7222
- }
7223
- }
7224
- return localizedFormula;
7225
- }
7226
-
7227
7205
  function boolAnd(args) {
7228
7206
  let foundBoolean = false;
7229
7207
  let acc = true;
@@ -9599,6 +9577,7 @@ class ComposerFocusStore extends SpreadsheetStore {
9599
9577
  }
9600
9578
 
9601
9579
  const TREND_LINE_XAXIS_ID = "x1";
9580
+ const MOVING_AVERAGE_TREND_LINE_XAXIS_ID = "xMovingAverage";
9602
9581
  /**
9603
9582
  * This file contains helpers that are common to different charts (mainly
9604
9583
  * line, bar and pie charts)
@@ -9949,6 +9928,9 @@ function truncateLabel(label) {
9949
9928
  }
9950
9929
  return label;
9951
9930
  }
9931
+ function isTrendLineAxis(axisID) {
9932
+ return axisID === TREND_LINE_XAXIS_ID || axisID === MOVING_AVERAGE_TREND_LINE_XAXIS_ID;
9933
+ }
9952
9934
 
9953
9935
  /** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
9954
9936
  const chartShowValuesPlugin = {
@@ -9993,7 +9975,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
9993
9975
  const yMin = chart.chartArea.top;
9994
9976
  const textsPositions = {};
9995
9977
  for (const dataset of chart._metasets) {
9996
- if (dataset.xAxisID === TREND_LINE_XAXIS_ID || dataset.hidden) {
9978
+ if (isTrendLineAxis(dataset.axisID) || dataset.hidden) {
9997
9979
  continue;
9998
9980
  }
9999
9981
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10036,7 +10018,7 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
10036
10018
  const xMin = chart.chartArea.left;
10037
10019
  const textsPositions = {};
10038
10020
  for (const dataset of chart._metasets) {
10039
- if (dataset.xAxisID === TREND_LINE_XAXIS_ID) {
10021
+ if (isTrendLineAxis(dataset.axisID)) {
10040
10022
  return; // ignore trend lines
10041
10023
  }
10042
10024
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -20544,11 +20526,26 @@ const SEARCH = {
20544
20526
  const _searchFor = toString(searchFor).toLowerCase();
20545
20527
  const _textToSearch = toString(textToSearch).toLowerCase();
20546
20528
  const _startingAt = toNumber(startingAt, this.locale);
20547
- assert(() => _textToSearch !== "", _t("The text_to_search must be non-empty."));
20548
- assert(() => _startingAt >= 1, _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt.toString()));
20529
+ if (_textToSearch === "") {
20530
+ return {
20531
+ value: CellErrorType.GenericError,
20532
+ message: _t("The text_to_search must be non-empty."),
20533
+ };
20534
+ }
20535
+ if (_startingAt < 1) {
20536
+ return {
20537
+ value: CellErrorType.GenericError,
20538
+ message: _t("The starting_at (%s) must be greater than or equal to 1.", _startingAt),
20539
+ };
20540
+ }
20549
20541
  const result = _textToSearch.indexOf(_searchFor, _startingAt - 1);
20550
- assert(() => result >= 0, _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch));
20551
- return result + 1;
20542
+ if (result === -1) {
20543
+ return {
20544
+ value: CellErrorType.GenericError,
20545
+ message: _t("In [[FUNCTION_NAME]] evaluation, cannot find '%s' within '%s'.", _searchFor, _textToSearch),
20546
+ };
20547
+ }
20548
+ return { value: result + 1 };
20552
20549
  },
20553
20550
  isExported: true,
20554
20551
  };
@@ -21883,11 +21880,14 @@ function compileTokens(tokens) {
21883
21880
  }
21884
21881
  }
21885
21882
  function compileTokensOrThrow(tokens) {
21886
- const { dependencies, constantValues, symbols } = formulaArguments(tokens);
21887
- const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
21883
+ const { dependencies, literalValues, symbols } = formulaArguments(tokens);
21884
+ const cacheKey = compilationCacheKey(tokens);
21888
21885
  if (!functionCache[cacheKey]) {
21889
21886
  const ast = parseTokens([...tokens]);
21890
21887
  const scope = new Scope();
21888
+ let stringCount = 0;
21889
+ let numberCount = 0;
21890
+ let dependencyCount = 0;
21891
21891
  if (ast.type === "BIN_OPERATION" && ast.value === ":") {
21892
21892
  throw new BadExpressionError(_t("Invalid formula"));
21893
21893
  }
@@ -21961,16 +21961,15 @@ function compileTokensOrThrow(tokens) {
21961
21961
  case "BOOLEAN":
21962
21962
  return code.return(`{ value: ${ast.value} }`);
21963
21963
  case "NUMBER":
21964
- return code.return(`{ value: this.constantValues.numbers[${constantValues.numbers.indexOf(ast.value)}] }`);
21964
+ return code.return(`this.literalValues.numbers[${numberCount++}]`);
21965
21965
  case "STRING":
21966
- return code.return(`{ value: this.constantValues.strings[${constantValues.strings.indexOf(ast.value)}] }`);
21966
+ return code.return(`this.literalValues.strings[${stringCount++}]`);
21967
21967
  case "REFERENCE":
21968
- const referenceIndex = dependencies.indexOf(ast.value);
21969
21968
  if ((!isMeta && ast.value.includes(":")) || hasRange) {
21970
- return code.return(`range(deps[${referenceIndex}])`);
21969
+ return code.return(`range(deps[${dependencyCount++}])`);
21971
21970
  }
21972
21971
  else {
21973
- return code.return(`ref(deps[${referenceIndex}], ${isMeta ? "true" : "false"})`);
21972
+ return code.return(`ref(deps[${dependencyCount++}], ${isMeta ? "true" : "false"})`);
21974
21973
  }
21975
21974
  case "FUNCALL":
21976
21975
  const args = compileFunctionArgs(ast).map((arg) => arg.assignResultToVariable());
@@ -22002,7 +22001,7 @@ function compileTokensOrThrow(tokens) {
22002
22001
  const compiledFormula = {
22003
22002
  execute: functionCache[cacheKey],
22004
22003
  dependencies,
22005
- constantValues,
22004
+ literalValues,
22006
22005
  symbols,
22007
22006
  tokens,
22008
22007
  isBadExpression: false,
@@ -22015,33 +22014,31 @@ function compileTokensOrThrow(tokens) {
22015
22014
  * References, numbers and strings are replaced with placeholders because
22016
22015
  * the compiled formula does not depend on their actual value.
22017
22016
  * Both `=A1+1+"2"` and `=A2+2+"3"` are compiled to the exact same function.
22018
- *
22019
22017
  * Spaces are also ignored to compute the cache key.
22020
22018
  *
22021
- * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|0|+|1|+SUM(|N0|,|N0|,|S0|)`
22019
+ * A formula `=A1+A2+SUM(2, 2, "2")` have the cache key `=|C|+|C|+SUM(|N|,|N|,|S|)`
22022
22020
  */
22023
- function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
22021
+ function compilationCacheKey(tokens) {
22024
22022
  let cacheKey = "";
22025
22023
  for (const token of tokens) {
22026
22024
  switch (token.type) {
22027
22025
  case "STRING":
22028
- const value = removeStringQuotes(token.value);
22029
- cacheKey += `|S${constantValues.strings.indexOf(value)}|`;
22026
+ cacheKey += "|S|";
22030
22027
  break;
22031
22028
  case "NUMBER":
22032
- cacheKey += `|N${constantValues.numbers.indexOf(parseNumber(token.value, DEFAULT_LOCALE))}|`;
22029
+ cacheKey += "|N|";
22033
22030
  break;
22034
22031
  case "REFERENCE":
22035
22032
  case "INVALID_REFERENCE":
22036
22033
  if (token.value.includes(":")) {
22037
- cacheKey += `R|${dependencies.indexOf(token.value)}|`;
22034
+ cacheKey += "|R|";
22038
22035
  }
22039
22036
  else {
22040
- cacheKey += `C|${dependencies.indexOf(token.value)}|`;
22037
+ cacheKey += "|C|";
22041
22038
  }
22042
22039
  break;
22043
22040
  case "SPACE":
22044
- cacheKey += "";
22041
+ // ignore spaces
22045
22042
  break;
22046
22043
  default:
22047
22044
  cacheKey += token.value;
@@ -22054,7 +22051,7 @@ function compilationCacheKey(tokens, dependencies, constantValues, symbols) {
22054
22051
  * Return formula arguments which are references, strings and numbers.
22055
22052
  */
22056
22053
  function formulaArguments(tokens) {
22057
- const constantValues = {
22054
+ const literalValues = {
22058
22055
  numbers: [],
22059
22056
  strings: [],
22060
22057
  };
@@ -22068,15 +22065,11 @@ function formulaArguments(tokens) {
22068
22065
  break;
22069
22066
  case "STRING":
22070
22067
  const value = removeStringQuotes(token.value);
22071
- if (!constantValues.strings.includes(value)) {
22072
- constantValues.strings.push(value);
22073
- }
22068
+ literalValues.strings.push({ value });
22074
22069
  break;
22075
22070
  case "NUMBER": {
22076
22071
  const value = parseNumber(token.value, DEFAULT_LOCALE);
22077
- if (!constantValues.numbers.includes(value)) {
22078
- constantValues.numbers.push(value);
22079
- }
22072
+ literalValues.numbers.push({ value });
22080
22073
  break;
22081
22074
  }
22082
22075
  case "SYMBOL": {
@@ -22087,7 +22080,7 @@ function formulaArguments(tokens) {
22087
22080
  }
22088
22081
  return {
22089
22082
  dependencies,
22090
- constantValues,
22083
+ literalValues,
22091
22084
  symbols,
22092
22085
  };
22093
22086
  }
@@ -23008,9 +23001,9 @@ const XLSX_CHART_TYPES = [
23008
23001
  /** In XLSX color format (no #) */
23009
23002
  const AUTO_COLOR = "000000";
23010
23003
  const XLSX_ICONSET_MAP = {
23011
- arrow: "3Arrows",
23004
+ arrows: "3Arrows",
23012
23005
  smiley: "3Symbols",
23013
- dot: "3TrafficLights1",
23006
+ dots: "3TrafficLights1",
23014
23007
  };
23015
23008
  const NAMESPACE = {
23016
23009
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -23541,6 +23534,7 @@ const ICON_SET_CONVERSION_MAP = {
23541
23534
  };
23542
23535
  /** Map between legend position in XLSX file and human readable position */
23543
23536
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
23537
+ none: "none",
23544
23538
  b: "bottom",
23545
23539
  t: "top",
23546
23540
  l: "left",
@@ -26303,7 +26297,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26303
26297
  default: "ffffff",
26304
26298
  }).asString(),
26305
26299
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
26306
- default: "b",
26300
+ default: "none",
26307
26301
  }).asString()],
26308
26302
  stacked: barChartGrouping === "stacked",
26309
26303
  fontColor: "000000",
@@ -26337,7 +26331,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
26337
26331
  default: "ffffff",
26338
26332
  }).asString(),
26339
26333
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(chartElement, "c:legendPos", "val", {
26340
- default: "b",
26334
+ default: "none",
26341
26335
  }).asString()],
26342
26336
  stacked: barChartGrouping === "stacked",
26343
26337
  fontColor: "000000",
@@ -28949,7 +28943,8 @@ function getChartLabelValues(getters, dataSets, labelRange) {
28949
28943
  }
28950
28944
  }
28951
28945
  else if (dataSets.length === 1) {
28952
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
28946
+ const dataLength = getData(getters, dataSets[0]).length;
28947
+ for (let i = 0; i < dataLength; i++) {
28953
28948
  labels.formattedValues.push("");
28954
28949
  labels.values.push("");
28955
28950
  }
@@ -29132,7 +29127,7 @@ function getLineChartDatasets(definition, args) {
29132
29127
  function getScatterChartDatasets(definition, args) {
29133
29128
  const dataSets = getLineChartDatasets(definition, args);
29134
29129
  for (const dataSet of dataSets) {
29135
- if (dataSet.xAxisID !== TREND_LINE_XAXIS_ID) {
29130
+ if (!isTrendLineAxis(dataSet.xAxisID)) {
29136
29131
  dataSet.showLine = false;
29137
29132
  }
29138
29133
  }
@@ -29259,7 +29254,9 @@ function getTrendingLineDataSet(dataset, config, data) {
29259
29254
  const borderColor = config.color || lightenColor(rgbaToHex(defaultBorderColor), 0.5);
29260
29255
  return {
29261
29256
  type: "line",
29262
- xAxisID: TREND_LINE_XAXIS_ID,
29257
+ xAxisID: config.type === "trailingMovingAverage"
29258
+ ? MOVING_AVERAGE_TREND_LINE_XAXIS_ID
29259
+ : TREND_LINE_XAXIS_ID,
29263
29260
  yAxisID: dataset.yAxisID,
29264
29261
  label: dataset.label ? _t("Trend line for %s", dataset.label) : "",
29265
29262
  data,
@@ -29334,22 +29331,19 @@ function getPieChartLegend(definition, args) {
29334
29331
  const { dataSetsValues } = args;
29335
29332
  const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
29336
29333
  const colors = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
29334
+ const fontColor = chartFontColor(definition.background);
29337
29335
  return {
29338
29336
  ...getLegendDisplayOptions(definition),
29339
29337
  labels: {
29340
- color: chartFontColor(definition.background),
29341
29338
  usePointStyle: true,
29342
- //@ts-ignore
29343
- generateLabels: (c) =>
29344
- //@ts-ignore
29345
- c.data.labels.map((label, index) => ({
29339
+ generateLabels: (c) => c.data.labels?.map((label, index) => ({
29346
29340
  text: truncateLabel(String(label)),
29347
29341
  strokeStyle: colors[index],
29348
29342
  fillStyle: colors[index],
29349
29343
  pointStyle: "rect",
29350
- hidden: false,
29351
29344
  lineWidth: 2,
29352
- })),
29345
+ fontColor,
29346
+ })) || [],
29353
29347
  filter: (legendItem, data) => {
29354
29348
  return "datasetIndex" in legendItem
29355
29349
  ? !data.datasets[legendItem.datasetIndex].hidden
@@ -29482,7 +29476,7 @@ function getCustomLegendLabels(fontColor, legendLabelConfig) {
29482
29476
  color: fontColor,
29483
29477
  usePointStyle: true,
29484
29478
  generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
29485
- if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
29479
+ if (isTrendLineAxis(dataset["xAxisID"])) {
29486
29480
  return {
29487
29481
  text: truncateLabel(dataset.label),
29488
29482
  fontColor,
@@ -29540,6 +29534,11 @@ function getBarChartScales(definition, args) {
29540
29534
  offset: false,
29541
29535
  display: false,
29542
29536
  };
29537
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29538
+ ...scales.x,
29539
+ offset: false,
29540
+ display: false,
29541
+ };
29543
29542
  }
29544
29543
  return scales;
29545
29544
  }
@@ -29573,6 +29572,10 @@ function getLineChartScales(definition, args) {
29573
29572
  ...scales.x,
29574
29573
  display: false,
29575
29574
  };
29575
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29576
+ ...scales.x,
29577
+ display: false,
29578
+ };
29576
29579
  if (axisType === "category" || axisType === "time") {
29577
29580
  /* We add a second x axis here to draw the trend lines, with the labels length being
29578
29581
  * set so that the second axis points match the classical x axis
@@ -29581,6 +29584,8 @@ function getLineChartScales(definition, args) {
29581
29584
  scales[TREND_LINE_XAXIS_ID]["type"] = "category";
29582
29585
  scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
29583
29586
  scales[TREND_LINE_XAXIS_ID]["offset"] = false;
29587
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["type"] = "category";
29588
+ scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID]["offset"] = false;
29584
29589
  }
29585
29590
  }
29586
29591
  return scales;
@@ -29899,9 +29904,7 @@ function getBarChartTooltip(definition, args) {
29899
29904
  external: customTooltipHandler,
29900
29905
  callbacks: {
29901
29906
  title: function (tooltipItems) {
29902
- return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
29903
- ? undefined
29904
- : "";
29907
+ return tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID)) ? undefined : "";
29905
29908
  },
29906
29909
  beforeLabel: (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label,
29907
29910
  label: function (tooltipItem) {
@@ -29928,7 +29931,7 @@ function getLineChartTooltip(definition, args) {
29928
29931
  if (axisType === "linear") {
29929
29932
  tooltip.callbacks.label = (tooltipItem) => {
29930
29933
  const dataSetPoint = tooltipItem.parsed.y;
29931
- let label = tooltipItem.dataset.xAxisID === TREND_LINE_XAXIS_ID
29934
+ let label = isTrendLineAxis(tooltipItem.dataset.xAxisID)
29932
29935
  ? ""
29933
29936
  : tooltipItem.parsed.x;
29934
29937
  if (typeof label === "string" && isNumber(label, locale)) {
@@ -29950,8 +29953,7 @@ function getLineChartTooltip(definition, args) {
29950
29953
  }
29951
29954
  tooltip.callbacks.beforeLabel = (tooltipItem) => tooltipItem.dataset?.label || tooltipItem.label;
29952
29955
  tooltip.callbacks.title = function (tooltipItems) {
29953
- const displayTooltipTitle = axisType !== "linear" &&
29954
- tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID);
29956
+ const displayTooltipTitle = axisType !== "linear" && tooltipItems.some((item) => !isTrendLineAxis(item.dataset.xAxisID));
29955
29957
  return displayTooltipTitle ? undefined : "";
29956
29958
  };
29957
29959
  return tooltip;
@@ -34205,6 +34207,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
34205
34207
  CHART_COMMON_OPTIONS: CHART_COMMON_OPTIONS,
34206
34208
  GaugeChart: GaugeChart,
34207
34209
  LineChart: LineChart,
34210
+ MOVING_AVERAGE_TREND_LINE_XAXIS_ID: MOVING_AVERAGE_TREND_LINE_XAXIS_ID,
34208
34211
  PieChart: PieChart,
34209
34212
  ScorecardChart: ScorecardChart$1,
34210
34213
  TREND_LINE_XAXIS_ID: TREND_LINE_XAXIS_ID,
@@ -34234,6 +34237,7 @@ var CHART_HELPERS = /*#__PURE__*/Object.freeze({
34234
34237
  getDefinedAxis: getDefinedAxis,
34235
34238
  getPieColors: getPieColors,
34236
34239
  getSmartChartDefinition: getSmartChartDefinition,
34240
+ isTrendLineAxis: isTrendLineAxis,
34237
34241
  shouldRemoveFirstLabel: shouldRemoveFirstLabel,
34238
34242
  toExcelDataset: toExcelDataset,
34239
34243
  toExcelLabelRange: toExcelLabelRange,
@@ -36281,9 +36285,7 @@ class FormulaFingerprintStore extends SpreadsheetStore {
36281
36285
  }
36282
36286
  }
36283
36287
  }
36284
- // removes the index placeholders from the normalized formula
36285
- // =|N0|+|N1|+|N0| -> =|N|+|N|+|N|
36286
- const normalizedFormula = cell.compiledFormula.normalizedFormula.replace(/(|\w)(\d)(|)/g, "$1$3");
36288
+ const normalizedFormula = cell.compiledFormula.normalizedFormula;
36287
36289
  return hash(fingerprintVector) + normalizedFormula;
36288
36290
  }
36289
36291
  getLiteralFingerprint(position) {
@@ -39628,9 +39630,11 @@ class SeriesDesignEditor extends Component {
39628
39630
  if (!runtime || !("chartJsConfig" in runtime)) {
39629
39631
  return [];
39630
39632
  }
39631
- return runtime.chartJsConfig.data.datasets.map((d) => d.label);
39633
+ return runtime.chartJsConfig.data.datasets
39634
+ .filter((d) => !isTrendLineAxis(d["xAxisID"] ?? ""))
39635
+ .map((d) => d.label);
39632
39636
  }
39633
- updateSerieEditor(ev) {
39637
+ updateEditedSeries(ev) {
39634
39638
  this.state.index = ev.target.selectedIndex;
39635
39639
  }
39636
39640
  updateDataSeriesColor(color) {
@@ -39643,7 +39647,7 @@ class SeriesDesignEditor extends Component {
39643
39647
  };
39644
39648
  this.props.updateChart(this.props.figureId, { dataSets });
39645
39649
  }
39646
- getDataSerieColor() {
39650
+ getDataSeriesColor() {
39647
39651
  const dataSets = this.props.definition.dataSets;
39648
39652
  if (!dataSets?.[this.state.index])
39649
39653
  return "";
@@ -39663,7 +39667,7 @@ class SeriesDesignEditor extends Component {
39663
39667
  };
39664
39668
  this.props.updateChart(this.props.figureId, { dataSets });
39665
39669
  }
39666
- getDataSerieLabel() {
39670
+ getDataSeriesLabel() {
39667
39671
  const dataSets = this.props.definition.dataSets;
39668
39672
  return dataSets[this.state.index]?.label || this.getDataSeries()[this.state.index];
39669
39673
  }
@@ -39776,7 +39780,7 @@ class SeriesWithAxisDesignEditor extends Component {
39776
39780
  }
39777
39781
  this.updateTrendLineValue(index, { window });
39778
39782
  }
39779
- getDataSerieColor(index) {
39783
+ getDataSeriesColor(index) {
39780
39784
  const dataSets = this.props.definition.dataSets;
39781
39785
  if (!dataSets?.[index])
39782
39786
  return "";
@@ -39787,7 +39791,7 @@ class SeriesWithAxisDesignEditor extends Component {
39787
39791
  }
39788
39792
  getTrendLineColor(index) {
39789
39793
  return (this.getTrendLineConfiguration(index)?.color ??
39790
- setColorAlpha(this.getDataSerieColor(index), 0.5));
39794
+ setColorAlpha(this.getDataSeriesColor(index), 0.5));
39791
39795
  }
39792
39796
  updateTrendLineColor(index, color) {
39793
39797
  this.updateTrendLineValue(index, { color });
@@ -70767,7 +70771,9 @@ css /* scss */ `
70767
70771
  border: 1px solid;
70768
70772
  font-family: ${DEFAULT_FONT};
70769
70773
 
70770
- .o-composer:empty:not(:focus):not(.active)::before {
70774
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
70775
+ .o-composer:empty:not(:focus):not(.active)::before,
70776
+ &.o-topbar-composer-readonly .o-composer:empty::before {
70771
70777
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
70772
70778
  position: relative;
70773
70779
  top: 20%;
@@ -74093,10 +74099,14 @@ function addIconSetRule(cf, rule) {
74093
74099
  continue;
74094
74100
  }
74095
74101
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
74102
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
74103
+ if (isIconSetReversed(rule.icons)) {
74104
+ iconSetAttrs.push(["reverse", "1"]);
74105
+ }
74096
74106
  conditionalFormats.push(escapeXml /*xml*/ `
74097
74107
  <conditionalFormatting sqref="${range}">
74098
74108
  <cfRule ${formatAttributes(ruleAttributes)}>
74099
- <iconSet iconSet="${getIconSet(rule.icons)}">
74109
+ <iconSet ${formatAttributes(iconSetAttrs)}>
74100
74110
  ${joinXmlNodes(cfValueObjectNodes)}
74101
74111
  </iconSet>
74102
74112
  </cfRule>
@@ -74114,9 +74124,21 @@ function commonCfAttributes(cf) {
74114
74124
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
74115
74125
  ];
74116
74126
  }
74127
+ function isIconSetReversed(iconSet) {
74128
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
74129
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
74130
+ }
74117
74131
  function getIconSet(iconSet) {
74118
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
74119
- "dots"];
74132
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
74133
+ }
74134
+ /**
74135
+ * Partial detection based on "upper" point only.
74136
+ * We support any arbitrary icon in the set, while excel doesn't allow
74137
+ * mixing icons from different types.
74138
+ */
74139
+ function detectIconsType(iconSet) {
74140
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
74141
+ return type;
74120
74142
  }
74121
74143
  function thresholdAttributes(threshold, position) {
74122
74144
  const type = getExcelThresholdType(threshold.type, position);
@@ -76021,6 +76043,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
76021
76043
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, 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 };
76022
76044
 
76023
76045
 
76024
- __info__.version = "18.2.4";
76025
- __info__.date = "2025-03-19T08:20:57.717Z";
76026
- __info__.hash = "958936a";
76046
+ __info__.version = "18.2.5";
76047
+ __info__.date = "2025-03-26T12:47:44.113Z";
76048
+ __info__.hash = "4675edd";