@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
  'use strict';
@@ -688,9 +688,16 @@ function deepEquals(o1, o2) {
688
688
  }
689
689
  return true;
690
690
  }
691
- /** Check if the given array contains all the values of the other array. */
691
+ /**
692
+ * Check if the given array contains all the values of the other array.
693
+ * It makes the assumption that both array do not contain duplicates.
694
+ */
692
695
  function includesAll(arr, values) {
693
- return values.every((value) => arr.includes(value));
696
+ if (arr.length < values.length) {
697
+ return false;
698
+ }
699
+ const set = new Set(arr);
700
+ return values.every((value) => set.has(value));
694
701
  }
695
702
  /**
696
703
  * Return an object with all the keys in the object that have a falsy value removed.
@@ -1903,12 +1910,12 @@ function isTargetDependent(cmd) {
1903
1910
  function isRangeDependant(cmd) {
1904
1911
  return "ranges" in cmd;
1905
1912
  }
1906
- function isZoneDependent(cmd) {
1907
- return "zone" in cmd;
1908
- }
1909
1913
  function isPositionDependent(cmd) {
1910
1914
  return "col" in cmd && "row" in cmd && "sheetId" in cmd;
1911
1915
  }
1916
+ function isZoneDependent(cmd) {
1917
+ return "sheetId" in cmd && "zone" in cmd;
1918
+ }
1912
1919
  const invalidateEvaluationCommands = new Set([
1913
1920
  "RENAME_SHEET",
1914
1921
  "DELETE_SHEET",
@@ -1918,6 +1925,7 @@ const invalidateEvaluationCommands = new Set([
1918
1925
  "UNDO",
1919
1926
  "REDO",
1920
1927
  "ADD_MERGE",
1928
+ "DUPLICATE_SHEET",
1921
1929
  "UPDATE_LOCALE",
1922
1930
  ]);
1923
1931
  const invalidateDependenciesCommands = new Set([
@@ -1926,7 +1934,6 @@ const invalidateDependenciesCommands = new Set([
1926
1934
  ]);
1927
1935
  const invalidateCFEvaluationCommands = new Set([
1928
1936
  ...invalidateEvaluationCommands,
1929
- "DUPLICATE_SHEET",
1930
1937
  "EVALUATE_CELLS",
1931
1938
  "ADD_CONDITIONAL_FORMAT",
1932
1939
  "REMOVE_CONDITIONAL_FORMAT",
@@ -2086,6 +2093,7 @@ exports.CommandResult = void 0;
2086
2093
  CommandResult["InvalidRange"] = "InvalidRange";
2087
2094
  CommandResult["InvalidZones"] = "InvalidZones";
2088
2095
  CommandResult["InvalidSheetId"] = "InvalidSheetId";
2096
+ CommandResult["InvalidCellId"] = "InvalidCellId";
2089
2097
  CommandResult["InvalidFigureId"] = "InvalidFigureId";
2090
2098
  CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
2091
2099
  CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
@@ -3666,17 +3674,20 @@ function toZoneWithoutBoundaryChanges(xc) {
3666
3674
  */
3667
3675
  function toUnboundedZone(xc) {
3668
3676
  const zone = toZoneWithoutBoundaryChanges(xc);
3677
+ reorderZone(zone);
3678
+ return zone;
3679
+ }
3680
+ function reorderZone(zone) {
3669
3681
  if (zone.right !== undefined && zone.right < zone.left) {
3670
- const tmp = zone.left;
3682
+ const right = zone.left;
3671
3683
  zone.left = zone.right;
3672
- zone.right = tmp;
3684
+ zone.right = right;
3673
3685
  }
3674
3686
  if (zone.bottom !== undefined && zone.bottom < zone.top) {
3675
- const tmp = zone.top;
3687
+ const bottom = zone.top;
3676
3688
  zone.top = zone.bottom;
3677
- zone.bottom = tmp;
3689
+ zone.bottom = bottom;
3678
3690
  }
3679
- return zone;
3680
3691
  }
3681
3692
  /**
3682
3693
  * Convert from a cartesian reference to a Zone.
@@ -4709,6 +4720,37 @@ class UuidGenerator {
4709
4720
  setIsFastStrategy(isFast) {
4710
4721
  this.isFastIdStrategy = isFast;
4711
4722
  }
4723
+ /**
4724
+ * Generates a custom UUID using a simple 26^8 method (8-character alphanumeric string with lowercase letters)
4725
+ * This has a higher chance of collision than a UUIDv4, but not only faster to generate than an UUIDV4,
4726
+ * it also has a smaller size, which is preferable to alleviate the overall data size.
4727
+ *
4728
+ * This method is preferable when generating uuids for the core data (sheetId, figureId, etc)
4729
+ * as they will appear several times in the revisions and local history.
4730
+ *
4731
+ */
4732
+ smallUuid() {
4733
+ if (this.isFastIdStrategy) {
4734
+ this.fastIdStart++;
4735
+ return String(this.fastIdStart);
4736
+ //@ts-ignore
4737
+ }
4738
+ else if (window.crypto && window.crypto.getRandomValues) {
4739
+ //@ts-ignore
4740
+ return ([1e7] + -1e3).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
4741
+ }
4742
+ else {
4743
+ // mainly for jest and other browsers that do not have the crypto functionality
4744
+ return "xxxxxxxx-xxxx".replace(/[xy]/g, function (c) {
4745
+ var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
4746
+ return v.toString(16);
4747
+ });
4748
+ }
4749
+ }
4750
+ /**
4751
+ * Generates an UUIDV4, has astronomically low chance of collision, but is larger in size than the smallUuid.
4752
+ * This method should be used when you need to avoid collisions at all costs, like the id of a revision.
4753
+ */
4712
4754
  uuidv4() {
4713
4755
  if (this.isFastIdStrategy) {
4714
4756
  this.fastIdStart++;
@@ -4722,7 +4764,7 @@ class UuidGenerator {
4722
4764
  else {
4723
4765
  // mainly for jest and other browsers that do not have the crypto functionality
4724
4766
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
4725
- var r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
4767
+ var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
4726
4768
  return v.toString(16);
4727
4769
  });
4728
4770
  }
@@ -7935,7 +7977,7 @@ const linkSheet = {
7935
7977
  const deleteSheet = {
7936
7978
  name: _t("Delete"),
7937
7979
  isVisible: (env) => {
7938
- return env.model.getters.getSheetIds().length > 1;
7980
+ return env.model.getters.getVisibleSheetIds().length > 1;
7939
7981
  },
7940
7982
  execute: (env) => env.askConfirmation(_t("Are you sure you want to delete this sheet?"), () => {
7941
7983
  env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
@@ -7945,7 +7987,7 @@ const duplicateSheet = {
7945
7987
  name: _t("Duplicate"),
7946
7988
  execute: (env) => {
7947
7989
  const sheetIdFrom = env.model.getters.getActiveSheetId();
7948
- const sheetIdTo = env.model.uuidGenerator.uuidv4();
7990
+ const sheetIdTo = env.model.uuidGenerator.smallUuid();
7949
7991
  env.model.dispatch("DUPLICATE_SHEET", {
7950
7992
  sheetId: sheetIdFrom,
7951
7993
  sheetIdTo,
@@ -8495,17 +8537,15 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
8495
8537
  plugins: [],
8496
8538
  };
8497
8539
  }
8498
- function getChartLabelFormat(getters, range) {
8540
+ function getChartLabelFormat(getters, range, shouldRemoveFirstLabel) {
8499
8541
  if (!range)
8500
8542
  return undefined;
8501
- const { sheetId, zone: { left, top, bottom }, } = range;
8502
- for (let row = top; row <= bottom; row++) {
8503
- const format = getters.getEvaluatedCell({ sheetId, col: left, row }).format;
8504
- if (format) {
8505
- return format;
8506
- }
8543
+ const { sheetId, zone } = range;
8544
+ const formats = positions(zone).map((position) => getters.getEvaluatedCell({ sheetId, ...position }).format);
8545
+ if (shouldRemoveFirstLabel) {
8546
+ formats.shift();
8507
8547
  }
8508
- return undefined;
8548
+ return formats.find((format) => format !== undefined);
8509
8549
  }
8510
8550
  function getChartLabelValues(getters, dataSets, labelRange) {
8511
8551
  let labels = { values: [], formattedValues: [] };
@@ -8786,9 +8826,7 @@ function createBarChartRuntime(chart, getters) {
8786
8826
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
8787
8827
  let labels = labelValues.formattedValues;
8788
8828
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
8789
- if (chart.dataSetsHaveTitle &&
8790
- dataSetsValues[0] &&
8791
- labels.length > dataSetsValues[0].data.length) {
8829
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
8792
8830
  labels.shift();
8793
8831
  }
8794
8832
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -9332,8 +9370,8 @@ function fixEmptyLabelsForDateCharts(labels, dataSetsValues) {
9332
9370
  }
9333
9371
  return { labels: newLabels, dataSetsValues: newDatasets };
9334
9372
  }
9335
- function canChartParseLabels(labelRange, getters) {
9336
- return canBeDateChart(labelRange, getters) || canBeLinearChart(labelRange, getters);
9373
+ function canChartParseLabels(chart, getters) {
9374
+ return canBeDateChart(chart, getters) || canBeLinearChart(chart, getters);
9337
9375
  }
9338
9376
  function getChartAxisType(chart, getters) {
9339
9377
  if (isDateChart(chart, getters) && isLuxonTimeAdapterInstalled()) {
@@ -9345,23 +9383,26 @@ function getChartAxisType(chart, getters) {
9345
9383
  return "category";
9346
9384
  }
9347
9385
  function isDateChart(chart, getters) {
9348
- return !chart.labelsAsText && canBeDateChart(chart.labelRange, getters);
9386
+ return !chart.labelsAsText && canBeDateChart(chart, getters);
9349
9387
  }
9350
9388
  function isLinearChart(chart, getters) {
9351
- return !chart.labelsAsText && canBeLinearChart(chart.labelRange, getters);
9389
+ return !chart.labelsAsText && canBeLinearChart(chart, getters);
9352
9390
  }
9353
- function canBeDateChart(labelRange, getters) {
9354
- if (!labelRange || !canBeLinearChart(labelRange, getters)) {
9391
+ function canBeDateChart(chart, getters) {
9392
+ if (!chart.labelRange || !canBeLinearChart(chart, getters)) {
9355
9393
  return false;
9356
9394
  }
9357
- const labelFormat = getChartLabelFormat(getters, labelRange);
9395
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle));
9358
9396
  return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
9359
9397
  }
9360
- function canBeLinearChart(labelRange, getters) {
9361
- if (!labelRange) {
9398
+ function canBeLinearChart(chart, getters) {
9399
+ if (!chart.labelRange) {
9362
9400
  return false;
9363
9401
  }
9364
- const labels = getters.getRangeValues(labelRange);
9402
+ const labels = getters.getRangeValues(chart.labelRange);
9403
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
9404
+ labels.shift();
9405
+ }
9365
9406
  if (labels.some((label) => isNaN(Number(label)) && label)) {
9366
9407
  return false;
9367
9408
  }
@@ -9435,9 +9476,8 @@ function createLineChartRuntime(chart, getters) {
9435
9476
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
9436
9477
  let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
9437
9478
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
9438
- if (chart.dataSetsHaveTitle &&
9439
- dataSetsValues[0] &&
9440
- labels.length > dataSetsValues[0].data.length) {
9479
+ const removeFirstLabel = shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle);
9480
+ if (removeFirstLabel) {
9441
9481
  labels.shift();
9442
9482
  }
9443
9483
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -9452,7 +9492,7 @@ function createLineChartRuntime(chart, getters) {
9452
9492
  const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
9453
9493
  const options = { format: dataSetFormat, locale, truncateLabels };
9454
9494
  const config = getLineConfiguration(chart, labels, options);
9455
- const labelFormat = getChartLabelFormat(getters, chart.labelRange);
9495
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, removeFirstLabel);
9456
9496
  if (axisType === "time") {
9457
9497
  const axis = {
9458
9498
  type: "time",
@@ -9674,9 +9714,7 @@ function createPieChartRuntime(chart, getters) {
9674
9714
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
9675
9715
  let labels = labelValues.formattedValues;
9676
9716
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
9677
- if (chart.dataSetsHaveTitle &&
9678
- dataSetsValues[0] &&
9679
- labels.length > dataSetsValues[0].data.length) {
9717
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
9680
9718
  labels.shift();
9681
9719
  }
9682
9720
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -10197,21 +10235,22 @@ function getSmartChartDefinition(zone, getters) {
10197
10235
  }
10198
10236
  // Only display legend for several datasets.
10199
10237
  const newLegendPos = dataSetZone.right === dataSetZone.left ? "none" : "top";
10200
- const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
10201
- if (canChartParseLabels(labelRange, getters)) {
10202
- return {
10203
- title,
10204
- dataSets,
10205
- labelsAsText: false,
10206
- stacked: false,
10207
- aggregated: false,
10208
- cumulative: false,
10209
- labelRange: labelRangeXc,
10210
- type: "line",
10211
- dataSetsHaveTitle,
10212
- verticalAxisPosition: "left",
10213
- legendPosition: newLegendPos,
10214
- };
10238
+ const lineChartDefinition = {
10239
+ title,
10240
+ dataSets,
10241
+ labelsAsText: false,
10242
+ stacked: false,
10243
+ aggregated: false,
10244
+ cumulative: false,
10245
+ labelRange: labelRangeXc,
10246
+ type: "line",
10247
+ dataSetsHaveTitle,
10248
+ verticalAxisPosition: "left",
10249
+ legendPosition: newLegendPos,
10250
+ };
10251
+ const chart = new LineChart(lineChartDefinition, sheetId, getters);
10252
+ if (canChartParseLabels(chart, getters)) {
10253
+ return lineChartDefinition;
10215
10254
  }
10216
10255
  return {
10217
10256
  title,
@@ -10811,7 +10850,7 @@ const HIDE_ROWS_NAME = (env) => {
10811
10850
  //------------------------------------------------------------------------------
10812
10851
  const CREATE_CHART = (env) => {
10813
10852
  const getters = env.model.getters;
10814
- const id = env.model.uuidGenerator.uuidv4();
10853
+ const id = env.model.uuidGenerator.smallUuid();
10815
10854
  const sheetId = getters.getActiveSheetId();
10816
10855
  if (getZoneArea(env.model.getters.getSelectedZone()) === 1) {
10817
10856
  env.model.selection.selectTableAroundSelection();
@@ -10845,7 +10884,7 @@ async function requestImage(env) {
10845
10884
  const CREATE_IMAGE = async (env) => {
10846
10885
  if (env.imageProvider) {
10847
10886
  const sheetId = env.model.getters.getActiveSheetId();
10848
- const figureId = env.model.uuidGenerator.uuidv4();
10887
+ const figureId = env.model.uuidGenerator.smallUuid();
10849
10888
  const image = await requestImage(env);
10850
10889
  if (!image) {
10851
10890
  throw new Error("No image provider was given to the environment");
@@ -12566,6 +12605,26 @@ const LN = {
12566
12605
  isExported: true,
12567
12606
  };
12568
12607
  // -----------------------------------------------------------------------------
12608
+ // LOG
12609
+ // -----------------------------------------------------------------------------
12610
+ const LOG = {
12611
+ description: _t("The logarithm of a number, for a given base."),
12612
+ args: [
12613
+ arg("value (number)", _t("The value for which to calculate the logarithm.")),
12614
+ arg("base (number, default=10)", _t("The base of the logarithm.")),
12615
+ ],
12616
+ returns: ["NUMBER"],
12617
+ compute: function (value, base = 10) {
12618
+ const _value = toNumber(value, this.locale);
12619
+ const _base = toNumber(base, this.locale);
12620
+ assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
12621
+ assert(() => _base > 0, _t("The base (%s) must be strictly positive.", _base.toString()));
12622
+ assert(() => _base !== 1, _t("The base must be different from 1."));
12623
+ return Math.log10(_value) / Math.log10(_base);
12624
+ },
12625
+ isExported: true,
12626
+ };
12627
+ // -----------------------------------------------------------------------------
12569
12628
  // MOD
12570
12629
  // -----------------------------------------------------------------------------
12571
12630
  const MOD = {
@@ -13086,6 +13145,7 @@ var math = /*#__PURE__*/Object.freeze({
13086
13145
  ISODD: ISODD,
13087
13146
  ISO_CEILING: ISO_CEILING,
13088
13147
  LN: LN,
13148
+ LOG: LOG,
13089
13149
  MOD: MOD,
13090
13150
  MUNIT: MUNIT,
13091
13151
  ODD: ODD,
@@ -15947,7 +16007,7 @@ const SORTN = {
15947
16007
  }
15948
16008
  }
15949
16009
  },
15950
- isExported: true,
16010
+ isExported: false,
15951
16011
  };
15952
16012
  // -----------------------------------------------------------------------------
15953
16013
  // UNIQUE
@@ -19848,7 +19908,7 @@ const insertSheet = {
19848
19908
  execute: (env) => {
19849
19909
  const activeSheetId = env.model.getters.getActiveSheetId();
19850
19910
  const position = env.model.getters.getSheetIds().indexOf(activeSheetId) + 1;
19851
- const sheetId = env.model.uuidGenerator.uuidv4();
19911
+ const sheetId = env.model.uuidGenerator.smallUuid();
19852
19912
  env.model.dispatch("CREATE_SHEET", { sheetId, position });
19853
19913
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
19854
19914
  },
@@ -21524,7 +21584,7 @@ css /* scss */ `
21524
21584
  */
21525
21585
  class SelectionInput extends owl.Component {
21526
21586
  static template = "o-spreadsheet-SelectionInput";
21527
- id = uuidGenerator$1.uuidv4();
21587
+ id = uuidGenerator$1.smallUuid();
21528
21588
  previousRanges = this.props.ranges() || [];
21529
21589
  originSheet = this.env.model.getters.getActiveSheetId();
21530
21590
  state = owl.useState({
@@ -22574,7 +22634,7 @@ class LineConfigPanel extends LineBarPieConfigPanel {
22574
22634
  get canTreatLabelsAsText() {
22575
22635
  const chart = this.env.model.getters.getChart(this.props.figureId);
22576
22636
  if (chart && chart instanceof LineChart) {
22577
- return canChartParseLabels(chart.labelRange, this.env.model.getters);
22637
+ return canChartParseLabels(chart, this.env.model.getters);
22578
22638
  }
22579
22639
  return false;
22580
22640
  }
@@ -23602,7 +23662,7 @@ class ConditionalFormattingEditor extends owl.Component {
23602
23662
  state;
23603
23663
  setup() {
23604
23664
  const cf = this.props.editedCf || {
23605
- id: this.env.model.uuidGenerator.uuidv4(),
23665
+ id: this.env.model.uuidGenerator.smallUuid(),
23606
23666
  ranges: this.env.model.getters
23607
23667
  .getSelectedZones()
23608
23668
  .map((zone) => this.env.model.getters.zoneToXC(this.env.model.getters.getActiveSheetId(), zone)),
@@ -25551,7 +25611,7 @@ class DataValidationEditor extends owl.Component {
25551
25611
  .getSelectedZones()
25552
25612
  .map((zone) => zoneToXc(this.env.model.getters.getUnboundedZone(sheetId, zone)));
25553
25613
  return {
25554
- id: this.env.model.uuidGenerator.uuidv4(),
25614
+ id: this.env.model.uuidGenerator.smallUuid(),
25555
25615
  criterion: { type: "textContains", values: [""] },
25556
25616
  ranges,
25557
25617
  };
@@ -34171,7 +34231,7 @@ function forceUnicityOfFigure(data) {
34171
34231
  for (const sheet of data.sheets || []) {
34172
34232
  for (const figure of sheet.figures || []) {
34173
34233
  if (figureIds.has(figure.id)) {
34174
- figure.id += uuidGenerator.uuidv4();
34234
+ figure.id += uuidGenerator.smallUuid();
34175
34235
  }
34176
34236
  figureIds.add(figure.id);
34177
34237
  }
@@ -35847,6 +35907,10 @@ class CellPlugin extends CorePlugin {
35847
35907
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
35848
35908
  case "CLEAR_CELL":
35849
35909
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
35910
+ case "UPDATE_CELL_POSITION":
35911
+ return !cmd.cellId || this.cells[cmd.sheetId]?.[cmd.cellId]
35912
+ ? "Success" /* CommandResult.Success */
35913
+ : "InvalidCellId" /* CommandResult.InvalidCellId */;
35850
35914
  default:
35851
35915
  return "Success" /* CommandResult.Success */;
35852
35916
  }
@@ -35888,6 +35952,9 @@ class CellPlugin extends CorePlugin {
35888
35952
  case "CLEAR_CELLS":
35889
35953
  this.clearCells(cmd.sheetId, cmd.target);
35890
35954
  break;
35955
+ case "DELETE_SHEET": {
35956
+ this.history.update("cells", cmd.sheetId, undefined);
35957
+ }
35891
35958
  }
35892
35959
  }
35893
35960
  /**
@@ -36966,8 +37033,14 @@ class DataValidationPlugin extends CorePlugin {
36966
37033
  allowDispatch(cmd) {
36967
37034
  switch (cmd.type) {
36968
37035
  case "ADD_DATA_VALIDATION_RULE":
37036
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
37037
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
37038
+ }
36969
37039
  return this.checkValidations(cmd, this.chainValidations(this.checkCriterionTypeIsValid, this.checkCriterionHasValidNumberOfValues, this.checkCriterionValuesAreValid));
36970
37040
  case "REMOVE_DATA_VALIDATION_RULE":
37041
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
37042
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
37043
+ }
36971
37044
  if (!this.rules[cmd.sheetId].find((rule) => rule.id === cmd.id)) {
36972
37045
  return "UnknownDataValidationRule" /* CommandResult.UnknownDataValidationRule */;
36973
37046
  }
@@ -37141,6 +37214,7 @@ class DataValidationPlugin extends CorePlugin {
37141
37214
  class FigurePlugin extends CorePlugin {
37142
37215
  static getters = ["getFigures", "getFigure", "getFigureSheetId"];
37143
37216
  figures = {};
37217
+ insertionOrders = []; // TODO use a list in master
37144
37218
  // ---------------------------------------------------------------------------
37145
37219
  // Command Handling
37146
37220
  // ---------------------------------------------------------------------------
@@ -37243,11 +37317,14 @@ class FigurePlugin extends CorePlugin {
37243
37317
  }
37244
37318
  addFigure(figure, sheetId) {
37245
37319
  this.history.update("figures", sheetId, figure.id, figure);
37320
+ this.history.update("insertionOrders", this.insertionOrders.length, figure.id);
37246
37321
  }
37247
37322
  deleteSheet(sheetId) {
37323
+ this.history.update("insertionOrders", this.insertionOrders.filter((id) => !this.figures[sheetId]?.[id]));
37248
37324
  this.history.update("figures", sheetId, undefined);
37249
37325
  }
37250
37326
  removeFigure(id, sheetId) {
37327
+ this.history.update("insertionOrders", this.insertionOrders.filter((figureId) => figureId !== id));
37251
37328
  this.history.update("figures", sheetId, id, undefined);
37252
37329
  }
37253
37330
  checkFigureExists(sheetId, figureId) {
@@ -37266,7 +37343,14 @@ class FigurePlugin extends CorePlugin {
37266
37343
  // Getters
37267
37344
  // ---------------------------------------------------------------------------
37268
37345
  getFigures(sheetId) {
37269
- return Object.values(this.figures[sheetId] || {}).filter(isDefined$1);
37346
+ const figures = [];
37347
+ for (const figureId of this.insertionOrders) {
37348
+ const figure = this.figures[sheetId]?.[figureId];
37349
+ if (figure) {
37350
+ figures.push(figure);
37351
+ }
37352
+ }
37353
+ return figures;
37270
37354
  }
37271
37355
  getFigure(sheetId, figureId) {
37272
37356
  return this.figures[sheetId]?.[figureId];
@@ -37279,11 +37363,9 @@ class FigurePlugin extends CorePlugin {
37279
37363
  // ---------------------------------------------------------------------------
37280
37364
  import(data) {
37281
37365
  for (let sheet of data.sheets) {
37282
- const figures = {};
37283
- sheet.figures.forEach((figure) => {
37284
- figures[figure.id] = figure;
37285
- });
37286
- this.figures[sheet.id] = figures;
37366
+ for (const figure of sheet.figures) {
37367
+ this.addFigure(figure, sheet.id);
37368
+ }
37287
37369
  }
37288
37370
  }
37289
37371
  export(data) {
@@ -37307,10 +37389,10 @@ class FilterTable {
37307
37389
  this.filters = [];
37308
37390
  this.zone = zone;
37309
37391
  const uuid = new UuidGenerator();
37310
- this.id = uuid.uuidv4();
37392
+ this.id = uuid.smallUuid();
37311
37393
  for (const i of range(zone.left, zone.right + 1)) {
37312
37394
  const filterZone = { ...this.zone, left: i, right: i };
37313
- this.filters.push(new Filter(uuid.uuidv4(), filterZone));
37395
+ this.filters.push(new Filter(uuid.smallUuid(), filterZone));
37314
37396
  }
37315
37397
  }
37316
37398
  /** Get zone of the table without the headers */
@@ -37512,7 +37594,7 @@ class FiltersPlugin extends CorePlugin {
37512
37594
  if (filters.length < zoneToDimension(zone).numberOfCols) {
37513
37595
  for (let col = zone.left; col <= zone.right; col++) {
37514
37596
  if (!filters.find((filter) => filter.col === col)) {
37515
- filters.push(new Filter(this.uuidGenerator.uuidv4(), { ...zone, left: col, right: col }));
37597
+ filters.push(new Filter(this.uuidGenerator.smallUuid(), { ...zone, left: col, right: col }));
37516
37598
  }
37517
37599
  }
37518
37600
  filters.sort((f1, f2) => f1.col - f2.col);
@@ -39001,6 +39083,9 @@ class SheetPlugin extends CorePlugin {
39001
39083
  case "CREATE_SHEET": {
39002
39084
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
39003
39085
  }
39086
+ case "DUPLICATE_SHEET": {
39087
+ return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
39088
+ }
39004
39089
  case "MOVE_SHEET":
39005
39090
  try {
39006
39091
  const currentIndex = this.orderedSheetIds.findIndex((id) => id === cmd.sheetId);
@@ -39013,7 +39098,7 @@ class SheetPlugin extends CorePlugin {
39013
39098
  case "RENAME_SHEET":
39014
39099
  return this.isRenameAllowed(cmd);
39015
39100
  case "DELETE_SHEET":
39016
- return this.orderedSheetIds.length > 1
39101
+ return this.getVisibleSheetIds().length > 1
39017
39102
  ? "Success" /* CommandResult.Success */
39018
39103
  : "NotEnoughSheets" /* CommandResult.NotEnoughSheets */;
39019
39104
  case "ADD_COLUMNS_ROWS":
@@ -39826,6 +39911,10 @@ class SheetPlugin extends CorePlugin {
39826
39911
  checkZonesAreInSheet(cmd) {
39827
39912
  if (!("sheetId" in cmd))
39828
39913
  return "Success" /* CommandResult.Success */;
39914
+ if ("ranges" in cmd &&
39915
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
39916
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39917
+ }
39829
39918
  return this.checkZonesExistInSheet(cmd.sheetId, this.getCommandZones(cmd));
39830
39919
  }
39831
39920
  }
@@ -39845,7 +39934,10 @@ class HeaderGroupingPlugin extends CorePlugin {
39845
39934
  allowDispatch(cmd) {
39846
39935
  switch (cmd.type) {
39847
39936
  case "GROUP_HEADERS": {
39848
- const { start, end } = cmd;
39937
+ const { start, end, sheetId } = cmd;
39938
+ if (!this.getters.tryGetSheet(sheetId)) {
39939
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39940
+ }
39849
39941
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
39850
39942
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
39851
39943
  }
@@ -39858,7 +39950,10 @@ class HeaderGroupingPlugin extends CorePlugin {
39858
39950
  break;
39859
39951
  }
39860
39952
  case "UNGROUP_HEADERS": {
39861
- const { start, end } = cmd;
39953
+ const { start, end, sheetId } = cmd;
39954
+ if (!this.getters.tryGetSheet(sheetId)) {
39955
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39956
+ }
39862
39957
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
39863
39958
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
39864
39959
  }
@@ -39869,6 +39964,9 @@ class HeaderGroupingPlugin extends CorePlugin {
39869
39964
  }
39870
39965
  case "UNFOLD_HEADER_GROUP":
39871
39966
  case "FOLD_HEADER_GROUP":
39967
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
39968
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39969
+ }
39872
39970
  const group = this.findGroupWithStartEnd(cmd.sheetId, cmd.dimension, cmd.start, cmd.end);
39873
39971
  if (!group) {
39874
39972
  return "UnknownHeaderGroup" /* CommandResult.UnknownHeaderGroup */;
@@ -44138,6 +44236,9 @@ function updateChartRangesTransformation(toTransform, executed) {
44138
44236
  };
44139
44237
  }
44140
44238
  function createSheetTransformation(toTransform, executed) {
44239
+ if (toTransform.sheetId === executed.sheetId) {
44240
+ toTransform = { ...toTransform, sheetId: `${toTransform.sheetId}~` };
44241
+ }
44141
44242
  if (toTransform.name === executed.name) {
44142
44243
  return {
44143
44244
  ...toTransform,
@@ -44774,21 +44875,14 @@ class Session extends EventBus {
44774
44875
  if (!message)
44775
44876
  return;
44776
44877
  if (message.type === "REMOTE_REVISION") {
44777
- const revision = this.revisions.get(message.nextRevisionId);
44878
+ let revision = this.revisions.get(message.nextRevisionId);
44778
44879
  if (revision.commands.length === 0) {
44779
44880
  /**
44780
- * The command is empty, we have to drop all the next local revisions
44881
+ * The command is empty, we have to rebase all the next local revisions
44781
44882
  * to avoid issues with undo/redo
44782
44883
  */
44783
- this.revisions.drop(revision.id);
44784
- const revisionIds = this.pendingMessages
44785
- .filter((message) => message.type === "REMOTE_REVISION")
44786
- .map((message) => message.nextRevisionId);
44787
- this.trigger("pending-revisions-dropped", { revisionIds });
44788
- this.waitingAck = false;
44789
- this.waitingUndoRedoAck = false;
44790
- this.pendingMessages = [];
44791
- return;
44884
+ this.revisions.rebase(revision.id);
44885
+ revision = this.revisions.get(message.nextRevisionId);
44792
44886
  }
44793
44887
  message = {
44794
44888
  ...message,
@@ -44812,7 +44906,6 @@ class Session extends EventBus {
44812
44906
  switch (message.type) {
44813
44907
  case "REMOTE_REVISION":
44814
44908
  case "REVISION_REDONE":
44815
- case "REVISION_UNDONE":
44816
44909
  case "SNAPSHOT_CREATED":
44817
44910
  this.waitingAck = false;
44818
44911
  this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
@@ -44820,6 +44913,25 @@ class Session extends EventBus {
44820
44913
  this.processedRevisions.add(message.nextRevisionId);
44821
44914
  this.sendPendingMessage();
44822
44915
  break;
44916
+ case "REVISION_UNDONE": {
44917
+ this.waitingAck = false;
44918
+ this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
44919
+ const firstPendingRevisionId = this.pendingMessages.findIndex((message) => message.type === "REMOTE_REVISION");
44920
+ if (firstPendingRevisionId !== -1) {
44921
+ /**
44922
+ * Some revisions undergo transformations that may cause issues with
44923
+ * undo/redo if the transformation is destructive (we don't get back
44924
+ * the original command by transforming it with the inverse).
44925
+ * To prevent these problems, we must rebase all subsequent local
44926
+ * revisions.
44927
+ */
44928
+ this.revisions.rebase(this.pendingMessages[firstPendingRevisionId].nextRevisionId);
44929
+ }
44930
+ this.serverRevisionId = message.nextRevisionId;
44931
+ this.processedRevisions.add(message.nextRevisionId);
44932
+ this.sendPendingMessage();
44933
+ break;
44934
+ }
44823
44935
  }
44824
44936
  }
44825
44937
  isAlreadyProcessed(message) {
@@ -45524,7 +45636,9 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45524
45636
  const cfInTarget = this.getters
45525
45637
  .getConditionalFormats(targetSheetId)
45526
45638
  .find((cf) => cf.stopIfTrue === originCF.stopIfTrue && deepEquals(cf.rule, originCF.rule));
45527
- return cfInTarget ? cfInTarget : { ...originCF, id: this.uuidGenerator.uuidv4(), ranges: [] };
45639
+ return cfInTarget
45640
+ ? cfInTarget
45641
+ : { ...originCF, id: this.uuidGenerator.smallUuid(), ranges: [] };
45528
45642
  }
45529
45643
  pasteDataValidation(origin, target) {
45530
45644
  const rule = this.getters.getValidationRuleForCell(origin);
@@ -45556,7 +45670,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45556
45670
  originRule.isBlocking === rule.isBlocking);
45557
45671
  return ruleInTargetSheet
45558
45672
  ? ruleInTargetSheet
45559
- : { ...originRule, id: this.uuidGenerator.uuidv4(), ranges: [] };
45673
+ : { ...originRule, id: this.uuidGenerator.smallUuid(), ranges: [] };
45560
45674
  }
45561
45675
  /**
45562
45676
  * Add or remove XCs to a given data validation rule.
@@ -47748,6 +47862,10 @@ class SheetUIPlugin extends UIPlugin {
47748
47862
  */
47749
47863
  checkZonesAreInSheet(cmd) {
47750
47864
  const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.tryGetActiveSheetId();
47865
+ if ("ranges" in cmd &&
47866
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
47867
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
47868
+ }
47751
47869
  const zones = this.getters.getCommandZones(cmd);
47752
47870
  if (!sheetId && zones.length > 0) {
47753
47871
  return "NoActiveSheet" /* CommandResult.NoActiveSheet */;
@@ -47796,23 +47914,23 @@ const uuidGenerator = new UuidGenerator();
47796
47914
  function repeatCreateChartCommand(getters, cmd) {
47797
47915
  return {
47798
47916
  ...repeatSheetDependantCommand(getters, cmd),
47799
- id: uuidGenerator.uuidv4(),
47917
+ id: uuidGenerator.smallUuid(),
47800
47918
  };
47801
47919
  }
47802
47920
  function repeatCreateImageCommand(getters, cmd) {
47803
47921
  return {
47804
47922
  ...repeatSheetDependantCommand(getters, cmd),
47805
- figureId: uuidGenerator.uuidv4(),
47923
+ figureId: uuidGenerator.smallUuid(),
47806
47924
  };
47807
47925
  }
47808
47926
  function repeatCreateFigureCommand(getters, cmd) {
47809
47927
  const newCmd = repeatSheetDependantCommand(getters, cmd);
47810
- newCmd.figure.id = uuidGenerator.uuidv4();
47928
+ newCmd.figure.id = uuidGenerator.smallUuid();
47811
47929
  return newCmd;
47812
47930
  }
47813
47931
  function repeatCreateSheetCommand(getters, cmd) {
47814
47932
  const newCmd = deepCopy(cmd);
47815
- newCmd.sheetId = uuidGenerator.uuidv4();
47933
+ newCmd.sheetId = uuidGenerator.smallUuid();
47816
47934
  const sheetName = cmd.name || getters.getSheet(getters.getActiveSheetId()).name;
47817
47935
  // Extract the prefix of the sheet name (everything before the number at the end of the name)
47818
47936
  const namePrefix = sheetName.match(/(.+?)\d*$/)?.[1] || sheetName;
@@ -48007,7 +48125,6 @@ class HistoryPlugin extends UIPlugin {
48007
48125
  super(config);
48008
48126
  this.session = config.session;
48009
48127
  this.session.on("new-local-state-update", this, this.onNewLocalStateUpdate);
48010
- this.session.on("pending-revisions-dropped", this, ({ revisionIds }) => this.drop(revisionIds));
48011
48128
  this.session.on("snapshot", this, () => {
48012
48129
  this.undoStack = [];
48013
48130
  this.redoStack = [];
@@ -48077,10 +48194,6 @@ class HistoryPlugin extends UIPlugin {
48077
48194
  const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
48078
48195
  return canRepeatRevision(lastNonRedoRevision);
48079
48196
  }
48080
- drop(revisionIds) {
48081
- this.undoStack = this.undoStack.filter((id) => !revisionIds.includes(id));
48082
- this.redoStack = [];
48083
- }
48084
48197
  onNewLocalStateUpdate({ id }) {
48085
48198
  this.undoStack.push(id);
48086
48199
  this.redoStack = [];
@@ -48347,7 +48460,7 @@ class ClipboardFigureState {
48347
48460
  x: maxX < width ? 0 : Math.min(targetX, maxX - width),
48348
48461
  y: maxY < height ? 0 : Math.min(targetY, maxY - height),
48349
48462
  };
48350
- const newId = new UuidGenerator().uuidv4();
48463
+ const newId = new UuidGenerator().smallUuid();
48351
48464
  this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
48352
48465
  if (this.operation === "CUT") {
48353
48466
  this.dispatch("DELETE_FIGURE", {
@@ -50050,23 +50163,7 @@ class GridSelectionPlugin extends UIPlugin {
50050
50163
  gridSelection: deepCopy(gridSelection),
50051
50164
  };
50052
50165
  }
50053
- if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
50054
- const currentSheetIds = this.getters.getVisibleSheetIds();
50055
- this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
50056
- if (this.activeSheet.id in this.sheetsData) {
50057
- const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
50058
- this.selectCell(anchor.cell.col, anchor.cell.row);
50059
- }
50060
- else {
50061
- this.selectCell(0, 0);
50062
- }
50063
- const { col, row } = this.gridSelection.anchor.cell;
50064
- this.moveClient({
50065
- sheetId: this.getters.getActiveSheetId(),
50066
- col,
50067
- row,
50068
- });
50069
- }
50166
+ this.fallbackToVisibleSheet();
50070
50167
  const sheetId = this.getters.getActiveSheetId();
50071
50168
  this.gridSelection.zones = this.gridSelection.zones.map((z) => this.getters.expandZone(sheetId, z));
50072
50169
  this.gridSelection.anchor.zone = this.getters.expandZone(sheetId, this.gridSelection.anchor.zone);
@@ -50076,6 +50173,7 @@ class GridSelectionPlugin extends UIPlugin {
50076
50173
  }
50077
50174
  }
50078
50175
  finalize() {
50176
+ this.fallbackToVisibleSheet();
50079
50177
  /** Any change to the selection has to be reflected in the selection processor. */
50080
50178
  this.selection.resetDefaultAnchor(this, deepCopy(this.gridSelection.anchor));
50081
50179
  }
@@ -50427,6 +50525,25 @@ class GridSelectionPlugin extends UIPlugin {
50427
50525
  }
50428
50526
  return "Success" /* CommandResult.Success */;
50429
50527
  }
50528
+ fallbackToVisibleSheet() {
50529
+ if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
50530
+ const currentSheetIds = this.getters.getVisibleSheetIds();
50531
+ this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
50532
+ if (this.activeSheet.id in this.sheetsData) {
50533
+ const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
50534
+ this.selectCell(anchor.cell.col, anchor.cell.row);
50535
+ }
50536
+ else {
50537
+ this.selectCell(0, 0);
50538
+ }
50539
+ const { col, row } = this.gridSelection.anchor.cell;
50540
+ this.moveClient({
50541
+ sheetId: this.getters.getActiveSheetId(),
50542
+ col,
50543
+ row,
50544
+ });
50545
+ }
50546
+ }
50430
50547
  //-------------------------------------------
50431
50548
  // Helpers for extensions
50432
50549
  // ------------------------------------------
@@ -51574,7 +51691,9 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51574
51691
  case "UNGROUP_HEADERS":
51575
51692
  case "GROUP_HEADERS":
51576
51693
  case "CREATE_SHEET":
51577
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51694
+ if (this.getters.tryGetSheet(cmd.sheetId)) {
51695
+ this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51696
+ }
51578
51697
  break;
51579
51698
  case "DUPLICATE_SHEET":
51580
51699
  this.headerPositions[cmd.sheetIdTo] = deepCopy(this.headerPositions[cmd.sheetId]);
@@ -51582,12 +51701,14 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51582
51701
  }
51583
51702
  }
51584
51703
  finalize() {
51585
- if (this.isDirty) {
51586
- for (const sheetId of this.getters.getSheetIds()) {
51704
+ for (const sheetId of this.getters.getSheetIds()) {
51705
+ // sheets can be created without this plugin being aware of it
51706
+ // in concurrent situations.
51707
+ if (this.isDirty || !this.headerPositions[sheetId]) {
51587
51708
  this.headerPositions[sheetId] = this.computeHeaderPositionsOfSheet(sheetId);
51588
51709
  }
51589
- this.isDirty = false;
51590
51710
  }
51711
+ this.isDirty = false;
51591
51712
  }
51592
51713
  /**
51593
51714
  * Returns the size, start and end coordinates of a column on an unfolded sheet
@@ -52271,7 +52392,7 @@ class BottomBar extends owl.Component {
52271
52392
  clickAddSheet(ev) {
52272
52393
  const activeSheetId = this.env.model.getters.getActiveSheetId();
52273
52394
  const position = this.env.model.getters.getSheetIds().findIndex((sheetId) => sheetId === activeSheetId) + 1;
52274
- const sheetId = this.env.model.uuidGenerator.uuidv4();
52395
+ const sheetId = this.env.model.uuidGenerator.smallUuid();
52275
52396
  const name = this.env.model.getters.getNextSheetName(_t("Sheet"));
52276
52397
  this.env.model.dispatch("CREATE_SHEET", { sheetId, position, name });
52277
52398
  this.env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
@@ -53333,7 +53454,7 @@ css /* scss */ `
53333
53454
  .o-font-size-editor {
53334
53455
  height: calc(100% - 4px);
53335
53456
  input.o-font-size {
53336
- outline-color: ${SELECTION_BORDER_COLOR};
53457
+ outline: none;
53337
53458
  height: 20px;
53338
53459
  width: 23px;
53339
53460
  }
@@ -54508,7 +54629,7 @@ class Tree {
54508
54629
  }
54509
54630
  /**
54510
54631
  * Drop the operation and all following operations in every
54511
- * branch
54632
+ * branches
54512
54633
  */
54513
54634
  drop(operationId) {
54514
54635
  for (const branch of this.branches) {
@@ -54813,9 +54934,16 @@ class SelectiveHistory {
54813
54934
  this.fastForward();
54814
54935
  this.insert(redoId, this.buildEmpty(redoId), insertAfter);
54815
54936
  }
54816
- drop(operationId) {
54937
+ rebase(operationId) {
54938
+ const operation = this.get(operationId);
54939
+ const execution = [...this.tree.execution(this.HEAD_BRANCH).startAfter(operationId)];
54817
54940
  this.revertBefore(operationId);
54941
+ const baseId = this.HEAD_OPERATION.id;
54818
54942
  this.tree.drop(operationId);
54943
+ this.insert(operationId, operation, baseId);
54944
+ for (const { operation } of execution) {
54945
+ this.insert(operation.id, operation.data, this.HEAD_OPERATION.id);
54946
+ }
54819
54947
  }
54820
54948
  getRevertedExecution() {
54821
54949
  const data = [];
@@ -57392,6 +57520,11 @@ class Model extends EventBus {
57392
57520
  dispatch: (command) => {
57393
57521
  const result = this.checkDispatchAllowed(command);
57394
57522
  if (!result.isSuccessful) {
57523
+ // core views plugins need to be invalidated
57524
+ this.dispatchToHandlers(this.coreHandlers, {
57525
+ type: "UNDO",
57526
+ commands: [command],
57527
+ });
57395
57528
  return;
57396
57529
  }
57397
57530
  this.isReplayingCommand = true;
@@ -57420,7 +57553,7 @@ class Model extends EventBus {
57420
57553
  }
57421
57554
  setupConfig(config) {
57422
57555
  const client = config.client || {
57423
- id: this.uuidGenerator.uuidv4(),
57556
+ id: this.uuidGenerator.smallUuid(),
57424
57557
  name: _t("Anonymous").toString(),
57425
57558
  };
57426
57559
  const transportService = config.transportService || new LocalTransportService();
@@ -57841,6 +57974,6 @@ exports.setTranslationMethod = setTranslationMethod;
57841
57974
  exports.tokenize = tokenize;
57842
57975
 
57843
57976
 
57844
- __info__.version = "17.0.48";
57845
- __info__.date = "2025-02-05T07:18:39.331Z";
57846
- __info__.hash = "aea9101";
57977
+ __info__.version = "17.0.50";
57978
+ __info__.date = "2025-02-14T08:37:34.289Z";
57979
+ __info__.hash = "cc1037d";