@odoo/o-spreadsheet 18.0.15 → 18.0.17

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 18.0.15
6
- * @date 2025-02-10T08:59:22.993Z
7
- * @hash 5b19f88
5
+ * @version 18.0.17
6
+ * @date 2025-02-25T05:58:39.632Z
7
+ * @hash 2ee4347
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -2065,17 +2065,7 @@
2065
2065
  */
2066
2066
  function toUnboundedZone(xc) {
2067
2067
  const zone = toZoneWithoutBoundaryChanges(xc);
2068
- if (zone.right !== undefined && zone.right < zone.left) {
2069
- const tmp = zone.left;
2070
- zone.left = zone.right;
2071
- zone.right = tmp;
2072
- }
2073
- if (zone.bottom !== undefined && zone.bottom < zone.top) {
2074
- const tmp = zone.top;
2075
- zone.top = zone.bottom;
2076
- zone.bottom = tmp;
2077
- }
2078
- return zone;
2068
+ return reorderZone(zone);
2079
2069
  }
2080
2070
  /**
2081
2071
  * Convert from a cartesian reference to a Zone.
@@ -2349,11 +2339,11 @@
2349
2339
  return positions;
2350
2340
  }
2351
2341
  function reorderZone(zone) {
2352
- if (zone.left > zone.right) {
2353
- zone = { left: zone.right, right: zone.left, top: zone.top, bottom: zone.bottom };
2342
+ if (zone.right !== undefined && zone.left > zone.right) {
2343
+ zone = { ...zone, left: zone.right, right: zone.left };
2354
2344
  }
2355
- if (zone.top > zone.bottom) {
2356
- zone = { left: zone.left, right: zone.right, top: zone.bottom, bottom: zone.top };
2345
+ if (zone.bottom !== undefined && zone.top > zone.bottom) {
2346
+ zone = { ...zone, top: zone.bottom, bottom: zone.top };
2357
2347
  }
2358
2348
  return zone;
2359
2349
  }
@@ -3247,12 +3237,12 @@
3247
3237
  function isRangeDependant(cmd) {
3248
3238
  return "ranges" in cmd;
3249
3239
  }
3250
- function isZoneDependent(cmd) {
3251
- return "zone" in cmd;
3252
- }
3253
3240
  function isPositionDependent(cmd) {
3254
3241
  return "col" in cmd && "row" in cmd && "sheetId" in cmd;
3255
3242
  }
3243
+ function isZoneDependent(cmd) {
3244
+ return "sheetId" in cmd && "zone" in cmd;
3245
+ }
3256
3246
  const invalidateEvaluationCommands = new Set([
3257
3247
  "RENAME_SHEET",
3258
3248
  "DELETE_SHEET",
@@ -3264,6 +3254,7 @@
3264
3254
  "REDO",
3265
3255
  "ADD_MERGE",
3266
3256
  "REMOVE_MERGE",
3257
+ "DUPLICATE_SHEET",
3267
3258
  "UPDATE_LOCALE",
3268
3259
  "ADD_PIVOT",
3269
3260
  "UPDATE_PIVOT",
@@ -3292,7 +3283,6 @@
3292
3283
  ]);
3293
3284
  const invalidateDependenciesCommands = new Set(["MOVE_RANGES"]);
3294
3285
  const invalidateCFEvaluationCommands = new Set([
3295
- "DUPLICATE_SHEET",
3296
3286
  "EVALUATE_CELLS",
3297
3287
  "ADD_CONDITIONAL_FORMAT",
3298
3288
  "REMOVE_CONDITIONAL_FORMAT",
@@ -3461,6 +3451,7 @@
3461
3451
  CommandResult["InvalidRange"] = "InvalidRange";
3462
3452
  CommandResult["InvalidZones"] = "InvalidZones";
3463
3453
  CommandResult["InvalidSheetId"] = "InvalidSheetId";
3454
+ CommandResult["InvalidCellId"] = "InvalidCellId";
3464
3455
  CommandResult["InvalidFigureId"] = "InvalidFigureId";
3465
3456
  CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
3466
3457
  CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
@@ -6346,20 +6337,53 @@
6346
6337
  setIsFastStrategy(isFast) {
6347
6338
  this.isFastIdStrategy = isFast;
6348
6339
  }
6340
+ /**
6341
+ * Generates a custom UUID using a simple 36^12 method (8-character alphanumeric string with lowercase letters)
6342
+ * This has a higher chance of collision than a UUIDv4, but not only faster to generate than an UUIDV4,
6343
+ * it also has a smaller size, which is preferable to alleviate the overall data size.
6344
+ *
6345
+ * This method is preferable when generating uuids for the core data (sheetId, figureId, etc)
6346
+ * as they will appear several times in the revisions and local history.
6347
+ *
6348
+ */
6349
+ smallUuid() {
6350
+ if (this.isFastIdStrategy) {
6351
+ this.fastIdStart++;
6352
+ return String(this.fastIdStart);
6353
+ }
6354
+ else if (window.crypto) {
6355
+ return "10000000-1000".replace(/[01]/g, (c) => {
6356
+ const n = Number(c);
6357
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
6358
+ });
6359
+ }
6360
+ else {
6361
+ // mainly for jest and other browsers that do not have the crypto functionality
6362
+ return "xxxxxxxx-xxxx".replace(/[xy]/g, function (c) {
6363
+ var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
6364
+ return v.toString(16);
6365
+ });
6366
+ }
6367
+ }
6368
+ /**
6369
+ * Generates an UUIDV4, has astronomically low chance of collision, but is larger in size than the smallUuid.
6370
+ * This method should be used when you need to avoid collisions at all costs, like the id of a revision.
6371
+ */
6349
6372
  uuidv4() {
6350
6373
  if (this.isFastIdStrategy) {
6351
6374
  this.fastIdStart++;
6352
6375
  return String(this.fastIdStart);
6353
- //@ts-ignore
6354
6376
  }
6355
- else if (window.crypto && window.crypto.getRandomValues) {
6356
- //@ts-ignore
6357
- return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
6377
+ else if (window.crypto) {
6378
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
6379
+ const n = Number(c);
6380
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
6381
+ });
6358
6382
  }
6359
6383
  else {
6360
6384
  // mainly for jest and other browsers that do not have the crypto functionality
6361
6385
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
6362
- var r = (Math.random() * 16) | 0, v = c === "x" ? r : (r & 0x3) | 0x8;
6386
+ var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
6363
6387
  return v.toString(16);
6364
6388
  });
6365
6389
  }
@@ -8338,7 +8362,7 @@
8338
8362
  };
8339
8363
  }
8340
8364
  getPasteTarget(sheetId, target, content, options) {
8341
- const newId = new UuidGenerator().uuidv4();
8365
+ const newId = new UuidGenerator().smallUuid();
8342
8366
  return { zones: [], figureId: newId, sheetId };
8343
8367
  }
8344
8368
  paste(target, clippedContent, options) {
@@ -8504,7 +8528,7 @@
8504
8528
  if (!targetCF && queuedCfs) {
8505
8529
  targetCF = queuedCfs.find((queued) => queued.cf.stopIfTrue === originCF.stopIfTrue && deepEquals(queued.cf.rule, originCF.rule))?.cf;
8506
8530
  }
8507
- return targetCF || { ...originCF, id: this.uuidGenerator.uuidv4(), ranges: [] };
8531
+ return targetCF || { ...originCF, id: this.uuidGenerator.smallUuid(), ranges: [] };
8508
8532
  }
8509
8533
  }
8510
8534
 
@@ -8597,7 +8621,7 @@
8597
8621
  }
8598
8622
  return (targetRule || {
8599
8623
  ...originRule,
8600
- id: newId ? this.uuidGenerator.uuidv4() : originRule.id,
8624
+ id: newId ? this.uuidGenerator.smallUuid() : originRule.id,
8601
8625
  ranges: [],
8602
8626
  });
8603
8627
  }
@@ -8659,7 +8683,7 @@
8659
8683
  };
8660
8684
  }
8661
8685
  getPasteTarget(sheetId, target, content, options) {
8662
- const newId = new UuidGenerator().uuidv4();
8686
+ const newId = new UuidGenerator().smallUuid();
8663
8687
  return { sheetId, zones: [], figureId: newId };
8664
8688
  }
8665
8689
  paste(target, clippedContent, options) {
@@ -9638,6 +9662,9 @@ stores.inject(MyMetaStore, storeInstance);
9638
9662
  const filteredValues = [];
9639
9663
  const filteredLabels = [];
9640
9664
  const labels = [];
9665
+ if (dataset.hidden) {
9666
+ return;
9667
+ }
9641
9668
  for (let i = 0; i < dataset.data.length; i++) {
9642
9669
  if (typeof dataset.data[i] === "number") {
9643
9670
  filteredValues.push(dataset.data[i]);
@@ -11973,6 +12000,25 @@ stores.inject(MyMetaStore, storeInstance);
11973
12000
  isExported: true,
11974
12001
  };
11975
12002
  // -----------------------------------------------------------------------------
12003
+ // LOG
12004
+ // -----------------------------------------------------------------------------
12005
+ const LOG = {
12006
+ description: _t("The logarithm of a number, for a given base."),
12007
+ args: [
12008
+ arg("value (number)", _t("The value for which to calculate the logarithm.")),
12009
+ arg("base (number, default=10)", _t("The base of the logarithm.")),
12010
+ ],
12011
+ compute: function (value, base = { value: 10 }) {
12012
+ const _value = toNumber(value, this.locale);
12013
+ const _base = toNumber(base, this.locale);
12014
+ assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
12015
+ assert(() => _base > 0, _t("The base (%s) must be strictly positive.", _base.toString()));
12016
+ assert(() => _base !== 1, _t("The base must be different from 1."));
12017
+ return Math.log10(_value) / Math.log10(_base);
12018
+ },
12019
+ isExported: true,
12020
+ };
12021
+ // -----------------------------------------------------------------------------
11976
12022
  // MOD
11977
12023
  // -----------------------------------------------------------------------------
11978
12024
  function mod(dividend, divisor) {
@@ -12512,6 +12558,7 @@ stores.inject(MyMetaStore, storeInstance);
12512
12558
  ISODD: ISODD,
12513
12559
  ISO_CEILING: ISO_CEILING,
12514
12560
  LN: LN,
12561
+ LOG: LOG,
12515
12562
  MOD: MOD,
12516
12563
  MUNIT: MUNIT,
12517
12564
  ODD: ODD,
@@ -15061,7 +15108,7 @@ stores.inject(MyMetaStore, storeInstance);
15061
15108
  }
15062
15109
  }
15063
15110
  },
15064
- isExported: true,
15111
+ isExported: false,
15065
15112
  };
15066
15113
  // -----------------------------------------------------------------------------
15067
15114
  // UNIQUE
@@ -28515,17 +28562,15 @@ stores.inject(MyMetaStore, storeInstance);
28515
28562
  plugins: [],
28516
28563
  };
28517
28564
  }
28518
- function getChartLabelFormat(getters, range) {
28565
+ function getChartLabelFormat(getters, range, shouldRemoveFirstLabel) {
28519
28566
  if (!range)
28520
28567
  return undefined;
28521
- const { sheetId, zone: { left, top, bottom }, } = range;
28522
- for (let row = top; row <= bottom; row++) {
28523
- const format = getters.getEvaluatedCell({ sheetId, col: left, row }).format;
28524
- if (format) {
28525
- return format;
28526
- }
28568
+ const { sheetId, zone } = range;
28569
+ const formats = positions(zone).map((position) => getters.getEvaluatedCell({ sheetId, ...position }).format);
28570
+ if (shouldRemoveFirstLabel) {
28571
+ formats.shift();
28527
28572
  }
28528
- return undefined;
28573
+ return formats.find((format) => format !== undefined);
28529
28574
  }
28530
28575
  function getChartLabelValues(getters, dataSets, labelRange) {
28531
28576
  let labels = { values: [], formattedValues: [] };
@@ -28580,10 +28625,8 @@ stores.inject(MyMetaStore, storeInstance);
28580
28625
  function getChartDatasetValues(getters, dataSets) {
28581
28626
  const datasetValues = [];
28582
28627
  for (const [dsIndex, ds] of Object.entries(dataSets)) {
28583
- if (getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left)) {
28584
- continue;
28585
- }
28586
28628
  let label;
28629
+ let hidden = getters.isColHidden(ds.dataRange.sheetId, ds.dataRange.zone.left);
28587
28630
  if (ds.labelCell) {
28588
28631
  const labelRange = ds.labelCell;
28589
28632
  const cell = labelRange
@@ -28610,9 +28653,9 @@ stores.inject(MyMetaStore, storeInstance);
28610
28653
  data.fill(1);
28611
28654
  }
28612
28655
  else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
28613
- continue;
28656
+ hidden = true;
28614
28657
  }
28615
- datasetValues.push({ data, label });
28658
+ datasetValues.push({ data, label, hidden });
28616
28659
  }
28617
28660
  return datasetValues;
28618
28661
  }
@@ -28679,6 +28722,20 @@ stores.inject(MyMetaStore, storeInstance);
28679
28722
  ctx.restore();
28680
28723
  },
28681
28724
  };
28725
+ function getChartJsLegend(fontColor, legend = {}) {
28726
+ return {
28727
+ ...legend,
28728
+ labels: {
28729
+ color: fontColor,
28730
+ filter: (legendItem, data) => {
28731
+ return "datasetIndex" in legendItem
28732
+ ? !data.datasets[legendItem.datasetIndex].hidden
28733
+ : true;
28734
+ },
28735
+ ...legend.labels,
28736
+ },
28737
+ };
28738
+ }
28682
28739
 
28683
28740
  class BarChart extends AbstractChart {
28684
28741
  dataSets;
@@ -28813,9 +28870,7 @@ stores.inject(MyMetaStore, storeInstance);
28813
28870
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
28814
28871
  let labels = labelValues.formattedValues;
28815
28872
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
28816
- if (chart.dataSetsHaveTitle &&
28817
- dataSetsValues[0] &&
28818
- labels.length > dataSetsValues[0].data.length) {
28873
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
28819
28874
  labels.shift();
28820
28875
  }
28821
28876
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -28830,9 +28885,7 @@ stores.inject(MyMetaStore, storeInstance);
28830
28885
  ...localeFormat,
28831
28886
  horizontalChart: chart.horizontal,
28832
28887
  });
28833
- const legend = {
28834
- labels: { color: fontColor },
28835
- };
28888
+ const legend = getChartJsLegend(fontColor);
28836
28889
  if (chart.legendPosition === "none") {
28837
28890
  legend.display = false;
28838
28891
  }
@@ -28896,11 +28949,12 @@ stores.inject(MyMetaStore, storeInstance);
28896
28949
  const colors = getChartColorsGenerator(definition, dataSetsValues.length);
28897
28950
  const trendDatasets = [];
28898
28951
  for (const index in dataSetsValues) {
28899
- const { label, data } = dataSetsValues[index];
28952
+ const { label, data, hidden } = dataSetsValues[index];
28900
28953
  const color = colors.next();
28901
28954
  const dataset = {
28902
28955
  label,
28903
28956
  data,
28957
+ hidden,
28904
28958
  borderColor: definition.background || BACKGROUND_CHART_COLOR,
28905
28959
  borderWidth: definition.stacked ? 1 : 0,
28906
28960
  backgroundColor: color,
@@ -29084,8 +29138,8 @@ stores.inject(MyMetaStore, storeInstance);
29084
29138
  }
29085
29139
  return { labels: newLabels, dataSetsValues: newDatasets };
29086
29140
  }
29087
- function canChartParseLabels(labelRange, getters) {
29088
- return canBeDateChart(labelRange, getters) || canBeLinearChart(labelRange, getters);
29141
+ function canChartParseLabels(chart, getters) {
29142
+ return canBeDateChart(chart, getters) || canBeLinearChart(chart, getters);
29089
29143
  }
29090
29144
  function getChartAxisType(chart, getters) {
29091
29145
  if (isDateChart(chart, getters) && isLuxonTimeAdapterInstalled()) {
@@ -29097,23 +29151,26 @@ stores.inject(MyMetaStore, storeInstance);
29097
29151
  return "category";
29098
29152
  }
29099
29153
  function isDateChart(chart, getters) {
29100
- return !chart.labelsAsText && canBeDateChart(chart.labelRange, getters);
29154
+ return !chart.labelsAsText && canBeDateChart(chart, getters);
29101
29155
  }
29102
29156
  function isLinearChart(chart, getters) {
29103
- return !chart.labelsAsText && canBeLinearChart(chart.labelRange, getters);
29157
+ return !chart.labelsAsText && canBeLinearChart(chart, getters);
29104
29158
  }
29105
- function canBeDateChart(labelRange, getters) {
29106
- if (!labelRange || !canBeLinearChart(labelRange, getters)) {
29159
+ function canBeDateChart(chart, getters) {
29160
+ if (!chart.labelRange || !canBeLinearChart(chart, getters)) {
29107
29161
  return false;
29108
29162
  }
29109
- const labelFormat = getChartLabelFormat(getters, labelRange);
29163
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle));
29110
29164
  return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
29111
29165
  }
29112
- function canBeLinearChart(labelRange, getters) {
29113
- if (!labelRange) {
29166
+ function canBeLinearChart(chart, getters) {
29167
+ if (!chart.labelRange) {
29114
29168
  return false;
29115
29169
  }
29116
- const labels = getters.getRangeValues(labelRange);
29170
+ const labels = getters.getRangeValues(chart.labelRange);
29171
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
29172
+ labels.shift();
29173
+ }
29117
29174
  if (labels.some((label) => isNaN(Number(label)) && label)) {
29118
29175
  return false;
29119
29176
  }
@@ -29141,6 +29198,9 @@ stores.inject(MyMetaStore, storeInstance);
29141
29198
  const filteredLabels = [];
29142
29199
  const labels = [];
29143
29200
  const datasetLength = dataset.data.length;
29201
+ if (dataset.hidden) {
29202
+ return;
29203
+ }
29144
29204
  if (datasetLength < 2) {
29145
29205
  return;
29146
29206
  }
@@ -29197,9 +29257,8 @@ stores.inject(MyMetaStore, storeInstance);
29197
29257
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
29198
29258
  let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
29199
29259
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
29200
- if (chart.dataSetsHaveTitle &&
29201
- dataSetsValues[0] &&
29202
- labels.length > dataSetsValues[0].data.length) {
29260
+ const removeFirstLabel = shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle);
29261
+ if (removeFirstLabel) {
29203
29262
  labels.shift();
29204
29263
  }
29205
29264
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -29215,9 +29274,8 @@ stores.inject(MyMetaStore, storeInstance);
29215
29274
  const options = { format: dataSetFormat, locale, truncateLabels };
29216
29275
  const fontColor = chartFontColor(chart.background);
29217
29276
  const config = getDefaultChartJsRuntime(chart, labels, fontColor, options);
29218
- const legend = {
29277
+ const legend = getChartJsLegend(fontColor, {
29219
29278
  labels: {
29220
- color: fontColor,
29221
29279
  generateLabels(chart) {
29222
29280
  // color the legend labels with the dataset color, without any transparency
29223
29281
  const { data } = chart;
@@ -29228,7 +29286,7 @@ stores.inject(MyMetaStore, storeInstance);
29228
29286
  return labels;
29229
29287
  },
29230
29288
  },
29231
- };
29289
+ });
29232
29290
  if (chart.legendPosition === "none") {
29233
29291
  legend.display = false;
29234
29292
  }
@@ -29289,12 +29347,7 @@ stores.inject(MyMetaStore, storeInstance);
29289
29347
  background: chart.background,
29290
29348
  callback: formatTickValue(options),
29291
29349
  };
29292
- if (chart.dataSetsHaveTitle &&
29293
- dataSetsValues[0] &&
29294
- labels.length > dataSetsValues[0].data.length) {
29295
- labels.shift();
29296
- }
29297
- const labelFormat = getChartLabelFormat(getters, chart.labelRange);
29350
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, removeFirstLabel);
29298
29351
  if (axisType === "time") {
29299
29352
  const axis = {
29300
29353
  type: "time",
@@ -29333,7 +29386,7 @@ stores.inject(MyMetaStore, storeInstance);
29333
29386
  const cumulative = "cumulative" in chart ? chart.cumulative : false;
29334
29387
  const definition = chart.getDefinition();
29335
29388
  const colors = getChartColorsGenerator(definition, dataSetsValues.length);
29336
- for (let [index, { label, data }] of dataSetsValues.entries()) {
29389
+ for (let [index, { label, data, hidden }] of dataSetsValues.entries()) {
29337
29390
  const color = colors.next();
29338
29391
  let backgroundRGBA = colorToRGBA(color);
29339
29392
  if (areaChart) {
@@ -29357,6 +29410,7 @@ stores.inject(MyMetaStore, storeInstance);
29357
29410
  const dataset = {
29358
29411
  label,
29359
29412
  data,
29413
+ hidden,
29360
29414
  tension: 0, // 0 -> render straight lines, which is much faster
29361
29415
  borderColor: color,
29362
29416
  backgroundColor,
@@ -29552,9 +29606,7 @@ stores.inject(MyMetaStore, storeInstance);
29552
29606
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
29553
29607
  let labels = labelValues.formattedValues;
29554
29608
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
29555
- if (chart.dataSetsHaveTitle &&
29556
- dataSetsValues[0] &&
29557
- labels.length > dataSetsValues[0].data.length) {
29609
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
29558
29610
  labels.shift();
29559
29611
  }
29560
29612
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -29564,9 +29616,7 @@ stores.inject(MyMetaStore, storeInstance);
29564
29616
  const localeFormat = { format: mainDataSetFormat, locale };
29565
29617
  const fontColor = chartFontColor(chart.background);
29566
29618
  const config = getDefaultChartJsRuntime(chart, labels, fontColor, localeFormat);
29567
- const legend = {
29568
- labels: { color: fontColor },
29569
- };
29619
+ const legend = getChartJsLegend(fontColor);
29570
29620
  if (chart.legendPosition === "none") {
29571
29621
  legend.display = false;
29572
29622
  }
@@ -29630,13 +29680,14 @@ stores.inject(MyMetaStore, storeInstance);
29630
29680
  const colors = getChartColorsGenerator(definition, dataSetsValues.length);
29631
29681
  let maxLength = 0;
29632
29682
  const trendDatasets = [];
29633
- for (let [index, { label, data }] of dataSetsValues.entries()) {
29683
+ for (let [index, { label, data, hidden }] of dataSetsValues.entries()) {
29634
29684
  const design = definition.dataSets[index];
29635
29685
  const color = colors.next();
29636
29686
  const type = design?.type ?? "line";
29637
29687
  const dataset = {
29638
29688
  label: design?.label ?? label,
29639
29689
  data,
29690
+ hidden,
29640
29691
  borderColor: color,
29641
29692
  backgroundColor: color,
29642
29693
  yAxisID: design?.yAxisId ?? "y",
@@ -30244,10 +30295,8 @@ stores.inject(MyMetaStore, storeInstance);
30244
30295
  function createPieChartRuntime(chart, getters) {
30245
30296
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
30246
30297
  let labels = labelValues.formattedValues;
30247
- let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
30248
- if (chart.dataSetsHaveTitle &&
30249
- dataSetsValues[0] &&
30250
- labels.length > dataSetsValues[0].data.length) {
30298
+ let dataSetsValues = getChartDatasetValues(getters, chart.dataSets).filter((dataSet) => !dataSet.hidden);
30299
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
30251
30300
  labels.shift();
30252
30301
  }
30253
30302
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -30264,7 +30313,7 @@ stores.inject(MyMetaStore, storeInstance);
30264
30313
  const dataset = {
30265
30314
  label,
30266
30315
  data,
30267
- borderColor: BACKGROUND_CHART_COLOR,
30316
+ borderColor: chart.background || "#FFFFFF",
30268
30317
  backgroundColor,
30269
30318
  hoverOffset: 30,
30270
30319
  };
@@ -30393,8 +30442,9 @@ stores.inject(MyMetaStore, storeInstance);
30393
30442
  const barDef = { ...chart.getDefinition(), type: "bar" };
30394
30443
  const barChart = new BarChart(barDef, chart.sheetId, getters);
30395
30444
  const barRuntime = createBarChartRuntime(barChart, getters);
30445
+ // align design with filtered datasets
30396
30446
  const config = barRuntime.chartJsConfig;
30397
- let datasets = config.data?.datasets;
30447
+ let datasets = config.data?.datasets.filter((dataSet) => !dataSet.hidden);
30398
30448
  if (datasets && datasets[0]) {
30399
30449
  datasets[0].data = datasets[0].data.map((value) => (value > 0 ? value : 0));
30400
30450
  }
@@ -30791,10 +30841,8 @@ stores.inject(MyMetaStore, storeInstance);
30791
30841
  function createWaterfallChartRuntime(chart, getters) {
30792
30842
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
30793
30843
  let labels = labelValues.formattedValues;
30794
- let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
30795
- if (chart.dataSetsHaveTitle &&
30796
- dataSetsValues[0] &&
30797
- labels.length > dataSetsValues[0].data.length) {
30844
+ let dataSetsValues = getChartDatasetValues(getters, chart.dataSets).filter((ds) => !ds.hidden);
30845
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
30798
30846
  labels.shift();
30799
30847
  }
30800
30848
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -32290,7 +32338,7 @@ stores.inject(MyMetaStore, storeInstance);
32290
32338
  const deleteSheet = {
32291
32339
  name: _t("Delete"),
32292
32340
  isVisible: (env) => {
32293
- return env.model.getters.getSheetIds().length > 1;
32341
+ return env.model.getters.getVisibleSheetIds().length > 1;
32294
32342
  },
32295
32343
  execute: (env) => env.askConfirmation(_t("Are you sure you want to delete this sheet?"), () => {
32296
32344
  env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
@@ -32301,7 +32349,7 @@ stores.inject(MyMetaStore, storeInstance);
32301
32349
  name: _t("Duplicate"),
32302
32350
  execute: (env) => {
32303
32351
  const sheetIdFrom = env.model.getters.getActiveSheetId();
32304
- const sheetIdTo = env.model.uuidGenerator.uuidv4();
32352
+ const sheetIdTo = env.model.uuidGenerator.smallUuid();
32305
32353
  env.model.dispatch("DUPLICATE_SHEET", {
32306
32354
  sheetId: sheetIdFrom,
32307
32355
  sheetIdTo,
@@ -32928,20 +32976,21 @@ stores.inject(MyMetaStore, storeInstance);
32928
32976
  }
32929
32977
  // Only display legend for several datasets.
32930
32978
  const newLegendPos = dataSetZone.right === dataSetZone.left ? "none" : "top";
32931
- const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
32932
- if (canChartParseLabels(labelRange, getters)) {
32933
- return {
32934
- title: {},
32935
- dataSets,
32936
- labelsAsText: false,
32937
- stacked: false,
32938
- aggregated: false,
32939
- cumulative: false,
32940
- labelRange: labelRangeXc,
32941
- type: "line",
32942
- dataSetsHaveTitle,
32943
- legendPosition: newLegendPos,
32944
- };
32979
+ const lineChartDefinition = {
32980
+ title: {},
32981
+ dataSets,
32982
+ labelsAsText: false,
32983
+ stacked: false,
32984
+ aggregated: false,
32985
+ cumulative: false,
32986
+ labelRange: labelRangeXc,
32987
+ type: "line",
32988
+ dataSetsHaveTitle,
32989
+ legendPosition: newLegendPos,
32990
+ };
32991
+ const chart = new LineChart(lineChartDefinition, sheetId, getters);
32992
+ if (canChartParseLabels(chart, getters)) {
32993
+ return lineChartDefinition;
32945
32994
  }
32946
32995
  const _dataSets = createDataSets(getters, dataSets, sheetId, dataSetsHaveTitle);
32947
32996
  if (singleColumn &&
@@ -33309,7 +33358,7 @@ stores.inject(MyMetaStore, storeInstance);
33309
33358
  //------------------------------------------------------------------------------
33310
33359
  const CREATE_CHART = (env) => {
33311
33360
  const getters = env.model.getters;
33312
- const id = env.model.uuidGenerator.uuidv4();
33361
+ const id = env.model.uuidGenerator.smallUuid();
33313
33362
  const sheetId = getters.getActiveSheetId();
33314
33363
  if (getZoneArea(env.model.getters.getSelectedZone()) === 1) {
33315
33364
  env.model.selection.selectTableAroundSelection();
@@ -33332,8 +33381,8 @@ stores.inject(MyMetaStore, storeInstance);
33332
33381
  // Pivots
33333
33382
  //------------------------------------------------------------------------------
33334
33383
  const CREATE_PIVOT = (env) => {
33335
- const pivotId = env.model.uuidGenerator.uuidv4();
33336
- const newSheetId = env.model.uuidGenerator.uuidv4();
33384
+ const pivotId = env.model.uuidGenerator.smallUuid();
33385
+ const newSheetId = env.model.uuidGenerator.smallUuid();
33337
33386
  const result = env.model.dispatch("INSERT_NEW_PIVOT", { pivotId, newSheetId });
33338
33387
  if (result.isSuccessful) {
33339
33388
  env.openSidePanel("PivotSidePanel", { pivotId });
@@ -33392,7 +33441,7 @@ stores.inject(MyMetaStore, storeInstance);
33392
33441
  const CREATE_IMAGE = async (env) => {
33393
33442
  if (env.imageProvider) {
33394
33443
  const sheetId = env.model.getters.getActiveSheetId();
33395
- const figureId = env.model.uuidGenerator.uuidv4();
33444
+ const figureId = env.model.uuidGenerator.smallUuid();
33396
33445
  const image = await requestImage(env);
33397
33446
  if (!image) {
33398
33447
  throw new Error("No image provider was given to the environment");
@@ -33945,7 +33994,7 @@ stores.inject(MyMetaStore, storeInstance);
33945
33994
  ranges,
33946
33995
  sheetId,
33947
33996
  rule: {
33948
- id: env.model.uuidGenerator.uuidv4(),
33997
+ id: env.model.uuidGenerator.smallUuid(),
33949
33998
  criterion: {
33950
33999
  type: "isBoolean",
33951
34000
  values: [],
@@ -33961,7 +34010,7 @@ stores.inject(MyMetaStore, storeInstance);
33961
34010
  const zones = env.model.getters.getSelectedZones();
33962
34011
  const sheetId = env.model.getters.getActiveSheetId();
33963
34012
  const ranges = zones.map((zone) => env.model.getters.getRangeDataFromZone(sheetId, zone));
33964
- const ruleID = env.model.uuidGenerator.uuidv4();
34013
+ const ruleID = env.model.uuidGenerator.smallUuid();
33965
34014
  env.model.dispatch("ADD_DATA_VALIDATION_RULE", {
33966
34015
  ranges,
33967
34016
  sheetId,
@@ -33992,7 +34041,7 @@ stores.inject(MyMetaStore, storeInstance);
33992
34041
  execute: (env) => {
33993
34042
  const activeSheetId = env.model.getters.getActiveSheetId();
33994
34043
  const position = env.model.getters.getSheetIds().indexOf(activeSheetId) + 1;
33995
- const sheetId = env.model.uuidGenerator.uuidv4();
34044
+ const sheetId = env.model.uuidGenerator.smallUuid();
33996
34045
  env.model.dispatch("CREATE_SHEET", { sheetId, position });
33997
34046
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
33998
34047
  },
@@ -37987,7 +38036,7 @@ stores.inject(MyMetaStore, storeInstance);
37987
38036
  get canTreatLabelsAsText() {
37988
38037
  const chart = this.env.model.getters.getChart(this.props.figureId);
37989
38038
  if (chart && chart instanceof LineChart) {
37990
- return canChartParseLabels(chart.labelRange, this.env.model.getters);
38039
+ return canChartParseLabels(chart, this.env.model.getters);
37991
38040
  }
37992
38041
  return false;
37993
38042
  }
@@ -38056,7 +38105,7 @@ stores.inject(MyMetaStore, storeInstance);
38056
38105
  get canTreatLabelsAsText() {
38057
38106
  const chart = this.env.model.getters.getChart(this.props.figureId);
38058
38107
  if (chart && chart instanceof ScatterChart) {
38059
- return canChartParseLabels(chart.labelRange, this.env.model.getters);
38108
+ return canChartParseLabels(chart, this.env.model.getters);
38060
38109
  }
38061
38110
  return false;
38062
38111
  }
@@ -39871,7 +39920,7 @@ stores.inject(MyMetaStore, storeInstance);
39871
39920
  state;
39872
39921
  setup() {
39873
39922
  const cf = this.props.editedCf || {
39874
- id: this.env.model.uuidGenerator.uuidv4(),
39923
+ id: this.env.model.uuidGenerator.smallUuid(),
39875
39924
  ranges: this.env.model.getters
39876
39925
  .getSelectedZones()
39877
39926
  .map((zone) => this.env.model.getters.zoneToXC(this.env.model.getters.getActiveSheetId(), zone)),
@@ -41467,7 +41516,7 @@ stores.inject(MyMetaStore, storeInstance);
41467
41516
  .getSelectedZones()
41468
41517
  .map((zone) => zoneToXc(this.env.model.getters.getUnboundedZone(sheetId, zone)));
41469
41518
  return {
41470
- id: this.env.model.uuidGenerator.uuidv4(),
41519
+ id: this.env.model.uuidGenerator.smallUuid(),
41471
41520
  criterion: { type: "textContains", values: [""] },
41472
41521
  ranges,
41473
41522
  };
@@ -42986,8 +43035,8 @@ stores.inject(MyMetaStore, storeInstance);
42986
43035
  return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
42987
43036
  }
42988
43037
  duplicatePivot() {
42989
- const newPivotId = this.env.model.uuidGenerator.uuidv4();
42990
- const newSheetId = this.env.model.uuidGenerator.uuidv4();
43038
+ const newPivotId = this.env.model.uuidGenerator.smallUuid();
43039
+ const newSheetId = this.env.model.uuidGenerator.smallUuid();
42991
43040
  const result = this.env.model.dispatch("DUPLICATE_PIVOT_IN_NEW_SHEET", {
42992
43041
  pivotId: this.props.pivotId,
42993
43042
  newPivotId,
@@ -45552,7 +45601,7 @@ stores.inject(MyMetaStore, storeInstance);
45552
45601
  this.state.selectedTemplateName = templateName;
45553
45602
  }
45554
45603
  onConfirm() {
45555
- const tableStyleId = this.props.styleId || this.env.model.uuidGenerator.uuidv4();
45604
+ const tableStyleId = this.props.styleId || this.env.model.uuidGenerator.smallUuid();
45556
45605
  this.env.model.dispatch("CREATE_TABLE_STYLE", {
45557
45606
  tableStyleId,
45558
45607
  tableStyleName: this.state.styleName,
@@ -51148,6 +51197,10 @@ stores.inject(MyMetaStore, storeInstance);
51148
51197
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
51149
51198
  case "CLEAR_CELL":
51150
51199
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
51200
+ case "UPDATE_CELL_POSITION":
51201
+ return !cmd.cellId || this.cells[cmd.sheetId]?.[cmd.cellId]
51202
+ ? "Success" /* CommandResult.Success */
51203
+ : "InvalidCellId" /* CommandResult.InvalidCellId */;
51151
51204
  default:
51152
51205
  return "Success" /* CommandResult.Success */;
51153
51206
  }
@@ -51192,6 +51245,9 @@ stores.inject(MyMetaStore, storeInstance);
51192
51245
  case "DELETE_CONTENT":
51193
51246
  this.clearZones(cmd.sheetId, cmd.target);
51194
51247
  break;
51248
+ case "DELETE_SHEET": {
51249
+ this.history.update("cells", cmd.sheetId, undefined);
51250
+ }
51195
51251
  }
51196
51252
  }
51197
51253
  clearZones(sheetId, zones) {
@@ -52413,8 +52469,14 @@ stores.inject(MyMetaStore, storeInstance);
52413
52469
  allowDispatch(cmd) {
52414
52470
  switch (cmd.type) {
52415
52471
  case "ADD_DATA_VALIDATION_RULE":
52472
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
52473
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
52474
+ }
52416
52475
  return this.checkValidations(cmd, this.chainValidations(this.checkEmptyRange, this.checkCriterionTypeIsValid, this.checkCriterionHasValidNumberOfValues, this.checkCriterionValuesAreValid));
52417
52476
  case "REMOVE_DATA_VALIDATION_RULE":
52477
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
52478
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
52479
+ }
52418
52480
  if (!this.rules[cmd.sheetId].find((rule) => rule.id === cmd.id)) {
52419
52481
  return "UnknownDataValidationRule" /* CommandResult.UnknownDataValidationRule */;
52420
52482
  }
@@ -52634,6 +52696,7 @@ stores.inject(MyMetaStore, storeInstance);
52634
52696
  class FigurePlugin extends CorePlugin {
52635
52697
  static getters = ["getFigures", "getFigure", "getFigureSheetId"];
52636
52698
  figures = {};
52699
+ insertionOrders = []; // TODO use a list in master
52637
52700
  // ---------------------------------------------------------------------------
52638
52701
  // Command Handling
52639
52702
  // ---------------------------------------------------------------------------
@@ -52736,11 +52799,14 @@ stores.inject(MyMetaStore, storeInstance);
52736
52799
  }
52737
52800
  addFigure(figure, sheetId) {
52738
52801
  this.history.update("figures", sheetId, figure.id, figure);
52802
+ this.history.update("insertionOrders", this.insertionOrders.length, figure.id);
52739
52803
  }
52740
52804
  deleteSheet(sheetId) {
52805
+ this.history.update("insertionOrders", this.insertionOrders.filter((id) => !this.figures[sheetId]?.[id]));
52741
52806
  this.history.update("figures", sheetId, undefined);
52742
52807
  }
52743
52808
  removeFigure(id, sheetId) {
52809
+ this.history.update("insertionOrders", this.insertionOrders.filter((figureId) => figureId !== id));
52744
52810
  this.history.update("figures", sheetId, id, undefined);
52745
52811
  }
52746
52812
  checkFigureExists(sheetId, figureId) {
@@ -52759,7 +52825,14 @@ stores.inject(MyMetaStore, storeInstance);
52759
52825
  // Getters
52760
52826
  // ---------------------------------------------------------------------------
52761
52827
  getFigures(sheetId) {
52762
- return Object.values(this.figures[sheetId] || {}).filter(isDefined);
52828
+ const figures = [];
52829
+ for (const figureId of this.insertionOrders) {
52830
+ const figure = this.figures[sheetId]?.[figureId];
52831
+ if (figure) {
52832
+ figures.push(figure);
52833
+ }
52834
+ }
52835
+ return figures;
52763
52836
  }
52764
52837
  getFigure(sheetId, figureId) {
52765
52838
  return this.figures[sheetId]?.[figureId];
@@ -52772,11 +52845,9 @@ stores.inject(MyMetaStore, storeInstance);
52772
52845
  // ---------------------------------------------------------------------------
52773
52846
  import(data) {
52774
52847
  for (let sheet of data.sheets) {
52775
- const figures = {};
52776
- sheet.figures.forEach((figure) => {
52777
- figures[figure.id] = figure;
52778
- });
52779
- this.figures[sheet.id] = figures;
52848
+ for (const figure of sheet.figures) {
52849
+ this.addFigure(figure, sheet.id);
52850
+ }
52780
52851
  }
52781
52852
  }
52782
52853
  export(data) {
@@ -54202,6 +54273,9 @@ stores.inject(MyMetaStore, storeInstance);
54202
54273
  case "CREATE_SHEET": {
54203
54274
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
54204
54275
  }
54276
+ case "DUPLICATE_SHEET": {
54277
+ return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
54278
+ }
54205
54279
  case "MOVE_SHEET":
54206
54280
  try {
54207
54281
  const currentIndex = this.orderedSheetIds.findIndex((id) => id === cmd.sheetId);
@@ -54218,7 +54292,7 @@ stores.inject(MyMetaStore, storeInstance);
54218
54292
  ? "Success" /* CommandResult.Success */
54219
54293
  : "InvalidColor" /* CommandResult.InvalidColor */;
54220
54294
  case "DELETE_SHEET":
54221
- return this.orderedSheetIds.length > 1
54295
+ return this.getVisibleSheetIds().length > 1
54222
54296
  ? "Success" /* CommandResult.Success */
54223
54297
  : "NotEnoughSheets" /* CommandResult.NotEnoughSheets */;
54224
54298
  case "ADD_COLUMNS_ROWS":
@@ -55013,6 +55087,10 @@ stores.inject(MyMetaStore, storeInstance);
55013
55087
  checkZonesAreInSheet(cmd) {
55014
55088
  if (!("sheetId" in cmd))
55015
55089
  return "Success" /* CommandResult.Success */;
55090
+ if ("ranges" in cmd &&
55091
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
55092
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
55093
+ }
55016
55094
  return this.checkZonesExistInSheet(cmd.sheetId, this.getCommandZones(cmd));
55017
55095
  }
55018
55096
  }
@@ -55020,6 +55098,7 @@ stores.inject(MyMetaStore, storeInstance);
55020
55098
  class TablePlugin extends CorePlugin {
55021
55099
  static getters = ["getCoreTable", "getCoreTables", "getCoreTableMatchingTopLeft"];
55022
55100
  tables = {};
55101
+ insertionOrders = {};
55023
55102
  adaptRanges(applyChange, sheetId) {
55024
55103
  const sheetIds = sheetId ? [sheetId] : this.getters.getSheetIds();
55025
55104
  for (const sheetId of sheetIds) {
@@ -55031,6 +55110,9 @@ stores.inject(MyMetaStore, storeInstance);
55031
55110
  allowDispatch(cmd) {
55032
55111
  switch (cmd.type) {
55033
55112
  case "CREATE_TABLE":
55113
+ if (cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId) || rangeData._sheetId !== cmd.sheetId)) {
55114
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
55115
+ }
55034
55116
  const zones = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData).zone);
55035
55117
  if (!areZonesContinuous(zones)) {
55036
55118
  return "NonContinuousTargets" /* CommandResult.NonContinuousTargets */;
@@ -55061,11 +55143,13 @@ stores.inject(MyMetaStore, storeInstance);
55061
55143
  switch (cmd.type) {
55062
55144
  case "CREATE_SHEET":
55063
55145
  this.history.update("tables", cmd.sheetId, {});
55146
+ this.history.update("insertionOrders", cmd.sheetId, []);
55064
55147
  break;
55065
55148
  case "DELETE_SHEET": {
55066
55149
  const tables = { ...this.tables };
55067
55150
  delete tables[cmd.sheetId];
55068
55151
  this.history.update("tables", tables);
55152
+ this.history.update("insertionOrders", cmd.sheetId, undefined);
55069
55153
  break;
55070
55154
  }
55071
55155
  case "DUPLICATE_SHEET": {
@@ -55077,6 +55161,9 @@ stores.inject(MyMetaStore, storeInstance);
55077
55161
  : this.copyStaticTableForSheet(cmd.sheetIdTo, table);
55078
55162
  }
55079
55163
  this.history.update("tables", cmd.sheetIdTo, newTables);
55164
+ this.history.update("insertionOrders", cmd.sheetIdTo, [
55165
+ ...(this.insertionOrders[cmd.sheetId] ?? []),
55166
+ ]);
55080
55167
  break;
55081
55168
  }
55082
55169
  case "CREATE_TABLE": {
@@ -55084,12 +55171,16 @@ stores.inject(MyMetaStore, storeInstance);
55084
55171
  const union = this.getters.getRangesUnion(ranges);
55085
55172
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
55086
55173
  this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
55087
- const id = this.uuidGenerator.uuidv4();
55174
+ const id = this.uuidGenerator.smallUuid();
55088
55175
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
55089
55176
  const newTable = cmd.tableType === "dynamic"
55090
55177
  ? this.createDynamicTable(id, union, config)
55091
55178
  : this.createStaticTable(id, cmd.tableType, union, config);
55092
55179
  this.history.update("tables", cmd.sheetId, newTable.id, newTable);
55180
+ this.history.update("insertionOrders", cmd.sheetId, [
55181
+ ...(this.insertionOrders[cmd.sheetId] ?? []),
55182
+ newTable.id,
55183
+ ]);
55093
55184
  break;
55094
55185
  }
55095
55186
  case "REMOVE_TABLE": {
@@ -55100,6 +55191,7 @@ stores.inject(MyMetaStore, storeInstance);
55100
55191
  }
55101
55192
  }
55102
55193
  this.history.update("tables", cmd.sheetId, tables);
55194
+ this.history.update("insertionOrders", cmd.sheetId, this.insertionOrders[cmd.sheetId]?.filter((id) => id in tables));
55103
55195
  break;
55104
55196
  }
55105
55197
  case "UPDATE_TABLE": {
@@ -55135,7 +55227,14 @@ stores.inject(MyMetaStore, storeInstance);
55135
55227
  }
55136
55228
  }
55137
55229
  getCoreTables(sheetId) {
55138
- return this.tables[sheetId] ? Object.values(this.tables[sheetId]).filter(isDefined) : [];
55230
+ const tables = [];
55231
+ for (const tableId of this.insertionOrders[sheetId] || []) {
55232
+ const table = this.tables[sheetId][tableId];
55233
+ if (table) {
55234
+ tables.push(table);
55235
+ }
55236
+ }
55237
+ return tables;
55139
55238
  }
55140
55239
  getCoreTable({ sheetId, col, row }) {
55141
55240
  return this.getCoreTables(sheetId).find((table) => isInside(col, row, table.range.zone));
@@ -55237,7 +55336,7 @@ stores.inject(MyMetaStore, storeInstance);
55237
55336
  filters = [];
55238
55337
  for (const i of range(zone.left, zone.right + 1)) {
55239
55338
  const filterZone = { ...zone, left: i, right: i };
55240
- const uid = this.uuidGenerator.uuidv4();
55339
+ const uid = this.uuidGenerator.smallUuid();
55241
55340
  filters.push(this.createFilterFromZone(uid, tableRange.sheetId, filterZone, config));
55242
55341
  }
55243
55342
  }
@@ -55302,7 +55401,7 @@ stores.inject(MyMetaStore, storeInstance);
55302
55401
  ? table.filters.find((f) => f.col === i)
55303
55402
  : undefined;
55304
55403
  const filterZone = { ...tableZone, left: i, right: i };
55305
- const filterId = oldFilter?.id || this.uuidGenerator.uuidv4();
55404
+ const filterId = oldFilter?.id || this.uuidGenerator.smallUuid();
55306
55405
  filters.push(this.createFilterFromZone(filterId, tableRange.sheetId, filterZone, config));
55307
55406
  }
55308
55407
  }
@@ -55403,7 +55502,7 @@ stores.inject(MyMetaStore, storeInstance);
55403
55502
  if (filters.length < zoneToDimension(tableZone).numberOfCols) {
55404
55503
  for (let col = tableZone.left; col <= tableZone.right; col++) {
55405
55504
  if (!filters.find((filter) => filter.col === col)) {
55406
- const uid = this.uuidGenerator.uuidv4();
55505
+ const uid = this.uuidGenerator.smallUuid();
55407
55506
  const filterZone = { ...tableZone, left: col, right: col };
55408
55507
  filters.push(this.createFilterFromZone(uid, sheetId, filterZone, table.config));
55409
55508
  }
@@ -55418,6 +55517,7 @@ stores.inject(MyMetaStore, storeInstance);
55418
55517
  // ---------------------------------------------------------------------------
55419
55518
  import(data) {
55420
55519
  for (const sheet of data.sheets) {
55520
+ const tableIds = [];
55421
55521
  for (const tableData of sheet.tables || []) {
55422
55522
  const uuid = this.uuidGenerator.uuidv4();
55423
55523
  const tableConfig = tableData.config || DEFAULT_TABLE_CONFIG;
@@ -55427,7 +55527,9 @@ stores.inject(MyMetaStore, storeInstance);
55427
55527
  ? this.createDynamicTable(uuid, range, tableConfig)
55428
55528
  : this.createStaticTable(uuid, tableType, range, tableConfig);
55429
55529
  this.history.update("tables", sheet.id, table.id, table);
55530
+ tableIds.push(table.id);
55430
55531
  }
55532
+ this.history.update("insertionOrders", sheet.id, tableIds);
55431
55533
  }
55432
55534
  }
55433
55535
  export(data) {
@@ -55467,7 +55569,10 @@ stores.inject(MyMetaStore, storeInstance);
55467
55569
  allowDispatch(cmd) {
55468
55570
  switch (cmd.type) {
55469
55571
  case "GROUP_HEADERS": {
55470
- const { start, end } = cmd;
55572
+ const { start, end, sheetId } = cmd;
55573
+ if (!this.getters.tryGetSheet(sheetId)) {
55574
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
55575
+ }
55471
55576
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
55472
55577
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
55473
55578
  }
@@ -55480,7 +55585,10 @@ stores.inject(MyMetaStore, storeInstance);
55480
55585
  break;
55481
55586
  }
55482
55587
  case "UNGROUP_HEADERS": {
55483
- const { start, end } = cmd;
55588
+ const { start, end, sheetId } = cmd;
55589
+ if (!this.getters.tryGetSheet(sheetId)) {
55590
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
55591
+ }
55484
55592
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
55485
55593
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
55486
55594
  }
@@ -55491,6 +55599,9 @@ stores.inject(MyMetaStore, storeInstance);
55491
55599
  }
55492
55600
  case "UNFOLD_HEADER_GROUP":
55493
55601
  case "FOLD_HEADER_GROUP":
55602
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
55603
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
55604
+ }
55494
55605
  const group = this.findGroupWithStartEnd(cmd.sheetId, cmd.dimension, cmd.start, cmd.end);
55495
55606
  if (!group) {
55496
55607
  return "UnknownHeaderGroup" /* CommandResult.UnknownHeaderGroup */;
@@ -55891,6 +56002,9 @@ stores.inject(MyMetaStore, storeInstance);
55891
56002
  return this.checkDuplicatedMeasureIds(cmd.pivot);
55892
56003
  }
55893
56004
  case "UPDATE_PIVOT": {
56005
+ if (!(cmd.pivotId in this.pivots)) {
56006
+ return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
56007
+ }
55894
56008
  if (deepEquals(cmd.pivot, this.pivots[cmd.pivotId]?.definition)) {
55895
56009
  return "NoChanges" /* CommandResult.NoChanges */;
55896
56010
  }
@@ -55907,6 +56021,8 @@ stores.inject(MyMetaStore, storeInstance);
55907
56021
  return "EmptyName" /* CommandResult.EmptyName */;
55908
56022
  }
55909
56023
  break;
56024
+ case "REMOVE_PIVOT":
56025
+ case "DUPLICATE_PIVOT":
55910
56026
  case "INSERT_PIVOT": {
55911
56027
  if (!(cmd.pivotId in this.pivots)) {
55912
56028
  return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
@@ -55956,7 +56072,7 @@ stores.inject(MyMetaStore, storeInstance);
55956
56072
  break;
55957
56073
  }
55958
56074
  case "UPDATE_PIVOT": {
55959
- this.history.update("pivots", cmd.pivotId, "definition", cmd.pivot);
56075
+ this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
55960
56076
  this.compileCalculatedMeasures(cmd.pivot.measures);
55961
56077
  break;
55962
56078
  }
@@ -56027,7 +56143,7 @@ stores.inject(MyMetaStore, storeInstance);
56027
56143
  // Private
56028
56144
  // -------------------------------------------------------------------------
56029
56145
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
56030
- this.history.update("pivots", pivotId, { definition: pivot, formulaId });
56146
+ this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
56031
56147
  this.compileCalculatedMeasures(pivot.measures);
56032
56148
  this.history.update("formulaIds", formulaId, pivotId);
56033
56149
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
@@ -60959,6 +61075,9 @@ stores.inject(MyMetaStore, storeInstance);
60959
61075
  };
60960
61076
  }
60961
61077
  function createSheetTransformation(toTransform, executed) {
61078
+ if (toTransform.sheetId === executed.sheetId) {
61079
+ toTransform = { ...toTransform, sheetId: `${toTransform.sheetId}~` };
61080
+ }
60962
61081
  if (toTransform.name === executed.name) {
60963
61082
  return {
60964
61083
  ...toTransform,
@@ -61611,21 +61730,14 @@ stores.inject(MyMetaStore, storeInstance);
61611
61730
  if (!message)
61612
61731
  return;
61613
61732
  if (message.type === "REMOTE_REVISION") {
61614
- const revision = this.revisions.get(message.nextRevisionId);
61733
+ let revision = this.revisions.get(message.nextRevisionId);
61615
61734
  if (revision.commands.length === 0) {
61616
61735
  /**
61617
- * The command is empty, we have to drop all the next local revisions
61736
+ * The command is empty, we have to rebase all the next local revisions
61618
61737
  * to avoid issues with undo/redo
61619
61738
  */
61620
- this.revisions.drop(revision.id);
61621
- const revisionIds = this.pendingMessages
61622
- .filter((message) => message.type === "REMOTE_REVISION")
61623
- .map((message) => message.nextRevisionId);
61624
- this.trigger("pending-revisions-dropped", { revisionIds });
61625
- this.waitingAck = false;
61626
- this.waitingUndoRedoAck = false;
61627
- this.pendingMessages = [];
61628
- return;
61739
+ this.revisions.rebase(revision.id);
61740
+ revision = this.revisions.get(message.nextRevisionId);
61629
61741
  }
61630
61742
  message = {
61631
61743
  ...message,
@@ -61649,7 +61761,6 @@ stores.inject(MyMetaStore, storeInstance);
61649
61761
  switch (message.type) {
61650
61762
  case "REMOTE_REVISION":
61651
61763
  case "REVISION_REDONE":
61652
- case "REVISION_UNDONE":
61653
61764
  case "SNAPSHOT_CREATED":
61654
61765
  this.waitingAck = false;
61655
61766
  this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
@@ -61658,6 +61769,25 @@ stores.inject(MyMetaStore, storeInstance);
61658
61769
  this.lastRevisionMessage = message;
61659
61770
  this.sendPendingMessage();
61660
61771
  break;
61772
+ case "REVISION_UNDONE": {
61773
+ this.waitingAck = false;
61774
+ this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
61775
+ const firstPendingRevisionId = this.pendingMessages.findIndex((message) => message.type === "REMOTE_REVISION");
61776
+ if (firstPendingRevisionId !== -1) {
61777
+ /**
61778
+ * Some revisions undergo transformations that may cause issues with
61779
+ * undo/redo if the transformation is destructive (we don't get back
61780
+ * the original command by transforming it with the inverse).
61781
+ * To prevent these problems, we must rebase all subsequent local
61782
+ * revisions.
61783
+ */
61784
+ this.revisions.rebase(this.pendingMessages[firstPendingRevisionId].nextRevisionId);
61785
+ }
61786
+ this.serverRevisionId = message.nextRevisionId;
61787
+ this.processedRevisions.add(message.nextRevisionId);
61788
+ this.sendPendingMessage();
61789
+ break;
61790
+ }
61661
61791
  }
61662
61792
  }
61663
61793
  isAlreadyProcessed(message) {
@@ -62740,6 +62870,10 @@ stores.inject(MyMetaStore, storeInstance);
62740
62870
  */
62741
62871
  checkZonesAreInSheet(cmd) {
62742
62872
  const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.tryGetActiveSheetId();
62873
+ if ("ranges" in cmd &&
62874
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
62875
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
62876
+ }
62743
62877
  const zones = this.getters.getCommandZones(cmd);
62744
62878
  if (!sheetId && zones.length > 0) {
62745
62879
  return "NoActiveSheet" /* CommandResult.NoActiveSheet */;
@@ -63089,23 +63223,23 @@ stores.inject(MyMetaStore, storeInstance);
63089
63223
  function repeatCreateChartCommand(getters, cmd) {
63090
63224
  return {
63091
63225
  ...repeatSheetDependantCommand(getters, cmd),
63092
- id: uuidGenerator.uuidv4(),
63226
+ id: uuidGenerator.smallUuid(),
63093
63227
  };
63094
63228
  }
63095
63229
  function repeatCreateImageCommand(getters, cmd) {
63096
63230
  return {
63097
63231
  ...repeatSheetDependantCommand(getters, cmd),
63098
- figureId: uuidGenerator.uuidv4(),
63232
+ figureId: uuidGenerator.smallUuid(),
63099
63233
  };
63100
63234
  }
63101
63235
  function repeatCreateFigureCommand(getters, cmd) {
63102
63236
  const newCmd = repeatSheetDependantCommand(getters, cmd);
63103
- newCmd.figure.id = uuidGenerator.uuidv4();
63237
+ newCmd.figure.id = uuidGenerator.smallUuid();
63104
63238
  return newCmd;
63105
63239
  }
63106
63240
  function repeatCreateSheetCommand(getters, cmd) {
63107
63241
  const newCmd = deepCopy(cmd);
63108
- newCmd.sheetId = uuidGenerator.uuidv4();
63242
+ newCmd.sheetId = uuidGenerator.smallUuid();
63109
63243
  const sheetName = cmd.name || getters.getSheet(getters.getActiveSheetId()).name;
63110
63244
  // Extract the prefix of the sheet name (everything before the number at the end of the name)
63111
63245
  const namePrefix = sheetName.match(/(.+?)\d*$/)?.[1] || sheetName;
@@ -63294,7 +63428,6 @@ stores.inject(MyMetaStore, storeInstance);
63294
63428
  super(config);
63295
63429
  this.session = config.session;
63296
63430
  this.session.on("new-local-state-update", this, this.onNewLocalStateUpdate);
63297
- this.session.on("pending-revisions-dropped", this, ({ revisionIds }) => this.drop(revisionIds));
63298
63431
  this.session.on("snapshot", this, () => {
63299
63432
  this.undoStack = [];
63300
63433
  this.redoStack = [];
@@ -63364,10 +63497,6 @@ stores.inject(MyMetaStore, storeInstance);
63364
63497
  const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
63365
63498
  return canRepeatRevision(lastNonRedoRevision);
63366
63499
  }
63367
- drop(revisionIds) {
63368
- this.undoStack = this.undoStack.filter((id) => !revisionIds.includes(id));
63369
- this.redoStack = [];
63370
- }
63371
63500
  onNewLocalStateUpdate({ id }) {
63372
63501
  this.undoStack.push(id);
63373
63502
  this.redoStack = [];
@@ -64568,23 +64697,7 @@ stores.inject(MyMetaStore, storeInstance);
64568
64697
  gridSelection: deepCopy(gridSelection),
64569
64698
  };
64570
64699
  }
64571
- if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
64572
- const currentSheetIds = this.getters.getVisibleSheetIds();
64573
- this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
64574
- if (this.activeSheet.id in this.sheetsData) {
64575
- const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
64576
- this.selectCell(anchor.cell.col, anchor.cell.row);
64577
- }
64578
- else {
64579
- this.selectCell(0, 0);
64580
- }
64581
- const { col, row } = this.gridSelection.anchor.cell;
64582
- this.moveClient({
64583
- sheetId: this.getters.getActiveSheetId(),
64584
- col,
64585
- row,
64586
- });
64587
- }
64700
+ this.fallbackToVisibleSheet();
64588
64701
  const sheetId = this.getters.getActiveSheetId();
64589
64702
  this.gridSelection.zones = this.gridSelection.zones.map((z) => this.getters.expandZone(sheetId, z));
64590
64703
  this.gridSelection.anchor.zone = this.getters.expandZone(sheetId, this.gridSelection.anchor.zone);
@@ -64594,6 +64707,7 @@ stores.inject(MyMetaStore, storeInstance);
64594
64707
  }
64595
64708
  }
64596
64709
  finalize() {
64710
+ this.fallbackToVisibleSheet();
64597
64711
  /** Any change to the selection has to be reflected in the selection processor. */
64598
64712
  this.selection.resetDefaultAnchor(this, deepCopy(this.gridSelection.anchor));
64599
64713
  }
@@ -64897,6 +65011,25 @@ stores.inject(MyMetaStore, storeInstance);
64897
65011
  }
64898
65012
  return "Success" /* CommandResult.Success */;
64899
65013
  }
65014
+ fallbackToVisibleSheet() {
65015
+ if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
65016
+ const currentSheetIds = this.getters.getVisibleSheetIds();
65017
+ this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
65018
+ if (this.activeSheet.id in this.sheetsData) {
65019
+ const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
65020
+ this.selectCell(anchor.cell.col, anchor.cell.row);
65021
+ }
65022
+ else {
65023
+ this.selectCell(0, 0);
65024
+ }
65025
+ const { col, row } = this.gridSelection.anchor.cell;
65026
+ this.moveClient({
65027
+ sheetId: this.getters.getActiveSheetId(),
65028
+ col,
65029
+ row,
65030
+ });
65031
+ }
65032
+ }
64900
65033
  //-------------------------------------------
64901
65034
  // Helpers for extensions
64902
65035
  // ------------------------------------------
@@ -66063,7 +66196,9 @@ stores.inject(MyMetaStore, storeInstance);
66063
66196
  case "UNGROUP_HEADERS":
66064
66197
  case "GROUP_HEADERS":
66065
66198
  case "CREATE_SHEET":
66066
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
66199
+ if (this.getters.tryGetSheet(cmd.sheetId)) {
66200
+ this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
66201
+ }
66067
66202
  break;
66068
66203
  case "DUPLICATE_SHEET":
66069
66204
  this.headerPositions[cmd.sheetIdTo] = deepCopy(this.headerPositions[cmd.sheetId]);
@@ -66071,12 +66206,14 @@ stores.inject(MyMetaStore, storeInstance);
66071
66206
  }
66072
66207
  }
66073
66208
  finalize() {
66074
- if (this.isDirty) {
66075
- for (const sheetId of this.getters.getSheetIds()) {
66209
+ for (const sheetId of this.getters.getSheetIds()) {
66210
+ // sheets can be created without this plugin being aware of it
66211
+ // in concurrent situations.
66212
+ if (this.isDirty || !this.headerPositions[sheetId]) {
66076
66213
  this.headerPositions[sheetId] = this.computeHeaderPositionsOfSheet(sheetId);
66077
66214
  }
66078
- this.isDirty = false;
66079
66215
  }
66216
+ this.isDirty = false;
66080
66217
  }
66081
66218
  /**
66082
66219
  * Returns the size, start and end coordinates of a column on an unfolded sheet
@@ -66899,7 +67036,7 @@ stores.inject(MyMetaStore, storeInstance);
66899
67036
  clickAddSheet(ev) {
66900
67037
  const activeSheetId = this.env.model.getters.getActiveSheetId();
66901
67038
  const position = this.env.model.getters.getSheetIds().findIndex((sheetId) => sheetId === activeSheetId) + 1;
66902
- const sheetId = this.env.model.uuidGenerator.uuidv4();
67039
+ const sheetId = this.env.model.uuidGenerator.smallUuid();
66903
67040
  const name = this.env.model.getters.getNextSheetName(_t("Sheet"));
66904
67041
  this.env.model.dispatch("CREATE_SHEET", { sheetId, position, name });
66905
67042
  this.env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
@@ -67987,7 +68124,7 @@ stores.inject(MyMetaStore, storeInstance);
67987
68124
  .o-font-size-editor {
67988
68125
  height: calc(100% - 4px);
67989
68126
  input.o-font-size {
67990
- outline-color: ${SELECTION_BORDER_COLOR};
68127
+ outline: none;
67991
68128
  height: 20px;
67992
68129
  width: 23px;
67993
68130
  }
@@ -69274,7 +69411,7 @@ stores.inject(MyMetaStore, storeInstance);
69274
69411
  }
69275
69412
  /**
69276
69413
  * Drop the operation and all following operations in every
69277
- * branch
69414
+ * branches
69278
69415
  */
69279
69416
  drop(operationId) {
69280
69417
  for (const branch of this.branches) {
@@ -69579,9 +69716,16 @@ stores.inject(MyMetaStore, storeInstance);
69579
69716
  this.fastForward();
69580
69717
  this.insert(redoId, this.buildEmpty(redoId), insertAfter);
69581
69718
  }
69582
- drop(operationId) {
69719
+ rebase(operationId) {
69720
+ const operation = this.get(operationId);
69721
+ const execution = [...this.tree.execution(this.HEAD_BRANCH).startAfter(operationId)];
69583
69722
  this.revertBefore(operationId);
69723
+ const baseId = this.HEAD_OPERATION.id;
69584
69724
  this.tree.drop(operationId);
69725
+ this.insert(operationId, operation, baseId);
69726
+ for (const { operation } of execution) {
69727
+ this.insert(operation.id, operation.data, this.HEAD_OPERATION.id);
69728
+ }
69585
69729
  }
69586
69730
  /**
69587
69731
  * Revert the state as it was *before* the given operation was executed.
@@ -72623,6 +72767,11 @@ stores.inject(MyMetaStore, storeInstance);
72623
72767
  dispatch: (command) => {
72624
72768
  const result = this.checkDispatchAllowed(command);
72625
72769
  if (!result.isSuccessful) {
72770
+ // core views plugins need to be invalidated
72771
+ this.dispatchToHandlers(this.coreHandlers, {
72772
+ type: "UNDO",
72773
+ commands: [command],
72774
+ });
72626
72775
  return;
72627
72776
  }
72628
72777
  this.isReplayingCommand = true;
@@ -72651,7 +72800,7 @@ stores.inject(MyMetaStore, storeInstance);
72651
72800
  }
72652
72801
  setupConfig(config) {
72653
72802
  const client = config.client || {
72654
- id: this.uuidGenerator.uuidv4(),
72803
+ id: this.uuidGenerator.smallUuid(),
72655
72804
  name: _t("Anonymous").toString(),
72656
72805
  };
72657
72806
  const transportService = config.transportService || new LocalTransportService();
@@ -73181,9 +73330,9 @@ stores.inject(MyMetaStore, storeInstance);
73181
73330
  exports.tokenize = tokenize;
73182
73331
 
73183
73332
 
73184
- __info__.version = "18.0.15";
73185
- __info__.date = "2025-02-10T08:59:22.993Z";
73186
- __info__.hash = "5b19f88";
73333
+ __info__.version = "18.0.17";
73334
+ __info__.date = "2025-02-25T05:58:39.632Z";
73335
+ __info__.hash = "2ee4347";
73187
73336
 
73188
73337
 
73189
73338
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);