@odoo/o-spreadsheet 19.5.0-alpha.12 → 19.5.0-alpha.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 19.5.0-alpha.12
6
- * @date 2026-08-19T09:47:03.774Z
7
- * @hash 68ca68e
5
+ * @version 19.5.0-alpha.13
6
+ * @date 2026-08-21T15:33:44.046Z
7
+ * @hash a73559e
8
8
  */
9
9
 
10
10
  (function(exports, _odoo_owl) {
@@ -403,7 +403,13 @@ _odoo_owl = __toESM(_odoo_owl, 1);
403
403
  if (isEnabled(env)) return item.execute(env, isMiddleClick);
404
404
  } : void 0,
405
405
  children: children ? (env) => {
406
- return children.map((child) => typeof child === "function" ? child(env) : child).flat().map(createAction).sort((a, b) => a.sequence - b.sequence);
406
+ const uniqueChildren = {};
407
+ children.flatMap((child) => typeof child === "function" ? child(env) : child).forEach((childSpec) => {
408
+ const childAction = createAction(childSpec);
409
+ if (uniqueChildren[childAction.id]) throw new Error(`Duplicate child action id "${childAction.id}" in action "${itemId}".`);
410
+ uniqueChildren[childAction.id] = childAction;
411
+ });
412
+ return Object.values(uniqueChildren).sort((a, b) => a.sequence - b.sequence);
407
413
  } : () => [],
408
414
  isReadonlyAllowed: item.isReadonlyAllowed || false,
409
415
  isEnabledOnLockedSheet: item.isEnabledOnLockedSheet || false,
@@ -5409,7 +5415,7 @@ set(value) {
5409
5415
  }
5410
5416
  function humanizeNumber({ value, format }, locale) {
5411
5417
  const numberValue = tryToNumber(value, locale);
5412
- if (numberValue === void 0) return "";
5418
+ if (numberValue === void 0) return value?.toString() || "";
5413
5419
  let numberFormat = format;
5414
5420
  if (Math.abs(numberValue) < 1e3) {
5415
5421
  const hasDecimal = numberValue % 1 !== 0;
@@ -8124,8 +8130,6 @@ set(value) {
8124
8130
  CommandResult["InvalidXRange"] = "InvalidXRange";
8125
8131
  CommandResult["InvalidLabelRange"] = "InvalidLabelRange";
8126
8132
  CommandResult["InvalidBubbleSizeRange"] = "InvalidBubbleSizeRange";
8127
- CommandResult["InvalidScorecardKeyValue"] = "InvalidScorecardKeyValue";
8128
- CommandResult["InvalidScorecardBaseline"] = "InvalidScorecardBaseline";
8129
8133
  CommandResult["InvalidGaugeDataRange"] = "InvalidGaugeDataRange";
8130
8134
  CommandResult["EmptyGaugeRangeMin"] = "EmptyGaugeRangeMin";
8131
8135
  CommandResult["GaugeRangeMinNaN"] = "GaugeRangeMinNaN";
@@ -12012,6 +12016,110 @@ set(value) {
12012
12016
  }
12013
12017
  };
12014
12018
 
12019
+ //#endregion
12020
+ //#region src/functions/helper_matrices.ts
12021
+ function getUnitMatrix(n) {
12022
+ const matrix = Array(n);
12023
+ for (let i = 0; i < n; i++) {
12024
+ matrix[i] = Array(n).fill(0);
12025
+ matrix[i][i] = 1;
12026
+ }
12027
+ return matrix;
12028
+ }
12029
+ /**
12030
+ * Invert a matrix and compute its determinant using Gaussian Elimination.
12031
+ *
12032
+ * The Matrix should be a square matrix, and should be indexed [col][row] instead of the
12033
+ * standard mathematical indexing [row][col].
12034
+ */
12035
+ function invertMatrix(M) {
12036
+ if (M.length < 1 || M[0].length < 1) throw new Error("invertMatrix: an empty matrix cannot be inverted.");
12037
+ if (M.length !== M[0].length) throw new Error("invertMatrix: only square matrices are invertible");
12038
+ let determinant = 1;
12039
+ const dim = M.length;
12040
+ const I = getUnitMatrix(dim);
12041
+ const C = M.map((row) => row.slice());
12042
+ for (let pivot = 0; pivot < dim; pivot++) {
12043
+ let diagonalElement = C[pivot][pivot];
12044
+ if (diagonalElement === 0) {
12045
+ for (let row = pivot + 1; row < dim; row++) if (C[pivot][row] !== 0) {
12046
+ swapMatrixRows(C, pivot, row);
12047
+ swapMatrixRows(I, pivot, row);
12048
+ determinant *= -1;
12049
+ break;
12050
+ }
12051
+ diagonalElement = C[pivot][pivot];
12052
+ if (diagonalElement === 0) return { determinant: 0 };
12053
+ }
12054
+ for (let col = 0; col < dim; col++) {
12055
+ C[col][pivot] = C[col][pivot] / diagonalElement;
12056
+ I[col][pivot] = I[col][pivot] / diagonalElement;
12057
+ }
12058
+ determinant *= diagonalElement;
12059
+ for (let row = 0; row < dim; row++) {
12060
+ if (row === pivot) continue;
12061
+ const e = C[pivot][row];
12062
+ for (let col = 0; col < dim; col++) {
12063
+ C[col][row] -= e * C[col][pivot];
12064
+ I[col][row] -= e * I[col][pivot];
12065
+ }
12066
+ }
12067
+ }
12068
+ return {
12069
+ inverted: I,
12070
+ determinant
12071
+ };
12072
+ }
12073
+ function swapMatrixRows(matrix, row1, row2) {
12074
+ for (let i = 0; i < matrix.length; i++) {
12075
+ const tmp = matrix[i][row1];
12076
+ matrix[i][row1] = matrix[i][row2];
12077
+ matrix[i][row2] = tmp;
12078
+ }
12079
+ }
12080
+ /**
12081
+ * Matrix multiplication of 2 matrices.
12082
+ * ex: matrix1 : n x l, matrix2 : m x n => result : m x l
12083
+ *
12084
+ * Note: we use indexing [col][row] instead of the standard mathematical notation [row][col]
12085
+ */
12086
+ function multiplyMatrices(matrix1, matrix2) {
12087
+ if (matrix1.length < 1 || matrix2.length < 1) throw new Error("multiplyMatrices: empty matrices cannot be multiplied.");
12088
+ if (matrix1.length !== matrix2[0].length) throw new Error("multiplyMatrices: incompatible matrices size.");
12089
+ const rowsM1 = matrix1[0].length;
12090
+ const colsM2 = matrix2.length;
12091
+ const n = matrix1.length;
12092
+ const result = Array(colsM2);
12093
+ for (let col = 0; col < colsM2; col++) {
12094
+ result[col] = Array(rowsM1);
12095
+ for (let row = 0; row < rowsM1; row++) {
12096
+ let sum = 0;
12097
+ for (let k = 0; k < n; k++) sum += matrix1[k][row] * matrix2[col][k];
12098
+ result[col][row] = sum;
12099
+ }
12100
+ }
12101
+ return result;
12102
+ }
12103
+ /**
12104
+ * Return the input if it's a scalar or the first element of the input if it's a matrix.
12105
+ */
12106
+ function toScalar(arg) {
12107
+ if (!isMatrix(arg)) return arg;
12108
+ if (!isSingleElementMatrix(arg)) throw new Error("The value should be a scalar or a 1x1 matrix");
12109
+ return arg[0][0];
12110
+ }
12111
+ function isSingleElementMatrix(matrix) {
12112
+ return matrix.length === 1 && matrix[0].length === 1;
12113
+ }
12114
+ function isMultipleElementMatrix(arg) {
12115
+ return isMatrix(arg) && !isSingleElementMatrix(arg);
12116
+ }
12117
+ function getMatrixArgIndices(args) {
12118
+ const indices = [];
12119
+ for (let i = 0; i < args.length; i++) if (isMultipleElementMatrix(args[i])) indices.push(i);
12120
+ return indices;
12121
+ }
12122
+
12015
12123
  //#endregion
12016
12124
  //#region src/helpers/figures/charts/abstract_chart.ts
12017
12125
  var AbstractChart = class {
@@ -12027,11 +12135,42 @@ set(value) {
12027
12135
 
12028
12136
  //#endregion
12029
12137
  //#region src/helpers/figures/charts/scorecard_chart.ts
12138
+ function getData$1(value, getters, sheetId) {
12139
+ if (!value) return {
12140
+ scalar: void 0,
12141
+ range: void 0
12142
+ };
12143
+ if (!isFormula(value)) return {
12144
+ scalar: { value },
12145
+ range: void 0
12146
+ };
12147
+ const result = getters.evaluateFormulaResult(sheetId, value);
12148
+ let scalar = isMultipleElementMatrix(result) ? result[0][0] : toScalar(result);
12149
+ let range = void 0;
12150
+ const xc = getFormulaRangeXc(value);
12151
+ if (xc) {
12152
+ range = createValidRange(getters, sheetId, xc);
12153
+ if (range) {
12154
+ if (getters.getEvaluatedCell({
12155
+ sheetId: range.sheetId,
12156
+ col: range.zone.left,
12157
+ row: range.zone.top
12158
+ }).type === "empty") scalar = void 0;
12159
+ }
12160
+ }
12161
+ return {
12162
+ scalar,
12163
+ range
12164
+ };
12165
+ }
12030
12166
  function getBaselineText(baseline, keyValue, baselineMode, humanizeNumbers, locale) {
12031
12167
  if (!baseline) return "";
12032
- else if (baselineMode === "text" || keyValue?.type !== "number" || baseline.type !== "number") {
12168
+ else if (baselineMode === "text" || typeof keyValue?.value !== "number" || typeof baseline.value !== "number") {
12033
12169
  if (humanizeNumbers) return humanizeNumber(baseline, locale);
12034
- return baseline.formattedValue;
12170
+ return formatValue(baseline.value, {
12171
+ format: baseline.format,
12172
+ locale
12173
+ });
12035
12174
  }
12036
12175
  let { value, format } = baseline;
12037
12176
  if (baselineMode === "progress") {
@@ -12052,29 +12191,31 @@ set(value) {
12052
12191
  locale
12053
12192
  });
12054
12193
  }
12055
- function getKeyValueText(keyValueCell, humanizeNumbers, locale) {
12056
- if (!keyValueCell) return "";
12057
- if (humanizeNumbers) return humanizeNumber(keyValueCell, locale);
12058
- return keyValueCell.formattedValue ?? String(keyValueCell.value ?? "");
12194
+ function getKeyValueText(keyValue, humanizeNumbers, locale) {
12195
+ if (keyValue?.value === void 0 || keyValue?.value === null) return "";
12196
+ if (humanizeNumbers) return humanizeNumber(keyValue, locale);
12197
+ return keyValue.format ? formatValue(keyValue.value, {
12198
+ format: keyValue.format,
12199
+ locale
12200
+ }) : String(keyValue.value ?? "");
12059
12201
  }
12060
12202
  function getBaselineColor(baseline, baselineMode, keyValue, colorUp, colorDown) {
12061
- if (baselineMode === "text" || baselineMode === "progress" || baseline?.type !== "number" || keyValue?.type !== "number") return;
12203
+ if (baselineMode === "text" || baselineMode === "progress" || typeof baseline?.value !== "number" || typeof keyValue?.value !== "number") return;
12062
12204
  const diff = keyValue.value - baseline.value;
12063
12205
  if (diff > 0) return colorUp;
12064
12206
  else if (diff < 0) return colorDown;
12065
12207
  }
12066
12208
  function getBaselineArrowDirection(baseline, keyValue, baselineMode) {
12067
- if (baselineMode === "text" || baseline?.type !== "number" || keyValue?.type !== "number") return "neutral";
12209
+ if (baselineMode === "text" || typeof baseline?.value !== "number" || typeof keyValue?.value !== "number") return "neutral";
12068
12210
  const diff = keyValue.value - baseline.value;
12069
12211
  if (diff > 0) return "up";
12070
12212
  else if (diff < 0) return "down";
12071
12213
  return "neutral";
12072
12214
  }
12073
- function checkKeyValue(definition) {
12074
- return definition.keyValue && !rangeReference.test(definition.keyValue) ? "InvalidScorecardKeyValue" : "Success";
12075
- }
12076
- function checkBaseline(definition) {
12077
- return definition.baseline && !rangeReference.test(definition.baseline) ? "InvalidScorecardBaseline" : "Success";
12215
+ function getFormulaRangeXc(formula) {
12216
+ if (!formula || !isFormula(formula)) return;
12217
+ const content = formula.slice(1);
12218
+ return rangeReference.test(content) ? content : void 0;
12078
12219
  }
12079
12220
  const Path2DConstructor = globalThis.Path2D;
12080
12221
  const arrowDownPath = Path2DConstructor && new Path2DConstructor("M8.6 4.8a.5.5 0 0 1 0 .75l-3.9 3.9a.5 .5 0 0 1 -.75 0l-3.8 -3.9a.5 .5 0 0 1 0 -.75l.4-.4a.5.5 0 0 1 .75 0l2.3 2.4v-5.7c0-.25.25-.5.5-.5h.6c.25 0 .5.25.5.5v5.8l2.3 -2.4a.5.5 0 0 1 .75 0z");
@@ -12091,84 +12232,76 @@ set(value) {
12091
12232
  "baselineColorUp",
12092
12233
  "baselineColorDown"
12093
12234
  ],
12094
- fromStrDefinition(definition, sheetId, getters) {
12095
- const baseline = createValidRange(getters, sheetId, definition.baseline);
12096
- const keyValue = createValidRange(getters, sheetId, definition.keyValue);
12235
+ fromStrDefinition: (definition) => definition,
12236
+ validateDefinition(validator, definition) {
12237
+ return "Success";
12238
+ },
12239
+ copyInSheetId: (definition, sheetIdFrom, sheetIdTo, getters) => {
12240
+ const adaptFormula = (formula) => getters.copyFormulaStringForSheet(sheetIdFrom, sheetIdTo, formula, "keepSameReference");
12097
12241
  return {
12098
12242
  ...definition,
12099
- baseline,
12100
- keyValue
12243
+ keyValue: definition.keyValue ? adaptFormula(definition.keyValue) : definition.keyValue,
12244
+ baseline: definition.baseline ? adaptFormula(definition.baseline) : definition.baseline
12101
12245
  };
12102
12246
  },
12103
- validateDefinition(validator, definition) {
12104
- return validator.checkValidations(definition, checkKeyValue, checkBaseline);
12105
- },
12106
- copyInSheetId: (definition) => definition,
12107
12247
  getDefinitionFromContextCreation(context, dataSourceBuilder) {
12248
+ const dataRange = context.dataSource?.type === "range" ? context.dataSource?.dataSets?.[0]?.dataRange : void 0;
12249
+ const keyValue = (context.scorecardKeyValueFormula === void 0 || getFormulaRangeXc(context.scorecardKeyValueFormula)) && dataRange ? `=${dataRange}` : context.scorecardKeyValueFormula;
12250
+ const baseline = (context.scorecardBaselineFormula === void 0 || getFormulaRangeXc(context.scorecardBaselineFormula)) && context.auxiliaryRange ? `=${context.auxiliaryRange}` : context.scorecardBaselineFormula;
12108
12251
  return {
12109
12252
  background: context.background,
12110
12253
  type: "scorecard",
12111
- keyValue: context.dataSource?.type === "range" ? context.dataSource?.dataSets?.[0]?.dataRange : void 0,
12254
+ keyValue,
12112
12255
  title: context.title || { text: "" },
12113
12256
  baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
12114
12257
  baselineColorUp: DEFAULT_SCORECARD_BASELINE_COLOR_UP,
12115
12258
  baselineColorDown: DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
12116
- baseline: context.auxiliaryRange || "",
12259
+ baseline,
12117
12260
  humanize: context.humanize,
12118
12261
  annotationLink: context.annotationLink,
12119
12262
  annotationText: context.annotationText
12120
12263
  };
12121
12264
  },
12122
- transformDefinition(definition, chartSheetId, { adaptRangeString }) {
12265
+ transformDefinition(definition, chartSheetId, { adaptFormulaString }) {
12123
12266
  let baseline;
12124
12267
  let keyValue;
12125
- if (definition.baseline) {
12126
- const { changeType, range: adaptedRange } = adaptRangeString(chartSheetId, definition.baseline);
12127
- if (changeType !== "REMOVE") baseline = adaptedRange;
12128
- }
12129
- if (definition.keyValue) {
12130
- const { changeType, range: adaptedRange } = adaptRangeString(chartSheetId, definition.keyValue);
12131
- if (changeType !== "REMOVE") keyValue = adaptedRange;
12132
- }
12133
- return {
12134
- ...definition,
12135
- baseline,
12136
- keyValue
12137
- };
12138
- },
12139
- duplicateInDuplicatedSheet(definition, sheetIdFrom, sheetIdTo) {
12140
- const baseline = duplicateLabelRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, definition.baseline);
12141
- const keyValue = duplicateLabelRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, definition.keyValue);
12268
+ if (definition.baseline) baseline = adaptFormulaString(chartSheetId, definition.baseline);
12269
+ if (definition.keyValue) keyValue = adaptFormulaString(chartSheetId, definition.keyValue);
12142
12270
  return {
12143
12271
  ...definition,
12144
12272
  baseline,
12145
12273
  keyValue
12146
12274
  };
12147
12275
  },
12148
- toStrDefinition(definition, sheetId, getters) {
12276
+ duplicateInDuplicatedSheet(definition, sheetIdFrom, sheetIdTo, getters) {
12277
+ const adaptFormula = (formula) => getters.copyFormulaStringForSheet(sheetIdFrom, sheetIdTo, formula, "moveReference");
12149
12278
  return {
12150
12279
  ...definition,
12151
- keyValue: definition.keyValue ? getters.getRangeString(definition.keyValue, sheetId) : void 0,
12152
- baseline: definition.baseline ? getters.getRangeString(definition.baseline, sheetId) : void 0
12280
+ keyValue: definition.keyValue ? adaptFormula(definition.keyValue) : definition.keyValue,
12281
+ baseline: definition.baseline ? adaptFormula(definition.baseline) : definition.baseline
12153
12282
  };
12154
12283
  },
12284
+ toStrDefinition: (definition) => definition,
12155
12285
  getContextCreation(definition, dataSource) {
12286
+ const keyValueXc = getFormulaRangeXc(definition.keyValue);
12156
12287
  return {
12157
12288
  ...definition,
12158
12289
  dataSource: {
12159
12290
  type: "range",
12160
- dataSets: definition.keyValue ? [{
12161
- dataRange: definition.keyValue,
12291
+ dataSets: keyValueXc ? [{
12292
+ dataRange: keyValueXc,
12162
12293
  dataSetId: "0"
12163
12294
  }] : []
12164
12295
  },
12165
- auxiliaryRange: definition.baseline
12296
+ auxiliaryRange: getFormulaRangeXc(definition.baseline),
12297
+ scorecardKeyValueFormula: definition.keyValue,
12298
+ scorecardBaselineFormula: definition.baseline
12166
12299
  };
12167
12300
  },
12168
12301
  getDefinitionForExcel: () => void 0,
12169
- updateRanges(definition, adapterFunctions) {
12170
- const baseline = adaptChartRange(definition.baseline, adapterFunctions);
12171
- const keyValue = adaptChartRange(definition.keyValue, adapterFunctions);
12302
+ updateRanges(definition, adapterFunctions, sheetId) {
12303
+ const baseline = definition.baseline ? adapterFunctions.adaptFormulaString(sheetId, definition.baseline) : definition.baseline;
12304
+ const keyValue = definition.keyValue ? adapterFunctions.adaptFormulaString(sheetId, definition.keyValue) : definition.keyValue;
12172
12305
  if (definition.baseline === baseline && definition.keyValue === keyValue) return definition;
12173
12306
  return {
12174
12307
  ...definition,
@@ -12176,32 +12309,21 @@ set(value) {
12176
12309
  keyValue
12177
12310
  };
12178
12311
  },
12179
- getFormulas: () => [],
12180
- getRuntime(getters, definition) {
12312
+ getFormulas(getters, sheetId, definition) {
12313
+ const formulas = [];
12314
+ if (definition.keyValue && isFormula(definition.keyValue)) formulas.push(CompiledFormula.Compile(definition.keyValue, sheetId, getters));
12315
+ if (definition.baseline && isFormula(definition.baseline)) formulas.push(CompiledFormula.Compile(definition.baseline, sheetId, getters));
12316
+ return formulas;
12317
+ },
12318
+ getRuntime(getters, definition, _dataExtractor, sheetId) {
12181
12319
  let formattedKeyValue = "";
12182
- let keyValueCell;
12320
+ const { scalar: keyValue, range: keyValueRange } = getData$1(definition.keyValue, getters, sheetId);
12183
12321
  const locale = getters.getLocale();
12184
- if (definition.keyValue) {
12185
- const keyValuePosition = {
12186
- sheetId: definition.keyValue.sheetId,
12187
- col: definition.keyValue.zone.left,
12188
- row: definition.keyValue.zone.top
12189
- };
12190
- keyValueCell = getters.getEvaluatedCell(keyValuePosition);
12191
- formattedKeyValue = getKeyValueText(keyValueCell, definition.humanize ?? true, locale);
12192
- }
12193
- let baselineCell;
12194
- const baseline = definition.baseline;
12195
- if (baseline) {
12196
- const baselinePosition = {
12197
- sheetId: baseline.sheetId,
12198
- col: baseline.zone.left,
12199
- row: baseline.zone.top
12200
- };
12201
- baselineCell = getters.getEvaluatedCell(baselinePosition);
12202
- }
12203
- const { background, fontColor } = getters.getStyleOfSingleCellChart(definition.background, definition.keyValue);
12204
- const baselineDisplay = getBaselineText(baselineCell, keyValueCell, definition.baselineMode, definition.humanize ?? true, locale);
12322
+ if (keyValue !== null && keyValue !== void 0) formattedKeyValue = getKeyValueText(keyValue, definition.humanize ?? true, locale);
12323
+ else formattedKeyValue = "";
12324
+ const { scalar: baseline, range: baselineRange } = getData$1(definition.baseline, getters, sheetId);
12325
+ const { background, fontColor } = getters.getStyleOfSingleCellChart(definition.background, keyValueRange);
12326
+ const baselineDisplay = getBaselineText(baseline, keyValue, definition.baselineMode, definition.humanize ?? true, locale);
12205
12327
  const baselineValue = definition.baselineMode === "progress" && isNumber(baselineDisplay, locale) ? toNumber(baselineDisplay, locale) : 0;
12206
12328
  const title = definition.title;
12207
12329
  return {
@@ -12212,16 +12334,16 @@ set(value) {
12212
12334
  keyValue: formattedKeyValue,
12213
12335
  keyDescr: definition.keyDescr?.text ? getters.dynamicTranslate(definition.keyDescr.text) : "",
12214
12336
  baselineDisplay,
12215
- baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, definition.baselineMode),
12216
- baselineColor: getBaselineColor(baselineCell, definition.baselineMode, keyValueCell, definition.baselineColorUp, definition.baselineColorDown),
12337
+ baselineArrow: getBaselineArrowDirection(baseline, keyValue, definition.baselineMode),
12338
+ baselineColor: getBaselineColor(baseline, definition.baselineMode, keyValue, definition.baselineColorUp, definition.baselineColorDown),
12217
12339
  baselineDescr: definition.baselineMode !== "progress" && definition.baselineDescr?.text ? getters.dynamicTranslate(definition.baselineDescr.text) : "",
12218
12340
  fontColor,
12219
12341
  background,
12220
12342
  baselineStyle: {
12221
- ...definition.baselineMode !== "percentage" && definition.baselineMode !== "progress" && baseline ? getters.getCellComputedStyle({
12222
- sheetId: baseline.sheetId,
12223
- col: baseline.zone.left,
12224
- row: baseline.zone.top
12343
+ ...definition.baselineMode !== "percentage" && definition.baselineMode !== "progress" && baselineRange ? getters.getCellComputedStyle({
12344
+ sheetId: baselineRange.sheetId,
12345
+ col: baselineRange.zone.left,
12346
+ row: baselineRange.zone.top
12225
12347
  }) : void 0,
12226
12348
  fontSize: definition.baselineDescr?.fontSize,
12227
12349
  align: definition.baselineDescr?.align
@@ -12231,10 +12353,10 @@ set(value) {
12231
12353
  ...definition.baselineDescr
12232
12354
  },
12233
12355
  keyValueStyle: {
12234
- ...definition.keyValue ? getters.getCellComputedStyle({
12235
- sheetId: definition.keyValue.sheetId,
12236
- col: definition.keyValue.zone.left,
12237
- row: definition.keyValue.zone.top
12356
+ ...keyValueRange ? getters.getCellComputedStyle({
12357
+ sheetId: keyValueRange.sheetId,
12358
+ col: keyValueRange.zone.left,
12359
+ row: keyValueRange.zone.top
12238
12360
  }) : void 0,
12239
12361
  fontSize: definition.keyDescr?.fontSize,
12240
12362
  align: definition.keyDescr?.align
@@ -13736,33 +13858,8 @@ set(value) {
13736
13858
  displayedSheetId = this.model.getters.getActiveSheetId();
13737
13859
  constructor(get) {
13738
13860
  super(get);
13739
- this.model.selection.observe(this, { handleEvent: this.handleEvent.bind(this) });
13740
- this.onDispose(() => {
13741
- this.model.selection.unobserve(this);
13742
- });
13743
13861
  this.viewports.resetViewports(this.displayedSheetId);
13744
13862
  }
13745
- handleEvent(event) {
13746
- const eventSheetId = this.getters.getActiveSheetId();
13747
- if (event.options.scrollIntoView) {
13748
- const oldZone = event.previousAnchor.zone;
13749
- const newZone = event.anchor.zone;
13750
- const isUpdateAnchorEvent = event.mode === "updateAnchor";
13751
- const sameZone = isEqual(oldZone, newZone);
13752
- let { col, row } = isUpdateAnchorEvent && sameZone ? event.anchor.cell : findCellInNewZone(oldZone, newZone);
13753
- if (isUpdateAnchorEvent && !sameZone) {
13754
- const { top, bottom, left, right } = this.viewports.getMainInternalViewport(eventSheetId);
13755
- if (oldZone.left === newZone.left && oldZone.right === newZone.right) col = left > col || col > right ? left : col;
13756
- if (oldZone.top === newZone.top && oldZone.bottom === newZone.bottom) row = top > row || row > bottom ? top : row;
13757
- }
13758
- col = Math.min(col, this.getters.getNumberCols(eventSheetId) - 1);
13759
- row = Math.min(row, this.getters.getNumberRows(eventSheetId) - 1);
13760
- if (!this.sheetsWithDirtyViewports.has(eventSheetId)) this.viewports.refreshViewport(eventSheetId, {
13761
- col,
13762
- row
13763
- });
13764
- }
13765
- }
13766
13863
  handle(cmd) {
13767
13864
  if (invalidateEvaluationCommands.has(cmd.type)) for (const sheetId of this.getters.getSheetIds()) this.sheetsWithDirtyViewports.add(sheetId);
13768
13865
  switch (cmd.type) {
@@ -13862,6 +13959,7 @@ set(value) {
13862
13959
  this.shiftVertically(topRowDims.end - boundaryTopY - viewportHeight);
13863
13960
  }
13864
13961
  scrollToCell(sheetId, col, row) {
13962
+ if (this.sheetsWithDirtyViewports.has(sheetId)) return;
13865
13963
  this.viewports.refreshViewport(sheetId, {
13866
13964
  col,
13867
13965
  row
@@ -16954,110 +17052,6 @@ set(value) {
16954
17052
  }
16955
17053
  const expectNumberGreaterThanOrEqualToOne = (value) => _t("The function [[FUNCTION_NAME]] expects a number value to be greater than or equal to 1, but receives %s.", value);
16956
17054
 
16957
- //#endregion
16958
- //#region src/functions/helper_matrices.ts
16959
- function getUnitMatrix(n) {
16960
- const matrix = Array(n);
16961
- for (let i = 0; i < n; i++) {
16962
- matrix[i] = Array(n).fill(0);
16963
- matrix[i][i] = 1;
16964
- }
16965
- return matrix;
16966
- }
16967
- /**
16968
- * Invert a matrix and compute its determinant using Gaussian Elimination.
16969
- *
16970
- * The Matrix should be a square matrix, and should be indexed [col][row] instead of the
16971
- * standard mathematical indexing [row][col].
16972
- */
16973
- function invertMatrix(M) {
16974
- if (M.length < 1 || M[0].length < 1) throw new Error("invertMatrix: an empty matrix cannot be inverted.");
16975
- if (M.length !== M[0].length) throw new Error("invertMatrix: only square matrices are invertible");
16976
- let determinant = 1;
16977
- const dim = M.length;
16978
- const I = getUnitMatrix(dim);
16979
- const C = M.map((row) => row.slice());
16980
- for (let pivot = 0; pivot < dim; pivot++) {
16981
- let diagonalElement = C[pivot][pivot];
16982
- if (diagonalElement === 0) {
16983
- for (let row = pivot + 1; row < dim; row++) if (C[pivot][row] !== 0) {
16984
- swapMatrixRows(C, pivot, row);
16985
- swapMatrixRows(I, pivot, row);
16986
- determinant *= -1;
16987
- break;
16988
- }
16989
- diagonalElement = C[pivot][pivot];
16990
- if (diagonalElement === 0) return { determinant: 0 };
16991
- }
16992
- for (let col = 0; col < dim; col++) {
16993
- C[col][pivot] = C[col][pivot] / diagonalElement;
16994
- I[col][pivot] = I[col][pivot] / diagonalElement;
16995
- }
16996
- determinant *= diagonalElement;
16997
- for (let row = 0; row < dim; row++) {
16998
- if (row === pivot) continue;
16999
- const e = C[pivot][row];
17000
- for (let col = 0; col < dim; col++) {
17001
- C[col][row] -= e * C[col][pivot];
17002
- I[col][row] -= e * I[col][pivot];
17003
- }
17004
- }
17005
- }
17006
- return {
17007
- inverted: I,
17008
- determinant
17009
- };
17010
- }
17011
- function swapMatrixRows(matrix, row1, row2) {
17012
- for (let i = 0; i < matrix.length; i++) {
17013
- const tmp = matrix[i][row1];
17014
- matrix[i][row1] = matrix[i][row2];
17015
- matrix[i][row2] = tmp;
17016
- }
17017
- }
17018
- /**
17019
- * Matrix multiplication of 2 matrices.
17020
- * ex: matrix1 : n x l, matrix2 : m x n => result : m x l
17021
- *
17022
- * Note: we use indexing [col][row] instead of the standard mathematical notation [row][col]
17023
- */
17024
- function multiplyMatrices(matrix1, matrix2) {
17025
- if (matrix1.length < 1 || matrix2.length < 1) throw new Error("multiplyMatrices: empty matrices cannot be multiplied.");
17026
- if (matrix1.length !== matrix2[0].length) throw new Error("multiplyMatrices: incompatible matrices size.");
17027
- const rowsM1 = matrix1[0].length;
17028
- const colsM2 = matrix2.length;
17029
- const n = matrix1.length;
17030
- const result = Array(colsM2);
17031
- for (let col = 0; col < colsM2; col++) {
17032
- result[col] = Array(rowsM1);
17033
- for (let row = 0; row < rowsM1; row++) {
17034
- let sum = 0;
17035
- for (let k = 0; k < n; k++) sum += matrix1[k][row] * matrix2[col][k];
17036
- result[col][row] = sum;
17037
- }
17038
- }
17039
- return result;
17040
- }
17041
- /**
17042
- * Return the input if it's a scalar or the first element of the input if it's a matrix.
17043
- */
17044
- function toScalar(arg) {
17045
- if (!isMatrix(arg)) return arg;
17046
- if (!isSingleElementMatrix(arg)) throw new Error("The value should be a scalar or a 1x1 matrix");
17047
- return arg[0][0];
17048
- }
17049
- function isSingleElementMatrix(matrix) {
17050
- return matrix.length === 1 && matrix[0].length === 1;
17051
- }
17052
- function isMultipleElementMatrix(arg) {
17053
- return isMatrix(arg) && !isSingleElementMatrix(arg);
17054
- }
17055
- function getMatrixArgIndices(args) {
17056
- const indices = [];
17057
- for (let i = 0; i < args.length; i++) if (isMultipleElementMatrix(args[i])) indices.push(i);
17058
- return indices;
17059
- }
17060
-
17061
17055
  //#endregion
17062
17056
  //#region src/functions/helper_statistical.ts
17063
17057
  function assertSameNumberOfElements(...args) {
@@ -18208,8 +18202,6 @@ set(value) {
18208
18202
  Unexpected: _t("The chart definition is invalid for an unknown reason"),
18209
18203
  ["InvalidDataSet"]: _t("The dataset is invalid"),
18210
18204
  ["InvalidLabelRange"]: _t("Labels are invalid"),
18211
- ["InvalidScorecardKeyValue"]: _t("The key value is invalid"),
18212
- ["InvalidScorecardBaseline"]: _t("The baseline value is invalid"),
18213
18205
  ["InvalidGaugeDataRange"]: _t("The data range is invalid"),
18214
18206
  ["EmptyGaugeRangeMin"]: _t("A minimum range limit value is needed"),
18215
18207
  ["GaugeRangeMinNaN"]: _t("The minimum range limit value must be a number"),
@@ -21886,7 +21878,7 @@ set(value) {
21886
21878
  };
21887
21879
  }
21888
21880
  function getDataFilterIcon(isActive, isHighContrast, isHovered) {
21889
- const symbolPath = isActive ? "M18.6 3.5H4.29c-.7 0-1.06.85-.56 1.35l6.1 6.1v6.8c0 .26.13.5.34.65l2.64 1.85a.79.79 0 0 0 1.25-.65v-8.64l6.1-6.1a.79.79 0 0 0-.56-1.35" : "M 339.667 681 L 510.333 681 L 510.333 595.667 L 339.667 595.667 L 339.667 681 Z M 41 169 L 41 254.333 L 809 254.333 L 809 169 L 41 169 Z M 169 467.667 L 681 467.667 L 681 382.333 L 169 382.333 L 169 467.667 Z";
21881
+ const symbolPath = isActive ? "M 11 20 Q 10.575 20 10.2875 19.7125 T 10 19 L 10 13 L 4.2 5.6 Q 3.825 5.1 4.0875 4.55 T 5 4 L 19 4 Q 19.65 4 19.9125 4.55 T 19.8 5.6 L 14 13 L 14 19 Q 14 19.425 13.7125 19.7125 T 13 20 L 11 20 Z" : "M 339.667 681 L 510.333 681 L 510.333 595.667 L 339.667 595.667 L 339.667 681 Z M 41 169 L 41 254.333 L 809 254.333 L 809 169 L 41 169 Z M 169 467.667 L 681 467.667 L 681 382.333 L 169 382.333 L 169 467.667 Z";
21890
21882
  const hoverBackgroundPath = isActive ? "M0,0 h24 v24 h-24" : "M0,0 h850 v850 h-850";
21891
21883
  const colors = {
21892
21884
  iconColor: FILTERS_COLOR,
@@ -29279,6 +29271,20 @@ set(value) {
29279
29271
  figure.data.chartDefinitions[chartId] = upgrade(definition);
29280
29272
  }
29281
29273
  return data;
29274
+ } }).add("19.5.1", { migrate(data) {
29275
+ function upgrade(definition) {
29276
+ if (definition.type !== "scorecard") return definition;
29277
+ definition = { ...definition };
29278
+ if (definition.keyValue) definition.keyValue = `=${definition.keyValue}`;
29279
+ if (definition.baseline) definition.baseline = `=${definition.baseline}`;
29280
+ return definition;
29281
+ }
29282
+ for (const sheet of data.sheets || []) for (const figure of sheet.figures || []) if (figure.tag === "chart") figure.data = upgrade(figure.data);
29283
+ else if (figure.tag === "carousel") for (const chartId in figure.data.chartDefinitions) {
29284
+ const definition = figure.data.chartDefinitions[chartId];
29285
+ figure.data.chartDefinitions[chartId] = upgrade(definition);
29286
+ }
29287
+ return data;
29282
29288
  } });
29283
29289
  function fixOverlappingFilters(data) {
29284
29290
  for (const sheet of data.sheets || []) {
@@ -29951,7 +29957,7 @@ set(value) {
29951
29957
  return {
29952
29958
  type: "scorecard",
29953
29959
  title: {},
29954
- keyValue: getUnboundRange(getters, zone),
29960
+ keyValue: `=${getUnboundRange(getters, zone)}`,
29955
29961
  background: cell?.style?.fillColor,
29956
29962
  baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
29957
29963
  baselineColorUp: DEFAULT_SCORECARD_BASELINE_COLOR_UP,
@@ -39649,10 +39655,10 @@ set(value) {
39649
39655
  var ScorecardChartConfigPanel = class extends Component {
39650
39656
  static template = "o-spreadsheet-ScorecardChartConfigPanel";
39651
39657
  static components = {
39652
- SelectionInput,
39653
39658
  ChartErrorSection,
39654
39659
  Section,
39655
- Select
39660
+ Select,
39661
+ StandaloneComposer
39656
39662
  };
39657
39663
  props = (0, _odoo_owl.useProps)(chartSidePanelPropsDefinition);
39658
39664
  state = (0, _odoo_owl.proxy)({
@@ -39664,30 +39670,18 @@ set(value) {
39664
39670
  get errorMessages() {
39665
39671
  return [...this.state.keyValueDispatchResult?.reasons || [], ...this.state.baselineDispatchResult?.reasons || []].filter((reason) => reason !== "NoChanges").map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
39666
39672
  }
39667
- get isKeyValueInvalid() {
39668
- return !!this.state.keyValueDispatchResult?.isCancelledBecause("InvalidScorecardKeyValue");
39669
- }
39670
- get isBaselineInvalid() {
39671
- return !!this.state.baselineDispatchResult?.isCancelledBecause("InvalidScorecardBaseline");
39672
- }
39673
- onKeyValueRangeChanged(ranges) {
39674
- this.keyValue = ranges[0];
39675
- this.state.keyValueDispatchResult = this.props.canUpdateChart(this.props.chartId, { keyValue: this.keyValue });
39676
- }
39677
- updateKeyValueRange() {
39673
+ onConfirmKeyValue(keyValue) {
39674
+ this.keyValue = keyValue;
39678
39675
  this.state.keyValueDispatchResult = this.props.updateChart(this.props.chartId, { keyValue: this.keyValue });
39679
39676
  }
39680
- getKeyValueRange() {
39677
+ getKeyValue() {
39681
39678
  return this.keyValue || "";
39682
39679
  }
39683
- onBaselineRangeChanged(ranges) {
39684
- this.baseline = ranges[0];
39685
- this.state.baselineDispatchResult = this.props.canUpdateChart(this.props.chartId, { baseline: this.baseline });
39686
- }
39687
- updateBaselineRange() {
39680
+ onConfirmBaseline(baseline) {
39681
+ this.baseline = baseline;
39688
39682
  this.state.baselineDispatchResult = this.props.updateChart(this.props.chartId, { baseline: this.baseline });
39689
39683
  }
39690
- getBaselineRange() {
39684
+ getBaseline() {
39691
39685
  return this.baseline || "";
39692
39686
  }
39693
39687
  updateBaselineMode(baselineMode) {
@@ -40144,6 +40138,7 @@ set(value) {
40144
40138
  changeChartType(chartId, newDisplayType) {
40145
40139
  const currentCreationContext = this.getters.getContextCreationChart(chartId);
40146
40140
  const savedCreationContext = this.creationContexts[chartId] || {};
40141
+ const auxiliaryRange = currentCreationContext && "auxiliaryRange" in currentCreationContext ? currentCreationContext.auxiliaryRange : savedCreationContext.auxiliaryRange;
40147
40142
  let dataSetStyles = savedCreationContext.dataSetStyles ?? currentCreationContext?.dataSetStyles;
40148
40143
  let dataSource = {
40149
40144
  ...savedCreationContext.dataSource,
@@ -40165,7 +40160,8 @@ set(value) {
40165
40160
  dataSetsHaveTitle: false,
40166
40161
  ...savedCreationContext.dataSource,
40167
40162
  ...currentCreationContext?.dataSource,
40168
- dataSets: newRanges ?? []
40163
+ dataSets: newRanges ?? [],
40164
+ labelRange: auxiliaryRange
40169
40165
  };
40170
40166
  }
40171
40167
  this.creationContexts[chartId] = {
@@ -40194,7 +40190,7 @@ set(value) {
40194
40190
  dataSetsStartWithSameRanges(currentDataSets, savedDataSets, currentStyles, savedStyles) {
40195
40191
  return currentDataSets.every((ds, i) => {
40196
40192
  const savedDs = savedDataSets[i];
40197
- return deepEquals(ds.dataRange, savedDs.dataRange) && deepEquals(currentStyles?.[ds.dataSetId], savedStyles?.[savedDs.dataSetId]);
40193
+ return deepEquals(ds.dataRange, savedDs?.dataRange) && deepEquals(currentStyles?.[ds.dataSetId], savedStyles?.[savedDs?.dataSetId]);
40198
40194
  });
40199
40195
  }
40200
40196
  /**
@@ -42714,8 +42710,8 @@ set(value) {
42714
42710
  {
42715
42711
  description: _t("Highlights the most recent value compared to the previous one."),
42716
42712
  isApplicable: ({ rowCount }) => rowCount < 3,
42717
- build: (ctx) => scorecardChart(ctx.title, ctx.lastCellXC, {
42718
- baseline: ctx.prevCellXC,
42713
+ build: (ctx) => scorecardChart(ctx.title, `=${ctx.lastCellXC}`, {
42714
+ baseline: ctx.prevCellXC ? `=${ctx.prevCellXC}` : void 0,
42719
42715
  baselineMode: "difference"
42720
42716
  })
42721
42717
  },
@@ -42748,8 +42744,8 @@ set(value) {
42748
42744
  {
42749
42745
  description: _t("Shows the last percentage value with its baseline."),
42750
42746
  isApplicable: ({ rowCount }) => rowCount < 3,
42751
- build: (ctx) => scorecardChart(ctx.title, ctx.lastCellXC, {
42752
- baseline: ctx.prevCellXC,
42747
+ build: (ctx) => scorecardChart(ctx.title, `=${ctx.lastCellXC}`, {
42748
+ baseline: ctx.prevCellXC ? `=${ctx.prevCellXC}` : void 0,
42753
42749
  baselineMode: "percentage"
42754
42750
  })
42755
42751
  },
@@ -42778,7 +42774,7 @@ set(value) {
42778
42774
  const SINGLE_DATE_COLUMN_SUGGESTIONS = [{
42779
42775
  description: _t("Shows the last date value."),
42780
42776
  isApplicable: ({ rowCount }) => rowCount === 1,
42781
- build: (ctx) => scorecardChart(ctx.title, ctx.lastCellXC)
42777
+ build: (ctx) => scorecardChart(ctx.title, `=${ctx.lastCellXC}`)
42782
42778
  }];
42783
42779
  /** Pattern D — Single categorical column */
42784
42780
  const SINGLE_CATEGORICAL_COLUMN_SUGGESTIONS = [
@@ -42812,7 +42808,7 @@ set(value) {
42812
42808
  const SINGLE_LABEL_COLUMN_SUGGESTIONS = [{
42813
42809
  description: _t("Displays a key performance indicator."),
42814
42810
  isApplicable: ({ rowCount }) => rowCount === 1,
42815
- build: (ctx) => scorecardChart(ctx.title, ctx.lastCellXC, {
42811
+ build: (ctx) => scorecardChart(ctx.title, `=${ctx.lastCellXC}`, {
42816
42812
  baselineMode: "text",
42817
42813
  humanize: false
42818
42814
  })
@@ -42870,8 +42866,8 @@ set(value) {
42870
42866
  {
42871
42867
  description: _t("Highlights the second metric compared to the first one."),
42872
42868
  isApplicable: ({ rowCount1, rowCount2 }) => rowCount1 === 1 && rowCount2 === 1,
42873
- build: (ctx) => scorecardChart(ctx.title, ctx.lastCellXC, {
42874
- baseline: ctx.prevCellXC,
42869
+ build: (ctx) => scorecardChart(ctx.title, `=${ctx.lastCellXC}`, {
42870
+ baseline: ctx.prevCellXC ? `=${ctx.prevCellXC}` : void 0,
42875
42871
  baselineMode: "difference"
42876
42872
  })
42877
42873
  },
@@ -42929,10 +42925,10 @@ set(value) {
42929
42925
  {
42930
42926
  description: _t("Highlights the most recent value for the named entity."),
42931
42927
  isApplicable: ({ rowCount }) => rowCount === 1,
42932
- build: (ctx) => scorecardChart("", ctx.lastCellXC, {
42928
+ build: (ctx) => scorecardChart("", `=${ctx.lastCellXC}`, {
42933
42929
  humanize: false,
42934
42930
  baselineMode: "text",
42935
- baseline: ctx.prevCellXC
42931
+ baseline: ctx.prevCellXC ? `=${ctx.prevCellXC}` : void 0
42936
42932
  })
42937
42933
  },
42938
42934
  {
@@ -71497,6 +71493,31 @@ set(value) {
71497
71493
  var MainViewportStore = class extends SpreadsheetStore {
71498
71494
  viewStore = this.get(ViewportsStore);
71499
71495
  sheetIdAtFinalize = void 0;
71496
+ constructor(get) {
71497
+ super(get);
71498
+ this.model.selection.observe(this, { handleEvent: this.handleEvent.bind(this) });
71499
+ this.onDispose(() => {
71500
+ this.model.selection.unobserve(this);
71501
+ });
71502
+ }
71503
+ handleEvent(event) {
71504
+ const eventSheetId = this.getters.getActiveSheetId();
71505
+ if (event.options.scrollIntoView) {
71506
+ const oldZone = event.previousAnchor.zone;
71507
+ const newZone = event.anchor.zone;
71508
+ const isUpdateAnchorEvent = event.mode === "updateAnchor";
71509
+ const sameZone = isEqual(oldZone, newZone);
71510
+ let { col, row } = isUpdateAnchorEvent && sameZone ? event.anchor.cell : findCellInNewZone(oldZone, newZone);
71511
+ if (isUpdateAnchorEvent && !sameZone) {
71512
+ const { top, bottom, left, right } = this.viewStore.viewports.getMainInternalViewport(eventSheetId);
71513
+ if (oldZone.left === newZone.left && oldZone.right === newZone.right) col = left > col || col > right ? left : col;
71514
+ if (oldZone.top === newZone.top && oldZone.bottom === newZone.bottom) row = top > row || row > bottom ? top : row;
71515
+ }
71516
+ col = Math.min(col, this.getters.getNumberCols(eventSheetId) - 1);
71517
+ row = Math.min(row, this.getters.getNumberRows(eventSheetId) - 1);
71518
+ this.viewStore.scrollToCell(eventSheetId, col, row);
71519
+ }
71520
+ }
71500
71521
  handle(cmd) {
71501
71522
  switch (cmd.type) {
71502
71523
  case "UNDO":
@@ -91010,8 +91031,8 @@ exports.stores = stores;
91010
91031
  exports.tokenColors = tokenColors;
91011
91032
  exports.tokenize = tokenize;
91012
91033
 
91013
- __info__.version = "19.5.0-alpha.12";
91014
- __info__.date = "2026-08-19T09:47:03.774Z";
91015
- __info__.hash = "68ca68e";
91034
+ __info__.version = "19.5.0-alpha.13";
91035
+ __info__.date = "2026-08-21T15:33:44.046Z";
91036
+ __info__.hash = "a73559e";
91016
91037
 
91017
91038
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);