@odoo/o-spreadsheet 17.0.49 → 17.0.51

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.49
6
- * @date 2025-02-10T08:55:47.771Z
7
- * @hash 1049319
5
+ * @version 17.0.51
6
+ * @date 2025-02-25T05:56:10.869Z
7
+ * @hash b433912
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -1908,12 +1908,12 @@ function isTargetDependent(cmd) {
1908
1908
  function isRangeDependant(cmd) {
1909
1909
  return "ranges" in cmd;
1910
1910
  }
1911
- function isZoneDependent(cmd) {
1912
- return "zone" in cmd;
1913
- }
1914
1911
  function isPositionDependent(cmd) {
1915
1912
  return "col" in cmd && "row" in cmd && "sheetId" in cmd;
1916
1913
  }
1914
+ function isZoneDependent(cmd) {
1915
+ return "sheetId" in cmd && "zone" in cmd;
1916
+ }
1917
1917
  const invalidateEvaluationCommands = new Set([
1918
1918
  "RENAME_SHEET",
1919
1919
  "DELETE_SHEET",
@@ -1923,6 +1923,7 @@ const invalidateEvaluationCommands = new Set([
1923
1923
  "UNDO",
1924
1924
  "REDO",
1925
1925
  "ADD_MERGE",
1926
+ "DUPLICATE_SHEET",
1926
1927
  "UPDATE_LOCALE",
1927
1928
  ]);
1928
1929
  const invalidateDependenciesCommands = new Set([
@@ -1931,7 +1932,6 @@ const invalidateDependenciesCommands = new Set([
1931
1932
  ]);
1932
1933
  const invalidateCFEvaluationCommands = new Set([
1933
1934
  ...invalidateEvaluationCommands,
1934
- "DUPLICATE_SHEET",
1935
1935
  "EVALUATE_CELLS",
1936
1936
  "ADD_CONDITIONAL_FORMAT",
1937
1937
  "REMOVE_CONDITIONAL_FORMAT",
@@ -2091,6 +2091,7 @@ var CommandResult;
2091
2091
  CommandResult["InvalidRange"] = "InvalidRange";
2092
2092
  CommandResult["InvalidZones"] = "InvalidZones";
2093
2093
  CommandResult["InvalidSheetId"] = "InvalidSheetId";
2094
+ CommandResult["InvalidCellId"] = "InvalidCellId";
2094
2095
  CommandResult["InvalidFigureId"] = "InvalidFigureId";
2095
2096
  CommandResult["InputAlreadyFocused"] = "InputAlreadyFocused";
2096
2097
  CommandResult["MaximumRangesReached"] = "MaximumRangesReached";
@@ -3671,17 +3672,20 @@ function toZoneWithoutBoundaryChanges(xc) {
3671
3672
  */
3672
3673
  function toUnboundedZone(xc) {
3673
3674
  const zone = toZoneWithoutBoundaryChanges(xc);
3675
+ reorderZone(zone);
3676
+ return zone;
3677
+ }
3678
+ function reorderZone(zone) {
3674
3679
  if (zone.right !== undefined && zone.right < zone.left) {
3675
- const tmp = zone.left;
3680
+ const right = zone.left;
3676
3681
  zone.left = zone.right;
3677
- zone.right = tmp;
3682
+ zone.right = right;
3678
3683
  }
3679
3684
  if (zone.bottom !== undefined && zone.bottom < zone.top) {
3680
- const tmp = zone.top;
3685
+ const bottom = zone.top;
3681
3686
  zone.top = zone.bottom;
3682
- zone.bottom = tmp;
3687
+ zone.bottom = bottom;
3683
3688
  }
3684
- return zone;
3685
3689
  }
3686
3690
  /**
3687
3691
  * Convert from a cartesian reference to a Zone.
@@ -4714,20 +4718,53 @@ class UuidGenerator {
4714
4718
  setIsFastStrategy(isFast) {
4715
4719
  this.isFastIdStrategy = isFast;
4716
4720
  }
4721
+ /**
4722
+ * Generates a custom UUID using a simple 26^8 method (8-character alphanumeric string with lowercase letters)
4723
+ * This has a higher chance of collision than a UUIDv4, but not only faster to generate than an UUIDV4,
4724
+ * it also has a smaller size, which is preferable to alleviate the overall data size.
4725
+ *
4726
+ * This method is preferable when generating uuids for the core data (sheetId, figureId, etc)
4727
+ * as they will appear several times in the revisions and local history.
4728
+ *
4729
+ */
4730
+ smallUuid() {
4731
+ if (this.isFastIdStrategy) {
4732
+ this.fastIdStart++;
4733
+ return String(this.fastIdStart);
4734
+ }
4735
+ else if (window.crypto) {
4736
+ return "10000000-1000".replace(/[01]/g, (c) => {
4737
+ const n = Number(c);
4738
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
4739
+ });
4740
+ }
4741
+ else {
4742
+ // mainly for jest and other browsers that do not have the crypto functionality
4743
+ return "xxxxxxxx-xxxx".replace(/[xy]/g, function (c) {
4744
+ var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8;
4745
+ return v.toString(16);
4746
+ });
4747
+ }
4748
+ }
4749
+ /**
4750
+ * Generates an UUIDV4, has astronomically low chance of collision, but is larger in size than the smallUuid.
4751
+ * This method should be used when you need to avoid collisions at all costs, like the id of a revision.
4752
+ */
4717
4753
  uuidv4() {
4718
4754
  if (this.isFastIdStrategy) {
4719
4755
  this.fastIdStart++;
4720
4756
  return String(this.fastIdStart);
4721
- //@ts-ignore
4722
4757
  }
4723
- else if (window.crypto && window.crypto.getRandomValues) {
4724
- //@ts-ignore
4725
- return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16));
4758
+ else if (window.crypto) {
4759
+ return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
4760
+ const n = Number(c);
4761
+ return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4)))).toString(16);
4762
+ });
4726
4763
  }
4727
4764
  else {
4728
4765
  // mainly for jest and other browsers that do not have the crypto functionality
4729
4766
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
4730
- 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;
4731
4768
  return v.toString(16);
4732
4769
  });
4733
4770
  }
@@ -6948,10 +6985,6 @@ class Popover extends Component {
6948
6985
  this.currentDisplayValue = newDisplay;
6949
6986
  if (!anchor)
6950
6987
  return;
6951
- el.style.top = "";
6952
- el.style.left = "";
6953
- el.style["max-height"] = "";
6954
- el.style["max-width"] = "";
6955
6988
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
6956
6989
  let elDims = {
6957
6990
  width: el.getBoundingClientRect().width,
@@ -7940,7 +7973,7 @@ const linkSheet = {
7940
7973
  const deleteSheet = {
7941
7974
  name: _t("Delete"),
7942
7975
  isVisible: (env) => {
7943
- return env.model.getters.getSheetIds().length > 1;
7976
+ return env.model.getters.getVisibleSheetIds().length > 1;
7944
7977
  },
7945
7978
  execute: (env) => env.askConfirmation(_t("Are you sure you want to delete this sheet?"), () => {
7946
7979
  env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
@@ -7950,7 +7983,7 @@ const duplicateSheet = {
7950
7983
  name: _t("Duplicate"),
7951
7984
  execute: (env) => {
7952
7985
  const sheetIdFrom = env.model.getters.getActiveSheetId();
7953
- const sheetIdTo = env.model.uuidGenerator.uuidv4();
7986
+ const sheetIdTo = env.model.uuidGenerator.smallUuid();
7954
7987
  env.model.dispatch("DUPLICATE_SHEET", {
7955
7988
  sheetId: sheetIdFrom,
7956
7989
  sheetIdTo,
@@ -8500,17 +8533,15 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale, tr
8500
8533
  plugins: [],
8501
8534
  };
8502
8535
  }
8503
- function getChartLabelFormat(getters, range) {
8536
+ function getChartLabelFormat(getters, range, shouldRemoveFirstLabel) {
8504
8537
  if (!range)
8505
8538
  return undefined;
8506
- const { sheetId, zone: { left, top, bottom }, } = range;
8507
- for (let row = top; row <= bottom; row++) {
8508
- const format = getters.getEvaluatedCell({ sheetId, col: left, row }).format;
8509
- if (format) {
8510
- return format;
8511
- }
8539
+ const { sheetId, zone } = range;
8540
+ const formats = positions(zone).map((position) => getters.getEvaluatedCell({ sheetId, ...position }).format);
8541
+ if (shouldRemoveFirstLabel) {
8542
+ formats.shift();
8512
8543
  }
8513
- return undefined;
8544
+ return formats.find((format) => format !== undefined);
8514
8545
  }
8515
8546
  function getChartLabelValues(getters, dataSets, labelRange) {
8516
8547
  let labels = { values: [], formattedValues: [] };
@@ -8791,9 +8822,7 @@ function createBarChartRuntime(chart, getters) {
8791
8822
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
8792
8823
  let labels = labelValues.formattedValues;
8793
8824
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
8794
- if (chart.dataSetsHaveTitle &&
8795
- dataSetsValues[0] &&
8796
- labels.length > dataSetsValues[0].data.length) {
8825
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
8797
8826
  labels.shift();
8798
8827
  }
8799
8828
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -9337,8 +9366,8 @@ function fixEmptyLabelsForDateCharts(labels, dataSetsValues) {
9337
9366
  }
9338
9367
  return { labels: newLabels, dataSetsValues: newDatasets };
9339
9368
  }
9340
- function canChartParseLabels(labelRange, getters) {
9341
- return canBeDateChart(labelRange, getters) || canBeLinearChart(labelRange, getters);
9369
+ function canChartParseLabels(chart, getters) {
9370
+ return canBeDateChart(chart, getters) || canBeLinearChart(chart, getters);
9342
9371
  }
9343
9372
  function getChartAxisType(chart, getters) {
9344
9373
  if (isDateChart(chart, getters) && isLuxonTimeAdapterInstalled()) {
@@ -9350,23 +9379,26 @@ function getChartAxisType(chart, getters) {
9350
9379
  return "category";
9351
9380
  }
9352
9381
  function isDateChart(chart, getters) {
9353
- return !chart.labelsAsText && canBeDateChart(chart.labelRange, getters);
9382
+ return !chart.labelsAsText && canBeDateChart(chart, getters);
9354
9383
  }
9355
9384
  function isLinearChart(chart, getters) {
9356
- return !chart.labelsAsText && canBeLinearChart(chart.labelRange, getters);
9385
+ return !chart.labelsAsText && canBeLinearChart(chart, getters);
9357
9386
  }
9358
- function canBeDateChart(labelRange, getters) {
9359
- if (!labelRange || !canBeLinearChart(labelRange, getters)) {
9387
+ function canBeDateChart(chart, getters) {
9388
+ if (!chart.labelRange || !canBeLinearChart(chart, getters)) {
9360
9389
  return false;
9361
9390
  }
9362
- const labelFormat = getChartLabelFormat(getters, labelRange);
9391
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle));
9363
9392
  return Boolean(labelFormat && timeFormatLuxonCompatible.test(labelFormat));
9364
9393
  }
9365
- function canBeLinearChart(labelRange, getters) {
9366
- if (!labelRange) {
9394
+ function canBeLinearChart(chart, getters) {
9395
+ if (!chart.labelRange) {
9367
9396
  return false;
9368
9397
  }
9369
- const labels = getters.getRangeValues(labelRange);
9398
+ const labels = getters.getRangeValues(chart.labelRange);
9399
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
9400
+ labels.shift();
9401
+ }
9370
9402
  if (labels.some((label) => isNaN(Number(label)) && label)) {
9371
9403
  return false;
9372
9404
  }
@@ -9440,9 +9472,8 @@ function createLineChartRuntime(chart, getters) {
9440
9472
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
9441
9473
  let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
9442
9474
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
9443
- if (chart.dataSetsHaveTitle &&
9444
- dataSetsValues[0] &&
9445
- labels.length > dataSetsValues[0].data.length) {
9475
+ const removeFirstLabel = shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle);
9476
+ if (removeFirstLabel) {
9446
9477
  labels.shift();
9447
9478
  }
9448
9479
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -9457,7 +9488,7 @@ function createLineChartRuntime(chart, getters) {
9457
9488
  const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
9458
9489
  const options = { format: dataSetFormat, locale, truncateLabels };
9459
9490
  const config = getLineConfiguration(chart, labels, options);
9460
- const labelFormat = getChartLabelFormat(getters, chart.labelRange);
9491
+ const labelFormat = getChartLabelFormat(getters, chart.labelRange, removeFirstLabel);
9461
9492
  if (axisType === "time") {
9462
9493
  const axis = {
9463
9494
  type: "time",
@@ -9679,9 +9710,7 @@ function createPieChartRuntime(chart, getters) {
9679
9710
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
9680
9711
  let labels = labelValues.formattedValues;
9681
9712
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
9682
- if (chart.dataSetsHaveTitle &&
9683
- dataSetsValues[0] &&
9684
- labels.length > dataSetsValues[0].data.length) {
9713
+ if (shouldRemoveFirstLabel(chart.labelRange, chart.dataSets[0], chart.dataSetsHaveTitle)) {
9685
9714
  labels.shift();
9686
9715
  }
9687
9716
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
@@ -9697,7 +9726,7 @@ function createPieChartRuntime(chart, getters) {
9697
9726
  const dataset = {
9698
9727
  label,
9699
9728
  data,
9700
- borderColor: "#FFFFFF",
9729
+ borderColor: chart.background || "#FFFFFF",
9701
9730
  backgroundColor,
9702
9731
  };
9703
9732
  config.data.datasets.push(dataset);
@@ -10202,21 +10231,22 @@ function getSmartChartDefinition(zone, getters) {
10202
10231
  }
10203
10232
  // Only display legend for several datasets.
10204
10233
  const newLegendPos = dataSetZone.right === dataSetZone.left ? "none" : "top";
10205
- const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
10206
- if (canChartParseLabels(labelRange, getters)) {
10207
- return {
10208
- title,
10209
- dataSets,
10210
- labelsAsText: false,
10211
- stacked: false,
10212
- aggregated: false,
10213
- cumulative: false,
10214
- labelRange: labelRangeXc,
10215
- type: "line",
10216
- dataSetsHaveTitle,
10217
- verticalAxisPosition: "left",
10218
- legendPosition: newLegendPos,
10219
- };
10234
+ const lineChartDefinition = {
10235
+ title,
10236
+ dataSets,
10237
+ labelsAsText: false,
10238
+ stacked: false,
10239
+ aggregated: false,
10240
+ cumulative: false,
10241
+ labelRange: labelRangeXc,
10242
+ type: "line",
10243
+ dataSetsHaveTitle,
10244
+ verticalAxisPosition: "left",
10245
+ legendPosition: newLegendPos,
10246
+ };
10247
+ const chart = new LineChart(lineChartDefinition, sheetId, getters);
10248
+ if (canChartParseLabels(chart, getters)) {
10249
+ return lineChartDefinition;
10220
10250
  }
10221
10251
  return {
10222
10252
  title,
@@ -10816,7 +10846,7 @@ const HIDE_ROWS_NAME = (env) => {
10816
10846
  //------------------------------------------------------------------------------
10817
10847
  const CREATE_CHART = (env) => {
10818
10848
  const getters = env.model.getters;
10819
- const id = env.model.uuidGenerator.uuidv4();
10849
+ const id = env.model.uuidGenerator.smallUuid();
10820
10850
  const sheetId = getters.getActiveSheetId();
10821
10851
  if (getZoneArea(env.model.getters.getSelectedZone()) === 1) {
10822
10852
  env.model.selection.selectTableAroundSelection();
@@ -10850,7 +10880,7 @@ async function requestImage(env) {
10850
10880
  const CREATE_IMAGE = async (env) => {
10851
10881
  if (env.imageProvider) {
10852
10882
  const sheetId = env.model.getters.getActiveSheetId();
10853
- const figureId = env.model.uuidGenerator.uuidv4();
10883
+ const figureId = env.model.uuidGenerator.smallUuid();
10854
10884
  const image = await requestImage(env);
10855
10885
  if (!image) {
10856
10886
  throw new Error("No image provider was given to the environment");
@@ -12571,6 +12601,26 @@ const LN = {
12571
12601
  isExported: true,
12572
12602
  };
12573
12603
  // -----------------------------------------------------------------------------
12604
+ // LOG
12605
+ // -----------------------------------------------------------------------------
12606
+ const LOG = {
12607
+ description: _t("The logarithm of a number, for a given base."),
12608
+ args: [
12609
+ arg("value (number)", _t("The value for which to calculate the logarithm.")),
12610
+ arg("base (number, default=10)", _t("The base of the logarithm.")),
12611
+ ],
12612
+ returns: ["NUMBER"],
12613
+ compute: function (value, base = 10) {
12614
+ const _value = toNumber(value, this.locale);
12615
+ const _base = toNumber(base, this.locale);
12616
+ assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
12617
+ assert(() => _base > 0, _t("The base (%s) must be strictly positive.", _base.toString()));
12618
+ assert(() => _base !== 1, _t("The base must be different from 1."));
12619
+ return Math.log10(_value) / Math.log10(_base);
12620
+ },
12621
+ isExported: true,
12622
+ };
12623
+ // -----------------------------------------------------------------------------
12574
12624
  // MOD
12575
12625
  // -----------------------------------------------------------------------------
12576
12626
  const MOD = {
@@ -13091,6 +13141,7 @@ var math = /*#__PURE__*/Object.freeze({
13091
13141
  ISODD: ISODD,
13092
13142
  ISO_CEILING: ISO_CEILING,
13093
13143
  LN: LN,
13144
+ LOG: LOG,
13094
13145
  MOD: MOD,
13095
13146
  MUNIT: MUNIT,
13096
13147
  ODD: ODD,
@@ -15952,7 +16003,7 @@ const SORTN = {
15952
16003
  }
15953
16004
  }
15954
16005
  },
15955
- isExported: true,
16006
+ isExported: false,
15956
16007
  };
15957
16008
  // -----------------------------------------------------------------------------
15958
16009
  // UNIQUE
@@ -19853,7 +19904,7 @@ const insertSheet = {
19853
19904
  execute: (env) => {
19854
19905
  const activeSheetId = env.model.getters.getActiveSheetId();
19855
19906
  const position = env.model.getters.getSheetIds().indexOf(activeSheetId) + 1;
19856
- const sheetId = env.model.uuidGenerator.uuidv4();
19907
+ const sheetId = env.model.uuidGenerator.smallUuid();
19857
19908
  env.model.dispatch("CREATE_SHEET", { sheetId, position });
19858
19909
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
19859
19910
  },
@@ -21529,7 +21580,7 @@ css /* scss */ `
21529
21580
  */
21530
21581
  class SelectionInput extends Component {
21531
21582
  static template = "o-spreadsheet-SelectionInput";
21532
- id = uuidGenerator$1.uuidv4();
21583
+ id = uuidGenerator$1.smallUuid();
21533
21584
  previousRanges = this.props.ranges() || [];
21534
21585
  originSheet = this.env.model.getters.getActiveSheetId();
21535
21586
  state = useState({
@@ -22579,7 +22630,7 @@ class LineConfigPanel extends LineBarPieConfigPanel {
22579
22630
  get canTreatLabelsAsText() {
22580
22631
  const chart = this.env.model.getters.getChart(this.props.figureId);
22581
22632
  if (chart && chart instanceof LineChart) {
22582
- return canChartParseLabels(chart.labelRange, this.env.model.getters);
22633
+ return canChartParseLabels(chart, this.env.model.getters);
22583
22634
  }
22584
22635
  return false;
22585
22636
  }
@@ -23607,7 +23658,7 @@ class ConditionalFormattingEditor extends Component {
23607
23658
  state;
23608
23659
  setup() {
23609
23660
  const cf = this.props.editedCf || {
23610
- id: this.env.model.uuidGenerator.uuidv4(),
23661
+ id: this.env.model.uuidGenerator.smallUuid(),
23611
23662
  ranges: this.env.model.getters
23612
23663
  .getSelectedZones()
23613
23664
  .map((zone) => this.env.model.getters.zoneToXC(this.env.model.getters.getActiveSheetId(), zone)),
@@ -25556,7 +25607,7 @@ class DataValidationEditor extends Component {
25556
25607
  .getSelectedZones()
25557
25608
  .map((zone) => zoneToXc(this.env.model.getters.getUnboundedZone(sheetId, zone)));
25558
25609
  return {
25559
- id: this.env.model.uuidGenerator.uuidv4(),
25610
+ id: this.env.model.uuidGenerator.smallUuid(),
25560
25611
  criterion: { type: "textContains", values: [""] },
25561
25612
  ranges,
25562
25613
  };
@@ -26707,25 +26758,21 @@ css /* scss */ `
26707
26758
  }
26708
26759
  }
26709
26760
  }
26761
+ }
26762
+ .o-spreadsheet .o-composer-assistant {
26763
+ pointer-events: none;
26710
26764
 
26711
- .o-composer-assistant {
26712
- position: absolute;
26713
- margin: 1px 4px;
26714
- pointer-events: none;
26715
- overflow: auto;
26716
-
26717
- .o-semi-bold {
26718
- /** FIXME: to remove in favor of Bootstrap
26719
- * 'fw-semibold' when we upgrade to Bootstrap 5.2
26720
- */
26721
- font-weight: 600 !important;
26722
- }
26765
+ .o-semi-bold {
26766
+ /** FIXME: to remove in favor of Bootstrap
26767
+ * 'fw-semibold' when we upgrade to Bootstrap 5.2
26768
+ */
26769
+ font-weight: 600 !important;
26723
26770
  }
26724
26771
  }
26725
26772
  `;
26726
26773
  class Composer extends Component {
26727
26774
  static template = "o-spreadsheet-Composer";
26728
- static components = { TextValueProvider, FunctionDescriptionProvider };
26775
+ static components = { TextValueProvider, FunctionDescriptionProvider, Popover };
26729
26776
  static defaultProps = {
26730
26777
  inputStyle: "",
26731
26778
  isDefaultFocus: false,
@@ -26750,35 +26797,13 @@ class Composer extends Component {
26750
26797
  argToFocus: 0,
26751
26798
  });
26752
26799
  compositionActive = false;
26753
- spreadsheetRect = useSpreadsheetRect();
26754
26800
  get assistantStyle() {
26755
- const composerRect = this.composerRef.el.getBoundingClientRect();
26756
26801
  const assistantStyle = {};
26757
- assistantStyle["min-width"] = `${this.props.rect?.width || ASSISTANT_WIDTH}px`;
26802
+ const minWidth = Math.min(getBoundingRectAsPOJO(this.composerRef.el).width || Infinity, ASSISTANT_WIDTH);
26803
+ assistantStyle["min-width"] = `${minWidth}px`;
26758
26804
  if (this.autoCompleteState.type === "function") {
26759
26805
  assistantStyle.width = `${ASSISTANT_WIDTH}px`;
26760
26806
  }
26761
- if (this.props.delimitation && this.props.rect) {
26762
- const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
26763
- const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
26764
- assistantStyle["max-height"] = `${remainingHeight}px`;
26765
- if (cellY > remainingHeight) {
26766
- const availableSpaceAbove = cellY;
26767
- assistantStyle["max-height"] = `${availableSpaceAbove}px`;
26768
- // render top
26769
- // We compensate 2 px of margin on the assistant style + 1px for design reasons
26770
- assistantStyle.top = `-3px`;
26771
- assistantStyle.transform = `translate(0, -100%)`;
26772
- }
26773
- if (cellX + ASSISTANT_WIDTH > this.props.delimitation.width) {
26774
- // render left
26775
- assistantStyle.right = `0px`;
26776
- }
26777
- }
26778
- if (this.props.focus === "contentFocus" &&
26779
- composerRect.left + ASSISTANT_WIDTH > this.spreadsheetRect.width) {
26780
- assistantStyle.right = "0px";
26781
- }
26782
26807
  return cssPropertiesToCss(assistantStyle);
26783
26808
  }
26784
26809
  // we can't allow input events to be triggered while we remove and add back the content of the composer in processContent
@@ -27027,7 +27052,7 @@ class Composer extends Component {
27027
27052
  this.autoCompleteState.selectedIndex = 0;
27028
27053
  }
27029
27054
  updateAutoCompleteIndex(index) {
27030
- this.autoCompleteState.selectedIndex = clip(0, index, 10);
27055
+ this.autoCompleteState.selectedIndex = index;
27031
27056
  }
27032
27057
  /**
27033
27058
  * This is required to ensure the content helper selection is
@@ -27315,11 +27340,16 @@ class Composer extends Component {
27315
27340
  this.autoCompleteState.values = values.map((value) => ({ text: value, description: "" }));
27316
27341
  this.autoCompleteState.getHtmlContent = (value) => [{ value }];
27317
27342
  }
27343
+ get popoverProps() {
27344
+ return {
27345
+ anchorRect: getBoundingRectAsPOJO(this.composerRef.el),
27346
+ positioning: "BottomLeft",
27347
+ verticalOffset: 0,
27348
+ };
27349
+ }
27318
27350
  }
27319
27351
  Composer.props = {
27320
27352
  inputStyle: { type: String, optional: true },
27321
- rect: { type: Object, optional: true },
27322
- delimitation: { type: Object, optional: true },
27323
27353
  focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
27324
27354
  onComposerCellFocused: { type: Function, optional: true },
27325
27355
  onComposerContentFocused: Function,
@@ -27389,13 +27419,7 @@ class GridComposer extends Component {
27389
27419
  });
27390
27420
  }
27391
27421
  get composerProps() {
27392
- const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
27393
27422
  return {
27394
- rect: { ...this.rect },
27395
- delimitation: {
27396
- width,
27397
- height,
27398
- },
27399
27423
  focus: this.props.focus,
27400
27424
  isDefaultFocus: true,
27401
27425
  onComposerContentFocused: this.props.onComposerContentFocused,
@@ -33842,7 +33866,7 @@ function normalizeV9(formula) {
33842
33866
  * a breaking change is made in the way the state is handled, and an upgrade
33843
33867
  * function should be defined
33844
33868
  */
33845
- const CURRENT_VERSION = 14;
33869
+ const CURRENT_VERSION = 14.5;
33846
33870
  const INITIAL_SHEET_ID = "Sheet1";
33847
33871
  /**
33848
33872
  * This function tries to load anything that could look like a valid
@@ -34176,7 +34200,7 @@ function forceUnicityOfFigure(data) {
34176
34200
  for (const sheet of data.sheets || []) {
34177
34201
  for (const figure of sheet.figures || []) {
34178
34202
  if (figureIds.has(figure.id)) {
34179
- figure.id += uuidGenerator.uuidv4();
34203
+ figure.id += uuidGenerator.smallUuid();
34180
34204
  }
34181
34205
  figureIds.add(figure.id);
34182
34206
  }
@@ -35852,6 +35876,10 @@ class CellPlugin extends CorePlugin {
35852
35876
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
35853
35877
  case "CLEAR_CELL":
35854
35878
  return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
35879
+ case "UPDATE_CELL_POSITION":
35880
+ return !cmd.cellId || this.cells[cmd.sheetId]?.[cmd.cellId]
35881
+ ? "Success" /* CommandResult.Success */
35882
+ : "InvalidCellId" /* CommandResult.InvalidCellId */;
35855
35883
  default:
35856
35884
  return "Success" /* CommandResult.Success */;
35857
35885
  }
@@ -35893,6 +35921,9 @@ class CellPlugin extends CorePlugin {
35893
35921
  case "CLEAR_CELLS":
35894
35922
  this.clearCells(cmd.sheetId, cmd.target);
35895
35923
  break;
35924
+ case "DELETE_SHEET": {
35925
+ this.history.update("cells", cmd.sheetId, undefined);
35926
+ }
35896
35927
  }
35897
35928
  }
35898
35929
  /**
@@ -36971,8 +37002,14 @@ class DataValidationPlugin extends CorePlugin {
36971
37002
  allowDispatch(cmd) {
36972
37003
  switch (cmd.type) {
36973
37004
  case "ADD_DATA_VALIDATION_RULE":
37005
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
37006
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
37007
+ }
36974
37008
  return this.checkValidations(cmd, this.chainValidations(this.checkCriterionTypeIsValid, this.checkCriterionHasValidNumberOfValues, this.checkCriterionValuesAreValid));
36975
37009
  case "REMOVE_DATA_VALIDATION_RULE":
37010
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
37011
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
37012
+ }
36976
37013
  if (!this.rules[cmd.sheetId].find((rule) => rule.id === cmd.id)) {
36977
37014
  return "UnknownDataValidationRule" /* CommandResult.UnknownDataValidationRule */;
36978
37015
  }
@@ -37146,6 +37183,7 @@ class DataValidationPlugin extends CorePlugin {
37146
37183
  class FigurePlugin extends CorePlugin {
37147
37184
  static getters = ["getFigures", "getFigure", "getFigureSheetId"];
37148
37185
  figures = {};
37186
+ insertionOrders = []; // TODO use a list in master
37149
37187
  // ---------------------------------------------------------------------------
37150
37188
  // Command Handling
37151
37189
  // ---------------------------------------------------------------------------
@@ -37248,11 +37286,14 @@ class FigurePlugin extends CorePlugin {
37248
37286
  }
37249
37287
  addFigure(figure, sheetId) {
37250
37288
  this.history.update("figures", sheetId, figure.id, figure);
37289
+ this.history.update("insertionOrders", this.insertionOrders.length, figure.id);
37251
37290
  }
37252
37291
  deleteSheet(sheetId) {
37292
+ this.history.update("insertionOrders", this.insertionOrders.filter((id) => !this.figures[sheetId]?.[id]));
37253
37293
  this.history.update("figures", sheetId, undefined);
37254
37294
  }
37255
37295
  removeFigure(id, sheetId) {
37296
+ this.history.update("insertionOrders", this.insertionOrders.filter((figureId) => figureId !== id));
37256
37297
  this.history.update("figures", sheetId, id, undefined);
37257
37298
  }
37258
37299
  checkFigureExists(sheetId, figureId) {
@@ -37271,7 +37312,14 @@ class FigurePlugin extends CorePlugin {
37271
37312
  // Getters
37272
37313
  // ---------------------------------------------------------------------------
37273
37314
  getFigures(sheetId) {
37274
- return Object.values(this.figures[sheetId] || {}).filter(isDefined$1);
37315
+ const figures = [];
37316
+ for (const figureId of this.insertionOrders) {
37317
+ const figure = this.figures[sheetId]?.[figureId];
37318
+ if (figure) {
37319
+ figures.push(figure);
37320
+ }
37321
+ }
37322
+ return figures;
37275
37323
  }
37276
37324
  getFigure(sheetId, figureId) {
37277
37325
  return this.figures[sheetId]?.[figureId];
@@ -37284,11 +37332,9 @@ class FigurePlugin extends CorePlugin {
37284
37332
  // ---------------------------------------------------------------------------
37285
37333
  import(data) {
37286
37334
  for (let sheet of data.sheets) {
37287
- const figures = {};
37288
- sheet.figures.forEach((figure) => {
37289
- figures[figure.id] = figure;
37290
- });
37291
- this.figures[sheet.id] = figures;
37335
+ for (const figure of sheet.figures) {
37336
+ this.addFigure(figure, sheet.id);
37337
+ }
37292
37338
  }
37293
37339
  }
37294
37340
  export(data) {
@@ -37312,10 +37358,10 @@ class FilterTable {
37312
37358
  this.filters = [];
37313
37359
  this.zone = zone;
37314
37360
  const uuid = new UuidGenerator();
37315
- this.id = uuid.uuidv4();
37361
+ this.id = uuid.smallUuid();
37316
37362
  for (const i of range(zone.left, zone.right + 1)) {
37317
37363
  const filterZone = { ...this.zone, left: i, right: i };
37318
- this.filters.push(new Filter(uuid.uuidv4(), filterZone));
37364
+ this.filters.push(new Filter(uuid.smallUuid(), filterZone));
37319
37365
  }
37320
37366
  }
37321
37367
  /** Get zone of the table without the headers */
@@ -37517,7 +37563,7 @@ class FiltersPlugin extends CorePlugin {
37517
37563
  if (filters.length < zoneToDimension(zone).numberOfCols) {
37518
37564
  for (let col = zone.left; col <= zone.right; col++) {
37519
37565
  if (!filters.find((filter) => filter.col === col)) {
37520
- filters.push(new Filter(this.uuidGenerator.uuidv4(), { ...zone, left: col, right: col }));
37566
+ filters.push(new Filter(this.uuidGenerator.smallUuid(), { ...zone, left: col, right: col }));
37521
37567
  }
37522
37568
  }
37523
37569
  filters.sort((f1, f2) => f1.col - f2.col);
@@ -39006,6 +39052,9 @@ class SheetPlugin extends CorePlugin {
39006
39052
  case "CREATE_SHEET": {
39007
39053
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
39008
39054
  }
39055
+ case "DUPLICATE_SHEET": {
39056
+ return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
39057
+ }
39009
39058
  case "MOVE_SHEET":
39010
39059
  try {
39011
39060
  const currentIndex = this.orderedSheetIds.findIndex((id) => id === cmd.sheetId);
@@ -39018,7 +39067,7 @@ class SheetPlugin extends CorePlugin {
39018
39067
  case "RENAME_SHEET":
39019
39068
  return this.isRenameAllowed(cmd);
39020
39069
  case "DELETE_SHEET":
39021
- return this.orderedSheetIds.length > 1
39070
+ return this.getVisibleSheetIds().length > 1
39022
39071
  ? "Success" /* CommandResult.Success */
39023
39072
  : "NotEnoughSheets" /* CommandResult.NotEnoughSheets */;
39024
39073
  case "ADD_COLUMNS_ROWS":
@@ -39831,6 +39880,10 @@ class SheetPlugin extends CorePlugin {
39831
39880
  checkZonesAreInSheet(cmd) {
39832
39881
  if (!("sheetId" in cmd))
39833
39882
  return "Success" /* CommandResult.Success */;
39883
+ if ("ranges" in cmd &&
39884
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
39885
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39886
+ }
39834
39887
  return this.checkZonesExistInSheet(cmd.sheetId, this.getCommandZones(cmd));
39835
39888
  }
39836
39889
  }
@@ -39850,7 +39903,10 @@ class HeaderGroupingPlugin extends CorePlugin {
39850
39903
  allowDispatch(cmd) {
39851
39904
  switch (cmd.type) {
39852
39905
  case "GROUP_HEADERS": {
39853
- const { start, end } = cmd;
39906
+ const { start, end, sheetId } = cmd;
39907
+ if (!this.getters.tryGetSheet(sheetId)) {
39908
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39909
+ }
39854
39910
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
39855
39911
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
39856
39912
  }
@@ -39863,7 +39919,10 @@ class HeaderGroupingPlugin extends CorePlugin {
39863
39919
  break;
39864
39920
  }
39865
39921
  case "UNGROUP_HEADERS": {
39866
- const { start, end } = cmd;
39922
+ const { start, end, sheetId } = cmd;
39923
+ if (!this.getters.tryGetSheet(sheetId)) {
39924
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39925
+ }
39867
39926
  if (!this.getters.doesHeadersExist(cmd.sheetId, cmd.dimension, [start, end])) {
39868
39927
  return "InvalidHeaderGroupStartEnd" /* CommandResult.InvalidHeaderGroupStartEnd */;
39869
39928
  }
@@ -39874,6 +39933,9 @@ class HeaderGroupingPlugin extends CorePlugin {
39874
39933
  }
39875
39934
  case "UNFOLD_HEADER_GROUP":
39876
39935
  case "FOLD_HEADER_GROUP":
39936
+ if (!this.getters.tryGetSheet(cmd.sheetId)) {
39937
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
39938
+ }
39877
39939
  const group = this.findGroupWithStartEnd(cmd.sheetId, cmd.dimension, cmd.start, cmd.end);
39878
39940
  if (!group) {
39879
39941
  return "UnknownHeaderGroup" /* CommandResult.UnknownHeaderGroup */;
@@ -44143,6 +44205,9 @@ function updateChartRangesTransformation(toTransform, executed) {
44143
44205
  };
44144
44206
  }
44145
44207
  function createSheetTransformation(toTransform, executed) {
44208
+ if (toTransform.sheetId === executed.sheetId) {
44209
+ toTransform = { ...toTransform, sheetId: `${toTransform.sheetId}~` };
44210
+ }
44146
44211
  if (toTransform.name === executed.name) {
44147
44212
  return {
44148
44213
  ...toTransform,
@@ -44779,21 +44844,14 @@ class Session extends EventBus {
44779
44844
  if (!message)
44780
44845
  return;
44781
44846
  if (message.type === "REMOTE_REVISION") {
44782
- const revision = this.revisions.get(message.nextRevisionId);
44847
+ let revision = this.revisions.get(message.nextRevisionId);
44783
44848
  if (revision.commands.length === 0) {
44784
44849
  /**
44785
- * The command is empty, we have to drop all the next local revisions
44850
+ * The command is empty, we have to rebase all the next local revisions
44786
44851
  * to avoid issues with undo/redo
44787
44852
  */
44788
- this.revisions.drop(revision.id);
44789
- const revisionIds = this.pendingMessages
44790
- .filter((message) => message.type === "REMOTE_REVISION")
44791
- .map((message) => message.nextRevisionId);
44792
- this.trigger("pending-revisions-dropped", { revisionIds });
44793
- this.waitingAck = false;
44794
- this.waitingUndoRedoAck = false;
44795
- this.pendingMessages = [];
44796
- return;
44853
+ this.revisions.rebase(revision.id);
44854
+ revision = this.revisions.get(message.nextRevisionId);
44797
44855
  }
44798
44856
  message = {
44799
44857
  ...message,
@@ -44817,7 +44875,6 @@ class Session extends EventBus {
44817
44875
  switch (message.type) {
44818
44876
  case "REMOTE_REVISION":
44819
44877
  case "REVISION_REDONE":
44820
- case "REVISION_UNDONE":
44821
44878
  case "SNAPSHOT_CREATED":
44822
44879
  this.waitingAck = false;
44823
44880
  this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
@@ -44825,6 +44882,25 @@ class Session extends EventBus {
44825
44882
  this.processedRevisions.add(message.nextRevisionId);
44826
44883
  this.sendPendingMessage();
44827
44884
  break;
44885
+ case "REVISION_UNDONE": {
44886
+ this.waitingAck = false;
44887
+ this.pendingMessages = this.pendingMessages.filter((msg) => msg.nextRevisionId !== message.nextRevisionId);
44888
+ const firstPendingRevisionId = this.pendingMessages.findIndex((message) => message.type === "REMOTE_REVISION");
44889
+ if (firstPendingRevisionId !== -1) {
44890
+ /**
44891
+ * Some revisions undergo transformations that may cause issues with
44892
+ * undo/redo if the transformation is destructive (we don't get back
44893
+ * the original command by transforming it with the inverse).
44894
+ * To prevent these problems, we must rebase all subsequent local
44895
+ * revisions.
44896
+ */
44897
+ this.revisions.rebase(this.pendingMessages[firstPendingRevisionId].nextRevisionId);
44898
+ }
44899
+ this.serverRevisionId = message.nextRevisionId;
44900
+ this.processedRevisions.add(message.nextRevisionId);
44901
+ this.sendPendingMessage();
44902
+ break;
44903
+ }
44828
44904
  }
44829
44905
  }
44830
44906
  isAlreadyProcessed(message) {
@@ -45529,7 +45605,9 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45529
45605
  const cfInTarget = this.getters
45530
45606
  .getConditionalFormats(targetSheetId)
45531
45607
  .find((cf) => cf.stopIfTrue === originCF.stopIfTrue && deepEquals(cf.rule, originCF.rule));
45532
- return cfInTarget ? cfInTarget : { ...originCF, id: this.uuidGenerator.uuidv4(), ranges: [] };
45608
+ return cfInTarget
45609
+ ? cfInTarget
45610
+ : { ...originCF, id: this.uuidGenerator.smallUuid(), ranges: [] };
45533
45611
  }
45534
45612
  pasteDataValidation(origin, target) {
45535
45613
  const rule = this.getters.getValidationRuleForCell(origin);
@@ -45561,7 +45639,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
45561
45639
  originRule.isBlocking === rule.isBlocking);
45562
45640
  return ruleInTargetSheet
45563
45641
  ? ruleInTargetSheet
45564
- : { ...originRule, id: this.uuidGenerator.uuidv4(), ranges: [] };
45642
+ : { ...originRule, id: this.uuidGenerator.smallUuid(), ranges: [] };
45565
45643
  }
45566
45644
  /**
45567
45645
  * Add or remove XCs to a given data validation rule.
@@ -47753,6 +47831,10 @@ class SheetUIPlugin extends UIPlugin {
47753
47831
  */
47754
47832
  checkZonesAreInSheet(cmd) {
47755
47833
  const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.tryGetActiveSheetId();
47834
+ if ("ranges" in cmd &&
47835
+ cmd.ranges.some((rangeData) => !this.getters.tryGetSheet(rangeData._sheetId))) {
47836
+ return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
47837
+ }
47756
47838
  const zones = this.getters.getCommandZones(cmd);
47757
47839
  if (!sheetId && zones.length > 0) {
47758
47840
  return "NoActiveSheet" /* CommandResult.NoActiveSheet */;
@@ -47801,23 +47883,23 @@ const uuidGenerator = new UuidGenerator();
47801
47883
  function repeatCreateChartCommand(getters, cmd) {
47802
47884
  return {
47803
47885
  ...repeatSheetDependantCommand(getters, cmd),
47804
- id: uuidGenerator.uuidv4(),
47886
+ id: uuidGenerator.smallUuid(),
47805
47887
  };
47806
47888
  }
47807
47889
  function repeatCreateImageCommand(getters, cmd) {
47808
47890
  return {
47809
47891
  ...repeatSheetDependantCommand(getters, cmd),
47810
- figureId: uuidGenerator.uuidv4(),
47892
+ figureId: uuidGenerator.smallUuid(),
47811
47893
  };
47812
47894
  }
47813
47895
  function repeatCreateFigureCommand(getters, cmd) {
47814
47896
  const newCmd = repeatSheetDependantCommand(getters, cmd);
47815
- newCmd.figure.id = uuidGenerator.uuidv4();
47897
+ newCmd.figure.id = uuidGenerator.smallUuid();
47816
47898
  return newCmd;
47817
47899
  }
47818
47900
  function repeatCreateSheetCommand(getters, cmd) {
47819
47901
  const newCmd = deepCopy(cmd);
47820
- newCmd.sheetId = uuidGenerator.uuidv4();
47902
+ newCmd.sheetId = uuidGenerator.smallUuid();
47821
47903
  const sheetName = cmd.name || getters.getSheet(getters.getActiveSheetId()).name;
47822
47904
  // Extract the prefix of the sheet name (everything before the number at the end of the name)
47823
47905
  const namePrefix = sheetName.match(/(.+?)\d*$/)?.[1] || sheetName;
@@ -48012,7 +48094,6 @@ class HistoryPlugin extends UIPlugin {
48012
48094
  super(config);
48013
48095
  this.session = config.session;
48014
48096
  this.session.on("new-local-state-update", this, this.onNewLocalStateUpdate);
48015
- this.session.on("pending-revisions-dropped", this, ({ revisionIds }) => this.drop(revisionIds));
48016
48097
  this.session.on("snapshot", this, () => {
48017
48098
  this.undoStack = [];
48018
48099
  this.redoStack = [];
@@ -48082,10 +48163,6 @@ class HistoryPlugin extends UIPlugin {
48082
48163
  const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
48083
48164
  return canRepeatRevision(lastNonRedoRevision);
48084
48165
  }
48085
- drop(revisionIds) {
48086
- this.undoStack = this.undoStack.filter((id) => !revisionIds.includes(id));
48087
- this.redoStack = [];
48088
- }
48089
48166
  onNewLocalStateUpdate({ id }) {
48090
48167
  this.undoStack.push(id);
48091
48168
  this.redoStack = [];
@@ -48352,7 +48429,7 @@ class ClipboardFigureState {
48352
48429
  x: maxX < width ? 0 : Math.min(targetX, maxX - width),
48353
48430
  y: maxY < height ? 0 : Math.min(targetY, maxY - height),
48354
48431
  };
48355
- const newId = new UuidGenerator().uuidv4();
48432
+ const newId = new UuidGenerator().smallUuid();
48356
48433
  this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
48357
48434
  if (this.operation === "CUT") {
48358
48435
  this.dispatch("DELETE_FIGURE", {
@@ -50055,23 +50132,7 @@ class GridSelectionPlugin extends UIPlugin {
50055
50132
  gridSelection: deepCopy(gridSelection),
50056
50133
  };
50057
50134
  }
50058
- if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
50059
- const currentSheetIds = this.getters.getVisibleSheetIds();
50060
- this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
50061
- if (this.activeSheet.id in this.sheetsData) {
50062
- const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
50063
- this.selectCell(anchor.cell.col, anchor.cell.row);
50064
- }
50065
- else {
50066
- this.selectCell(0, 0);
50067
- }
50068
- const { col, row } = this.gridSelection.anchor.cell;
50069
- this.moveClient({
50070
- sheetId: this.getters.getActiveSheetId(),
50071
- col,
50072
- row,
50073
- });
50074
- }
50135
+ this.fallbackToVisibleSheet();
50075
50136
  const sheetId = this.getters.getActiveSheetId();
50076
50137
  this.gridSelection.zones = this.gridSelection.zones.map((z) => this.getters.expandZone(sheetId, z));
50077
50138
  this.gridSelection.anchor.zone = this.getters.expandZone(sheetId, this.gridSelection.anchor.zone);
@@ -50081,6 +50142,7 @@ class GridSelectionPlugin extends UIPlugin {
50081
50142
  }
50082
50143
  }
50083
50144
  finalize() {
50145
+ this.fallbackToVisibleSheet();
50084
50146
  /** Any change to the selection has to be reflected in the selection processor. */
50085
50147
  this.selection.resetDefaultAnchor(this, deepCopy(this.gridSelection.anchor));
50086
50148
  }
@@ -50432,6 +50494,25 @@ class GridSelectionPlugin extends UIPlugin {
50432
50494
  }
50433
50495
  return "Success" /* CommandResult.Success */;
50434
50496
  }
50497
+ fallbackToVisibleSheet() {
50498
+ if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
50499
+ const currentSheetIds = this.getters.getVisibleSheetIds();
50500
+ this.activeSheet = this.getters.getSheet(currentSheetIds[0]);
50501
+ if (this.activeSheet.id in this.sheetsData) {
50502
+ const { anchor } = this.clipSelection(this.activeSheet.id, this.sheetsData[this.activeSheet.id].gridSelection);
50503
+ this.selectCell(anchor.cell.col, anchor.cell.row);
50504
+ }
50505
+ else {
50506
+ this.selectCell(0, 0);
50507
+ }
50508
+ const { col, row } = this.gridSelection.anchor.cell;
50509
+ this.moveClient({
50510
+ sheetId: this.getters.getActiveSheetId(),
50511
+ col,
50512
+ row,
50513
+ });
50514
+ }
50515
+ }
50435
50516
  //-------------------------------------------
50436
50517
  // Helpers for extensions
50437
50518
  // ------------------------------------------
@@ -51579,7 +51660,9 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51579
51660
  case "UNGROUP_HEADERS":
51580
51661
  case "GROUP_HEADERS":
51581
51662
  case "CREATE_SHEET":
51582
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51663
+ if (this.getters.tryGetSheet(cmd.sheetId)) {
51664
+ this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
51665
+ }
51583
51666
  break;
51584
51667
  case "DUPLICATE_SHEET":
51585
51668
  this.headerPositions[cmd.sheetIdTo] = deepCopy(this.headerPositions[cmd.sheetId]);
@@ -51587,12 +51670,14 @@ class HeaderPositionsUIPlugin extends UIPlugin {
51587
51670
  }
51588
51671
  }
51589
51672
  finalize() {
51590
- if (this.isDirty) {
51591
- for (const sheetId of this.getters.getSheetIds()) {
51673
+ for (const sheetId of this.getters.getSheetIds()) {
51674
+ // sheets can be created without this plugin being aware of it
51675
+ // in concurrent situations.
51676
+ if (this.isDirty || !this.headerPositions[sheetId]) {
51592
51677
  this.headerPositions[sheetId] = this.computeHeaderPositionsOfSheet(sheetId);
51593
51678
  }
51594
- this.isDirty = false;
51595
51679
  }
51680
+ this.isDirty = false;
51596
51681
  }
51597
51682
  /**
51598
51683
  * Returns the size, start and end coordinates of a column on an unfolded sheet
@@ -52276,7 +52361,7 @@ class BottomBar extends Component {
52276
52361
  clickAddSheet(ev) {
52277
52362
  const activeSheetId = this.env.model.getters.getActiveSheetId();
52278
52363
  const position = this.env.model.getters.getSheetIds().findIndex((sheetId) => sheetId === activeSheetId) + 1;
52279
- const sheetId = this.env.model.uuidGenerator.uuidv4();
52364
+ const sheetId = this.env.model.uuidGenerator.smallUuid();
52280
52365
  const name = this.env.model.getters.getNextSheetName(_t("Sheet"));
52281
52366
  this.env.model.dispatch("CREATE_SHEET", { sheetId, position, name });
52282
52367
  this.env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: activeSheetId, sheetIdTo: sheetId });
@@ -53338,7 +53423,7 @@ css /* scss */ `
53338
53423
  .o-font-size-editor {
53339
53424
  height: calc(100% - 4px);
53340
53425
  input.o-font-size {
53341
- outline-color: ${SELECTION_BORDER_COLOR};
53426
+ outline: none;
53342
53427
  height: 20px;
53343
53428
  width: 23px;
53344
53429
  }
@@ -54513,7 +54598,7 @@ class Tree {
54513
54598
  }
54514
54599
  /**
54515
54600
  * Drop the operation and all following operations in every
54516
- * branch
54601
+ * branches
54517
54602
  */
54518
54603
  drop(operationId) {
54519
54604
  for (const branch of this.branches) {
@@ -54818,9 +54903,16 @@ class SelectiveHistory {
54818
54903
  this.fastForward();
54819
54904
  this.insert(redoId, this.buildEmpty(redoId), insertAfter);
54820
54905
  }
54821
- drop(operationId) {
54906
+ rebase(operationId) {
54907
+ const operation = this.get(operationId);
54908
+ const execution = [...this.tree.execution(this.HEAD_BRANCH).startAfter(operationId)];
54822
54909
  this.revertBefore(operationId);
54910
+ const baseId = this.HEAD_OPERATION.id;
54823
54911
  this.tree.drop(operationId);
54912
+ this.insert(operationId, operation, baseId);
54913
+ for (const { operation } of execution) {
54914
+ this.insert(operation.id, operation.data, this.HEAD_OPERATION.id);
54915
+ }
54824
54916
  }
54825
54917
  getRevertedExecution() {
54826
54918
  const data = [];
@@ -57397,6 +57489,11 @@ class Model extends EventBus {
57397
57489
  dispatch: (command) => {
57398
57490
  const result = this.checkDispatchAllowed(command);
57399
57491
  if (!result.isSuccessful) {
57492
+ // core views plugins need to be invalidated
57493
+ this.dispatchToHandlers(this.coreHandlers, {
57494
+ type: "UNDO",
57495
+ commands: [command],
57496
+ });
57400
57497
  return;
57401
57498
  }
57402
57499
  this.isReplayingCommand = true;
@@ -57425,7 +57522,7 @@ class Model extends EventBus {
57425
57522
  }
57426
57523
  setupConfig(config) {
57427
57524
  const client = config.client || {
57428
- id: this.uuidGenerator.uuidv4(),
57525
+ id: this.uuidGenerator.smallUuid(),
57429
57526
  name: _t("Anonymous").toString(),
57430
57527
  };
57431
57528
  const transportService = config.transportService || new LocalTransportService();
@@ -57811,6 +57908,6 @@ const constants = {
57811
57908
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
57812
57909
 
57813
57910
 
57814
- __info__.version = "17.0.49";
57815
- __info__.date = "2025-02-10T08:55:47.771Z";
57816
- __info__.hash = "1049319";
57911
+ __info__.version = "17.0.51";
57912
+ __info__.date = "2025-02-25T05:56:10.869Z";
57913
+ __info__.hash = "b433912";