@odoo/o-spreadsheet 18.0.50 → 18.0.53

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.0.50
6
- * @date 2025-12-02T05:32:00.480Z
7
- * @hash 7ed20c4
5
+ * @version 18.0.53
6
+ * @date 2025-12-26T10:18:09.933Z
7
+ * @hash 7ca8390
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';
@@ -5838,17 +5838,41 @@ function toCriterionDateNumber(dateValue) {
5838
5838
  const today = DateTime.now();
5839
5839
  switch (dateValue) {
5840
5840
  case "today":
5841
- return jsDateToNumber(today);
5842
- case "yesterday":
5843
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
5844
- case "tomorrow":
5845
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
5841
+ return Math.floor(jsDateToNumber(today));
5842
+ case "yesterday": {
5843
+ today.setDate(today.getDate() - 1);
5844
+ return Math.floor(jsDateToNumber(today));
5845
+ }
5846
+ case "tomorrow": {
5847
+ today.setDate(today.getDate() + 1);
5848
+ return Math.floor(jsDateToNumber(today));
5849
+ }
5846
5850
  case "lastWeek":
5847
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
5848
- case "lastMonth":
5849
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
5851
+ today.setDate(today.getDate() - 6);
5852
+ return Math.floor(jsDateToNumber(today));
5853
+ case "lastMonth": {
5854
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
5855
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
5856
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
5857
+ today.setDate(1);
5858
+ }
5859
+ else {
5860
+ today.setDate(today.getDate() + 1);
5861
+ today.setMonth(today.getMonth() - 1);
5862
+ }
5863
+ return Math.floor(jsDateToNumber(today));
5864
+ }
5850
5865
  case "lastYear":
5851
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
5866
+ // Handle leap year case
5867
+ if (today.getMonth() === 1 && today.getDate() === 29) {
5868
+ today.setDate(28);
5869
+ today.setFullYear(today.getFullYear() - 1);
5870
+ }
5871
+ else {
5872
+ today.setDate(today.getDate() + 1);
5873
+ today.setFullYear(today.getFullYear() - 1);
5874
+ }
5875
+ return Math.floor(jsDateToNumber(today));
5852
5876
  }
5853
5877
  }
5854
5878
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -40345,14 +40369,15 @@ function useHighlights(highlightProvider) {
40345
40369
  }
40346
40370
 
40347
40371
  css /* scss */ `
40348
- .o-cf-preview {
40372
+ .o-spreadsheet .o-cf-preview {
40349
40373
  &.o-cf-cursor-ptr {
40350
40374
  cursor: pointer;
40351
40375
  }
40352
40376
 
40353
40377
  border-bottom: 1px solid ${GRAY_300};
40354
- height: 60px;
40378
+ height: 80px;
40355
40379
  padding: 10px;
40380
+ box-sizing: border-box;
40356
40381
  position: relative;
40357
40382
  cursor: pointer;
40358
40383
  &:hover,
@@ -40366,7 +40391,6 @@ css /* scss */ `
40366
40391
  .o-cf-preview-icon {
40367
40392
  border: 1px solid ${GRAY_300};
40368
40393
  background-color: #fff;
40369
- position: absolute;
40370
40394
  height: 50px;
40371
40395
  width: 50px;
40372
40396
  .o-icon {
@@ -40375,12 +40399,6 @@ css /* scss */ `
40375
40399
  }
40376
40400
  }
40377
40401
  .o-cf-preview-description {
40378
- left: 65px;
40379
- margin-bottom: auto;
40380
- margin-right: 8px;
40381
- margin-top: auto;
40382
- position: relative;
40383
- width: 142px;
40384
40402
  .o-cf-preview-description-rule {
40385
40403
  margin-bottom: 4px;
40386
40404
  max-height: 2.8em;
@@ -40390,16 +40408,11 @@ css /* scss */ `
40390
40408
  font-size: 12px;
40391
40409
  }
40392
40410
  }
40393
- .o-cf-delete {
40394
- left: 90%;
40395
- top: 39%;
40396
- position: absolute;
40397
- }
40398
40411
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
40399
40412
  display: none !important;
40400
40413
  }
40401
40414
  .o-cf-drag-handle {
40402
- left: -8px;
40415
+ left: 2px;
40403
40416
  cursor: move;
40404
40417
  .o-icon {
40405
40418
  width: 6px;
@@ -41284,7 +41297,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
41284
41297
  return false;
41285
41298
  }
41286
41299
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
41287
- const today = jsDateToRoundNumber(DateTime.now());
41300
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
41288
41301
  return isDateBetween(dateValue, today, criterionValue);
41289
41302
  }
41290
41303
  return areDatesSameDay(dateValue, criterionValue);
@@ -44988,7 +45001,37 @@ pivotRegistry.add("SPREADSHEET", {
44988
45001
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
44989
45002
  isMeasureCandidate: (field) => !["datetime", "boolean"].includes(field.type),
44990
45003
  isGroupable: () => true,
45004
+ adaptRanges: (getters, definition, applyChange) => {
45005
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
45006
+ return definition;
45007
+ }
45008
+ const { sheetId, zone } = definition.dataSet;
45009
+ const range = getters.getRangeFromZone(sheetId, zone);
45010
+ const adaptedRange = adaptPivotRange(range, applyChange);
45011
+ if (adaptedRange === range) {
45012
+ return definition;
45013
+ }
45014
+ const dataSet = adaptedRange && {
45015
+ sheetId: adaptedRange.sheetId,
45016
+ zone: adaptedRange.zone,
45017
+ };
45018
+ return { ...definition, dataSet };
45019
+ },
44991
45020
  });
45021
+ function adaptPivotRange(range, applyChange) {
45022
+ if (!range) {
45023
+ return undefined;
45024
+ }
45025
+ const change = applyChange(range);
45026
+ switch (change.changeType) {
45027
+ case "NONE":
45028
+ return range;
45029
+ case "REMOVE":
45030
+ return undefined;
45031
+ default:
45032
+ return change.range;
45033
+ }
45034
+ }
44992
45035
 
44993
45036
  class PivotSidePanelStore extends SpreadsheetStore {
44994
45037
  pivotId;
@@ -46875,21 +46918,20 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
46875
46918
  this.highlightStore.register(this);
46876
46919
  }
46877
46920
  get highlights() {
46878
- let zone;
46879
46921
  const position = this.model.getters.getActivePosition();
46880
- const cell = this.getters.getEvaluatedCell(position);
46881
46922
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
46882
- zone = spreader
46923
+ const zone = spreader
46883
46924
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
46884
46925
  : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
46885
46926
  if (!zone) {
46886
46927
  return [];
46887
46928
  }
46929
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
46888
46930
  return [
46889
46931
  {
46890
46932
  sheetId: position.sheetId,
46891
46933
  zone,
46892
- dashed: cell.value === CellErrorType.SpilledBlocked,
46934
+ dashed: isArrayFormulaBlocked,
46893
46935
  color: "#17A2B8",
46894
46936
  noFill: true,
46895
46937
  thinLine: true,
@@ -54950,6 +54992,7 @@ function rangeToMerge(mergeId, range) {
54950
54992
  class RangeAdapter {
54951
54993
  getters;
54952
54994
  providers = [];
54995
+ isAdaptingRanges = false;
54953
54996
  constructor(getters) {
54954
54997
  this.getters = getters;
54955
54998
  }
@@ -54978,6 +55021,9 @@ class RangeAdapter {
54978
55021
  }
54979
55022
  beforeHandle(command) { }
54980
55023
  handle(cmd) {
55024
+ if (this.isAdaptingRanges) {
55025
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
55026
+ }
54981
55027
  switch (cmd.type) {
54982
55028
  case "REMOVE_COLUMNS_ROWS": {
54983
55029
  let start = cmd.dimension === "COL" ? "left" : "top";
@@ -55133,10 +55179,12 @@ class RangeAdapter {
55133
55179
  return adaptedRange;
55134
55180
  }
55135
55181
  executeOnAllRanges(adaptRange, sheetId) {
55182
+ this.isAdaptingRanges = true;
55136
55183
  const func = this.verifyRangeRemoved(adaptRange);
55137
55184
  for (const provider of this.providers) {
55138
55185
  provider(func, sheetId);
55139
55186
  }
55187
+ this.isAdaptingRanges = false;
55140
55188
  }
55141
55189
  /**
55142
55190
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -57243,6 +57291,18 @@ class PivotCorePlugin extends CorePlugin {
57243
57291
  }
57244
57292
  }
57245
57293
  adaptRanges(applyChange) {
57294
+ for (const pivotId in this.pivots) {
57295
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
57296
+ if (!definition) {
57297
+ continue;
57298
+ }
57299
+ const newDefinition = pivotRegistry
57300
+ .get(definition.type)
57301
+ ?.adaptRanges?.(this.getters, definition, applyChange);
57302
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
57303
+ this.history.update("pivots", pivotId, "definition", newDefinition);
57304
+ }
57305
+ }
57246
57306
  for (const sheetId in this.compiledMeasureFormulas) {
57247
57307
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
57248
57308
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -57385,17 +57445,10 @@ class PivotCorePlugin extends CorePlugin {
57385
57445
  if (!pivot) {
57386
57446
  continue;
57387
57447
  }
57388
- const def = deepCopy(pivot.definition);
57389
- for (const measure of def.measures) {
57448
+ for (const measure of pivot.definition.measures) {
57390
57449
  if (measure.computedBy?.formula === formulaString) {
57391
- const measureIndex = def.measures.indexOf(measure);
57392
- if (measureIndex !== -1) {
57393
- def.measures[measureIndex].computedBy = {
57394
- formula: newFormulaString,
57395
- sheetId,
57396
- };
57397
- }
57398
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
57450
+ const measureIndex = pivot.definition.measures.indexOf(measure);
57451
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
57399
57452
  }
57400
57453
  }
57401
57454
  }
@@ -57494,20 +57547,6 @@ class SettingsPlugin extends CorePlugin {
57494
57547
  }
57495
57548
  }
57496
57549
 
57497
- function adaptPivotRange(range, applyChange) {
57498
- if (!range) {
57499
- return undefined;
57500
- }
57501
- const change = applyChange(range);
57502
- switch (change.changeType) {
57503
- case "NONE":
57504
- return range;
57505
- case "REMOVE":
57506
- return undefined;
57507
- default:
57508
- return change.range;
57509
- }
57510
- }
57511
57550
  class SpreadsheetPivotCorePlugin extends CorePlugin {
57512
57551
  allowDispatch(cmd) {
57513
57552
  switch (cmd.type) {
@@ -57518,27 +57557,6 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
57518
57557
  }
57519
57558
  return "Success" /* CommandResult.Success */;
57520
57559
  }
57521
- adaptRanges(applyChange) {
57522
- for (const pivotId of this.getters.getPivotIds()) {
57523
- const definition = this.getters.getPivotCoreDefinition(pivotId);
57524
- if (definition.type !== "SPREADSHEET") {
57525
- continue;
57526
- }
57527
- if (definition.dataSet) {
57528
- const { sheetId, zone } = definition.dataSet;
57529
- const range = this.getters.getRangeFromZone(sheetId, zone);
57530
- const adaptedRange = adaptPivotRange(range, applyChange);
57531
- if (adaptedRange === range) {
57532
- return;
57533
- }
57534
- const dataSet = adaptedRange && {
57535
- sheetId: adaptedRange.sheetId,
57536
- zone: adaptedRange.zone,
57537
- };
57538
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
57539
- }
57540
- }
57541
- }
57542
57560
  checkDataSetValidity(definition) {
57543
57561
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
57544
57562
  const { zone, sheetId } = definition.dataSet;
@@ -58896,6 +58914,9 @@ class Evaluator {
58896
58914
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
58897
58915
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
58898
58916
  }
58917
+ isArrayFormulaSpillBlocked(position) {
58918
+ return this.blockedArrayFormulas.has(position);
58919
+ }
58899
58920
  updateDependencies(position) {
58900
58921
  // removing dependencies is slow because it requires
58901
58922
  // to traverse the entire r-tree.
@@ -58907,13 +58928,8 @@ class Evaluator {
58907
58928
  addDependencies(position, dependencies) {
58908
58929
  this.formulaDependencies().addDependencies(position, dependencies);
58909
58930
  for (const range of dependencies) {
58910
- const sheetId = range.sheetId;
58911
- const { left, bottom, right, top } = range.zone;
58912
- for (let col = left; col <= right; col++) {
58913
- for (let row = top; row <= bottom; row++) {
58914
- this.computeAndSave({ sheetId, col, row });
58915
- }
58916
- }
58931
+ // ensure that all ranges are computed
58932
+ this.compilationParams.ensureRange(range);
58917
58933
  }
58918
58934
  }
58919
58935
  updateCompilationParameters() {
@@ -59112,6 +59128,10 @@ class Evaluator {
59112
59128
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
59113
59129
  const nbColumns = formulaReturn.length;
59114
59130
  const nbRows = formulaReturn[0].length;
59131
+ if (nbRows === 0) {
59132
+ // empty matrix
59133
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
59134
+ }
59115
59135
  const resultZone = {
59116
59136
  top: formulaPosition.row,
59117
59137
  bottom: formulaPosition.row + nbRows - 1,
@@ -59384,6 +59404,7 @@ class EvaluationPlugin extends UIPlugin {
59384
59404
  "getEvaluatedCellsPositions",
59385
59405
  "getSpreadZone",
59386
59406
  "getArrayFormulaSpreadingOn",
59407
+ "isArrayFormulaSpillBlocked",
59387
59408
  "isEmpty",
59388
59409
  ];
59389
59410
  shouldRebuildDependenciesGraph = true;
@@ -59496,6 +59517,9 @@ class EvaluationPlugin extends UIPlugin {
59496
59517
  getArrayFormulaSpreadingOn(position) {
59497
59518
  return this.evaluator.getArrayFormulaSpreadingOn(position);
59498
59519
  }
59520
+ isArrayFormulaSpillBlocked(position) {
59521
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
59522
+ }
59499
59523
  /**
59500
59524
  * Check if a zone only contains empty cells
59501
59525
  */
@@ -74725,6 +74749,6 @@ const constants = {
74725
74749
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, 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 };
74726
74750
 
74727
74751
 
74728
- __info__.version = "18.0.50";
74729
- __info__.date = "2025-12-02T05:32:00.480Z";
74730
- __info__.hash = "7ed20c4";
74752
+ __info__.version = "18.0.53";
74753
+ __info__.date = "2025-12-26T10:18:09.933Z";
74754
+ __info__.hash = "7ca8390";