@odoo/o-spreadsheet 17.0.48 → 17.0.50

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 17.0.48
6
- * @date 2025-02-05T07:18:39.331Z
7
- * @hash aea9101
5
+ * @version 17.0.50
6
+ * @date 2025-02-14T08:37:34.289Z
7
+ * @hash cc1037d
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -686,9 +686,16 @@ function deepEquals(o1, o2) {
686
686
  }
687
687
  return true;
688
688
  }
689
- /** Check if the given array contains all the values of the other array. */
689
+ /**
690
+ * Check if the given array contains all the values of the other array.
691
+ * It makes the assumption that both array do not contain duplicates.
692
+ */
690
693
  function includesAll(arr, values) {
691
- return values.every((value) => arr.includes(value));
694
+ if (arr.length < values.length) {
695
+ return false;
696
+ }
697
+ const set = new Set(arr);
698
+ return values.every((value) => set.has(value));
692
699
  }
693
700
  /**
694
701
  * Return an object with all the keys in the object that have a falsy value removed.
@@ -1901,12 +1908,12 @@ function isTargetDependent(cmd) {
1901
1908
  function isRangeDependant(cmd) {
1902
1909
  return "ranges" in cmd;
1903
1910
  }
1904
- function isZoneDependent(cmd) {
1905
- return "zone" in cmd;
1906
- }
1907
1911
  function isPositionDependent(cmd) {
1908
1912
  return "col" in cmd && "row" in cmd && "sheetId" in cmd;
1909
1913
  }
1914
+ function isZoneDependent(cmd) {
1915
+ return "sheetId" in cmd && "zone" in cmd;
1916
+ }
1910
1917
  const invalidateEvaluationCommands = new Set([
1911
1918
  "RENAME_SHEET",
1912
1919
  "DELETE_SHEET",
@@ -1916,6 +1923,7 @@ const invalidateEvaluationCommands = new Set([
1916
1923
  "UNDO",
1917
1924
  "REDO",
1918
1925
  "ADD_MERGE",
1926
+ "DUPLICATE_SHEET",
1919
1927
  "UPDATE_LOCALE",
1920
1928
  ]);
1921
1929
  const invalidateDependenciesCommands = new Set([
@@ -1924,7 +1932,6 @@ const invalidateDependenciesCommands = new Set([
1924
1932
  ]);
1925
1933
  const invalidateCFEvaluationCommands = new Set([
1926
1934
  ...invalidateEvaluationCommands,
1927
- "DUPLICATE_SHEET",
1928
1935
  "EVALUATE_CELLS",
1929
1936
  "ADD_CONDITIONAL_FORMAT",
1930
1937
  "REMOVE_CONDITIONAL_FORMAT",
@@ -2084,6 +2091,7 @@ var CommandResult;
2084
2091
  CommandResult["InvalidRange"] = "InvalidRange";
2085
2092
  CommandResult["InvalidZones"] = "InvalidZones";
2086
2093
  CommandResult["InvalidSheetId"] = "InvalidSheetId";
2094
+ CommandResult["InvalidCellId"] = "InvalidCellId";
2087
2095
  CommandResult["InvalidFigureId"] = "InvalidFigureId";
2088
2096
  CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
2089
2097
  CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
@@ -3664,17 +3672,20 @@ function toZoneWithoutBoundaryChanges(xc) {
3664
3672
  */
3665
3673
  function toUnboundedZone(xc) {
3666
3674
  const zone = toZoneWithoutBoundaryChanges(xc);
3675
+ reorderZone(zone);
3676
+ return zone;
3677
+ }
3678
+ function reorderZone(zone) {
3667
3679
  if (zone.right !== undefined && zone.right < zone.left) {
3668
- const tmp = zone.left;
3680
+ const right = zone.left;
3669
3681
  zone.left = zone.right;
3670
- zone.right = tmp;
3682
+ zone.right = right;
3671
3683
  }
3672
3684
  if (zone.bottom !== undefined && zone.bottom < zone.top) {
3673
- const tmp = zone.top;
3685
+ const bottom = zone.top;
3674
3686
  zone.top = zone.bottom;
3675
- zone.bottom = tmp;
3687
+ zone.bottom = bottom;
3676
3688
  }
3677
- return zone;
3678
3689
  }
3679
3690
  /**
3680
3691
  * Convert from a cartesian reference to a Zone.
@@ -4707,6 +4718,37 @@ class UuidGenerator {
4707
4718
  setIsFastStrategy(isFast) {
4708
4719
  this.isFastIdStrategy = isFast;
4709
4720
  }
4721
+ /**
4722
+ * Generates a custom UUID using a simple 26^8 method (8-character alphanumeric string with lowercase letters)
4723
+ * This has a higher chance of collision than a UUIDv4, but not only faster to generate than an UUIDV4,
4724
+ * it also has a smaller size, which is preferable to alleviate the overall data size.
4725
+ *
4726
+ * This method is preferable when generating uuids for the core data (sheetId, figureId, etc)
4727
+ * as they will appear several times in the revisions and local history.
4728
+ *
4729
+ */
4730
+ smallUuid() {
4731
+ if (this.isFastIdStrategy) {
4732
+ this.fastIdStart++;
4733
+ return String(this.fastIdStart);
4734
+ //@ts-ignore
4735
+ }
4736
+ else if (window.crypto && window.crypto.getRandomValues) {
4737
+ //@ts-ignore
4738
+ return ([1e7] + -1e3).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
4739
+ }
4740
+ else {
4741
+ // mainly for jest and other browsers that do not have the crypto functionality
4742
+ return "xxxxxxxx-xxxx".replace(/[xy]/g, function (c) {
4743
+ var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
4744
+ return v.toString(16);
4745
+ });
4746
+ }
4747
+ }
4748
+ /**
4749
+ * Generates an UUIDV4, has astronomically low chance of collision, but is larger in size than the smallUuid.
4750
+ * This method should be used when you need to avoid collisions at all costs, like the id of a revision.
4751
+ */
4710
4752
  uuidv4() {
4711
4753
  if (this.isFastIdStrategy) {
4712
4754
  this.fastIdStart++;
@@ -4720,7 +4762,7 @@ class UuidGenerator {
4720
4762
  else {
4721
4763
  // mainly for jest and other browsers that do not have the crypto functionality
4722
4764
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
4723
- var r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
4765
+ var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
4724
4766
  return v.toString(16);
4725
4767
  });
4726
4768
  }
@@ -7933,7 +7975,7 @@ const linkSheet = {
7933
7975
  const deleteSheet = {
7934
7976
  name: _t("Delete"),
7935
7977
  isVisible: (env) => {
7936
- return env.model.getters.getSheetIds().length > 1;
7978
+ return env.model.getters.getVisibleSheetIds().length > 1;
7937
7979
  },
7938
7980
  execute: (env) => env.askConfirmation(_t("Are you sure you want to delete this sheet?"), () => {
7939
7981
  env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
@@ -7943,7 +7985,7 @@ const duplicateSheet = {
7943
7985
  name: _t("Duplicate"),
7944
7986
  execute: (env) => {
7945
7987
  const sheetIdFrom = env.model.getters.getActiveSheetId();
7946
- const sheetIdTo = env.model.uuidGenerator.uuidv4();
7988
+ const sheetIdTo = env.model.uuidGenerator.smallUuid();
7947
7989
  env.model.dispatch("DUPLICATE_SHEET", {
7948
7990
  sheetId: sheetIdFrom,
7949
7991
  sheetIdTo,
@@ -8493,17 +8535,15 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
8493
8535
  plugins: [],
8494
8536
  };
8495
8537
  }
8496
- function getChartLabelFormat(getters, range) {
8538
+ function getChartLabelFormat(getters, range, shouldRemoveFirstLabel) {
8497
8539
  if (!range)
8498
8540
  return undefined;
8499
- const { sheetId, zone: { left, top, bottom }, } = range;
8500
- for (let row = top; row <= bottom; row++) {
8501
- const format = getters.getEvaluatedCell({ sheetId, col: left, row }).format;
8502
- if (format) {
8503
- return format;
8504
- }
8541
+ const { sheetId, zone } = range;
8542
+ const formats = positions(zone).map((position) => getters.getEvaluatedCell({ sheetId, ...position }).format);
8543
+ if (shouldRemoveFirstLabel) {
8544
+ formats.shift();
8505
8545
  }
8506
- return undefined;
8546
+ return formats.find((format) => format !== undefined);
8507
8547
  }
8508
8548
  function getChartLabelValues(getters, dataSets, labelRange) {
8509
8549
  let labels = { values: [], formattedValues: [] };
@@ -8784,9 +8824,7 @@ function createBarChartRuntime(chart, getters) {
8784
8824
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
8785
8825
  let labels = labelValues.formattedValues;
8786
8826
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
8787
- if (chart.dataSetsHaveTitle &&
8788
- dataSetsValues[0] &&
8789
- labels.length > dataSetsValues[0].data.length) {
8827
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
8790
8828
  labels.shift();
8791
8829
  }
8792
8830
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -9330,8 +9368,8 @@ function fixEmptyLabelsForDateCharts(labels, dataSetsValues) {
9330
9368
  }
9331
9369
  return { labels: newLabels, dataSetsValues: newDatasets };
9332
9370
  }
9333
- function canChartParseLabels(labelRange, getters) {
9334
- return canBeDateChart(labelRange, getters) || canBeLinearChart(labelRange, getters);
9371
+ function canChartParseLabels(chart, getters) {
9372
+ return canBeDateChart(chart, getters) || canBeLinearChart(chart, getters);
9335
9373
  }
9336
9374
  function getChartAxisType(chart, getters) {
9337
9375
  if (isDateChart(chart, getters) && isLuxonTimeAdapterInstalled()) {
@@ -9343,23 +9381,26 @@ function getChartAxisType(chart, getters) {
9343
9381
  return "category";
9344
9382
  }
9345
9383
  function isDateChart(chart, getters) {
9346
- return !chart.labelsAsText && canBeDateChart(chart.labelRange, getters);
9384
+ return !chart.labelsAsText && canBeDateChart(chart, getters);
9347
9385
  }
9348
9386
  function isLinearChart(chart, getters) {
9349
- return !chart.labelsAsText && canBeLinearChart(chart.labelRange, getters);
9387
+ return !chart.labelsAsText && canBeLinearChart(chart, getters);
9350
9388
  }
9351
- function canBeDateChart(labelRange, getters) {
9352
- if (!labelRange || !canBeLinearChart(labelRange, getters)) {
9389
+ function canBeDateChart(chart, getters) {
9390
+ if (!chart.labelRange || !canBeLinearChart(chart, getters)) {
9353
9391
  return false;
9354
9392
  }
9355
- const labelFormat = getChartLabelFormat(getters, labelRange);
9393
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle));
9356
9394
  return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
9357
9395
  }
9358
- function canBeLinearChart(labelRange, getters) {
9359
- if (!labelRange) {
9396
+ function canBeLinearChart(chart, getters) {
9397
+ if (!chart.labelRange) {
9360
9398
  return false;
9361
9399
  }
9362
- const labels = getters.getRangeValues(labelRange);
9400
+ const labels = getters.getRangeValues(chart.labelRange);
9401
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
9402
+ labels.shift();
9403
+ }
9363
9404
  if (labels.some((label) => isNaN(Number(label)) && label)) {
9364
9405
  return false;
9365
9406
  }
@@ -9433,9 +9474,8 @@ function createLineChartRuntime(chart, getters) {
9433
9474
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
9434
9475
  let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
9435
9476
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
9436
- if (chart.dataSetsHaveTitle &&
9437
- dataSetsValues[0] &&
9438
- labels.length > dataSetsValues[0].data.length) {
9477
+ const removeFirstLabel = shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle);
9478
+ if (removeFirstLabel) {
9439
9479
  labels.shift();
9440
9480
  }
9441
9481
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -9450,7 +9490,7 @@ function createLineChartRuntime(chart, getters) {
9450
9490
  const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
9451
9491
  const options = { format: dataSetFormat, locale, truncateLabels };
9452
9492
  const config = getLineConfiguration(chart, labels, options);
9453
- const labelFormat = getChartLabelFormat(getters, chart.labelRange);
9493
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, removeFirstLabel);
9454
9494
  if (axisType === "time") {
9455
9495
  const axis = {
9456
9496
  type: "time",
@@ -9672,9 +9712,7 @@ function createPieChartRuntime(chart, getters) {
9672
9712
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
9673
9713
  let labels = labelValues.formattedValues;
9674
9714
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
9675
- if (chart.dataSetsHaveTitle &&
9676
- dataSetsValues[0] &&
9677
- labels.length > dataSetsValues[0].data.length) {
9715
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
9678
9716
  labels.shift();
9679
9717
  }
9680
9718
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -10195,21 +10233,22 @@ function getSmartChartDefinition(zone, getters) {
10195
10233
  }
10196
10234
  // Only display legend for several datasets.
10197
10235
  const newLegendPos = dataSetZone.right === dataSetZone.left ? "none" : "top";
10198
- const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
10199
- if (canChartParseLabels(labelRange, getters)) {
10200
- return {
10201
- title,
10202
- dataSets,
10203
- labelsAsText: false,
10204
- stacked: false,
10205
- aggregated: false,
10206
- cumulative: false,
10207
- labelRange: labelRangeXc,
10208
- type: "line",
10209
- dataSetsHaveTitle,
10210
- verticalAxisPosition: "left",
10211
- legendPosition: newLegendPos,
10212
- };
10236
+ const lineChartDefinition = {
10237
+ title,
10238
+ dataSets,
10239
+ labelsAsText: false,
10240
+ stacked: false,
10241
+ aggregated: false,
10242
+ cumulative: false,
10243
+ labelRange: labelRangeXc,
10244
+ type: "line",
10245
+ dataSetsHaveTitle,
10246
+ verticalAxisPosition: "left",
10247
+ legendPosition: newLegendPos,
10248
+ };
10249
+ const chart = new LineChart(lineChartDefinition, sheetId, getters);
10250
+ if (canChartParseLabels(chart, getters)) {
10251
+ return lineChartDefinition;
10213
10252
  }
10214
10253
  return {
10215
10254
  title,
@@ -10809,7 +10848,7 @@ const HIDE_ROWS_NAME = (env) => {
10809
10848
  //------------------------------------------------------------------------------
10810
10849
  const CREATE_CHART = (env) => {
10811
10850
  const getters = env.model.getters;
10812
- const id = env.model.uuidGenerator.uuidv4();
10851
+ const id = env.model.uuidGenerator.smallUuid();
10813
10852
  const sheetId = getters.getActiveSheetId();
10814
10853
  if (getZoneArea(env.model.getters.getSelectedZone()) === 1) {
10815
10854
  env.model.selection.selectTableAroundSelection();
@@ -10843,7 +10882,7 @@ async function requestImage(env) {
10843
10882
  const CREATE_IMAGE = async (env) => {
10844
10883
  if (env.imageProvider) {
10845
10884
  const sheetId = env.model.getters.getActiveSheetId();
10846
- const figureId = env.model.uuidGenerator.uuidv4();
10885
+ const figureId = env.model.uuidGenerator.smallUuid();
10847
10886
  const image = await requestImage(env);
10848
10887
  if (!image) {
10849
10888
  throw new Error("No image provider was given to the environment");
@@ -12564,6 +12603,26 @@ const LN = {
12564
12603
  isExported: true,
12565
12604
  };
12566
12605
  // -----------------------------------------------------------------------------
12606
+ // LOG
12607
+ // -----------------------------------------------------------------------------
12608
+ const LOG = {
12609
+ description: _t("The logarithm of a number, for a given base."),
12610
+ args: [
12611
+ arg("value (number)", _t("The value for which to calculate the logarithm.")),
12612
+ arg("base (number, default=10)", _t("The base of the logarithm.")),
12613
+ ],
12614
+ returns: ["NUMBER"],
12615
+ compute: function (value, base = 10) {
12616
+ const _value = toNumber(value, this.locale);
12617
+ const _base = toNumber(base, this.locale);
12618
+ assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
12619
+ assert(() => _base > 0, _t("The base (%s) must be strictly positive.", _base.toString()));
12620
+ assert(() => _base !== 1, _t("The base must be different from 1."));
12621
+ return Math.log10(_value) / Math.log10(_base);
12622
+ },
12623
+ isExported: true,
12624
+ };
12625
+ // -----------------------------------------------------------------------------
12567
12626
  // MOD
12568
12627
  // -----------------------------------------------------------------------------
12569
12628
  const MOD = {
@@ -13084,6 +13143,7 @@ var math = /*#__PURE__*/Object.freeze({
13084
13143
  ISODD: ISODD,
13085
13144
  ISO_CEILING: ISO_CEILING,
13086
13145
  LN: LN,
13146
+ LOG: LOG,
13087
13147
  MOD: MOD,
13088
13148
  MUNIT: MUNIT,
13089
13149
  ODD: ODD,
@@ -15945,7 +16005,7 @@ const SORTN = {
15945
16005
  }
15946
16006
  }
15947
16007
  },
15948
- isExported: true,
16008
+ isExported: false,
15949
16009
  };
15950
16010
  // -----------------------------------------------------------------------------
15951
16011
  // UNIQUE
@@ -19846,7 +19906,7 @@ const insertSheet = {
19846
19906
  execute: (env) => {
19847
19907
  const activeSheetId = env.model.getters.getActiveSheetId();
19848
19908
  const position = env.model.getters.getSheetIds().indexOf(activeSheetId) + 1;
19849
- const sheetId = env.model.uuidGenerator.uuidv4();
19909
+ const sheetId = env.model.uuidGenerator.smallUuid();
19850
19910
  env.model.dispatch("CREATE_SHEET", { sheetId, position });
19851
19911
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
19852
19912
  },
@@ -21522,7 +21582,7 @@ css /* scss */ `
21522
21582
  */
21523
21583
  class SelectionInput extends Component {
21524
21584
  static template = "o-spreadsheet-SelectionInput";
21525
- id = uuidGenerator$1.uuidv4();
21585
+ id = uuidGenerator$1.smallUuid();
21526
21586
  previousRanges = this.props.ranges() || [];
21527
21587
  originSheet = this.env.model.getters.getActiveSheetId();
21528
21588
  state = useState({
@@ -22572,7 +22632,7 @@ class LineConfigPanel extends LineBarPieConfigPanel {
22572
22632
  get canTreatLabelsAsText() {
22573
22633
  const chart = this.env.model.getters.getChart(this.props.figureId);
22574
22634
  if (chart && chart instanceof LineChart) {
22575
- return canChartParseLabels(chart.labelRange, this.env.model.getters);
22635
+ return canChartParseLabels(chart, this.env.model.getters);
22576
22636
  }
22577
22637
  return false;
22578
22638
  }
@@ -23600,7 +23660,7 @@ class ConditionalFormattingEditor extends Component {
23600
23660
  state;
23601
23661
  setup() {
23602
23662
  const cf = this.props.editedCf || {
23603
- id: this.env.model.uuidGenerator.uuidv4(),
23663
+ id: this.env.model.uuidGenerator.smallUuid(),
23604
23664
  ranges: this.env.model.getters
23605
23665
  .getSelectedZones()
23606
23666
  .map((zone) => this.env.model.getters.zoneToXC(this.env.model.getters.getActiveSheetId(), zone)),
@@ -25549,7 +25609,7 @@ class DataValidationEditor extends Component {
25549
25609
  .getSelectedZones()
25550
25610
  .map((zone) => zoneToXc(this.env.model.getters.getUnboundedZone(sheetId, zone)));
25551
25611
  return {
25552
- id: this.env.model.uuidGenerator.uuidv4(),
25612
+ id: this.env.model.uuidGenerator.smallUuid(),
25553
25613
  criterion: { type: "textContains", values: [""] },
25554
25614
  ranges,
25555
25615
  };
@@ -34169,7 +34229,7 @@ function forceUnicityOfFigure(data) {
34169
34229
  for (const sheet of data.sheets || []) {
34170
34230
  for (const figure of sheet.figures || []) {
34171
34231
  if (figureIds.has(figure.id)) {
34172
- figure.id += uuidGenerator.uuidv4();
34232
+ figure.id += uuidGenerator.smallUuid();
34173
34233
  }
34174
34234
  figureIds.add(figure.id);
34175
34235
  }
@@ -35845,6 +35905,10 @@ class CellPlugin extends CorePlugin {
35845
35905
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
35846
35906
  case "CLEAR_CELL":
35847
35907
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
35908
+ case "UPDATE_CELL_POSITION":
35909
+ return !cmd.cellId || this.cells[cmd.sheetId]?.[cmd.cellId]
35910
+ ? "Success" /* CommandResult.Success */
35911
+ : "InvalidCellId" /* CommandResult.InvalidCellId */;
35848
35912
  default:
35849
35913
  return "Success" /* CommandResult.Success */;
35850
35914
  }
@@ -35886,6 +35950,9 @@ class CellPlugin extends CorePlugin {
35886
35950
  case "CLEAR_CELLS":
35887
35951
  this.clearCells(cmd.sheetId, cmd.target);
35888
35952
  break;
35953
+ case "DELETE_SHEET": {
35954
+ this.history.update("cells", cmd.sheetId, undefined);
35955
+ }
35889
35956
  }
35890
35957
  }
35891
35958
  /**
@@ -36964,8 +37031,14 @@ class DataValidationPlugin extends CorePlugin {
36964
37031
  allowDispatch(cmd) {
36965
37032
  switch (cmd.type) {
36966
37033
  case "ADD_DATA_VALIDATION_RULE":
37034
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
37035
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
37036
+ }
36967
37037
  return this.checkValidations(cmd, this.chainValidations(this.checkCriterionTypeIsValid, this.checkCriterionHasValidNumberOfValues, this.checkCriterionValuesAreValid));
36968
37038
  case "REMOVE_DATA_VALIDATION_RULE":
37039
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
37040
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
37041
+ }
36969
37042
  if (!this.rules[cmd.sheetId].find((rule) => rule.id === cmd.id)) {
36970
37043
  return "UnknownDataValidationRule" /* CommandResult.UnknownDataValidationRule */;
36971
37044
  }
@@ -37139,6 +37212,7 @@ class DataValidationPlugin extends CorePlugin {
37139
37212
  class FigurePlugin extends CorePlugin {
37140
37213
  static getters = ["getFigures", "getFigure", "getFigureSheetId"];
37141
37214
  figures = {};
37215
+ insertionOrders = []; // TODO use a list in master
37142
37216
  // ---------------------------------------------------------------------------
37143
37217
  // Command Handling
37144
37218
  // ---------------------------------------------------------------------------
@@ -37241,11 +37315,14 @@ class FigurePlugin extends CorePlugin {
37241
37315
  }
37242
37316
  addFigure(figure, sheetId) {
37243
37317
  this.history.update("figures", sheetId, figure.id, figure);
37318
+ this.history.update("insertionOrders", this.insertionOrders.length, figure.id);
37244
37319
  }
37245
37320
  deleteSheet(sheetId) {
37321
+ this.history.update("insertionOrders", this.insertionOrders.filter((id) => !this.figures[sheetId]?.[id]));
37246
37322
  this.history.update("figures", sheetId, undefined);
37247
37323
  }
37248
37324
  removeFigure(id, sheetId) {
37325
+ this.history.update("insertionOrders", this.insertionOrders.filter((figureId) => figureId !== id));
37249
37326
  this.history.update("figures", sheetId, id, undefined);
37250
37327
  }
37251
37328
  checkFigureExists(sheetId, figureId) {
@@ -37264,7 +37341,14 @@ class FigurePlugin extends CorePlugin {
37264
37341
  // Getters
37265
37342
  // ---------------------------------------------------------------------------
37266
37343
  getFigures(sheetId) {
37267
- return Object.values(this.figures[sheetId] || {}).filter(isDefined$1);
37344
+ const figures = [];
37345
+ for (const figureId of this.insertionOrders) {
37346
+ const figure = this.figures[sheetId]?.[figureId];
37347
+ if (figure) {
37348
+ figures.push(figure);
37349
+ }
37350
+ }
37351
+ return figures;
37268
37352
  }
37269
37353
  getFigure(sheetId, figureId) {
37270
37354
  return this.figures[sheetId]?.[figureId];
@@ -37277,11 +37361,9 @@ class FigurePlugin extends CorePlugin {
37277
37361
  // ---------------------------------------------------------------------------
37278
37362
  import(data) {
37279
37363
  for (let sheet of data.sheets) {
37280
- const figures = {};
37281
- sheet.figures.forEach((figure) => {
37282
- figures[figure.id] = figure;
37283
- });
37284
- this.figures[sheet.id] = figures;
37364
+ for (const figure of sheet.figures) {
37365
+ this.addFigure(figure, sheet.id);
37366
+ }
37285
37367
  }
37286
37368
  }
37287
37369
  export(data) {
@@ -37305,10 +37387,10 @@ class FilterTable {
37305
37387
  this.filters = [];
37306
37388
  this.zone = zone;
37307
37389
  const uuid = new UuidGenerator();
37308
- this.id = uuid.uuidv4();
37390
+ this.id = uuid.smallUuid();
37309
37391
  for (const i of range(zone.left, zone.right + 1)) {
37310
37392
  const filterZone = { ...this.zone, left: i, right: i };
37311
- this.filters.push(new Filter(uuid.uuidv4(), filterZone));
37393
+ this.filters.push(new Filter(uuid.smallUuid(), filterZone));
37312
37394
  }
37313
37395
  }
37314
37396
  /** Get zone of the table without the headers */
@@ -37510,7 +37592,7 @@ class FiltersPlugin extends CorePlugin {
37510
37592
  if (filters.length < zoneToDimension(zone).numberOfCols) {
37511
37593
  for (let col = zone.left; col <= zone.right; col++) {
37512
37594
  if (!filters.find((filter) => filter.col === col)) {
37513
- filters.push(new Filter(this.uuidGenerator.uuidv4(), { ...zone, left: col, right: col }));
37595
+ filters.push(new Filter(this.uuidGenerator.smallUuid(), { ...zone, left: col, right: col }));
37514
37596
  }
37515
37597
  }
37516
37598
  filters.sort((f1, f2) => f1.col - f2.col);
@@ -38999,6 +39081,9 @@ class SheetPlugin extends CorePlugin {
38999
39081
  case "CREATE_SHEET": {
39000
39082
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
39001
39083
  }
39084
+ case "DUPLICATE_SHEET": {
39085
+ return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
39086
+ }
39002
39087
  case "MOVE_SHEET":
39003
39088
  try {
39004
39089
  const currentIndex = this.orderedSheetIds.findIndex((id) => id === cmd.sheetId);
@@ -39011,7 +39096,7 @@ class SheetPlugin extends CorePlugin {
39011
39096
  case "RENAME_SHEET":
39012
39097
  return this.isRenameAllowed(cmd);
39013
39098
  case "DELETE_SHEET":
39014
- return this.orderedSheetIds.length > 1
39099
+ return this.getVisibleSheetIds().length > 1
39015
39100
  ? "Success" /* CommandResult.Success */
39016
39101
  : "NotEnoughSheets" /* CommandResult.NotEnoughSheets */;
39017
39102
  case "ADD_COLUMNS_ROWS":
@@ -39824,6 +39909,10 @@ class SheetPlugin extends CorePlugin {
39824
39909
  checkZonesAreInSheet(cmd) {
39825
39910
  if (!("sheetId" in cmd))
39826
39911
  return "Success" /* CommandResult.Success */;
39912
+ if ("ranges" in cmd &&
39913
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
39914
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39915
+ }
39827
39916
  return this.checkZonesExistInSheet(cmd.sheetId, this.getCommandZones(cmd));
39828
39917
  }
39829
39918
  }
@@ -39843,7 +39932,10 @@ class HeaderGroupingPlugin extends CorePlugin {
39843
39932
  allowDispatch(cmd) {
39844
39933
  switch (cmd.type) {
39845
39934
  case "GROUP_HEADERS": {
39846
- const { start, end } = cmd;
39935
+ const { start, end, sheetId } = cmd;
39936
+ if (!this.getters.tryGetSheet(sheetId)) {
39937
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39938
+ }
39847
39939
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
39848
39940
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
39849
39941
  }
@@ -39856,7 +39948,10 @@ class HeaderGroupingPlugin extends CorePlugin {
39856
39948
  break;
39857
39949
  }
39858
39950
  case "UNGROUP_HEADERS": {
39859
- const { start, end } = cmd;
39951
+ const { start, end, sheetId } = cmd;
39952
+ if (!this.getters.tryGetSheet(sheetId)) {
39953
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39954
+ }
39860
39955
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
39861
39956
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
39862
39957
  }
@@ -39867,6 +39962,9 @@ class HeaderGroupingPlugin extends CorePlugin {
39867
39962
  }
39868
39963
  case "UNFOLD_HEADER_GROUP":
39869
39964
  case "FOLD_HEADER_GROUP":
39965
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
39966
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39967
+ }
39870
39968
  const group = this.findGroupWithStartEnd(cmd.sheetId, cmd.dimension, cmd.start, cmd.end);
39871
39969
  if (!group) {
39872
39970
  return "UnknownHeaderGroup" /* CommandResult.UnknownHeaderGroup */;
@@ -44136,6 +44234,9 @@ function updateChartRangesTransformation(toTransform, executed) {
44136
44234
  };
44137
44235
  }
44138
44236
  function createSheetTransformation(toTransform, executed) {
44237
+ if (toTransform.sheetId === executed.sheetId) {
44238
+ toTransform = { ...toTransform, sheetId: `${toTransform.sheetId}~` };
44239
+ }
44139
44240
  if (toTransform.name === executed.name) {
44140
44241
  return {
44141
44242
  ...toTransform,
@@ -44772,21 +44873,14 @@ class Session extends EventBus {
44772
44873
  if (!message)
44773
44874
  return;
44774
44875
  if (message.type === "REMOTE_REVISION") {
44775
- const revision = this.revisions.get(message.nextRevisionId);
44876
+ let revision = this.revisions.get(message.nextRevisionId);
44776
44877
  if (revision.commands.length === 0) {
44777
44878
  /**
44778
- * The command is empty, we have to drop all the next local revisions
44879
+ * The command is empty, we have to rebase all the next local revisions
44779
44880
  * to avoid issues with undo/redo
44780
44881
  */
44781
- this.revisions.drop(revision.id);
44782
- const revisionIds = this.pendingMessages
44783
- .filter((message) => message.type === "REMOTE_REVISION")
44784
- .map((message) => message.nextRevisionId);
44785
- this.trigger("pending-revisions-dropped", { revisionIds });
44786
- this.waitingAck = false;
44787
- this.waitingUndoRedoAck = false;
44788
- this.pendingMessages = [];
44789
- return;
44882
+ this.revisions.rebase(revision.id);
44883
+ revision = this.revisions.get(message.nextRevisionId);
44790
44884
  }
44791
44885
  message = {
44792
44886
  ...message,
@@ -44810,7 +44904,6 @@ class Session extends EventBus {
44810
44904
  switch (message.type) {
44811
44905
  case "REMOTE_REVISION":
44812
44906
  case "REVISION_REDONE":
44813
- case "REVISION_UNDONE":
44814
44907
  case "SNAPSHOT_CREATED":
44815
44908
  this.waitingAck = false;
44816
44909
  this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
@@ -44818,6 +44911,25 @@ class Session extends EventBus {
44818
44911
  this.processedRevisions.add(message.nextRevisionId);
44819
44912
  this.sendPendingMessage();
44820
44913
  break;
44914
+ case "REVISION_UNDONE": {
44915
+ this.waitingAck = false;
44916
+ this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
44917
+ const firstPendingRevisionId = this.pendingMessages.findIndex((message) => message.type === "REMOTE_REVISION");
44918
+ if (firstPendingRevisionId !== -1) {
44919
+ /**
44920
+ * Some revisions undergo transformations that may cause issues with
44921
+ * undo/redo if the transformation is destructive (we don't get back
44922
+ * the original command by transforming it with the inverse).
44923
+ * To prevent these problems, we must rebase all subsequent local
44924
+ * revisions.
44925
+ */
44926
+ this.revisions.rebase(this.pendingMessages[firstPendingRevisionId].nextRevisionId);
44927
+ }
44928
+ this.serverRevisionId = message.nextRevisionId;
44929
+ this.processedRevisions.add(message.nextRevisionId);
44930
+ this.sendPendingMessage();
44931
+ break;
44932
+ }
44821
44933
  }
44822
44934
  }
44823
44935
  isAlreadyProcessed(message) {
@@ -45522,7 +45634,9 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45522
45634
  const cfInTarget = this.getters
45523
45635
  .getConditionalFormats(targetSheetId)
45524
45636
  .find((cf) => cf.stopIfTrue === originCF.stopIfTrue && deepEquals(cf.rule, originCF.rule));
45525
- return cfInTarget ? cfInTarget : { ...originCF, id: this.uuidGenerator.uuidv4(), ranges: [] };
45637
+ return cfInTarget
45638
+ ? cfInTarget
45639
+ : { ...originCF, id: this.uuidGenerator.smallUuid(), ranges: [] };
45526
45640
  }
45527
45641
  pasteDataValidation(origin, target) {
45528
45642
  const rule = this.getters.getValidationRuleForCell(origin);
@@ -45554,7 +45668,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45554
45668
  originRule.isBlocking === rule.isBlocking);
45555
45669
  return ruleInTargetSheet
45556
45670
  ? ruleInTargetSheet
45557
- : { ...originRule, id: this.uuidGenerator.uuidv4(), ranges: [] };
45671
+ : { ...originRule, id: this.uuidGenerator.smallUuid(), ranges: [] };
45558
45672
  }
45559
45673
  /**
45560
45674
  * Add or remove XCs to a given data validation rule.
@@ -47746,6 +47860,10 @@ class SheetUIPlugin extends UIPlugin {
47746
47860
  */
47747
47861
  checkZonesAreInSheet(cmd) {
47748
47862
  const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.tryGetActiveSheetId();
47863
+ if ("ranges" in cmd &&
47864
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
47865
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
47866
+ }
47749
47867
  const zones = this.getters.getCommandZones(cmd);
47750
47868
  if (!sheetId && zones.length > 0) {
47751
47869
  return "NoActiveSheet" /* CommandResult.NoActiveSheet */;
@@ -47794,23 +47912,23 @@ const uuidGenerator = new UuidGenerator();
47794
47912
  function repeatCreateChartCommand(getters, cmd) {
47795
47913
  return {
47796
47914
  ...repeatSheetDependantCommand(getters, cmd),
47797
- id: uuidGenerator.uuidv4(),
47915
+ id: uuidGenerator.smallUuid(),
47798
47916
  };
47799
47917
  }
47800
47918
  function repeatCreateImageCommand(getters, cmd) {
47801
47919
  return {
47802
47920
  ...repeatSheetDependantCommand(getters, cmd),
47803
- figureId: uuidGenerator.uuidv4(),
47921
+ figureId: uuidGenerator.smallUuid(),
47804
47922
  };
47805
47923
  }
47806
47924
  function repeatCreateFigureCommand(getters, cmd) {
47807
47925
  const newCmd = repeatSheetDependantCommand(getters, cmd);
47808
- newCmd.figure.id = uuidGenerator.uuidv4();
47926
+ newCmd.figure.id = uuidGenerator.smallUuid();
47809
47927
  return newCmd;
47810
47928
  }
47811
47929
  function repeatCreateSheetCommand(getters, cmd) {
47812
47930
  const newCmd = deepCopy(cmd);
47813
- newCmd.sheetId = uuidGenerator.uuidv4();
47931
+ newCmd.sheetId = uuidGenerator.smallUuid();
47814
47932
  const sheetName = cmd.name || getters.getSheet(getters.getActiveSheetId()).name;
47815
47933
  // Extract the prefix of the sheet name (everything before the number at the end of the name)
47816
47934
  const namePrefix = sheetName.match(/(.+?)\d*$/)?.[1] || sheetName;
@@ -48005,7 +48123,6 @@ class HistoryPlugin extends UIPlugin {
48005
48123
  super(config);
48006
48124
  this.session = config.session;
48007
48125
  this.session.on("new-local-state-update", this, this.onNewLocalStateUpdate);
48008
- this.session.on("pending-revisions-dropped", this, ({ revisionIds }) => this.drop(revisionIds));
48009
48126
  this.session.on("snapshot", this, () => {
48010
48127
  this.undoStack = [];
48011
48128
  this.redoStack = [];
@@ -48075,10 +48192,6 @@ class HistoryPlugin extends UIPlugin {
48075
48192
  const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
48076
48193
  return canRepeatRevision(lastNonRedoRevision);
48077
48194
  }
48078
- drop(revisionIds) {
48079
- this.undoStack = this.undoStack.filter((id) => !revisionIds.includes(id));
48080
- this.redoStack = [];
48081
- }
48082
48195
  onNewLocalStateUpdate({ id }) {
48083
48196
  this.undoStack.push(id);
48084
48197
  this.redoStack = [];
@@ -48345,7 +48458,7 @@ class ClipboardFigureState {
48345
48458
  x: maxX < width ? 0 : Math.min(targetX, maxX - width),
48346
48459
  y: maxY < height ? 0 : Math.min(targetY, maxY - height),
48347
48460
  };
48348
- const newId = new UuidGenerator().uuidv4();
48461
+ const newId = new UuidGenerator().smallUuid();
48349
48462
  this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
48350
48463
  if (this.operation === "CUT") {
48351
48464
  this.dispatch("DELETE_FIGURE", {
@@ -50048,23 +50161,7 @@ class GridSelectionPlugin extends UIPlugin {
50048
50161
  gridSelection: deepCopy(gridSelection),
50049
50162
  };
50050
50163
  }
50051
- if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
50052
- const currentSheetIds = this.getters.getVisibleSheetIds();
50053
- this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
50054
- if (this.activeSheet.id in this.sheetsData) {
50055
- const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
50056
- this.selectCell(anchor.cell.col, anchor.cell.row);
50057
- }
50058
- else {
50059
- this.selectCell(0, 0);
50060
- }
50061
- const { col, row } = this.gridSelection.anchor.cell;
50062
- this.moveClient({
50063
- sheetId: this.getters.getActiveSheetId(),
50064
- col,
50065
- row,
50066
- });
50067
- }
50164
+ this.fallbackToVisibleSheet();
50068
50165
  const sheetId = this.getters.getActiveSheetId();
50069
50166
  this.gridSelection.zones = this.gridSelection.zones.map((z) => this.getters.expandZone(sheetId, z));
50070
50167
  this.gridSelection.anchor.zone = this.getters.expandZone(sheetId, this.gridSelection.anchor.zone);
@@ -50074,6 +50171,7 @@ class GridSelectionPlugin extends UIPlugin {
50074
50171
  }
50075
50172
  }
50076
50173
  finalize() {
50174
+ this.fallbackToVisibleSheet();
50077
50175
  /** Any change to the selection has to be reflected in the selection processor. */
50078
50176
  this.selection.resetDefaultAnchor(this, deepCopy(this.gridSelection.anchor));
50079
50177
  }
@@ -50425,6 +50523,25 @@ class GridSelectionPlugin extends UIPlugin {
50425
50523
  }
50426
50524
  return "Success" /* CommandResult.Success */;
50427
50525
  }
50526
+ fallbackToVisibleSheet() {
50527
+ if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
50528
+ const currentSheetIds = this.getters.getVisibleSheetIds();
50529
+ this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
50530
+ if (this.activeSheet.id in this.sheetsData) {
50531
+ const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
50532
+ this.selectCell(anchor.cell.col, anchor.cell.row);
50533
+ }
50534
+ else {
50535
+ this.selectCell(0, 0);
50536
+ }
50537
+ const { col, row } = this.gridSelection.anchor.cell;
50538
+ this.moveClient({
50539
+ sheetId: this.getters.getActiveSheetId(),
50540
+ col,
50541
+ row,
50542
+ });
50543
+ }
50544
+ }
50428
50545
  //-------------------------------------------
50429
50546
  // Helpers for extensions
50430
50547
  // ------------------------------------------
@@ -51572,7 +51689,9 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51572
51689
  case "UNGROUP_HEADERS":
51573
51690
  case "GROUP_HEADERS":
51574
51691
  case "CREATE_SHEET":
51575
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51692
+ if (this.getters.tryGetSheet(cmd.sheetId)) {
51693
+ this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51694
+ }
51576
51695
  break;
51577
51696
  case "DUPLICATE_SHEET":
51578
51697
  this.headerPositions[cmd.sheetIdTo] = deepCopy(this.headerPositions[cmd.sheetId]);
@@ -51580,12 +51699,14 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51580
51699
  }
51581
51700
  }
51582
51701
  finalize() {
51583
- if (this.isDirty) {
51584
- for (const sheetId of this.getters.getSheetIds()) {
51702
+ for (const sheetId of this.getters.getSheetIds()) {
51703
+ // sheets can be created without this plugin being aware of it
51704
+ // in concurrent situations.
51705
+ if (this.isDirty || !this.headerPositions[sheetId]) {
51585
51706
  this.headerPositions[sheetId] = this.computeHeaderPositionsOfSheet(sheetId);
51586
51707
  }
51587
- this.isDirty = false;
51588
51708
  }
51709
+ this.isDirty = false;
51589
51710
  }
51590
51711
  /**
51591
51712
  * Returns the size, start and end coordinates of a column on an unfolded sheet
@@ -52269,7 +52390,7 @@ class BottomBar extends Component {
52269
52390
  clickAddSheet(ev) {
52270
52391
  const activeSheetId = this.env.model.getters.getActiveSheetId();
52271
52392
  const position = this.env.model.getters.getSheetIds().findIndex((sheetId) => sheetId === activeSheetId) + 1;
52272
- const sheetId = this.env.model.uuidGenerator.uuidv4();
52393
+ const sheetId = this.env.model.uuidGenerator.smallUuid();
52273
52394
  const name = this.env.model.getters.getNextSheetName(_t("Sheet"));
52274
52395
  this.env.model.dispatch("CREATE_SHEET", { sheetId, position, name });
52275
52396
  this.env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
@@ -53331,7 +53452,7 @@ css /* scss */ `
53331
53452
  .o-font-size-editor {
53332
53453
  height: calc(100% - 4px);
53333
53454
  input.o-font-size {
53334
- outline-color: ${SELECTION_BORDER_COLOR};
53455
+ outline: none;
53335
53456
  height: 20px;
53336
53457
  width: 23px;
53337
53458
  }
@@ -54506,7 +54627,7 @@ class Tree {
54506
54627
  }
54507
54628
  /**
54508
54629
  * Drop the operation and all following operations in every
54509
- * branch
54630
+ * branches
54510
54631
  */
54511
54632
  drop(operationId) {
54512
54633
  for (const branch of this.branches) {
@@ -54811,9 +54932,16 @@ class SelectiveHistory {
54811
54932
  this.fastForward();
54812
54933
  this.insert(redoId, this.buildEmpty(redoId), insertAfter);
54813
54934
  }
54814
- drop(operationId) {
54935
+ rebase(operationId) {
54936
+ const operation = this.get(operationId);
54937
+ const execution = [...this.tree.execution(this.HEAD_BRANCH).startAfter(operationId)];
54815
54938
  this.revertBefore(operationId);
54939
+ const baseId = this.HEAD_OPERATION.id;
54816
54940
  this.tree.drop(operationId);
54941
+ this.insert(operationId, operation, baseId);
54942
+ for (const { operation } of execution) {
54943
+ this.insert(operation.id, operation.data, this.HEAD_OPERATION.id);
54944
+ }
54817
54945
  }
54818
54946
  getRevertedExecution() {
54819
54947
  const data = [];
@@ -57390,6 +57518,11 @@ class Model extends EventBus {
57390
57518
  dispatch: (command) => {
57391
57519
  const result = this.checkDispatchAllowed(command);
57392
57520
  if (!result.isSuccessful) {
57521
+ // core views plugins need to be invalidated
57522
+ this.dispatchToHandlers(this.coreHandlers, {
57523
+ type: "UNDO",
57524
+ commands: [command],
57525
+ });
57393
57526
  return;
57394
57527
  }
57395
57528
  this.isReplayingCommand = true;
@@ -57418,7 +57551,7 @@ class Model extends EventBus {
57418
57551
  }
57419
57552
  setupConfig(config) {
57420
57553
  const client = config.client || {
57421
- id: this.uuidGenerator.uuidv4(),
57554
+ id: this.uuidGenerator.smallUuid(),
57422
57555
  name: _t("Anonymous").toString(),
57423
57556
  };
57424
57557
  const transportService = config.transportService || new LocalTransportService();
@@ -57804,6 +57937,6 @@ const constants = {
57804
57937
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
57805
57938
 
57806
57939
 
57807
- __info__.version = "17.0.48";
57808
- __info__.date = "2025-02-05T07:18:39.331Z";
57809
- __info__.hash = "aea9101";
57940
+ __info__.version = "17.0.50";
57941
+ __info__.date = "2025-02-14T08:37:34.289Z";
57942
+ __info__.hash = "cc1037d";