@odoo/o-spreadsheet 17.3.1 → 17.3.3

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.3.1
7
- * @date 2024-06-03T15:28:03.284Z
8
- * @hash 605d098
6
+ * @version 17.3.3
7
+ * @date 2024-06-14T10:02:58.082Z
8
+ * @hash c690e9f
9
9
  */
10
10
 
11
11
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -309,7 +309,10 @@ function deepCopy(obj) {
309
309
  * Check if the object is a plain old javascript object.
310
310
  */
311
311
  function isPlainObject(obj) {
312
- return typeof obj === "object" && obj?.constructor === Object;
312
+ return (typeof obj === "object" &&
313
+ obj !== null &&
314
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
315
+ (obj?.constructor === Object || obj?.constructor === undefined));
313
316
  }
314
317
  /**
315
318
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -2776,7 +2779,7 @@ function evaluatePredicate(value, criterion) {
2776
2779
  return false;
2777
2780
  }
2778
2781
  if (typeof operand === "number" && operator === "=") {
2779
- return toString(value) === toString(operand);
2782
+ return value.toString() === operand.toString();
2780
2783
  }
2781
2784
  if (operator === "<>" || operator === "=") {
2782
2785
  let result;
@@ -2836,14 +2839,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2836
2839
  if (countArg % 2 === 1) {
2837
2840
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2838
2841
  }
2839
- const dimRow = args[0].length;
2840
- const dimCol = args[0][0].length;
2842
+ const firstArg = toMatrix(args[0]);
2843
+ const dimRow = firstArg.length;
2844
+ const dimCol = firstArg[0].length;
2841
2845
  let predicates = [];
2842
2846
  for (let i = 0; i < countArg - 1; i += 2) {
2843
- const criteriaRange = args[i];
2844
- if (!isMatrix(criteriaRange) ||
2845
- criteriaRange.length !== dimRow ||
2846
- criteriaRange[0].length !== dimCol) {
2847
+ const criteriaRange = toMatrix(args[i]);
2848
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2847
2849
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2848
2850
  }
2849
2851
  const description = toString(args[i + 1]);
@@ -2857,7 +2859,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2857
2859
  for (let j = 0; j < dimCol; j++) {
2858
2860
  let validatedPredicates = true;
2859
2861
  for (let k = 0; k < countArg - 1; k += 2) {
2860
- const criteriaValue = args[k][i][j].value;
2862
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2861
2863
  const criterion = predicates[k / 2];
2862
2864
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2863
2865
  if (!validatedPredicates) {
@@ -10985,6 +10987,9 @@ function makeArg(str, description) {
10985
10987
  if (types.some((t) => t.startsWith("RANGE"))) {
10986
10988
  result.acceptMatrix = true;
10987
10989
  }
10990
+ if (types.every((t) => t.startsWith("RANGE"))) {
10991
+ result.acceptMatrixOnly = true;
10992
+ }
10988
10993
  return result;
10989
10994
  }
10990
10995
  /**
@@ -11266,11 +11271,16 @@ const CHOOSECOLS = {
11266
11271
  compute: function (array, ...columns) {
11267
11272
  const _array = toMatrix(array);
11268
11273
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11269
- assert(() => _columns.every((col) => col > 0 && col <= _array.length), _t("The columns arguments must be between 1 and %s (got %s).", _array.length.toString(), (_columns.find((col) => col <= 0 || col > _array.length) || 0).toString()));
11274
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11275
+ assert(() => argOutOfRange.length === 0, _t("The columns arguments must be between -%s and %s (got %s), excluding 0.", _array.length.toString(), _array.length.toString(), argOutOfRange.join(",")));
11270
11276
  const result = Array(_columns.length);
11271
11277
  for (let col = 0; col < _columns.length; col++) {
11272
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11273
- result[col] = _array[colIndex];
11278
+ if (_columns[col] > 0) {
11279
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11280
+ }
11281
+ else {
11282
+ result[col] = _array[_array.length + _columns[col]];
11283
+ }
11274
11284
  }
11275
11285
  return result;
11276
11286
  },
@@ -11291,8 +11301,14 @@ const CHOOSEROWS = {
11291
11301
  const _array = toMatrix(array);
11292
11302
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11293
11303
  const _nbColumns = _array.length;
11294
- assert(() => _rows.every((row) => row > 0 && row <= _array[0].length), _t("The rows arguments must be between 1 and %s (got %s).", _array[0].length.toString(), (_rows.find((row) => row <= 0 || row > _array[0].length) || 0).toString()));
11295
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11304
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11305
+ assert(() => argOutOfRange.length === 0, _t("The rows arguments must be between -%s and %s (got %s), excluding 0.", _array[0].length.toString(), _array[0].length.toString(), argOutOfRange.join(",")));
11306
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11307
+ if (_rows[row] > 0) {
11308
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11309
+ }
11310
+ return _array[col][_array[col].length + _rows[row]];
11311
+ });
11296
11312
  },
11297
11313
  isExported: true,
11298
11314
  };
@@ -19759,6 +19775,9 @@ function addInputHandling(descr) {
19759
19775
  }
19760
19776
  args[i] = arg[0][0];
19761
19777
  }
19778
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19779
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19780
+ }
19762
19781
  }
19763
19782
  return descr.compute.apply(this, args);
19764
19783
  }
@@ -20900,8 +20919,15 @@ class Composer extends Component {
20900
20919
  }
20901
20920
  onPaste(ev) {
20902
20921
  if (this.composerStore.editionMode !== "inactive") {
20922
+ // let the browser clipboard work
20903
20923
  ev.stopPropagation();
20904
20924
  }
20925
+ else {
20926
+ // the user meant to paste in the sheet, not open the composer with the pasted content
20927
+ // While we're not editing, we still have the focus and should therefore prevent
20928
+ // the native "paste" to occur.
20929
+ ev.preventDefault();
20930
+ }
20905
20931
  }
20906
20932
  /*
20907
20933
  * Triggered automatically by the content-editable between the keydown and key up
@@ -20910,9 +20936,6 @@ class Composer extends Component {
20910
20936
  if (!this.shouldProcessInputEvents) {
20911
20937
  return;
20912
20938
  }
20913
- if (ev.inputType === "insertFromPaste" && this.composerStore.editionMode === "inactive") {
20914
- return;
20915
- }
20916
20939
  ev.stopPropagation();
20917
20940
  let content;
20918
20941
  if (this.composerStore.editionMode === "inactive") {
@@ -21349,12 +21372,6 @@ function compileTokens(tokens) {
21349
21372
  // detect when an argument need to be evaluated as a meta argument
21350
21373
  const isMeta = argTypes.includes("META");
21351
21374
  const hasRange = argTypes.some((t) => isRangeType(t));
21352
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
21353
- if (isRangeOnly) {
21354
- if (!isRangeInput(currentArg)) {
21355
- throw new BadExpressionError(_t("Function %(function_name)s expects the parameter %(arg_index)s to be a reference to a cell or a range.", { function_name: functionName, arg_index: i + 1 }));
21356
- }
21357
- }
21358
21375
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
21359
21376
  }
21360
21377
  return compiledArgs;
@@ -21519,16 +21536,6 @@ function assertEnoughArgs(ast) {
21519
21536
  function isRangeType(type) {
21520
21537
  return type.startsWith("RANGE");
21521
21538
  }
21522
- function isRangeInput(arg) {
21523
- if (arg.type === "REFERENCE") {
21524
- return true;
21525
- }
21526
- if (arg.type === "FUNCALL") {
21527
- const fnDef = functions$1[arg.value.toUpperCase()];
21528
- return fnDef && isRangeType(fnDef.returns[0]);
21529
- }
21530
- return false;
21531
- }
21532
21539
 
21533
21540
  const functions = functionRegistry.content;
21534
21541
  function isExportableToExcel(tokens) {
@@ -21957,7 +21964,9 @@ autoCompleteProviders.add("pivot_group_values", {
21957
21964
  if (!groupByField) {
21958
21965
  return;
21959
21966
  }
21960
- return dataSource.getPossibleFieldValues(groupByField.split(":")[0]).map(({ value, label }) => {
21967
+ return dataSource
21968
+ .getPossibleFieldValues(groupByField.toString().split(":")[0])
21969
+ .map(({ value, label }) => {
21961
21970
  const isString = typeof value === "string";
21962
21971
  const text = isString ? `"${value}"` : value.toString();
21963
21972
  const color = isString ? tokenColors.STRING : tokenColors.NUMBER;
@@ -25321,8 +25330,7 @@ function zoneToRect(zone) {
25321
25330
  */
25322
25331
  function useSpreadsheetRect() {
25323
25332
  const position = useState({ x: 0, y: 0, width: 0, height: 0 });
25324
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
25325
- updatePosition();
25333
+ let spreadsheetElement = null;
25326
25334
  function updatePosition() {
25327
25335
  if (!spreadsheetElement) {
25328
25336
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -25444,7 +25452,7 @@ class Popover extends Component {
25444
25452
  if (!anchor)
25445
25453
  return;
25446
25454
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
25447
- const elDims = {
25455
+ let elDims = {
25448
25456
  width: el.getBoundingClientRect().width,
25449
25457
  height: el.getBoundingClientRect().height,
25450
25458
  };
@@ -25452,7 +25460,14 @@ class Popover extends Component {
25452
25460
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
25453
25461
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
25454
25462
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
25455
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25463
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
25464
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
25465
+ // Re-compute the dimensions after setting the max-width and max-height
25466
+ elDims = {
25467
+ width: el.getBoundingClientRect().width,
25468
+ height: el.getBoundingClientRect().height,
25469
+ };
25470
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25456
25471
  for (const property of Object.keys(style)) {
25457
25472
  el.style[property] = style[property];
25458
25473
  }
@@ -25515,8 +25530,6 @@ class PopoverPositionContext {
25515
25530
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
25516
25531
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
25517
25532
  const cssProperties = {
25518
- "max-height": maxHeight + "px",
25519
- "max-width": maxWidth + "px",
25520
25533
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
25521
25534
  this.spreadsheetOffset.y -
25522
25535
  verticalOffset +
@@ -31330,10 +31343,8 @@ class ChartTitle extends Component {
31330
31343
 
31331
31344
  class AxisDesignEditor extends Component {
31332
31345
  static template = "o-spreadsheet-AxisDesignEditor";
31333
- static components = {
31334
- Section,
31335
- ChartTitle,
31336
- };
31346
+ static components = { Section, ChartTitle };
31347
+ static props = { figureId: String, definition: Object, updateChart: Function, axesList: Array };
31337
31348
  state = useState({ currentAxis: "x" });
31338
31349
  get axisTitleStyle() {
31339
31350
  const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
@@ -31484,6 +31495,12 @@ class ChartWithAxisDesignPanel extends Component {
31484
31495
  AxisDesignEditor,
31485
31496
  RoundColorPicker,
31486
31497
  };
31498
+ static props = {
31499
+ figureId: String,
31500
+ definition: Object,
31501
+ canUpdateChart: Function,
31502
+ updateChart: Function,
31503
+ };
31487
31504
  state = useState({ index: 0 });
31488
31505
  get axesList() {
31489
31506
  const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
@@ -31665,14 +31682,6 @@ class GaugeChartDesignPanel extends Component {
31665
31682
  const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
31666
31683
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
31667
31684
  }
31668
- updateBackgroundColor(color) {
31669
- this.props.updateChart(this.props.figureId, {
31670
- background: color,
31671
- });
31672
- }
31673
- updateTitle(content) {
31674
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31675
- }
31676
31685
  isRangeMinInvalid() {
31677
31686
  return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
31678
31687
  this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */) ||
@@ -31712,9 +31721,6 @@ class GaugeChartDesignPanel extends Component {
31712
31721
  sectionRule,
31713
31722
  });
31714
31723
  }
31715
- get backgroundColorTitle() {
31716
- return ChartTerms.BackgroundColor;
31717
- }
31718
31724
  }
31719
31725
 
31720
31726
  class LineConfigPanel extends GenericChartConfigPanel {
@@ -31897,9 +31903,6 @@ class ScorecardChartDesignPanel extends Component {
31897
31903
  get humanizeNumbersLabel() {
31898
31904
  return _t("Humanize numbers");
31899
31905
  }
31900
- updateTitle(content) {
31901
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31902
- }
31903
31906
  updateHumanizeNumbers(humanize) {
31904
31907
  this.props.updateChart(this.props.figureId, { humanize });
31905
31908
  }
@@ -31922,9 +31925,6 @@ class ScorecardChartDesignPanel extends Component {
31922
31925
  break;
31923
31926
  }
31924
31927
  }
31925
- get backgroundColorTitle() {
31926
- return ChartTerms.BackgroundColor;
31927
- }
31928
31928
  }
31929
31929
 
31930
31930
  class WaterfallChartDesignPanel extends Component {
@@ -33425,13 +33425,17 @@ class SelectMenu extends Component {
33425
33425
  class: { type: String, optional: true },
33426
33426
  };
33427
33427
  static components = { Menu };
33428
+ menuId = new UuidGenerator().uuidv4();
33428
33429
  selectRef = useRef("select");
33429
33430
  selectRect = useAbsoluteBoundingRect(this.selectRef);
33430
33431
  state = useState({
33431
33432
  isMenuOpen: false,
33432
33433
  });
33433
- onClick() {
33434
- this.state.isMenuOpen = true;
33434
+ onClick(ev) {
33435
+ if (ev.closedMenuId === this.menuId) {
33436
+ return;
33437
+ }
33438
+ this.state.isMenuOpen = !this.state.isMenuOpen;
33435
33439
  }
33436
33440
  onMenuClosed() {
33437
33441
  this.state.isMenuOpen = false;
@@ -33439,7 +33443,7 @@ class SelectMenu extends Component {
33439
33443
  get menuPosition() {
33440
33444
  return {
33441
33445
  x: this.selectRect.x,
33442
- y: this.selectRect.y,
33446
+ y: this.selectRect.y + this.selectRect.height,
33443
33447
  };
33444
33448
  }
33445
33449
  }
@@ -34379,9 +34383,9 @@ class FindAndReplacePanel extends Component {
34379
34383
  static props = {
34380
34384
  onCloseSidePanel: Function,
34381
34385
  };
34382
- dataRange = "";
34383
34386
  searchInput = useRef("searchInput");
34384
34387
  store;
34388
+ state;
34385
34389
  get hasSearchResult() {
34386
34390
  return this.store.selectedMatchIndex !== null;
34387
34391
  }
@@ -34411,6 +34415,7 @@ class FindAndReplacePanel extends Component {
34411
34415
  }
34412
34416
  setup() {
34413
34417
  this.store = useLocalStore(FindAndReplaceStore);
34418
+ this.state = useState({ dataRange: "" });
34414
34419
  onMounted(() => this.searchInput.el?.focus());
34415
34420
  }
34416
34421
  onFocusSearch() {
@@ -34447,13 +34452,13 @@ class FindAndReplacePanel extends Component {
34447
34452
  this.store.updateSearchOptions({ searchScope });
34448
34453
  }
34449
34454
  onSearchRangeChanged(ranges) {
34450
- this.dataRange = ranges[0];
34455
+ this.state.dataRange = ranges[0];
34451
34456
  }
34452
34457
  updateDataRange() {
34453
- if (!this.dataRange || this.searchOptions.searchScope !== "specificRange") {
34458
+ if (!this.state.dataRange || this.searchOptions.searchScope !== "specificRange") {
34454
34459
  return;
34455
34460
  }
34456
- const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange);
34461
+ const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
34457
34462
  this.store.updateSearchOptions({ specificRange });
34458
34463
  }
34459
34464
  }
@@ -36124,6 +36129,7 @@ css /* scss */ `
36124
36129
  class RemoveDuplicatesPanel extends Component {
36125
36130
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
36126
36131
  static components = { ValidationMessages, Section, Checkbox };
36132
+ static props = { onCloseSidePanel: Function };
36127
36133
  state = useState({
36128
36134
  hasHeader: false,
36129
36135
  columns: {},
@@ -37916,10 +37922,7 @@ class GridComposer extends Component {
37916
37922
  }
37917
37923
  get containerStyle() {
37918
37924
  if (this.composerStore.editionMode === "inactive") {
37919
- return `
37920
- position: absolute;
37921
- z-index: -1000;
37922
- `;
37925
+ return `z-index: -1000;`;
37923
37926
  }
37924
37927
  const isFormula = this.composerStore.currentContent.startsWith("=");
37925
37928
  const cell = this.env.model.getters.getActiveCell();
@@ -38551,7 +38554,7 @@ class FiguresContainer extends Component {
38551
38554
  });
38552
38555
  }
38553
38556
  getContainerRect(container) {
38554
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
38557
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
38555
38558
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
38556
38559
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
38557
38560
  const width = viewWidth - x;
@@ -51156,22 +51159,6 @@ class PivotCorePlugin extends CorePlugin {
51156
51159
  this.addPivotFormula(cellPosition, formulaId, pivotCell);
51157
51160
  }
51158
51161
  }
51159
- const pivotZone = {
51160
- top: position.row,
51161
- bottom: position.row + pivotCells[0].length - 1,
51162
- left: position.col,
51163
- right: position.col + pivotCells.length - 1,
51164
- };
51165
- const numberOfHeaders = table.columns.length - 1;
51166
- const cmdContent = {
51167
- sheetId: position.sheetId,
51168
- ranges: [this.getters.getRangeDataFromZone(position.sheetId, pivotZone)],
51169
- config: { ...PIVOT_TABLE_CONFIG, numberOfHeaders },
51170
- tableType: "static",
51171
- };
51172
- if (this.canDispatch("CREATE_TABLE", cmdContent).isSuccessful) {
51173
- this.dispatch("CREATE_TABLE", cmdContent);
51174
- }
51175
51162
  }
51176
51163
  resizeSheet(sheetId, { col, row }, table) {
51177
51164
  const colLimit = table.getNumberOfDataColumns() + 1; // +1 for the Top-Left
@@ -54566,17 +54553,18 @@ class PivotUIPlugin extends UIPlugin {
54566
54553
  const pivotCol = position.col - mainPosition.col;
54567
54554
  const pivotRow = position.row - mainPosition.row;
54568
54555
  const pivotCell = pivotCells[pivotCol][pivotRow];
54569
- const domain = pivotCell.domain;
54556
+ let domain = pivotCell.domain;
54570
54557
  if (domain?.at(-2) === "measure") {
54571
- return domain.slice(0, -2);
54558
+ domain = domain.slice(0, -2);
54572
54559
  }
54573
- return domain;
54560
+ return { domainArgs: domain, isHeader: pivotCell.isHeader };
54574
54561
  }
54575
- const domain = args.slice(functionName === "PIVOT.VALUE" ? 2 : 1);
54562
+ let domain = args.slice(functionName === "PIVOT.VALUE" ? 2 : 1);
54576
54563
  if (domain.at(-2) === "measure") {
54577
- return domain.slice(0, -2);
54564
+ domain = domain.slice(0, -2);
54578
54565
  }
54579
- return domain;
54566
+ const isHeader = functionName === "PIVOT.HEADER";
54567
+ return { domainArgs: domain, isHeader };
54580
54568
  }
54581
54569
  getPivot(pivotId) {
54582
54570
  return this.pivots[pivotId];
@@ -55896,7 +55884,10 @@ class Session extends EventBus {
55896
55884
  /**
55897
55885
  * Notify the server that the user client left the collaborative session
55898
55886
  */
55899
- leave() {
55887
+ leave(data) {
55888
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
55889
+ this.snapshot(data);
55890
+ }
55900
55891
  delete this.clients[this.clientId];
55901
55892
  this.transportService.leave(this.clientId);
55902
55893
  this.transportService.sendMessage({
@@ -55909,6 +55900,9 @@ class Session extends EventBus {
55909
55900
  * Send a snapshot of the spreadsheet to the collaboration server
55910
55901
  */
55911
55902
  snapshot(data) {
55903
+ if (this.pendingMessages.length !== 0) {
55904
+ return;
55905
+ }
55912
55906
  const snapshotId = this.uuidGenerator.uuidv4();
55913
55907
  this.transportService.sendMessage({
55914
55908
  type: "SNAPSHOT",
@@ -66396,7 +66390,7 @@ class Model extends EventBus {
66396
66390
  this.session.join(this.config.client);
66397
66391
  }
66398
66392
  leaveSession() {
66399
- this.session.leave();
66393
+ this.session.leave(this.exportData());
66400
66394
  }
66401
66395
  setupUiPlugin(Plugin) {
66402
66396
  const plugin = new Plugin(this.uiPluginConfig);
@@ -66944,6 +66938,6 @@ const constants = {
66944
66938
  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 };
66945
66939
 
66946
66940
 
66947
- __info__.version = "17.3.1";
66948
- __info__.date = "2024-06-03T15:28:03.284Z";
66949
- __info__.hash = "605d098";
66941
+ __info__.version = "17.3.3";
66942
+ __info__.date = "2024-06-14T10:02:58.082Z";
66943
+ __info__.hash = "c690e9f";