@odoo/o-spreadsheet 18.4.22 → 18.4.24

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.4.22
6
- * @date 2025-12-26T10:19:07.786Z
7
- * @hash 6ddac00
5
+ * @version 18.4.24
6
+ * @date 2026-01-14T10:00:55.867Z
7
+ * @hash 0364f56
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -19068,9 +19068,10 @@ function assertDomainLength(domain) {
19068
19068
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
19069
19069
  }
19070
19070
  }
19071
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
19071
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
19072
19072
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
19073
19073
  const dependencies = [];
19074
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
19074
19075
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
19075
19076
  const { sheetId, zone } = coreDefinition.dataSet;
19076
19077
  const xc = zoneToXc(zone);
@@ -19087,8 +19088,7 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
19087
19088
  }
19088
19089
  for (const measure of forMeasures) {
19089
19090
  if (measure.computedBy) {
19090
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
19091
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
19091
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
19092
19092
  }
19093
19093
  }
19094
19094
  const originPosition = evalContext.__originCellPosition;
@@ -19557,7 +19557,7 @@ const PIVOT_VALUE = {
19557
19557
  assertDomainLength(domainArgs);
19558
19558
  const pivot = this.getters.getPivot(pivotId);
19559
19559
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19560
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
19560
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
19561
19561
  pivot.init({ reload: pivot.needsReevaluation });
19562
19562
  const error = pivot.assertIsValid({ throwOnError: false });
19563
19563
  if (error) {
@@ -19590,8 +19590,7 @@ const PIVOT_HEADER = {
19590
19590
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
19591
19591
  assertDomainLength(domainArgs);
19592
19592
  const pivot = this.getters.getPivot(_pivotId);
19593
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19594
- addPivotDependencies(this, coreDefinition, []);
19593
+ addPivotDependencies(this, _pivotId, []);
19595
19594
  pivot.init({ reload: pivot.needsReevaluation });
19596
19595
  const error = pivot.assertIsValid({ throwOnError: false });
19597
19596
  if (error) {
@@ -19649,7 +19648,7 @@ const PIVOT = {
19649
19648
  const pivotId = getPivotId(_pivotFormulaId, this.getters);
19650
19649
  const pivot = this.getters.getPivot(pivotId);
19651
19650
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
19652
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
19651
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
19653
19652
  pivot.init({ reload: pivot.needsReevaluation });
19654
19653
  const error = pivot.assertIsValid({ throwOnError: false });
19655
19654
  if (error) {
@@ -32903,7 +32902,7 @@ class AbstractComposerStore extends SpreadsheetStore {
32903
32902
  }
32904
32903
  captureSelection(zone, col, row) {
32905
32904
  this.model.selection.capture(this, {
32906
- cell: { col: col ?? zone.left, row: row ?? zone.right },
32905
+ cell: { col: col ?? zone.left, row: row ?? zone.top },
32907
32906
  zone,
32908
32907
  }, {
32909
32908
  handleEvent: this.handleEvent.bind(this),
@@ -47104,7 +47103,6 @@ class GridOverlay extends Component {
47104
47103
  onGridMoved: Function,
47105
47104
  gridOverlayDimensions: String,
47106
47105
  slots: { type: Object, optional: true },
47107
- getGridSize: Function,
47108
47106
  };
47109
47107
  static components = {
47110
47108
  FiguresContainer,
@@ -47123,14 +47121,7 @@ class GridOverlay extends Component {
47123
47121
  setup() {
47124
47122
  useCellHovered(this.env, this.gridOverlay);
47125
47123
  const resizeObserver = new ResizeObserver(() => {
47126
- const boundingRect = this.gridOverlayEl.getBoundingClientRect();
47127
- const { width, height } = this.props.getGridSize();
47128
- this.props.onGridResized({
47129
- x: boundingRect.left,
47130
- y: boundingRect.top,
47131
- height: height,
47132
- width: width,
47133
- });
47124
+ this.props.onGridResized();
47134
47125
  });
47135
47126
  onMounted(() => {
47136
47127
  resizeObserver.observe(this.gridOverlayEl);
@@ -53211,6 +53202,12 @@ class FindAndReplaceStore extends SpreadsheetStore {
53211
53202
  case "ACTIVATE_SHEET":
53212
53203
  this.isSearchDirty = true;
53213
53204
  this.shouldFinalizeUpdateSelection = true;
53205
+ if (this.searchOptions.specificRange) {
53206
+ this.searchOptions.specificRange = {
53207
+ ...this.searchOptions.specificRange,
53208
+ sheetId: this.getters.getActiveSheetId(),
53209
+ };
53210
+ }
53214
53211
  break;
53215
53212
  case "REPLACE_SEARCH":
53216
53213
  for (const match of cmd.matches) {
@@ -53630,9 +53627,20 @@ class FindAndReplacePanel extends Component {
53630
53627
  const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
53631
53628
  this.store.updateSearchOptions({ specificRange });
53632
53629
  }
53630
+ get specificRange() {
53631
+ const range = this.store.searchOptions.specificRange;
53632
+ return range ? this.env.model.getters.getRangeString(range, "forceSheetReference") : "";
53633
+ }
53633
53634
  get pendingSearch() {
53634
53635
  return this.updateSearchContent.isDebouncePending();
53635
53636
  }
53637
+ get selectionInputKey() {
53638
+ // Selections input are made to work with objects linked to a sheet id. They store the active sheet id at their creation,
53639
+ // and have specific behaviour linked to it (eg. go back to the initial sheet after confirmation).
53640
+ // We don't want all those behaviors here, so we force the recreation of the component when the active sheet changes.
53641
+ // The only drawback is that the input loses focus when changing sheet.
53642
+ return this.env.model.getters.getActiveSheetId();
53643
+ }
53636
53644
  }
53637
53645
 
53638
53646
  css /* scss */ `
@@ -58066,7 +58074,8 @@ class Grid extends Component {
58066
58074
  });
58067
58075
  return !(rect.width === 0 || rect.height === 0);
58068
58076
  }
58069
- onGridResized({ height, width }) {
58077
+ onGridResized() {
58078
+ const { height, width } = this.props.getGridSize();
58070
58079
  this.env.model.dispatch("RESIZE_SHEETVIEW", {
58071
58080
  width: width - HEADER_WIDTH,
58072
58081
  height: height - HEADER_HEIGHT,
@@ -64258,6 +64267,7 @@ class PivotCorePlugin extends CorePlugin {
64258
64267
  "getMeasureCompiledFormula",
64259
64268
  "getPivotName",
64260
64269
  "isExistingPivot",
64270
+ "getMeasureFullDependencies",
64261
64271
  ];
64262
64272
  nextFormulaId = 1;
64263
64273
  pivots = {};
@@ -64340,7 +64350,7 @@ class PivotCorePlugin extends CorePlugin {
64340
64350
  }
64341
64351
  case "UPDATE_PIVOT": {
64342
64352
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
64343
- this.compileCalculatedMeasures(cmd.pivot.measures);
64353
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
64344
64354
  break;
64345
64355
  }
64346
64356
  }
@@ -64358,9 +64368,14 @@ class PivotCorePlugin extends CorePlugin {
64358
64368
  this.history.update("pivots", pivotId, "definition", newDefinition);
64359
64369
  }
64360
64370
  }
64361
- for (const sheetId in this.compiledMeasureFormulas) {
64362
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
64363
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
64371
+ for (const pivotId in this.compiledMeasureFormulas) {
64372
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
64373
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
64374
+ if (!measure || !measure.computedBy) {
64375
+ continue;
64376
+ }
64377
+ const sheetId = measure.computedBy.sheetId;
64378
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
64364
64379
  const newDependencies = [];
64365
64380
  for (const range of compiledFormula.dependencies) {
64366
64381
  const change = applyChange(range);
@@ -64372,8 +64387,9 @@ class PivotCorePlugin extends CorePlugin {
64372
64387
  }
64373
64388
  }
64374
64389
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
64375
- if (newFormulaString !== formulaString) {
64376
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
64390
+ const oldFormulaString = measure.computedBy.formula;
64391
+ if (newFormulaString !== oldFormulaString) {
64392
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
64377
64393
  }
64378
64394
  }
64379
64395
  }
@@ -64411,31 +64427,60 @@ class PivotCorePlugin extends CorePlugin {
64411
64427
  isExistingPivot(pivotId) {
64412
64428
  return pivotId in this.pivots;
64413
64429
  }
64414
- getMeasureCompiledFormula(measure) {
64430
+ getMeasureCompiledFormula(pivotId, measure) {
64415
64431
  if (!measure.computedBy) {
64416
64432
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
64417
64433
  }
64418
- const sheetId = measure.computedBy.sheetId;
64419
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
64434
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
64435
+ }
64436
+ getMeasureFullDependencies(pivotId, measure) {
64437
+ if (!measure.computedBy) {
64438
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
64439
+ }
64440
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
64420
64441
  }
64421
64442
  // -------------------------------------------------------------------------
64422
64443
  // Private
64423
64444
  // -------------------------------------------------------------------------
64424
64445
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
64425
64446
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
64426
- this.compileCalculatedMeasures(pivot.measures);
64447
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
64427
64448
  this.history.update("formulaIds", formulaId, pivotId);
64428
64449
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
64429
64450
  }
64430
- compileCalculatedMeasures(measures) {
64451
+ compileCalculatedMeasures(pivotId, measures) {
64431
64452
  for (const measure of measures) {
64432
64453
  if (measure.computedBy) {
64433
- const sheetId = measure.computedBy.sheetId;
64434
64454
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
64435
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
64455
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
64456
+ }
64457
+ }
64458
+ for (const measure of measures) {
64459
+ if (measure.computedBy) {
64460
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
64461
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
64436
64462
  }
64437
64463
  }
64438
64464
  }
64465
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
64466
+ const rangeDependencies = [];
64467
+ const definition = this.getPivotCoreDefinition(pivotId);
64468
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
64469
+ exploredMeasures.add(measure.id);
64470
+ for (const token of formula.tokens) {
64471
+ if (token.type !== "SYMBOL") {
64472
+ continue;
64473
+ }
64474
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
64475
+ measure.id !== measureCandidate.id);
64476
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
64477
+ continue;
64478
+ }
64479
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
64480
+ }
64481
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
64482
+ return rangeDependencies;
64483
+ }
64439
64484
  insertPivot(position, formulaId, table) {
64440
64485
  this.resizeSheet(position.sheetId, position, table);
64441
64486
  const pivotCells = table.getPivotCells();
@@ -64494,21 +64539,17 @@ class PivotCorePlugin extends CorePlugin {
64494
64539
  dependencies: rangeDependencies,
64495
64540
  };
64496
64541
  }
64497
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
64498
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
64499
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
64500
- for (const pivotId in this.pivots) {
64501
- const pivot = this.pivots[pivotId];
64502
- if (!pivot) {
64503
- continue;
64504
- }
64505
- for (const measure of pivot.definition.measures) {
64506
- if (measure.computedBy?.formula === formulaString) {
64507
- const measureIndex = pivot.definition.measures.indexOf(measure);
64508
- this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
64509
- }
64510
- }
64542
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
64543
+ const pivot = this.pivots[pivotId];
64544
+ if (!pivot) {
64545
+ return;
64511
64546
  }
64547
+ const measureIndex = pivot.definition.measures.indexOf(measure);
64548
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
64549
+ formula: newFormulaString,
64550
+ sheetId: measure.computedBy.sheetId,
64551
+ });
64552
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
64512
64553
  }
64513
64554
  checkSortedColumnInMeasures(definition) {
64514
64555
  const measures = definition.measures.map((measure) => measure.id);
@@ -68036,14 +68077,16 @@ const PERCENT_FORMAT = "0.00%";
68036
68077
  function withPivotPresentationLayer (PivotClass) {
68037
68078
  class PivotPresentationLayer extends PivotClass {
68038
68079
  getters;
68080
+ pivotId;
68039
68081
  cache = {};
68040
68082
  rankAsc = {};
68041
68083
  rankDesc = {};
68042
68084
  runningTotal = {};
68043
68085
  runningTotalInPercent = {};
68044
- constructor(custom, params) {
68086
+ constructor(pivotId, custom, params) {
68045
68087
  super(custom, params);
68046
68088
  this.getters = params.getters;
68089
+ this.pivotId = pivotId;
68047
68090
  }
68048
68091
  markAsDirtyForEvaluation() {
68049
68092
  this.cache = {};
@@ -68093,7 +68136,7 @@ function withPivotPresentationLayer (PivotClass) {
68093
68136
  return handleError(error, measure.aggregator.toUpperCase());
68094
68137
  }
68095
68138
  }
68096
- const formula = this.getters.getMeasureCompiledFormula(measure);
68139
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
68097
68140
  const getSymbolValue = (symbolName) => {
68098
68141
  const { columns, rows } = this.definition;
68099
68142
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -68833,7 +68876,7 @@ class PivotUIPlugin extends CoreViewPlugin {
68833
68876
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
68834
68877
  if (!(pivotId in this.pivots)) {
68835
68878
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
68836
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
68879
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
68837
68880
  }
68838
68881
  else if (recreate) {
68839
68882
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -78172,10 +78215,8 @@ class SpreadsheetDashboard extends Component {
78172
78215
  });
78173
78216
  }
78174
78217
  get gridContainer() {
78175
- const sheetId = this.env.model.getters.getActiveSheetId();
78176
- const { right } = this.env.model.getters.getSheetZone(sheetId);
78177
- const { end } = this.env.model.getters.getColDimensions(sheetId, right);
78178
- return cssPropertiesToCss({ "max-width": `${end}px` });
78218
+ const maxWidth = this.getMaxSheetWidth();
78219
+ return cssPropertiesToCss({ "max-width": `${maxWidth}px` });
78179
78220
  }
78180
78221
  get gridOverlayDimensions() {
78181
78222
  return cssPropertiesToCss({
@@ -78207,10 +78248,12 @@ class SpreadsheetDashboard extends Component {
78207
78248
  onClosePopover() {
78208
78249
  this.cellPopovers.close();
78209
78250
  }
78210
- onGridResized({ height, width }) {
78251
+ onGridResized() {
78252
+ const { height, width } = this.props.getGridSize();
78253
+ const maxWidth = this.getMaxSheetWidth();
78211
78254
  this.env.model.dispatch("RESIZE_SHEETVIEW", {
78212
- width: width,
78213
- height: height,
78255
+ width: Math.min(maxWidth, width),
78256
+ height,
78214
78257
  gridOffsetX: 0,
78215
78258
  gridOffsetY: 0,
78216
78259
  });
@@ -78228,6 +78271,11 @@ class SpreadsheetDashboard extends Component {
78228
78271
  ...this.env.model.getters.getSheetViewDimensionWithHeaders(),
78229
78272
  };
78230
78273
  }
78274
+ getMaxSheetWidth() {
78275
+ const sheetId = this.env.model.getters.getActiveSheetId();
78276
+ const { right } = this.env.model.getters.getSheetZone(sheetId);
78277
+ return this.env.model.getters.getColDimensions(sheetId, right).end;
78278
+ }
78231
78279
  }
78232
78280
 
78233
78281
  css /* scss */ `
@@ -80468,22 +80516,20 @@ class Spreadsheet extends Component {
80468
80516
  return this.env.model.getters.getVisibleGroupLayers(sheetId, "COL");
80469
80517
  }
80470
80518
  getGridSize() {
80471
- const topBarHeight = this.spreadsheetRef.el
80472
- ?.querySelector(".o-spreadsheet-topbar-wrapper")
80473
- ?.getBoundingClientRect().height || 0;
80474
- const bottomBarHeight = this.spreadsheetRef.el
80475
- ?.querySelector(".o-spreadsheet-bottombar-wrapper")
80476
- ?.getBoundingClientRect().height || 0;
80477
- const gridWidth = this.spreadsheetRef.el?.querySelector(".o-grid")?.getBoundingClientRect().width || 0;
80478
- const gridHeight = (this.spreadsheetRef.el?.getBoundingClientRect().height || 0) -
80479
- (this.spreadsheetRef.el?.querySelector(".o-column-groups")?.getBoundingClientRect().height ||
80480
- 0) -
80481
- topBarHeight -
80482
- bottomBarHeight;
80483
- return {
80484
- width: Math.max(gridWidth - SCROLLBAR_WIDTH, 0),
80485
- height: Math.max(gridHeight - SCROLLBAR_WIDTH, 0),
80486
- };
80519
+ const el = this.spreadsheetRef.el;
80520
+ if (!el) {
80521
+ return { width: 0, height: 0 };
80522
+ }
80523
+ const getHeight = (selector) => el.querySelector(selector)?.getBoundingClientRect().height || 0;
80524
+ const getWidth = (selector) => el.querySelector(selector)?.getBoundingClientRect().width || 0;
80525
+ const rect = el.getBoundingClientRect();
80526
+ const topBarHeight = getHeight(".o-spreadsheet-topbar-wrapper");
80527
+ const bottomBarHeight = getHeight(".o-spreadsheet-bottombar-wrapper");
80528
+ const colGroupHeight = getHeight(".o-column-groups");
80529
+ const gridWidth = getWidth(".o-grid");
80530
+ const width = Math.max(gridWidth - SCROLLBAR_WIDTH, 0);
80531
+ const height = Math.max(rect.height - topBarHeight - bottomBarHeight - colGroupHeight - SCROLLBAR_WIDTH, 0);
80532
+ return { width, height };
80487
80533
  }
80488
80534
  }
80489
80535
 
@@ -84968,6 +85014,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
84968
85014
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, 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, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
84969
85015
 
84970
85016
 
84971
- __info__.version = "18.4.22";
84972
- __info__.date = "2025-12-26T10:19:07.786Z";
84973
- __info__.hash = "6ddac00";
85017
+ __info__.version = "18.4.24";
85018
+ __info__.date = "2026-01-14T10:00:55.867Z";
85019
+ __info__.hash = "0364f56";