@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
  'use strict';
@@ -5840,17 +5840,41 @@ function toCriterionDateNumber(dateValue) {
5840
5840
  const today = DateTime.now();
5841
5841
  switch (dateValue) {
5842
5842
  case "today":
5843
- return jsDateToNumber(today);
5844
- case "yesterday":
5845
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
5846
- case "tomorrow":
5847
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
5843
+ return Math.floor(jsDateToNumber(today));
5844
+ case "yesterday": {
5845
+ today.setDate(today.getDate() - 1);
5846
+ return Math.floor(jsDateToNumber(today));
5847
+ }
5848
+ case "tomorrow": {
5849
+ today.setDate(today.getDate() + 1);
5850
+ return Math.floor(jsDateToNumber(today));
5851
+ }
5848
5852
  case "lastWeek":
5849
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
5850
- case "lastMonth":
5851
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
5853
+ today.setDate(today.getDate() - 6);
5854
+ return Math.floor(jsDateToNumber(today));
5855
+ case "lastMonth": {
5856
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
5857
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
5858
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
5859
+ today.setDate(1);
5860
+ }
5861
+ else {
5862
+ today.setDate(today.getDate() + 1);
5863
+ today.setMonth(today.getMonth() - 1);
5864
+ }
5865
+ return Math.floor(jsDateToNumber(today));
5866
+ }
5852
5867
  case "lastYear":
5853
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
5868
+ // Handle leap year case
5869
+ if (today.getMonth() === 1 && today.getDate() === 29) {
5870
+ today.setDate(28);
5871
+ today.setFullYear(today.getFullYear() - 1);
5872
+ }
5873
+ else {
5874
+ today.setDate(today.getDate() + 1);
5875
+ today.setFullYear(today.getFullYear() - 1);
5876
+ }
5877
+ return Math.floor(jsDateToNumber(today));
5854
5878
  }
5855
5879
  }
5856
5880
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -40347,14 +40371,15 @@ function useHighlights(highlightProvider) {
40347
40371
  }
40348
40372
 
40349
40373
  css /* scss */ `
40350
- .o-cf-preview {
40374
+ .o-spreadsheet .o-cf-preview {
40351
40375
  &.o-cf-cursor-ptr {
40352
40376
  cursor: pointer;
40353
40377
  }
40354
40378
 
40355
40379
  border-bottom: 1px solid ${GRAY_300};
40356
- height: 60px;
40380
+ height: 80px;
40357
40381
  padding: 10px;
40382
+ box-sizing: border-box;
40358
40383
  position: relative;
40359
40384
  cursor: pointer;
40360
40385
  &:hover,
@@ -40368,7 +40393,6 @@ css /* scss */ `
40368
40393
  .o-cf-preview-icon {
40369
40394
  border: 1px solid ${GRAY_300};
40370
40395
  background-color: #fff;
40371
- position: absolute;
40372
40396
  height: 50px;
40373
40397
  width: 50px;
40374
40398
  .o-icon {
@@ -40377,12 +40401,6 @@ css /* scss */ `
40377
40401
  }
40378
40402
  }
40379
40403
  .o-cf-preview-description {
40380
- left: 65px;
40381
- margin-bottom: auto;
40382
- margin-right: 8px;
40383
- margin-top: auto;
40384
- position: relative;
40385
- width: 142px;
40386
40404
  .o-cf-preview-description-rule {
40387
40405
  margin-bottom: 4px;
40388
40406
  max-height: 2.8em;
@@ -40392,16 +40410,11 @@ css /* scss */ `
40392
40410
  font-size: 12px;
40393
40411
  }
40394
40412
  }
40395
- .o-cf-delete {
40396
- left: 90%;
40397
- top: 39%;
40398
- position: absolute;
40399
- }
40400
40413
  &:not(:hover):not(.o-cf-dragging) .o-cf-drag-handle {
40401
40414
  display: none !important;
40402
40415
  }
40403
40416
  .o-cf-drag-handle {
40404
- left: -8px;
40417
+ left: 2px;
40405
40418
  cursor: move;
40406
40419
  .o-icon {
40407
40420
  width: 6px;
@@ -41286,7 +41299,7 @@ dataValidationEvaluatorRegistry.add("dateIs", {
41286
41299
  return false;
41287
41300
  }
41288
41301
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
41289
- const today = jsDateToRoundNumber(DateTime.now());
41302
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
41290
41303
  return isDateBetween(dateValue, today, criterionValue);
41291
41304
  }
41292
41305
  return areDatesSameDay(dateValue, criterionValue);
@@ -44990,7 +45003,37 @@ pivotRegistry.add("SPREADSHEET", {
44990
45003
  datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
44991
45004
  isMeasureCandidate: (field) => !["datetime", "boolean"].includes(field.type),
44992
45005
  isGroupable: () => true,
45006
+ adaptRanges: (getters, definition, applyChange) => {
45007
+ if (definition.type !== "SPREADSHEET" || !definition.dataSet) {
45008
+ return definition;
45009
+ }
45010
+ const { sheetId, zone } = definition.dataSet;
45011
+ const range = getters.getRangeFromZone(sheetId, zone);
45012
+ const adaptedRange = adaptPivotRange(range, applyChange);
45013
+ if (adaptedRange === range) {
45014
+ return definition;
45015
+ }
45016
+ const dataSet = adaptedRange && {
45017
+ sheetId: adaptedRange.sheetId,
45018
+ zone: adaptedRange.zone,
45019
+ };
45020
+ return { ...definition, dataSet };
45021
+ },
44993
45022
  });
45023
+ function adaptPivotRange(range, applyChange) {
45024
+ if (!range) {
45025
+ return undefined;
45026
+ }
45027
+ const change = applyChange(range);
45028
+ switch (change.changeType) {
45029
+ case "NONE":
45030
+ return range;
45031
+ case "REMOVE":
45032
+ return undefined;
45033
+ default:
45034
+ return change.range;
45035
+ }
45036
+ }
44994
45037
 
44995
45038
  class PivotSidePanelStore extends SpreadsheetStore {
44996
45039
  pivotId;
@@ -46877,21 +46920,20 @@ class ArrayFormulaHighlight extends SpreadsheetStore {
46877
46920
  this.highlightStore.register(this);
46878
46921
  }
46879
46922
  get highlights() {
46880
- let zone;
46881
46923
  const position = this.model.getters.getActivePosition();
46882
- const cell = this.getters.getEvaluatedCell(position);
46883
46924
  const spreader = this.model.getters.getArrayFormulaSpreadingOn(position);
46884
- zone = spreader
46925
+ const zone = spreader
46885
46926
  ? this.model.getters.getSpreadZone(spreader, { ignoreSpillError: true })
46886
46927
  : this.model.getters.getSpreadZone(position, { ignoreSpillError: true });
46887
46928
  if (!zone) {
46888
46929
  return [];
46889
46930
  }
46931
+ const isArrayFormulaBlocked = this.model.getters.isArrayFormulaSpillBlocked(spreader ?? position);
46890
46932
  return [
46891
46933
  {
46892
46934
  sheetId: position.sheetId,
46893
46935
  zone,
46894
- dashed: cell.value === CellErrorType.SpilledBlocked,
46936
+ dashed: isArrayFormulaBlocked,
46895
46937
  color: "#17A2B8",
46896
46938
  noFill: true,
46897
46939
  thinLine: true,
@@ -54952,6 +54994,7 @@ function rangeToMerge(mergeId, range) {
54952
54994
  class RangeAdapter {
54953
54995
  getters;
54954
54996
  providers = [];
54997
+ isAdaptingRanges = false;
54955
54998
  constructor(getters) {
54956
54999
  this.getters = getters;
54957
55000
  }
@@ -54980,6 +55023,9 @@ class RangeAdapter {
54980
55023
  }
54981
55024
  beforeHandle(command) { }
54982
55025
  handle(cmd) {
55026
+ if (this.isAdaptingRanges) {
55027
+ throw new Error("Plugins cannot dispatch commands during adaptRanges phase");
55028
+ }
54983
55029
  switch (cmd.type) {
54984
55030
  case "REMOVE_COLUMNS_ROWS": {
54985
55031
  let start = cmd.dimension === "COL" ? "left" : "top";
@@ -55135,10 +55181,12 @@ class RangeAdapter {
55135
55181
  return adaptedRange;
55136
55182
  }
55137
55183
  executeOnAllRanges(adaptRange, sheetId) {
55184
+ this.isAdaptingRanges = true;
55138
55185
  const func = this.verifyRangeRemoved(adaptRange);
55139
55186
  for (const provider of this.providers) {
55140
55187
  provider(func, sheetId);
55141
55188
  }
55189
+ this.isAdaptingRanges = false;
55142
55190
  }
55143
55191
  /**
55144
55192
  * Stores the functions bound to each plugin to be able to iterate over all ranges of the application,
@@ -57245,6 +57293,18 @@ class PivotCorePlugin extends CorePlugin {
57245
57293
  }
57246
57294
  }
57247
57295
  adaptRanges(applyChange) {
57296
+ for (const pivotId in this.pivots) {
57297
+ const definition = deepCopy(this.pivots[pivotId]?.definition);
57298
+ if (!definition) {
57299
+ continue;
57300
+ }
57301
+ const newDefinition = pivotRegistry
57302
+ .get(definition.type)
57303
+ ?.adaptRanges?.(this.getters, definition, applyChange);
57304
+ if (newDefinition && !deepEquals(definition, newDefinition)) {
57305
+ this.history.update("pivots", pivotId, "definition", newDefinition);
57306
+ }
57307
+ }
57248
57308
  for (const sheetId in this.compiledMeasureFormulas) {
57249
57309
  for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
57250
57310
  const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
@@ -57387,17 +57447,10 @@ class PivotCorePlugin extends CorePlugin {
57387
57447
  if (!pivot) {
57388
57448
  continue;
57389
57449
  }
57390
- const def = deepCopy(pivot.definition);
57391
- for (const measure of def.measures) {
57450
+ for (const measure of pivot.definition.measures) {
57392
57451
  if (measure.computedBy?.formula === formulaString) {
57393
- const measureIndex = def.measures.indexOf(measure);
57394
- if (measureIndex !== -1) {
57395
- def.measures[measureIndex].computedBy = {
57396
- formula: newFormulaString,
57397
- sheetId,
57398
- };
57399
- }
57400
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: def });
57452
+ const measureIndex = pivot.definition.measures.indexOf(measure);
57453
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
57401
57454
  }
57402
57455
  }
57403
57456
  }
@@ -57496,20 +57549,6 @@ class SettingsPlugin extends CorePlugin {
57496
57549
  }
57497
57550
  }
57498
57551
 
57499
- function adaptPivotRange(range, applyChange) {
57500
- if (!range) {
57501
- return undefined;
57502
- }
57503
- const change = applyChange(range);
57504
- switch (change.changeType) {
57505
- case "NONE":
57506
- return range;
57507
- case "REMOVE":
57508
- return undefined;
57509
- default:
57510
- return change.range;
57511
- }
57512
- }
57513
57552
  class SpreadsheetPivotCorePlugin extends CorePlugin {
57514
57553
  allowDispatch(cmd) {
57515
57554
  switch (cmd.type) {
@@ -57520,27 +57559,6 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
57520
57559
  }
57521
57560
  return "Success" /* CommandResult.Success */;
57522
57561
  }
57523
- adaptRanges(applyChange) {
57524
- for (const pivotId of this.getters.getPivotIds()) {
57525
- const definition = this.getters.getPivotCoreDefinition(pivotId);
57526
- if (definition.type !== "SPREADSHEET") {
57527
- continue;
57528
- }
57529
- if (definition.dataSet) {
57530
- const { sheetId, zone } = definition.dataSet;
57531
- const range = this.getters.getRangeFromZone(sheetId, zone);
57532
- const adaptedRange = adaptPivotRange(range, applyChange);
57533
- if (adaptedRange === range) {
57534
- return;
57535
- }
57536
- const dataSet = adaptedRange && {
57537
- sheetId: adaptedRange.sheetId,
57538
- zone: adaptedRange.zone,
57539
- };
57540
- this.dispatch("UPDATE_PIVOT", { pivotId, pivot: { ...definition, dataSet } });
57541
- }
57542
- }
57543
- }
57544
57562
  checkDataSetValidity(definition) {
57545
57563
  if (definition.type === "SPREADSHEET" && definition.dataSet) {
57546
57564
  const { zone, sheetId } = definition.dataSet;
@@ -58898,6 +58916,9 @@ class Evaluator {
58898
58916
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
58899
58917
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
58900
58918
  }
58919
+ isArrayFormulaSpillBlocked(position) {
58920
+ return this.blockedArrayFormulas.has(position);
58921
+ }
58901
58922
  updateDependencies(position) {
58902
58923
  // removing dependencies is slow because it requires
58903
58924
  // to traverse the entire r-tree.
@@ -58909,13 +58930,8 @@ class Evaluator {
58909
58930
  addDependencies(position, dependencies) {
58910
58931
  this.formulaDependencies().addDependencies(position, dependencies);
58911
58932
  for (const range of dependencies) {
58912
- const sheetId = range.sheetId;
58913
- const { left, bottom, right, top } = range.zone;
58914
- for (let col = left; col <= right; col++) {
58915
- for (let row = top; row <= bottom; row++) {
58916
- this.computeAndSave({ sheetId, col, row });
58917
- }
58918
- }
58933
+ // ensure that all ranges are computed
58934
+ this.compilationParams.ensureRange(range);
58919
58935
  }
58920
58936
  }
58921
58937
  updateCompilationParameters() {
@@ -59114,6 +59130,10 @@ class Evaluator {
59114
59130
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
59115
59131
  const nbColumns = formulaReturn.length;
59116
59132
  const nbRows = formulaReturn[0].length;
59133
+ if (nbRows === 0) {
59134
+ // empty matrix
59135
+ return createEvaluatedCell({ value: 0 }, this.getters.getLocale(), cellData);
59136
+ }
59117
59137
  const resultZone = {
59118
59138
  top: formulaPosition.row,
59119
59139
  bottom: formulaPosition.row + nbRows - 1,
@@ -59386,6 +59406,7 @@ class EvaluationPlugin extends UIPlugin {
59386
59406
  "getEvaluatedCellsPositions",
59387
59407
  "getSpreadZone",
59388
59408
  "getArrayFormulaSpreadingOn",
59409
+ "isArrayFormulaSpillBlocked",
59389
59410
  "isEmpty",
59390
59411
  ];
59391
59412
  shouldRebuildDependenciesGraph = true;
@@ -59498,6 +59519,9 @@ class EvaluationPlugin extends UIPlugin {
59498
59519
  getArrayFormulaSpreadingOn(position) {
59499
59520
  return this.evaluator.getArrayFormulaSpreadingOn(position);
59500
59521
  }
59522
+ isArrayFormulaSpillBlocked(position) {
59523
+ return this.evaluator.isArrayFormulaSpillBlocked(position);
59524
+ }
59501
59525
  /**
59502
59526
  * Check if a zone only contains empty cells
59503
59527
  */
@@ -74770,6 +74794,6 @@ exports.tokenColors = tokenColors;
74770
74794
  exports.tokenize = tokenize;
74771
74795
 
74772
74796
 
74773
- __info__.version = "18.0.50";
74774
- __info__.date = "2025-12-02T05:32:00.480Z";
74775
- __info__.hash = "7ed20c4";
74797
+ __info__.version = "18.0.53";
74798
+ __info__.date = "2025-12-26T10:18:09.933Z";
74799
+ __info__.hash = "7ca8390";
@@ -3487,6 +3487,7 @@ interface RangeStringOptions {
3487
3487
  declare class RangeAdapter implements CommandHandler<CoreCommand> {
3488
3488
  private getters;
3489
3489
  private providers;
3490
+ private isAdaptingRanges;
3490
3491
  constructor(getters: CoreGetters);
3491
3492
  static getters: readonly ["extendRange", "getRangeString", "getRangeFromSheetXC", "createAdaptedRanges", "getRangeDataFromXc", "getRangeDataFromZone", "getRangeFromRangeData", "getRangeFromZone", "getRangesUnion", "recomputeRanges", "isRangeValid", "removeRangesSheetPrefix"];
3492
3493
  allowDispatch(cmd: Command): CommandResult;
@@ -4539,7 +4540,7 @@ declare class TablePlugin extends CorePlugin<TableState> implements TableState {
4539
4540
  }
4540
4541
 
4541
4542
  declare class EvaluationPlugin extends UIPlugin {
4542
- static getters: readonly ["evaluateFormula", "evaluateFormulaResult", "evaluateCompiledFormula", "getCorrespondingFormulaCell", "getRangeFormattedValues", "getRangeValues", "getRangeFormats", "getEvaluatedCell", "getEvaluatedCells", "getEvaluatedCellsInZone", "getEvaluatedCellsPositions", "getSpreadZone", "getArrayFormulaSpreadingOn", "isEmpty"];
4543
+ static getters: readonly ["evaluateFormula", "evaluateFormulaResult", "evaluateCompiledFormula", "getCorrespondingFormulaCell", "getRangeFormattedValues", "getRangeValues", "getRangeFormats", "getEvaluatedCell", "getEvaluatedCells", "getEvaluatedCellsInZone", "getEvaluatedCellsPositions", "getSpreadZone", "getArrayFormulaSpreadingOn", "isArrayFormulaSpillBlocked", "isEmpty"];
4543
4544
  private shouldRebuildDependenciesGraph;
4544
4545
  private evaluator;
4545
4546
  private positionsToUpdate;
@@ -4573,6 +4574,7 @@ declare class EvaluationPlugin extends UIPlugin {
4573
4574
  ignoreSpillError: boolean;
4574
4575
  }): Zone | undefined;
4575
4576
  getArrayFormulaSpreadingOn(position: CellPosition): CellPosition | undefined;
4577
+ isArrayFormulaSpillBlocked(position: CellPosition): boolean;
4576
4578
  /**
4577
4579
  * Check if a zone only contains empty cells
4578
4580
  */
@@ -6193,6 +6195,7 @@ interface PivotRegistryItem {
6193
6195
  datetimeGranularities: string[];
6194
6196
  isMeasureCandidate: (field: PivotField) => boolean;
6195
6197
  isGroupable: (field: PivotField) => boolean;
6198
+ adaptRanges?: (getters: CoreGetters, definition: PivotCoreDefinition, applyChange: ApplyRangeChange) => PivotCoreDefinition;
6196
6199
  }
6197
6200
 
6198
6201
  declare class ClipboardHandler<T> {