@odoo/o-spreadsheet 17.3.2 → 17.3.4

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.2
7
- * @date 2024-06-10T09:38:56.657Z
8
- * @hash c3b358f
6
+ * @version 17.3.4
7
+ * @date 2024-06-21T20:00:08.515Z
8
+ * @hash 6efbf3b
9
9
  */
10
10
 
11
11
  'use strict';
@@ -2781,7 +2781,7 @@ function evaluatePredicate(value, criterion) {
2781
2781
  return false;
2782
2782
  }
2783
2783
  if (typeof operand === "number" && operator === "=") {
2784
- return toString(value) === toString(operand);
2784
+ return value.toString() === operand.toString();
2785
2785
  }
2786
2786
  if (operator === "<>" || operator === "=") {
2787
2787
  let result;
@@ -2841,14 +2841,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2841
2841
  if (countArg % 2 === 1) {
2842
2842
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2843
2843
  }
2844
- const dimRow = args[0].length;
2845
- const dimCol = args[0][0].length;
2844
+ const firstArg = toMatrix(args[0]);
2845
+ const dimRow = firstArg.length;
2846
+ const dimCol = firstArg[0].length;
2846
2847
  let predicates = [];
2847
2848
  for (let i = 0; i < countArg - 1; i += 2) {
2848
- const criteriaRange = args[i];
2849
- if (!isMatrix(criteriaRange) ||
2850
- criteriaRange.length !== dimRow ||
2851
- criteriaRange[0].length !== dimCol) {
2849
+ const criteriaRange = toMatrix(args[i]);
2850
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2852
2851
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2853
2852
  }
2854
2853
  const description = toString(args[i + 1]);
@@ -2862,7 +2861,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2862
2861
  for (let j = 0; j < dimCol; j++) {
2863
2862
  let validatedPredicates = true;
2864
2863
  for (let k = 0; k < countArg - 1; k += 2) {
2865
- const criteriaValue = args[k][i][j].value;
2864
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2866
2865
  const criterion = predicates[k / 2];
2867
2866
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2868
2867
  if (!validatedPredicates) {
@@ -9462,10 +9461,8 @@ class ComposerStore extends SpreadsheetStore {
9462
9461
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
9463
9462
  return isEqual(this.getters.expandZone(activeSheetId, refRange.zone), oldZone);
9464
9463
  });
9465
- // this function assumes that the previous range is always found because
9466
- // it's called when changing a highlight, which exists by definition
9467
9464
  if (!previousRefToken) {
9468
- throw new Error("Previous range not found");
9465
+ return;
9469
9466
  }
9470
9467
  const previousRange = this.getters.getRangeFromSheetXC(activeSheetId, previousRefToken.value);
9471
9468
  this.selectionStart = previousRefToken.start;
@@ -10990,6 +10987,9 @@ function makeArg(str, description) {
10990
10987
  if (types.some((t) => t.startsWith("RANGE"))) {
10991
10988
  result.acceptMatrix = true;
10992
10989
  }
10990
+ if (types.every((t) => t.startsWith("RANGE"))) {
10991
+ result.acceptMatrixOnly = true;
10992
+ }
10993
10993
  return result;
10994
10994
  }
10995
10995
  /**
@@ -11271,11 +11271,16 @@ const CHOOSECOLS = {
11271
11271
  compute: function (array, ...columns) {
11272
11272
  const _array = toMatrix(array);
11273
11273
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11274
- 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(",")));
11275
11276
  const result = Array(_columns.length);
11276
11277
  for (let col = 0; col < _columns.length; col++) {
11277
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11278
- 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
+ }
11279
11284
  }
11280
11285
  return result;
11281
11286
  },
@@ -11296,8 +11301,14 @@ const CHOOSEROWS = {
11296
11301
  const _array = toMatrix(array);
11297
11302
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11298
11303
  const _nbColumns = _array.length;
11299
- 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()));
11300
- 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
+ });
11301
11312
  },
11302
11313
  isExported: true,
11303
11314
  };
@@ -19764,6 +19775,9 @@ function addInputHandling(descr) {
19764
19775
  }
19765
19776
  args[i] = arg[0][0];
19766
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
+ }
19767
19781
  }
19768
19782
  return descr.compute.apply(this, args);
19769
19783
  }
@@ -21358,12 +21372,6 @@ function compileTokens(tokens) {
21358
21372
  // detect when an argument need to be evaluated as a meta argument
21359
21373
  const isMeta = argTypes.includes("META");
21360
21374
  const hasRange = argTypes.some((t) => isRangeType(t));
21361
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
21362
- if (isRangeOnly) {
21363
- if (!isRangeInput(currentArg)) {
21364
- 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 }));
21365
- }
21366
- }
21367
21375
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
21368
21376
  }
21369
21377
  return compiledArgs;
@@ -21528,16 +21536,6 @@ function assertEnoughArgs(ast) {
21528
21536
  function isRangeType(type) {
21529
21537
  return type.startsWith("RANGE");
21530
21538
  }
21531
- function isRangeInput(arg) {
21532
- if (arg.type === "REFERENCE") {
21533
- return true;
21534
- }
21535
- if (arg.type === "FUNCALL") {
21536
- const fnDef = functions$1[arg.value.toUpperCase()];
21537
- return fnDef && isRangeType(fnDef.returns[0]);
21538
- }
21539
- return false;
21540
- }
21541
21539
 
21542
21540
  const functions = functionRegistry.content;
21543
21541
  function isExportableToExcel(tokens) {
@@ -21966,7 +21964,9 @@ autoCompleteProviders.add("pivot_group_values", {
21966
21964
  if (!groupByField) {
21967
21965
  return;
21968
21966
  }
21969
- return dataSource.getPossibleFieldValues(groupByField.split(":")[0]).map(({ value, label }) => {
21967
+ return dataSource
21968
+ .getPossibleFieldValues(groupByField.toString().split(":")[0])
21969
+ .map(({ value, label }) => {
21970
21970
  const isString = typeof value === "string";
21971
21971
  const text = isString ? `"${value}"` : value.toString();
21972
21972
  const color = isString ? tokenColors.STRING : tokenColors.NUMBER;
@@ -25452,7 +25452,7 @@ class Popover extends owl.Component {
25452
25452
  if (!anchor)
25453
25453
  return;
25454
25454
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
25455
- const elDims = {
25455
+ let elDims = {
25456
25456
  width: el.getBoundingClientRect().width,
25457
25457
  height: el.getBoundingClientRect().height,
25458
25458
  };
@@ -25460,7 +25460,14 @@ class Popover extends owl.Component {
25460
25460
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
25461
25461
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
25462
25462
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
25463
- 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);
25464
25471
  for (const property of Object.keys(style)) {
25465
25472
  el.style[property] = style[property];
25466
25473
  }
@@ -25523,8 +25530,6 @@ class PopoverPositionContext {
25523
25530
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
25524
25531
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
25525
25532
  const cssProperties = {
25526
- "max-height": maxHeight + "px",
25527
- "max-width": maxWidth + "px",
25528
25533
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
25529
25534
  this.spreadsheetOffset.y -
25530
25535
  verticalOffset +
@@ -31338,10 +31343,8 @@ class ChartTitle extends owl.Component {
31338
31343
 
31339
31344
  class AxisDesignEditor extends owl.Component {
31340
31345
  static template = "o-spreadsheet-AxisDesignEditor";
31341
- static components = {
31342
- Section,
31343
- ChartTitle,
31344
- };
31346
+ static components = { Section, ChartTitle };
31347
+ static props = { figureId: String, definition: Object, updateChart: Function, axesList: Array };
31345
31348
  state = owl.useState({ currentAxis: "x" });
31346
31349
  get axisTitleStyle() {
31347
31350
  const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
@@ -31492,6 +31495,12 @@ class ChartWithAxisDesignPanel extends owl.Component {
31492
31495
  AxisDesignEditor,
31493
31496
  RoundColorPicker,
31494
31497
  };
31498
+ static props = {
31499
+ figureId: String,
31500
+ definition: Object,
31501
+ canUpdateChart: Function,
31502
+ updateChart: Function,
31503
+ };
31495
31504
  state = owl.useState({ index: 0 });
31496
31505
  get axesList() {
31497
31506
  const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
@@ -31673,14 +31682,6 @@ class GaugeChartDesignPanel extends owl.Component {
31673
31682
  const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
31674
31683
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
31675
31684
  }
31676
- updateBackgroundColor(color) {
31677
- this.props.updateChart(this.props.figureId, {
31678
- background: color,
31679
- });
31680
- }
31681
- updateTitle(content) {
31682
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31683
- }
31684
31685
  isRangeMinInvalid() {
31685
31686
  return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
31686
31687
  this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */) ||
@@ -31720,9 +31721,6 @@ class GaugeChartDesignPanel extends owl.Component {
31720
31721
  sectionRule,
31721
31722
  });
31722
31723
  }
31723
- get backgroundColorTitle() {
31724
- return ChartTerms.BackgroundColor;
31725
- }
31726
31724
  }
31727
31725
 
31728
31726
  class LineConfigPanel extends GenericChartConfigPanel {
@@ -31905,9 +31903,6 @@ class ScorecardChartDesignPanel extends owl.Component {
31905
31903
  get humanizeNumbersLabel() {
31906
31904
  return _t("Humanize numbers");
31907
31905
  }
31908
- updateTitle(content) {
31909
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31910
- }
31911
31906
  updateHumanizeNumbers(humanize) {
31912
31907
  this.props.updateChart(this.props.figureId, { humanize });
31913
31908
  }
@@ -31930,9 +31925,6 @@ class ScorecardChartDesignPanel extends owl.Component {
31930
31925
  break;
31931
31926
  }
31932
31927
  }
31933
- get backgroundColorTitle() {
31934
- return ChartTerms.BackgroundColor;
31935
- }
31936
31928
  }
31937
31929
 
31938
31930
  class WaterfallChartDesignPanel extends owl.Component {
@@ -33433,13 +33425,17 @@ class SelectMenu extends owl.Component {
33433
33425
  class: { type: String, optional: true },
33434
33426
  };
33435
33427
  static components = { Menu };
33428
+ menuId = new UuidGenerator().uuidv4();
33436
33429
  selectRef = owl.useRef("select");
33437
33430
  selectRect = useAbsoluteBoundingRect(this.selectRef);
33438
33431
  state = owl.useState({
33439
33432
  isMenuOpen: false,
33440
33433
  });
33441
- onClick() {
33442
- this.state.isMenuOpen = true;
33434
+ onClick(ev) {
33435
+ if (ev.closedMenuId === this.menuId) {
33436
+ return;
33437
+ }
33438
+ this.state.isMenuOpen = !this.state.isMenuOpen;
33443
33439
  }
33444
33440
  onMenuClosed() {
33445
33441
  this.state.isMenuOpen = false;
@@ -33447,7 +33443,7 @@ class SelectMenu extends owl.Component {
33447
33443
  get menuPosition() {
33448
33444
  return {
33449
33445
  x: this.selectRect.x,
33450
- y: this.selectRect.y,
33446
+ y: this.selectRect.y + this.selectRect.height,
33451
33447
  };
33452
33448
  }
33453
33449
  }
@@ -34387,9 +34383,9 @@ class FindAndReplacePanel extends owl.Component {
34387
34383
  static props = {
34388
34384
  onCloseSidePanel: Function,
34389
34385
  };
34390
- dataRange = "";
34391
34386
  searchInput = owl.useRef("searchInput");
34392
34387
  store;
34388
+ state;
34393
34389
  get hasSearchResult() {
34394
34390
  return this.store.selectedMatchIndex !== null;
34395
34391
  }
@@ -34419,6 +34415,7 @@ class FindAndReplacePanel extends owl.Component {
34419
34415
  }
34420
34416
  setup() {
34421
34417
  this.store = useLocalStore(FindAndReplaceStore);
34418
+ this.state = owl.useState({ dataRange: "" });
34422
34419
  owl.onMounted(() => this.searchInput.el?.focus());
34423
34420
  }
34424
34421
  onFocusSearch() {
@@ -34455,13 +34452,13 @@ class FindAndReplacePanel extends owl.Component {
34455
34452
  this.store.updateSearchOptions({ searchScope });
34456
34453
  }
34457
34454
  onSearchRangeChanged(ranges) {
34458
- this.dataRange = ranges[0];
34455
+ this.state.dataRange = ranges[0];
34459
34456
  }
34460
34457
  updateDataRange() {
34461
- if (!this.dataRange || this.searchOptions.searchScope !== "specificRange") {
34458
+ if (!this.state.dataRange || this.searchOptions.searchScope !== "specificRange") {
34462
34459
  return;
34463
34460
  }
34464
- 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);
34465
34462
  this.store.updateSearchOptions({ specificRange });
34466
34463
  }
34467
34464
  }
@@ -34927,7 +34924,7 @@ function createMeasure(fields, measure) {
34927
34924
  function createPivotDimension(fields, dimension) {
34928
34925
  const field = fields[dimension.name];
34929
34926
  const type = field?.type ?? "integer";
34930
- const granularity = field && isDateField(field) ? dimension.granularity ?? "month_number" : undefined;
34927
+ const granularity = field && isDateField(field) ? dimension.granularity : undefined;
34931
34928
  return {
34932
34929
  /**
34933
34930
  * Get the display name of the dimension
@@ -35330,10 +35327,13 @@ function compareDimensionValues(dimension, a, b) {
35330
35327
  }
35331
35328
 
35332
35329
  function createDate(dimension, value, locale) {
35333
- const granularity = dimension.granularity || "month_number";
35334
- if (!(granularity in MAP_VALUE_DIMENSION_DATE)) {
35330
+ const granularity = dimension.granularity;
35331
+ if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
35335
35332
  throw new Error(`Unknown date granularity: ${granularity}`);
35336
35333
  }
35334
+ if (value === null) {
35335
+ return null;
35336
+ }
35337
35337
  if (!MAP_VALUE_DIMENSION_DATE[granularity].set.has(value)) {
35338
35338
  MAP_VALUE_DIMENSION_DATE[granularity].set.add(value);
35339
35339
  const date = toJsDate(value, locale);
@@ -35560,7 +35560,8 @@ class SpreadsheetPivot {
35560
35560
  if (!finalCell) {
35561
35561
  return { value: "" };
35562
35562
  }
35563
- if (finalCell.value === null) {
35563
+ // Value can be null but stringified (e.g. an empty date, as for now every date is stringified)
35564
+ if (finalCell.value === null || finalCell.value === `${null}`) {
35564
35565
  return { value: _t("(Undefined)") };
35565
35566
  }
35566
35567
  if (dimension.type === "date") {
@@ -35596,10 +35597,15 @@ class SpreadsheetPivot {
35596
35597
  if (!operator) {
35597
35598
  throw new Error(`Aggregator ${aggregator} does not exist`);
35598
35599
  }
35599
- return {
35600
- value: values.length ? operator.fn([values], this.getters.getLocale()) : "",
35601
- format: operator.format(values[0]),
35602
- };
35600
+ try {
35601
+ return {
35602
+ value: values.length ? operator.fn([values], this.getters.getLocale()) : "",
35603
+ format: operator.format(values[0]),
35604
+ };
35605
+ }
35606
+ catch (e) {
35607
+ return handleError(e, aggregator.toUpperCase());
35608
+ }
35603
35609
  }
35604
35610
  getPossibleFieldValues(groupBy) {
35605
35611
  //TODO This method should be implemented for the autocomplete feature
@@ -36132,6 +36138,7 @@ css /* scss */ `
36132
36138
  class RemoveDuplicatesPanel extends owl.Component {
36133
36139
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
36134
36140
  static components = { ValidationMessages, Section, Checkbox };
36141
+ static props = { onCloseSidePanel: Function };
36135
36142
  state = owl.useState({
36136
36143
  hasHeader: false,
36137
36144
  columns: {},
@@ -38556,7 +38563,7 @@ class FiguresContainer extends owl.Component {
38556
38563
  });
38557
38564
  }
38558
38565
  getContainerRect(container) {
38559
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
38566
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
38560
38567
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
38561
38568
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
38562
38569
  const width = viewWidth - x;
@@ -51161,22 +51168,6 @@ class PivotCorePlugin extends CorePlugin {
51161
51168
  this.addPivotFormula(cellPosition, formulaId, pivotCell);
51162
51169
  }
51163
51170
  }
51164
- const pivotZone = {
51165
- top: position.row,
51166
- bottom: position.row + pivotCells[0].length - 1,
51167
- left: position.col,
51168
- right: position.col + pivotCells.length - 1,
51169
- };
51170
- const numberOfHeaders = table.columns.length - 1;
51171
- const cmdContent = {
51172
- sheetId: position.sheetId,
51173
- ranges: [this.getters.getRangeDataFromZone(position.sheetId, pivotZone)],
51174
- config: { ...PIVOT_TABLE_CONFIG, numberOfHeaders },
51175
- tableType: "static",
51176
- };
51177
- if (this.canDispatch("CREATE_TABLE", cmdContent).isSuccessful) {
51178
- this.dispatch("CREATE_TABLE", cmdContent);
51179
- }
51180
51171
  }
51181
51172
  resizeSheet(sheetId, { col, row }, table) {
51182
51173
  const colLimit = table.getNumberOfDataColumns() + 1; // +1 for the Top-Left
@@ -52856,7 +52847,6 @@ class Evaluator {
52856
52847
  if (!this.blockedArrayFormulas.has(position)) {
52857
52848
  this.invalidateSpreading(position);
52858
52849
  }
52859
- this.spreadingRelations.removeNode(position);
52860
52850
  const cell = this.getters.getCell(position);
52861
52851
  if (cell === undefined) {
52862
52852
  return EMPTY_CELL;
@@ -52898,6 +52888,7 @@ class Evaluator {
52898
52888
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
52899
52889
  const nbColumns = formulaReturn.length;
52900
52890
  const nbRows = formulaReturn[0].length;
52891
+ this.spreadingRelations.removeNode(formulaPosition);
52901
52892
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
52902
52893
  this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
52903
52894
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
@@ -55902,7 +55893,10 @@ class Session extends EventBus {
55902
55893
  /**
55903
55894
  * Notify the server that the user client left the collaborative session
55904
55895
  */
55905
- leave() {
55896
+ leave(data) {
55897
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
55898
+ this.snapshot(data);
55899
+ }
55906
55900
  delete this.clients[this.clientId];
55907
55901
  this.transportService.leave(this.clientId);
55908
55902
  this.transportService.sendMessage({
@@ -55915,6 +55909,9 @@ class Session extends EventBus {
55915
55909
  * Send a snapshot of the spreadsheet to the collaboration server
55916
55910
  */
55917
55911
  snapshot(data) {
55912
+ if (this.pendingMessages.length !== 0) {
55913
+ return;
55914
+ }
55918
55915
  const snapshotId = this.uuidGenerator.uuidv4();
55919
55916
  this.transportService.sendMessage({
55920
55917
  type: "SNAPSHOT",
@@ -66402,7 +66399,7 @@ class Model extends EventBus {
66402
66399
  this.session.join(this.config.client);
66403
66400
  }
66404
66401
  leaveSession() {
66405
- this.session.leave();
66402
+ this.session.leave(this.exportData());
66406
66403
  }
66407
66404
  setupUiPlugin(Plugin) {
66408
66405
  const plugin = new Plugin(this.uiPluginConfig);
@@ -66993,6 +66990,6 @@ exports.tokenColors = tokenColors;
66993
66990
  exports.tokenize = tokenize;
66994
66991
 
66995
66992
 
66996
- __info__.version = "17.3.2";
66997
- __info__.date = "2024-06-10T09:38:56.657Z";
66998
- __info__.hash = "c3b358f";
66993
+ __info__.version = "17.3.4";
66994
+ __info__.date = "2024-06-21T20:00:08.515Z";
66995
+ __info__.hash = "6efbf3b";
@@ -3800,7 +3800,7 @@ declare class Session extends EventBus<CollaborativeEvent> {
3800
3800
  /**
3801
3801
  * Notify the server that the user client left the collaborative session
3802
3802
  */
3803
- leave(): void;
3803
+ leave(data: WorkbookData): void;
3804
3804
  /**
3805
3805
  * Send a snapshot of the spreadsheet to the collaboration server
3806
3806
  */
@@ -5144,6 +5144,7 @@ type Getters = {
5144
5144
  type ArgType = "ANY" | "BOOLEAN" | "NUMBER" | "STRING" | "DATE" | "RANGE" | "RANGE<BOOLEAN>" | "RANGE<NUMBER>" | "RANGE<DATE>" | "RANGE<STRING>" | "RANGE<ANY>" | "META";
5145
5145
  interface ArgDefinition {
5146
5146
  acceptMatrix?: boolean;
5147
+ acceptMatrixOnly?: boolean;
5147
5148
  repeating?: boolean;
5148
5149
  optional?: boolean;
5149
5150
  description: string;
@@ -6986,6 +6987,12 @@ declare class AxisDesignEditor extends Component<Props$O, SpreadsheetChildEnv> {
6986
6987
  Section: typeof Section;
6987
6988
  ChartTitle: typeof ChartTitle;
6988
6989
  };
6990
+ static props: {
6991
+ figureId: StringConstructor;
6992
+ definition: ObjectConstructor;
6993
+ updateChart: FunctionConstructor;
6994
+ axesList: ArrayConstructor;
6995
+ };
6989
6996
  state: {
6990
6997
  currentAxis: string;
6991
6998
  };
@@ -7049,6 +7056,12 @@ declare class ChartWithAxisDesignPanel extends Component<Props$M, SpreadsheetChi
7049
7056
  AxisDesignEditor: typeof AxisDesignEditor;
7050
7057
  RoundColorPicker: typeof RoundColorPicker;
7051
7058
  };
7059
+ static props: {
7060
+ figureId: StringConstructor;
7061
+ definition: ObjectConstructor;
7062
+ canUpdateChart: FunctionConstructor;
7063
+ updateChart: FunctionConstructor;
7064
+ };
7052
7065
  private state;
7053
7066
  get axesList(): AxisDefinition[];
7054
7067
  updateLegendPosition(ev: any): void;
@@ -7120,8 +7133,6 @@ declare class GaugeChartDesignPanel extends Component<Props$K, SpreadsheetChildE
7120
7133
  protected state: PanelState;
7121
7134
  setup(): void;
7122
7135
  get designErrorMessages(): string[];
7123
- updateBackgroundColor(color: Color): void;
7124
- updateTitle(content: string): void;
7125
7136
  isRangeMinInvalid(): boolean;
7126
7137
  isRangeMaxInvalid(): boolean;
7127
7138
  get isLowerInflectionPointInvalid(): boolean;
@@ -7129,7 +7140,6 @@ declare class GaugeChartDesignPanel extends Component<Props$K, SpreadsheetChildE
7129
7140
  updateSectionColor(target: string, color: Color): void;
7130
7141
  updateSectionRule(sectionRule: SectionRule): void;
7131
7142
  canUpdateSectionRule(sectionRule: SectionRule): void;
7132
- get backgroundColorTitle(): string;
7133
7143
  }
7134
7144
 
7135
7145
  declare class LineConfigPanel extends GenericChartConfigPanel {
@@ -7210,12 +7220,10 @@ declare class ScorecardChartDesignPanel extends Component<Props$I, SpreadsheetCh
7210
7220
  };
7211
7221
  get colorsSectionTitle(): string;
7212
7222
  get humanizeNumbersLabel(): string;
7213
- updateTitle(content: string): void;
7214
7223
  updateHumanizeNumbers(humanize: boolean): void;
7215
7224
  translate(term: any): string;
7216
7225
  updateBaselineDescr(ev: any): void;
7217
7226
  setColor(color: Color, colorPickerId: ColorPickerId): void;
7218
- get backgroundColorTitle(): string;
7219
7227
  }
7220
7228
 
7221
7229
  interface ChartSidePanel {