@odoo/o-spreadsheet 18.1.29 → 18.1.31

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.1.29
6
- * @date 2025-07-11T11:11:55.442Z
7
- * @hash 3456a93
5
+ * @version 18.1.31
6
+ * @date 2025-08-04T06:52:11.010Z
7
+ * @hash 4f581fb
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';
@@ -10477,6 +10477,7 @@ class ChartJsComponent extends Component {
10477
10477
  }
10478
10478
  setup() {
10479
10479
  onMounted(() => {
10480
+ registerChartJSExtensions();
10480
10481
  const runtime = this.chartRuntime;
10481
10482
  this.currentRuntime = runtime;
10482
10483
  // Note: chartJS modify the runtime in place, so it's important to give it a copy
@@ -11134,6 +11135,7 @@ const autoCompleteProviders = new Registry();
11134
11135
 
11135
11136
  autoCompleteProviders.add("dataValidation", {
11136
11137
  displayAllOnInitialContent: true,
11138
+ canBeToggled: false,
11137
11139
  getProposals(tokenAtCursor, content) {
11138
11140
  if (content.startsWith("=")) {
11139
11141
  return [];
@@ -11141,31 +11143,40 @@ autoCompleteProviders.add("dataValidation", {
11141
11143
  if (!this.composer.currentEditedCell) {
11142
11144
  return [];
11143
11145
  }
11144
- const position = this.composer.currentEditedCell;
11145
- const rule = this.getters.getValidationRuleForCell(position);
11146
- if (!rule ||
11147
- (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
11148
- return [];
11149
- }
11150
- let values;
11151
- if (rule.criterion.type === "isValueInList") {
11152
- values = rule.criterion.values;
11153
- }
11154
- else {
11155
- const range = this.getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
11156
- values = Array.from(new Set(this.getters
11157
- .getRangeValues(range)
11158
- .filter(isNotNull)
11159
- .map((value) => value.toString())
11160
- .filter((val) => val !== "")));
11161
- }
11162
- return values.map((value) => ({ text: value }));
11146
+ return getProposedValues(this.getters, this.composer.currentEditedCell).map((value) => ({
11147
+ text: value.value?.toString() || "",
11148
+ htmlContent: [{ value: value.label }],
11149
+ fuzzySearchKey: value.label,
11150
+ }));
11163
11151
  },
11164
11152
  selectProposal(tokenAtCursor, value) {
11165
11153
  this.composer.setCurrentContent(value);
11166
11154
  this.composer.stopEdition();
11167
11155
  },
11168
11156
  });
11157
+ function getProposedValues(getters, position) {
11158
+ const rule = getters.getValidationRuleForCell(position);
11159
+ if (!rule ||
11160
+ (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
11161
+ return [];
11162
+ }
11163
+ let values = [];
11164
+ if (rule.criterion.type === "isValueInList") {
11165
+ values = rule.criterion.values.map((value) => ({ label: value, value }));
11166
+ }
11167
+ else {
11168
+ const labelsSet = new Set();
11169
+ const range = getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
11170
+ for (const p of positions(range.zone)) {
11171
+ const cell = getters.getEvaluatedCell({ ...p, sheetId: range.sheetId });
11172
+ if (cell.formattedValue && !labelsSet.has(cell.formattedValue)) {
11173
+ labelsSet.add(cell.formattedValue);
11174
+ values.push({ label: cell.formattedValue, value: cell.value });
11175
+ }
11176
+ }
11177
+ }
11178
+ return values;
11179
+ }
11169
11180
 
11170
11181
  function getHtmlContentFromPattern(pattern, value, highlightColor, className) {
11171
11182
  const pendingHtmlContent = [];
@@ -18936,11 +18947,17 @@ const COLUMN = {
18936
18947
  if (isEvaluationError(cellReference?.value)) {
18937
18948
  return cellReference;
18938
18949
  }
18939
- const column = cellReference === undefined
18940
- ? this.__originCellPosition?.col
18941
- : toZone(cellReference.value).left;
18942
- assert(() => column !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
18943
- return column + 1;
18950
+ if (cellReference === undefined) {
18951
+ assert(() => this.__originCellPosition?.col !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
18952
+ return this.__originCellPosition.col + 1;
18953
+ }
18954
+ const zone = this.getters.getRangeFromSheetXC(this.getters.getActiveSheetId(), cellReference.value).zone;
18955
+ if (zone.left === zone.right) {
18956
+ return zone.left + 1;
18957
+ }
18958
+ return generateMatrix(zone.right - zone.left + 1, 1, (col, row) => ({
18959
+ value: zone.left + col + 1,
18960
+ }));
18944
18961
  },
18945
18962
  isExported: true,
18946
18963
  };
@@ -19159,11 +19176,17 @@ const ROW = {
19159
19176
  if (isEvaluationError(cellReference?.value)) {
19160
19177
  return cellReference;
19161
19178
  }
19162
- const row = cellReference === undefined
19163
- ? this.__originCellPosition?.row
19164
- : toZone(cellReference.value).top;
19165
- assert(() => row !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
19166
- return row + 1;
19179
+ if (cellReference === undefined) {
19180
+ assert(() => this.__originCellPosition?.row !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
19181
+ return this.__originCellPosition.row + 1;
19182
+ }
19183
+ const zone = this.getters.getRangeFromSheetXC(this.getters.getActiveSheetId(), cellReference.value).zone;
19184
+ if (zone.top === zone.bottom) {
19185
+ return zone.top + 1;
19186
+ }
19187
+ return generateMatrix(1, zone.bottom - zone.top + 1, (col, row) => ({
19188
+ value: zone.top + row + 1,
19189
+ }));
19167
19190
  },
19168
19191
  isExported: true,
19169
19192
  };
@@ -21439,6 +21462,7 @@ class AbstractComposerStore extends SpreadsheetStore {
21439
21462
  proposals,
21440
21463
  selectProposal: provider.selectProposal,
21441
21464
  autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
21465
+ canBeToggled: provider.canBeToggled,
21442
21466
  };
21443
21467
  }
21444
21468
  if (exactMatch && this._currentContent !== this.initialContent) {
@@ -21461,6 +21485,7 @@ class AbstractComposerStore extends SpreadsheetStore {
21461
21485
  proposals,
21462
21486
  selectProposal: provider.selectProposal,
21463
21487
  autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
21488
+ canBeToggled: provider.canBeToggled,
21464
21489
  };
21465
21490
  }
21466
21491
  }
@@ -41499,9 +41524,13 @@ class Composer extends Component {
41499
41524
  }
41500
41525
  }
41501
41526
  closeAssistant() {
41527
+ if (!this.canBeToggled)
41528
+ return;
41502
41529
  this.assistant.forcedClosed = true;
41503
41530
  }
41504
41531
  openAssistant() {
41532
+ if (!this.canBeToggled)
41533
+ return;
41505
41534
  this.assistant.forcedClosed = false;
41506
41535
  }
41507
41536
  onWheel(event) {
@@ -41511,6 +41540,9 @@ class Composer extends Component {
41511
41540
  event.stopPropagation();
41512
41541
  }
41513
41542
  }
41543
+ get canBeToggled() {
41544
+ return this.autoCompleteState.provider?.canBeToggled ?? true;
41545
+ }
41514
41546
  // ---------------------------------------------------------------------------
41515
41547
  // Private
41516
41548
  // ---------------------------------------------------------------------------
@@ -41646,7 +41678,7 @@ class Composer extends Component {
41646
41678
  }
41647
41679
  }
41648
41680
  autoComplete(value) {
41649
- if (!value || this.assistant.forcedClosed) {
41681
+ if (!value || (this.assistant.forcedClosed && this.canBeToggled)) {
41650
41682
  return;
41651
41683
  }
41652
41684
  this.autoCompleteState.provider?.selectProposal(value);
@@ -42443,7 +42475,8 @@ class ConditionalFormattingEditor extends Component {
42443
42475
  static props = {
42444
42476
  editedCf: Object,
42445
42477
  onCancel: Function,
42446
- onSave: Function,
42478
+ onExit: Function,
42479
+ isNewCf: Boolean,
42447
42480
  };
42448
42481
  static components = {
42449
42482
  SelectionInput,
@@ -42462,6 +42495,7 @@ class ConditionalFormattingEditor extends Component {
42462
42495
  getTextDecoration = getTextDecoration;
42463
42496
  colorNumberString = colorNumberString;
42464
42497
  state;
42498
+ hasEditedCf = this.props.isNewCf;
42465
42499
  setup() {
42466
42500
  this.state = useState({
42467
42501
  errors: [],
@@ -42519,6 +42553,9 @@ class ConditionalFormattingEditor extends Component {
42519
42553
  ranges: ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(sheetId, xc)),
42520
42554
  sheetId,
42521
42555
  });
42556
+ if (result.isSuccessful) {
42557
+ this.hasEditedCf = true;
42558
+ }
42522
42559
  const reasons = result.reasons.filter((r) => r !== "NoChanges" /* CommandResult.NoChanges */);
42523
42560
  if (!newCf.suppressErrors) {
42524
42561
  this.state.errors = reasons;
@@ -42540,7 +42577,15 @@ class ConditionalFormattingEditor extends Component {
42540
42577
  onSave() {
42541
42578
  const result = this.updateConditionalFormat({});
42542
42579
  if (result.length === 0) {
42543
- this.props.onSave();
42580
+ this.props.onExit();
42581
+ }
42582
+ }
42583
+ onCancel() {
42584
+ if (this.hasEditedCf) {
42585
+ this.props.onCancel();
42586
+ }
42587
+ else {
42588
+ this.props.onExit();
42544
42589
  }
42545
42590
  }
42546
42591
  getDefaultRules() {
@@ -46891,9 +46936,15 @@ class SpreadsheetPivot {
46891
46936
  return domain.reduce((current, acc) => this.filterDataEntriesFromDomainNode(current, acc), dataEntries);
46892
46937
  }
46893
46938
  filterDataEntriesFromDomainNode(dataEntries, domain) {
46894
- const { field, value } = domain;
46939
+ const { field, value, type } = domain;
46895
46940
  const { nameWithGranularity } = this.getDimension(field);
46896
- return dataEntries.filter((entry) => entry[nameWithGranularity]?.value === value);
46941
+ return dataEntries.filter((entry) => {
46942
+ const cellValue = entry[nameWithGranularity]?.value;
46943
+ if (type === "char") {
46944
+ return String(cellValue) === String(value);
46945
+ }
46946
+ return cellValue === value;
46947
+ });
46897
46948
  }
46898
46949
  getDimension(nameWithGranularity) {
46899
46950
  return this.definition.getDimension(nameWithGranularity);
@@ -49393,6 +49444,11 @@ class GridComposer extends Component {
49393
49444
  rect = this.defaultRect;
49394
49445
  isEditing = false;
49395
49446
  isCellReferenceVisible = false;
49447
+ currentEditedCell = {
49448
+ col: 0,
49449
+ row: 0,
49450
+ sheetId: this.env.model.getters.getActiveSheetId(),
49451
+ };
49396
49452
  composerStore;
49397
49453
  composerFocusStore;
49398
49454
  composerInterface;
@@ -49422,7 +49478,7 @@ class GridComposer extends Component {
49422
49478
  return this.isCellReferenceVisible;
49423
49479
  }
49424
49480
  get cellReference() {
49425
- const { col, row, sheetId } = this.composerStore.currentEditedCell;
49481
+ const { col, row, sheetId } = this.currentEditedCell;
49426
49482
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
49427
49483
  return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
49428
49484
  }
@@ -49514,12 +49570,17 @@ class GridComposer extends Component {
49514
49570
  if (!isEditing && this.composerFocusStore.activeComposer !== this.composerInterface) {
49515
49571
  this.composerFocusStore.focusComposer(this.composerInterface, { focusMode: "inactive" });
49516
49572
  }
49573
+ let shouldRecomputeRect = isEditing && !deepEquals(this.currentEditedCell, this.composerStore.currentEditedCell);
49517
49574
  if (this.isEditing !== isEditing) {
49518
49575
  this.isEditing = isEditing;
49519
49576
  if (!isEditing) {
49520
49577
  this.rect = this.defaultRect;
49521
49578
  return;
49522
49579
  }
49580
+ this.currentEditedCell = this.composerStore.currentEditedCell;
49581
+ shouldRecomputeRect = true;
49582
+ }
49583
+ if (shouldRecomputeRect) {
49523
49584
  const position = this.env.model.getters.getActivePosition();
49524
49585
  const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
49525
49586
  this.rect = this.env.model.getters.getVisibleRect(zone);
@@ -62487,6 +62548,23 @@ class HeaderSizeUIPlugin extends UIPlugin {
62487
62548
  static getters = ["getRowSize", "getHeaderSize"];
62488
62549
  tallestCellInRow = {};
62489
62550
  ctx = document.createElement("canvas").getContext("2d");
62551
+ beforeHandle(cmd) {
62552
+ switch (cmd.type) {
62553
+ // Ensure rows are updated before "UPDATE_CELL" is dispatched from cell plugin.
62554
+ // "UPDATE_CELL" uses the Sheet core plugin to access row data.
62555
+ // If "ADD_COLUMNS_ROWS" has not been processed yet by header_sizes_ui,
62556
+ // size updates may apply to incorrect (pre-insert) rows.
62557
+ case "ADD_COLUMNS_ROWS":
62558
+ if (cmd.dimension === "COL") {
62559
+ return;
62560
+ }
62561
+ const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
62562
+ const newCells = Array(cmd.quantity).fill(undefined);
62563
+ const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
62564
+ this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
62565
+ break;
62566
+ }
62567
+ }
62490
62568
  handle(cmd) {
62491
62569
  switch (cmd.type) {
62492
62570
  case "START":
@@ -62516,16 +62594,6 @@ class HeaderSizeUIPlugin extends UIPlugin {
62516
62594
  this.history.update("tallestCellInRow", cmd.sheetId, tallestCells);
62517
62595
  break;
62518
62596
  }
62519
- case "ADD_COLUMNS_ROWS": {
62520
- if (cmd.dimension === "COL") {
62521
- return;
62522
- }
62523
- const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
62524
- const newCells = Array(cmd.quantity).fill(undefined);
62525
- const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
62526
- this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
62527
- break;
62528
- }
62529
62597
  case "RESIZE_COLUMNS_ROWS":
62530
62598
  {
62531
62599
  const sheetId = cmd.sheetId;
@@ -68266,6 +68334,14 @@ class GridSelectionPlugin extends UIPlugin {
68266
68334
  const isBasedBefore = cmd.base < start;
68267
68335
  const deltaCol = isBasedBefore && isCol ? thickness : 0;
68268
68336
  const deltaRow = isBasedBefore && !isCol ? thickness : 0;
68337
+ const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
68338
+ const originalSize = Object.fromEntries(toRemove.map((element) => {
68339
+ const size = isCol
68340
+ ? this.getters.getColSize(cmd.sheetId, element)
68341
+ : this.getters.getUserRowSize(cmd.sheetId, element);
68342
+ const isDefaultCol = isCol && size === DEFAULT_CELL_WIDTH;
68343
+ return [element, isDefaultCol ? undefined : size];
68344
+ }));
68269
68345
  const target = [
68270
68346
  {
68271
68347
  left: isCol ? start + deltaCol : 0,
@@ -68296,13 +68372,12 @@ class GridSelectionPlugin extends UIPlugin {
68296
68372
  const col = selection.left;
68297
68373
  const row = selection.top;
68298
68374
  this.setSelectionMixin({ zone: selection, cell: { col, row } }, [selection]);
68299
- const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
68300
68375
  let currentIndex = isBasedBefore ? cmd.base : cmd.base + 1;
68301
68376
  const resizingGroups = {};
68302
68377
  for (const element of toRemove) {
68303
- const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
68378
+ const size = originalSize[element];
68304
68379
  const currentSize = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, currentIndex);
68305
- if (size != currentSize) {
68380
+ if (size && size != currentSize) {
68306
68381
  resizingGroups[size] ??= [];
68307
68382
  resizingGroups[size].push(currentIndex);
68308
68383
  currentIndex += 1;
@@ -70021,14 +70096,12 @@ class BottomBarSheet extends Component {
70021
70096
  this.editionState = "initializing";
70022
70097
  }
70023
70098
  stopEdition() {
70024
- const input = this.sheetNameRef.el;
70025
- if (!this.state.isEditing || !input)
70099
+ if (!this.state.isEditing || !this.sheetNameRef.el)
70026
70100
  return;
70027
70101
  this.state.isEditing = false;
70028
70102
  this.editionState = "initializing";
70029
- input.blur();
70103
+ this.sheetNameRef.el.blur();
70030
70104
  const inputValue = this.getInputContent() || "";
70031
- input.innerText = inputValue;
70032
70105
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
70033
70106
  }
70034
70107
  cancelEdition() {
@@ -72193,7 +72266,6 @@ class Spreadsheet extends Component {
72193
72266
  this.checkViewportSize();
72194
72267
  stores.on("store-updated", this, render);
72195
72268
  resizeObserver.observe(this.spreadsheetRef.el);
72196
- registerChartJSExtensions();
72197
72269
  });
72198
72270
  onWillUnmount(() => {
72199
72271
  this.unbindModelEvents();
@@ -76660,6 +76732,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
76660
76732
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
76661
76733
 
76662
76734
 
76663
- __info__.version = "18.1.29";
76664
- __info__.date = "2025-07-11T11:11:55.442Z";
76665
- __info__.hash = "3456a93";
76735
+ __info__.version = "18.1.31";
76736
+ __info__.date = "2025-08-04T06:52:11.010Z";
76737
+ __info__.hash = "4f581fb";