@odoo/o-spreadsheet 17.2.25 → 17.2.27

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.2.25
7
- * @date 2024-11-08T12:13:19.966Z
8
- * @hash 40d42f8
6
+ * @version 17.2.27
7
+ * @date 2024-11-22T14:17:16.936Z
8
+ * @hash 139e5a3
9
9
  */
10
10
 
11
11
  'use strict';
@@ -2933,7 +2933,9 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
2933
2933
  return reverseSearch ? numberOfValues - i - 1 : i;
2934
2934
  }
2935
2935
  }
2936
- return reverseSearch ? numberOfValues - closestMatchIndex - 1 : closestMatchIndex;
2936
+ return reverseSearch && closestMatchIndex !== -1
2937
+ ? numberOfValues - closestMatchIndex - 1
2938
+ : closestMatchIndex;
2937
2939
  }
2938
2940
  /**
2939
2941
  * Normalize a value.
@@ -19695,11 +19697,14 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
19695
19697
  function getChartLabelFormat(getters, range) {
19696
19698
  if (!range)
19697
19699
  return undefined;
19698
- return getters.getEvaluatedCell({
19699
- sheetId: range.sheetId,
19700
- col: range.zone.left,
19701
- row: range.zone.top,
19702
- }).format;
19700
+ const { sheetId, zone: { left, top, bottom }, } = range;
19701
+ for (let row = top; row <= bottom; row++) {
19702
+ const format = getters.getEvaluatedCell({ sheetId, col: left, row }).format;
19703
+ if (format) {
19704
+ return format;
19705
+ }
19706
+ }
19707
+ return undefined;
19703
19708
  }
19704
19709
  function getChartLabelValues(getters, dataSets, labelRange) {
19705
19710
  let labels = { values: [], formattedValues: [] };
@@ -20415,11 +20420,7 @@ function canBeDateChart(labelRange, getters) {
20415
20420
  if (!labelRange || !canBeLinearChart(labelRange, getters)) {
20416
20421
  return false;
20417
20422
  }
20418
- const labelFormat = getters.getEvaluatedCell({
20419
- sheetId: labelRange.sheetId,
20420
- col: labelRange.zone.left,
20421
- row: labelRange.zone.top,
20422
- }).format;
20423
+ const labelFormat = getChartLabelFormat(getters, labelRange);
20423
20424
  return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
20424
20425
  }
20425
20426
  function canBeLinearChart(labelRange, getters) {
@@ -27218,6 +27219,7 @@ class ColorPicker extends owl.Component {
27218
27219
  currentColor: { type: String, optional: true },
27219
27220
  maxHeight: { type: Number, optional: true },
27220
27221
  anchorRect: Object,
27222
+ disableNoColor: { type: Boolean, optional: true },
27221
27223
  };
27222
27224
  static defaultProps = { currentColor: "" };
27223
27225
  static components = { Popover };
@@ -27401,6 +27403,7 @@ class ColorPickerWidget extends owl.Component {
27401
27403
  disabled: { type: Boolean, optional: true },
27402
27404
  dropdownMaxHeight: { type: Number, optional: true },
27403
27405
  class: { type: String, optional: true },
27406
+ disableNoColor: { type: Boolean, optional: true },
27404
27407
  };
27405
27408
  static components = { ColorPicker };
27406
27409
  colorPickerButtonRef = owl.useRef("colorPickerButton");
@@ -28959,6 +28962,9 @@ class ConditionalFormattingEditor extends owl.Component {
28959
28962
  }
28960
28963
  }
28961
28964
  setColorScaleColor(target, color) {
28965
+ if (!isColorValid(color)) {
28966
+ return;
28967
+ }
28962
28968
  const point = this.state.rules.colorScale[target];
28963
28969
  if (point) {
28964
28970
  point.color = Number.parseInt(color.substr(1), 16);
@@ -47827,12 +47833,18 @@ class Evaluator {
47827
47833
  }
47828
47834
  for (let i = 0; i < positions.length; ++i) {
47829
47835
  const position = positions[i];
47836
+ if (this.nextPositionsToUpdate.has(position)) {
47837
+ continue;
47838
+ }
47830
47839
  const evaluatedCell = this.computeCell(position);
47831
47840
  if (evaluatedCell !== EMPTY_CELL) {
47832
47841
  this.evaluatedCells.set(position, evaluatedCell);
47833
47842
  }
47834
47843
  }
47835
47844
  }
47845
+ if (currentIteration >= MAX_ITERATION) {
47846
+ console.warn("Maximum iteration reached while evaluating cells");
47847
+ }
47836
47848
  }
47837
47849
  computeCell(position) {
47838
47850
  const evaluation = this.evaluatedCells.get(position);
@@ -47864,7 +47876,6 @@ class Evaluator {
47864
47876
  }
47865
47877
  finally {
47866
47878
  this.cellsBeingComputed.delete(cellId);
47867
- this.nextPositionsToUpdate.delete(position);
47868
47879
  }
47869
47880
  }
47870
47881
  computeAndSave(position) {
@@ -47914,6 +47925,7 @@ class Evaluator {
47914
47925
  { sheetId, zone: rightPartZone },
47915
47926
  { sheetId, zone: leftColumnZone },
47916
47927
  ]);
47928
+ invalidatedPositions.delete(arrayFormulaPosition);
47917
47929
  this.nextPositionsToUpdate.addMany(invalidatedPositions);
47918
47930
  }
47919
47931
  assertSheetHasEnoughSpaceToSpreadFormulaResult({ sheetId, col, row }, matrixResult) {
@@ -48958,25 +48970,11 @@ class EvaluationDataValidationPlugin extends UIPlugin {
48958
48970
  }
48959
48971
  switch (cmd.type) {
48960
48972
  case "ADD_DATA_VALIDATION_RULE":
48961
- const ranges = cmd.ranges.map((range) => this.getters.getRangeFromRangeData(range));
48962
- if (cmd.rule.criterion.type === "isBoolean") {
48963
- this.setContentToBooleanCells({ ...cmd.rule, ranges });
48964
- }
48965
- delete this.validationResults[cmd.sheetId];
48966
- break;
48967
48973
  case "REMOVE_DATA_VALIDATION_RULE":
48968
48974
  delete this.validationResults[cmd.sheetId];
48969
48975
  break;
48970
48976
  }
48971
48977
  }
48972
- setContentToBooleanCells(rule) {
48973
- for (const position of getCellPositionsInRanges(rule.ranges)) {
48974
- const evaluatedCell = this.getters.getEvaluatedCell(position);
48975
- if (evaluatedCell.type !== CellValueType.boolean) {
48976
- this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
48977
- }
48978
- }
48979
- }
48980
48978
  isDataValidationInvalid(cellPosition) {
48981
48979
  return !this.getValidationResultForCell(cellPosition).isValid;
48982
48980
  }
@@ -50448,7 +50446,7 @@ class Session extends EventBus {
50448
50446
  * Notify the server that the user client left the collaborative session
50449
50447
  */
50450
50448
  async leave(data) {
50451
- if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
50449
+ if (data && Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
50452
50450
  await this.snapshot(data());
50453
50451
  }
50454
50452
  delete this.clients[this.clientId];
@@ -51554,6 +51552,42 @@ class SheetUIPlugin extends UIPlugin {
51554
51552
  }
51555
51553
  }
51556
51554
 
51555
+ class DataValidationInsertionPlugin extends UIPlugin {
51556
+ handle(cmd) {
51557
+ switch (cmd.type) {
51558
+ case "ADD_DATA_VALIDATION_RULE":
51559
+ if (cmd.rule.criterion.type === "isBoolean") {
51560
+ const ranges = cmd.ranges.map((range) => this.getters.getRangeFromRangeData(range));
51561
+ for (const position of getCellPositionsInRanges(ranges)) {
51562
+ const cell = this.getters.getCell(position);
51563
+ const evaluatedCell = this.getters.getEvaluatedCell(position);
51564
+ if (!cell?.content) {
51565
+ this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
51566
+ // In this case, a cell has been updated in the core plugin but
51567
+ // not yet evaluated. This can occur after a paste operation.
51568
+ }
51569
+ else if (cell?.content && evaluatedCell.type === CellValueType.empty) {
51570
+ let value;
51571
+ if (cell.content.startsWith("=")) {
51572
+ const result = this.getters.evaluateFormula(position.sheetId, cell.content);
51573
+ value = (isMatrix(result) ? result[0][0] : result)?.toString();
51574
+ }
51575
+ else {
51576
+ value = cell.content;
51577
+ }
51578
+ if (!value || !isBoolean(value)) {
51579
+ this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
51580
+ }
51581
+ }
51582
+ else if (evaluatedCell.type !== CellValueType.boolean) {
51583
+ this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
51584
+ }
51585
+ }
51586
+ }
51587
+ }
51588
+ }
51589
+ }
51590
+
51557
51591
  const genericRepeatsTransforms = [
51558
51592
  repeatSheetDependantCommand,
51559
51593
  repeatTargetDependantCommand,
@@ -54787,7 +54821,8 @@ const featurePluginRegistry = new Registry()
54787
54821
  .add("collaborative", CollaborativePlugin)
54788
54822
  .add("history", HistoryPlugin)
54789
54823
  .add("data_cleanup", DataCleanupPlugin)
54790
- .add("table_autofill", TableAutofillPlugin);
54824
+ .add("table_autofill", TableAutofillPlugin)
54825
+ .add("datavalidation_insert", DataValidationInsertionPlugin);
54791
54826
  // Plugins which have a state, but which should not be shared in collaborative
54792
54827
  const statefulUIPluginRegistry = new Registry()
54793
54828
  .add("selection", GridSelectionPlugin)
@@ -60415,7 +60450,8 @@ class Model extends EventBus {
60415
60450
  this.session.join(this.config.client);
60416
60451
  }
60417
60452
  async leaveSession() {
60418
- await this.session.leave(lazy(() => this.exportData()));
60453
+ const snapshot = this.getters.isReadonly() ? undefined : lazy(() => this.exportData());
60454
+ await this.session.leave(snapshot);
60419
60455
  }
60420
60456
  setupUiPlugin(Plugin) {
60421
60457
  const plugin = new Plugin(this.uiPluginConfig);
@@ -60969,6 +61005,6 @@ exports.tokenColors = tokenColors;
60969
61005
  exports.tokenize = tokenize;
60970
61006
 
60971
61007
 
60972
- __info__.version = "17.2.25";
60973
- __info__.date = "2024-11-08T12:13:19.966Z";
60974
- __info__.hash = "40d42f8";
61008
+ __info__.version = "17.2.27";
61009
+ __info__.date = "2024-11-22T14:17:16.936Z";
61010
+ __info__.hash = "139e5a3";
@@ -3451,7 +3451,7 @@ declare class Session extends EventBus<CollaborativeEvent> {
3451
3451
  /**
3452
3452
  * Notify the server that the user client left the collaborative session
3453
3453
  */
3454
- leave(data: Lazy<WorkbookData>): Promise<void>;
3454
+ leave(data?: Lazy<WorkbookData>): Promise<void>;
3455
3455
  /**
3456
3456
  * Send a snapshot of the spreadsheet to the collaboration server
3457
3457
  */
@@ -3703,7 +3703,6 @@ declare class EvaluationDataValidationPlugin extends UIPlugin {
3703
3703
  static getters: readonly ["getDataValidationInvalidCriterionValueMessage", "getInvalidDataValidationMessage", "getValidationResultForCellValue", "isCellValidCheckbox", "isDataValidationInvalid"];
3704
3704
  validationResults: Record<UID, SheetValidationResult>;
3705
3705
  handle(cmd: CoreViewCommand): void;
3706
- private setContentToBooleanCells;
3707
3706
  isDataValidationInvalid(cellPosition: CellPosition): boolean;
3708
3707
  getInvalidDataValidationMessage(cellPosition: CellPosition): string | undefined;
3709
3708
  /**
@@ -5932,6 +5931,7 @@ interface ColorPickerProps {
5932
5931
  maxHeight?: Pixel;
5933
5932
  onColorPicked: (color: Color) => void;
5934
5933
  currentColor: Color;
5934
+ disableNoColor?: boolean;
5935
5935
  }
5936
5936
  declare class ColorPicker extends Component<ColorPickerProps, SpreadsheetChildEnv> {
5937
5937
  static template: string;
@@ -5946,6 +5946,10 @@ declare class ColorPicker extends Component<ColorPickerProps, SpreadsheetChildEn
5946
5946
  optional: boolean;
5947
5947
  };
5948
5948
  anchorRect: ObjectConstructor;
5949
+ disableNoColor: {
5950
+ type: BooleanConstructor;
5951
+ optional: boolean;
5952
+ };
5949
5953
  };
5950
5954
  static defaultProps: {
5951
5955
  currentColor: string;
@@ -5986,6 +5990,7 @@ interface Props$I {
5986
5990
  disabled?: boolean;
5987
5991
  dropdownMaxHeight?: Pixel;
5988
5992
  class?: string;
5993
+ disableNoColor?: boolean;
5989
5994
  }
5990
5995
  declare class ColorPickerWidget extends Component<Props$I, SpreadsheetChildEnv> {
5991
5996
  static template: string;
@@ -6014,6 +6019,10 @@ declare class ColorPickerWidget extends Component<Props$I, SpreadsheetChildEnv>
6014
6019
  type: StringConstructor;
6015
6020
  optional: boolean;
6016
6021
  };
6022
+ disableNoColor: {
6023
+ type: BooleanConstructor;
6024
+ optional: boolean;
6025
+ };
6017
6026
  };
6018
6027
  static components: {
6019
6028
  ColorPicker: typeof ColorPicker;
@@ -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.2.25
7
- * @date 2024-11-08T12:13:19.966Z
8
- * @hash 40d42f8
6
+ * @version 17.2.27
7
+ * @date 2024-11-22T14:17:16.936Z
8
+ * @hash 139e5a3
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 } from '@odoo/owl';
@@ -2931,7 +2931,9 @@ function linearSearch(data, target, mode, numberOfValues, getValueInData, revers
2931
2931
  return reverseSearch ? numberOfValues - i - 1 : i;
2932
2932
  }
2933
2933
  }
2934
- return reverseSearch ? numberOfValues - closestMatchIndex - 1 : closestMatchIndex;
2934
+ return reverseSearch && closestMatchIndex !== -1
2935
+ ? numberOfValues - closestMatchIndex - 1
2936
+ : closestMatchIndex;
2935
2937
  }
2936
2938
  /**
2937
2939
  * Normalize a value.
@@ -19693,11 +19695,14 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
19693
19695
  function getChartLabelFormat(getters, range) {
19694
19696
  if (!range)
19695
19697
  return undefined;
19696
- return getters.getEvaluatedCell({
19697
- sheetId: range.sheetId,
19698
- col: range.zone.left,
19699
- row: range.zone.top,
19700
- }).format;
19698
+ const { sheetId, zone: { left, top, bottom }, } = range;
19699
+ for (let row = top; row <= bottom; row++) {
19700
+ const format = getters.getEvaluatedCell({ sheetId, col: left, row }).format;
19701
+ if (format) {
19702
+ return format;
19703
+ }
19704
+ }
19705
+ return undefined;
19701
19706
  }
19702
19707
  function getChartLabelValues(getters, dataSets, labelRange) {
19703
19708
  let labels = { values: [], formattedValues: [] };
@@ -20413,11 +20418,7 @@ function canBeDateChart(labelRange, getters) {
20413
20418
  if (!labelRange || !canBeLinearChart(labelRange, getters)) {
20414
20419
  return false;
20415
20420
  }
20416
- const labelFormat = getters.getEvaluatedCell({
20417
- sheetId: labelRange.sheetId,
20418
- col: labelRange.zone.left,
20419
- row: labelRange.zone.top,
20420
- }).format;
20421
+ const labelFormat = getChartLabelFormat(getters, labelRange);
20421
20422
  return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
20422
20423
  }
20423
20424
  function canBeLinearChart(labelRange, getters) {
@@ -27216,6 +27217,7 @@ class ColorPicker extends Component {
27216
27217
  currentColor: { type: String, optional: true },
27217
27218
  maxHeight: { type: Number, optional: true },
27218
27219
  anchorRect: Object,
27220
+ disableNoColor: { type: Boolean, optional: true },
27219
27221
  };
27220
27222
  static defaultProps = { currentColor: "" };
27221
27223
  static components = { Popover };
@@ -27399,6 +27401,7 @@ class ColorPickerWidget extends Component {
27399
27401
  disabled: { type: Boolean, optional: true },
27400
27402
  dropdownMaxHeight: { type: Number, optional: true },
27401
27403
  class: { type: String, optional: true },
27404
+ disableNoColor: { type: Boolean, optional: true },
27402
27405
  };
27403
27406
  static components = { ColorPicker };
27404
27407
  colorPickerButtonRef = useRef("colorPickerButton");
@@ -28957,6 +28960,9 @@ class ConditionalFormattingEditor extends Component {
28957
28960
  }
28958
28961
  }
28959
28962
  setColorScaleColor(target, color) {
28963
+ if (!isColorValid(color)) {
28964
+ return;
28965
+ }
28960
28966
  const point = this.state.rules.colorScale[target];
28961
28967
  if (point) {
28962
28968
  point.color = Number.parseInt(color.substr(1), 16);
@@ -47825,12 +47831,18 @@ class Evaluator {
47825
47831
  }
47826
47832
  for (let i = 0; i < positions.length; ++i) {
47827
47833
  const position = positions[i];
47834
+ if (this.nextPositionsToUpdate.has(position)) {
47835
+ continue;
47836
+ }
47828
47837
  const evaluatedCell = this.computeCell(position);
47829
47838
  if (evaluatedCell !== EMPTY_CELL) {
47830
47839
  this.evaluatedCells.set(position, evaluatedCell);
47831
47840
  }
47832
47841
  }
47833
47842
  }
47843
+ if (currentIteration >= MAX_ITERATION) {
47844
+ console.warn("Maximum iteration reached while evaluating cells");
47845
+ }
47834
47846
  }
47835
47847
  computeCell(position) {
47836
47848
  const evaluation = this.evaluatedCells.get(position);
@@ -47862,7 +47874,6 @@ class Evaluator {
47862
47874
  }
47863
47875
  finally {
47864
47876
  this.cellsBeingComputed.delete(cellId);
47865
- this.nextPositionsToUpdate.delete(position);
47866
47877
  }
47867
47878
  }
47868
47879
  computeAndSave(position) {
@@ -47912,6 +47923,7 @@ class Evaluator {
47912
47923
  { sheetId, zone: rightPartZone },
47913
47924
  { sheetId, zone: leftColumnZone },
47914
47925
  ]);
47926
+ invalidatedPositions.delete(arrayFormulaPosition);
47915
47927
  this.nextPositionsToUpdate.addMany(invalidatedPositions);
47916
47928
  }
47917
47929
  assertSheetHasEnoughSpaceToSpreadFormulaResult({ sheetId, col, row }, matrixResult) {
@@ -48956,25 +48968,11 @@ class EvaluationDataValidationPlugin extends UIPlugin {
48956
48968
  }
48957
48969
  switch (cmd.type) {
48958
48970
  case "ADD_DATA_VALIDATION_RULE":
48959
- const ranges = cmd.ranges.map((range) => this.getters.getRangeFromRangeData(range));
48960
- if (cmd.rule.criterion.type === "isBoolean") {
48961
- this.setContentToBooleanCells({ ...cmd.rule, ranges });
48962
- }
48963
- delete this.validationResults[cmd.sheetId];
48964
- break;
48965
48971
  case "REMOVE_DATA_VALIDATION_RULE":
48966
48972
  delete this.validationResults[cmd.sheetId];
48967
48973
  break;
48968
48974
  }
48969
48975
  }
48970
- setContentToBooleanCells(rule) {
48971
- for (const position of getCellPositionsInRanges(rule.ranges)) {
48972
- const evaluatedCell = this.getters.getEvaluatedCell(position);
48973
- if (evaluatedCell.type !== CellValueType.boolean) {
48974
- this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
48975
- }
48976
- }
48977
- }
48978
48976
  isDataValidationInvalid(cellPosition) {
48979
48977
  return !this.getValidationResultForCell(cellPosition).isValid;
48980
48978
  }
@@ -50446,7 +50444,7 @@ class Session extends EventBus {
50446
50444
  * Notify the server that the user client left the collaborative session
50447
50445
  */
50448
50446
  async leave(data) {
50449
- if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
50447
+ if (data && Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
50450
50448
  await this.snapshot(data());
50451
50449
  }
50452
50450
  delete this.clients[this.clientId];
@@ -51552,6 +51550,42 @@ class SheetUIPlugin extends UIPlugin {
51552
51550
  }
51553
51551
  }
51554
51552
 
51553
+ class DataValidationInsertionPlugin extends UIPlugin {
51554
+ handle(cmd) {
51555
+ switch (cmd.type) {
51556
+ case "ADD_DATA_VALIDATION_RULE":
51557
+ if (cmd.rule.criterion.type === "isBoolean") {
51558
+ const ranges = cmd.ranges.map((range) => this.getters.getRangeFromRangeData(range));
51559
+ for (const position of getCellPositionsInRanges(ranges)) {
51560
+ const cell = this.getters.getCell(position);
51561
+ const evaluatedCell = this.getters.getEvaluatedCell(position);
51562
+ if (!cell?.content) {
51563
+ this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
51564
+ // In this case, a cell has been updated in the core plugin but
51565
+ // not yet evaluated. This can occur after a paste operation.
51566
+ }
51567
+ else if (cell?.content && evaluatedCell.type === CellValueType.empty) {
51568
+ let value;
51569
+ if (cell.content.startsWith("=")) {
51570
+ const result = this.getters.evaluateFormula(position.sheetId, cell.content);
51571
+ value = (isMatrix(result) ? result[0][0] : result)?.toString();
51572
+ }
51573
+ else {
51574
+ value = cell.content;
51575
+ }
51576
+ if (!value || !isBoolean(value)) {
51577
+ this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
51578
+ }
51579
+ }
51580
+ else if (evaluatedCell.type !== CellValueType.boolean) {
51581
+ this.dispatch("UPDATE_CELL", { ...position, content: "FALSE" });
51582
+ }
51583
+ }
51584
+ }
51585
+ }
51586
+ }
51587
+ }
51588
+
51555
51589
  const genericRepeatsTransforms = [
51556
51590
  repeatSheetDependantCommand,
51557
51591
  repeatTargetDependantCommand,
@@ -54785,7 +54819,8 @@ const featurePluginRegistry = new Registry()
54785
54819
  .add("collaborative", CollaborativePlugin)
54786
54820
  .add("history", HistoryPlugin)
54787
54821
  .add("data_cleanup", DataCleanupPlugin)
54788
- .add("table_autofill", TableAutofillPlugin);
54822
+ .add("table_autofill", TableAutofillPlugin)
54823
+ .add("datavalidation_insert", DataValidationInsertionPlugin);
54789
54824
  // Plugins which have a state, but which should not be shared in collaborative
54790
54825
  const statefulUIPluginRegistry = new Registry()
54791
54826
  .add("selection", GridSelectionPlugin)
@@ -60413,7 +60448,8 @@ class Model extends EventBus {
60413
60448
  this.session.join(this.config.client);
60414
60449
  }
60415
60450
  async leaveSession() {
60416
- await this.session.leave(lazy(() => this.exportData()));
60451
+ const snapshot = this.getters.isReadonly() ? undefined : lazy(() => this.exportData());
60452
+ await this.session.leave(snapshot);
60417
60453
  }
60418
60454
  setupUiPlugin(Plugin) {
60419
60455
  const plugin = new Plugin(this.uiPluginConfig);
@@ -60926,6 +60962,6 @@ const constants = {
60926
60962
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, 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 };
60927
60963
 
60928
60964
 
60929
- __info__.version = "17.2.25";
60930
- __info__.date = "2024-11-08T12:13:19.966Z";
60931
- __info__.hash = "40d42f8";
60965
+ __info__.version = "17.2.27";
60966
+ __info__.date = "2024-11-22T14:17:16.936Z";
60967
+ __info__.hash = "139e5a3";