@odoo/o-spreadsheet 18.2.9 → 18.2.11

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.2.9
6
- * @date 2025-04-25T08:06:52.677Z
7
- * @hash 3e88645
5
+ * @version 18.2.11
6
+ * @date 2025-05-12T05:25:59.138Z
7
+ * @hash eb87dca
8
8
  */
9
9
 
10
10
  'use strict';
@@ -3771,6 +3771,7 @@ exports.CommandResult = void 0;
3771
3771
  CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
3772
3772
  CommandResult["InvalidDefinition"] = "InvalidDefinition";
3773
3773
  CommandResult["InvalidColor"] = "InvalidColor";
3774
+ CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
3774
3775
  })(exports.CommandResult || (exports.CommandResult = {}));
3775
3776
 
3776
3777
  const DEFAULT_LOCALES = [
@@ -6281,6 +6282,25 @@ function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
6281
6282
  })
6282
6283
  .filter(isDefined);
6283
6284
  }
6285
+ function getNextSheetName(existingNames, baseName = "Sheet") {
6286
+ let i = 1;
6287
+ let name = `${baseName}${i}`;
6288
+ while (existingNames.includes(name)) {
6289
+ name = `${baseName}${i}`;
6290
+ i++;
6291
+ }
6292
+ return name;
6293
+ }
6294
+ function getDuplicateSheetName(nameToDuplicate, existingNames) {
6295
+ let i = 1;
6296
+ const baseName = _t("Copy of %s", nameToDuplicate);
6297
+ let name = baseName.toString();
6298
+ while (existingNames.includes(name)) {
6299
+ name = `${baseName} (${i})`;
6300
+ i++;
6301
+ }
6302
+ return name;
6303
+ }
6284
6304
 
6285
6305
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
6286
6306
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
@@ -7979,6 +7999,24 @@ const monthNumberAdapter = {
7979
7999
  return `${normalizedValue}`;
7980
8000
  },
7981
8001
  };
8002
+ /**
8003
+ * normalizes month number + year
8004
+ */
8005
+ const monthAdapter = {
8006
+ normalizeFunctionValue(value) {
8007
+ const date = toNumber(value, DEFAULT_LOCALE);
8008
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
8009
+ },
8010
+ toValueAndFormat(normalizedValue) {
8011
+ return {
8012
+ value: toNumber(normalizedValue, DEFAULT_LOCALE),
8013
+ format: "mmmm yyyy",
8014
+ };
8015
+ },
8016
+ toFunctionValue(normalizedValue) {
8017
+ return `"${normalizedValue}"`;
8018
+ },
8019
+ };
7982
8020
  /**
7983
8021
  * normalizes quarter number
7984
8022
  */
@@ -8109,6 +8147,7 @@ pivotTimeAdapterRegistry
8109
8147
  .add("day_of_month", nullHandlerDecorator(dayOfMonthAdapter))
8110
8148
  .add("iso_week_number", nullHandlerDecorator(isoWeekNumberAdapter))
8111
8149
  .add("month_number", nullHandlerDecorator(monthNumberAdapter))
8150
+ .add("month", nullHandlerDecorator(monthAdapter))
8112
8151
  .add("quarter_number", nullHandlerDecorator(quarterNumberAdapter))
8113
8152
  .add("day_of_week", nullHandlerDecorator(dayOfWeekAdapter))
8114
8153
  .add("hour_number", nullHandlerDecorator(hourNumberAdapter))
@@ -8289,10 +8328,7 @@ function toNormalizedPivotValue(dimension, groupValue) {
8289
8328
  return normalizer(groupValueString, dimension.granularity);
8290
8329
  }
8291
8330
  function normalizeDateTime(value, granularity) {
8292
- if (!granularity) {
8293
- throw new Error("Missing granularity");
8294
- }
8295
- return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
8331
+ return pivotTimeAdapter(granularity ?? "month").normalizeFunctionValue(value);
8296
8332
  }
8297
8333
  function toFunctionPivotValue(value, dimension) {
8298
8334
  if (value === null) {
@@ -8304,10 +8340,7 @@ function toFunctionPivotValue(value, dimension) {
8304
8340
  return pivotToFunctionValueRegistry.get(dimension.type)(value, dimension.granularity);
8305
8341
  }
8306
8342
  function toFunctionValueDateTime(value, granularity) {
8307
- if (!granularity) {
8308
- throw new Error("Missing granularity");
8309
- }
8310
- return pivotTimeAdapter(granularity).toFunctionValue(value);
8343
+ return pivotTimeAdapter(granularity ?? "month").toFunctionValue(value);
8311
8344
  }
8312
8345
  const pivotNormalizationValueRegistry = new Registry();
8313
8346
  pivotNormalizationValueRegistry
@@ -9766,12 +9799,24 @@ function getElementMargins(el) {
9766
9799
  }
9767
9800
 
9768
9801
  const chartJsExtensionRegistry = new Registry();
9769
- /** Return window.Chart, making sure all our extensions are loaded in ChartJS */
9770
- function getChartJSConstructor() {
9771
- if (window.Chart && !window.Chart?.registry.plugins.get("chartShowValuesPlugin")) {
9772
- window.Chart.register(...chartJsExtensionRegistry.getAll());
9802
+ function areChartJSExtensionsLoaded() {
9803
+ return !!window.Chart.registry.plugins.get("chartShowValuesPlugin");
9804
+ }
9805
+ function registerChartJSExtensions() {
9806
+ if (!window.Chart || areChartJSExtensionsLoaded()) {
9807
+ return;
9808
+ }
9809
+ for (const registryItem of chartJsExtensionRegistry.getAll()) {
9810
+ registryItem.register(window.Chart);
9811
+ }
9812
+ }
9813
+ function unregisterChartJsExtensions() {
9814
+ if (!window.Chart) {
9815
+ return;
9816
+ }
9817
+ for (const registryItem of chartJsExtensionRegistry.getAll()) {
9818
+ registryItem.unregister(window.Chart);
9773
9819
  }
9774
- return window.Chart;
9775
9820
  }
9776
9821
 
9777
9822
  const TREND_LINE_XAXIS_ID = "x1";
@@ -10173,7 +10218,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
10173
10218
  const yMin = chart.chartArea.top;
10174
10219
  const textsPositions = {};
10175
10220
  for (const dataset of chart._metasets) {
10176
- if (isTrendLineAxis(dataset.axisID) || dataset.hidden) {
10221
+ if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
10177
10222
  continue;
10178
10223
  }
10179
10224
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10216,7 +10261,7 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
10216
10261
  const xMin = chart.chartArea.left;
10217
10262
  const textsPositions = {};
10218
10263
  for (const dataset of chart._metasets) {
10219
- if (isTrendLineAxis(dataset.axisID)) {
10264
+ if (isTrendLineAxis(dataset.xAxisID)) {
10220
10265
  return; // ignore trend lines
10221
10266
  }
10222
10267
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10331,8 +10376,14 @@ css /* scss */ `
10331
10376
  }
10332
10377
  }
10333
10378
  `;
10334
- chartJsExtensionRegistry.add("chartShowValuesPlugin", chartShowValuesPlugin);
10335
- chartJsExtensionRegistry.add("waterfallLinesPlugin", waterfallLinesPlugin);
10379
+ chartJsExtensionRegistry.add("chartShowValuesPlugin", {
10380
+ register: (Chart) => Chart.register(chartShowValuesPlugin),
10381
+ unregister: (Chart) => Chart.unregister(chartShowValuesPlugin),
10382
+ });
10383
+ chartJsExtensionRegistry.add("waterfallLinesPlugin", {
10384
+ register: (Chart) => Chart.register(waterfallLinesPlugin),
10385
+ unregister: (Chart) => Chart.unregister(waterfallLinesPlugin),
10386
+ });
10336
10387
  class ChartJsComponent extends owl.Component {
10337
10388
  static template = "o-spreadsheet-ChartJsComponent";
10338
10389
  static props = {
@@ -10341,6 +10392,7 @@ class ChartJsComponent extends owl.Component {
10341
10392
  canvas = owl.useRef("graphContainer");
10342
10393
  chart;
10343
10394
  currentRuntime;
10395
+ currentDevicePixelRatio = window.devicePixelRatio;
10344
10396
  get background() {
10345
10397
  return this.chartRuntime.background;
10346
10398
  }
@@ -10374,13 +10426,16 @@ class ChartJsComponent extends owl.Component {
10374
10426
  }
10375
10427
  this.currentRuntime = runtime;
10376
10428
  }
10429
+ else if (this.currentDevicePixelRatio !== window.devicePixelRatio) {
10430
+ this.currentDevicePixelRatio = window.devicePixelRatio;
10431
+ this.updateChartJs(deepCopy(this.currentRuntime.chartJsConfig));
10432
+ }
10377
10433
  });
10378
10434
  }
10379
10435
  createChart(chartData) {
10380
10436
  const canvas = this.canvas.el;
10381
10437
  const ctx = canvas.getContext("2d");
10382
- const Chart = getChartJSConstructor();
10383
- this.chart = new Chart(ctx, chartData);
10438
+ this.chart = new window.Chart(ctx, chartData);
10384
10439
  }
10385
10440
  updateChartJs(chartData) {
10386
10441
  if (chartData.data && chartData.data.datasets) {
@@ -10629,9 +10684,11 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
10629
10684
  };
10630
10685
  function drawScoreChart(structure, canvas) {
10631
10686
  const ctx = canvas.getContext("2d");
10632
- canvas.width = structure.canvas.width;
10633
- const availableWidth = canvas.width - CHART_PADDING$1 * 2;
10634
- canvas.height = structure.canvas.height;
10687
+ const dpr = window.devicePixelRatio || 1;
10688
+ canvas.width = dpr * structure.canvas.width;
10689
+ canvas.height = dpr * structure.canvas.height;
10690
+ ctx.scale(dpr, dpr);
10691
+ const availableWidth = structure.canvas.width - CHART_PADDING$1 * 2;
10635
10692
  ctx.fillStyle = structure.canvas.backgroundColor;
10636
10693
  ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
10637
10694
  if (structure.title) {
@@ -10994,7 +11051,7 @@ class ScorecardChart extends owl.Component {
10994
11051
  owl.useEffect(this.createChart.bind(this), () => {
10995
11052
  const canvas = this.canvas.el;
10996
11053
  const rect = canvas.getBoundingClientRect();
10997
- return [rect.width, rect.height, this.runtime, this.canvas.el];
11054
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
10998
11055
  });
10999
11056
  }
11000
11057
  createChart() {
@@ -18510,7 +18567,7 @@ const IF = {
18510
18567
  return { value: "" };
18511
18568
  }
18512
18569
  if (result.value === null) {
18513
- result.value = "";
18570
+ return { ...result, value: "" };
18514
18571
  }
18515
18572
  return result;
18516
18573
  },
@@ -18531,7 +18588,7 @@ const IFERROR = {
18531
18588
  return { value: "" };
18532
18589
  }
18533
18590
  if (result.value === null) {
18534
- result.value = "";
18591
+ return { ...result, value: "" };
18535
18592
  }
18536
18593
  return result;
18537
18594
  },
@@ -18552,7 +18609,7 @@ const IFNA = {
18552
18609
  return { value: "" };
18553
18610
  }
18554
18611
  if (result.value === null) {
18555
- result.value = "";
18612
+ return { ...result, value: "" };
18556
18613
  }
18557
18614
  return result;
18558
18615
  },
@@ -18578,7 +18635,7 @@ const IFS = {
18578
18635
  return { value: "" };
18579
18636
  }
18580
18637
  if (result.value === null) {
18581
- result.value = "";
18638
+ return { ...result, value: "" };
18582
18639
  }
18583
18640
  return result;
18584
18641
  }
@@ -18696,6 +18753,11 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
18696
18753
  if (range === undefined || range.invalidXc || range.invalidSheetName) {
18697
18754
  throw new InvalidReferenceError();
18698
18755
  }
18756
+ if (evalContext.__originCellPosition &&
18757
+ range.sheetId === evalContext.__originSheetId &&
18758
+ isZoneInside(positionToZone(evalContext.__originCellPosition), zone)) {
18759
+ throw new CircularDependencyError();
18760
+ }
18699
18761
  dependencies.push(range);
18700
18762
  }
18701
18763
  for (const measure of forMeasures) {
@@ -22583,9 +22645,11 @@ const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
22583
22645
  const GAUGE_TITLE_SECTION_HEIGHT = 25;
22584
22646
  function drawGaugeChart(canvas, runtime) {
22585
22647
  const canvasBoundingRect = canvas.getBoundingClientRect();
22586
- canvas.width = canvasBoundingRect.width;
22587
- canvas.height = canvasBoundingRect.height;
22648
+ const dpr = window.devicePixelRatio || 1;
22649
+ canvas.width = dpr * canvasBoundingRect.width;
22650
+ canvas.height = dpr * canvasBoundingRect.height;
22588
22651
  const ctx = canvas.getContext("2d");
22652
+ ctx.scale(dpr, dpr);
22589
22653
  const config = getGaugeRenderingConfig(canvasBoundingRect, runtime, ctx);
22590
22654
  drawBackground(ctx, config);
22591
22655
  drawGauge(ctx, config);
@@ -22920,7 +22984,7 @@ class GaugeChartComponent extends owl.Component {
22920
22984
  owl.useEffect(() => drawGaugeChart(this.canvas.el, this.runtime), () => {
22921
22985
  const canvas = this.canvas.el;
22922
22986
  const rect = canvas.getBoundingClientRect();
22923
- return [rect.width, rect.height, this.runtime, this.canvas.el];
22987
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
22924
22988
  });
22925
22989
  }
22926
22990
  }
@@ -22955,6 +23019,7 @@ const CHART_COMMON_OPTIONS = {
22955
23019
  },
22956
23020
  },
22957
23021
  animation: false,
23022
+ events: ["mousemove", "mouseout", "click", "touchstart", "touchmove", "mouseup"],
22958
23023
  };
22959
23024
  function chartToImage(runtime, figure, type) {
22960
23025
  // wrap the canvas in a div with a fixed size because chart.js would
@@ -22971,8 +23036,7 @@ function chartToImage(runtime, figure, type) {
22971
23036
  if ("chartJsConfig" in runtime) {
22972
23037
  const config = deepCopy(runtime.chartJsConfig);
22973
23038
  config.plugins = [backgroundColorChartJSPlugin];
22974
- const Chart = getChartJSConstructor();
22975
- const chart = new Chart(canvas, config);
23039
+ const chart = new window.Chart(canvas, config);
22976
23040
  const imgContent = chart.toBase64Image();
22977
23041
  chart.destroy();
22978
23042
  div.remove();
@@ -27965,6 +28029,7 @@ function repairInitialMessages(data, initialMessages) {
27965
28029
  initialMessages = dropCommands(initialMessages, "SORT_CELLS");
27966
28030
  initialMessages = dropCommands(initialMessages, "SET_DECIMAL");
27967
28031
  initialMessages = fixChartDefinitions(data, initialMessages);
28032
+ initialMessages = fixTranslatedDuplicateSheetName(data, initialMessages);
27968
28033
  return initialMessages;
27969
28034
  }
27970
28035
  /**
@@ -28064,6 +28129,40 @@ function fixChartDefinitions(data, initialMessages) {
28064
28129
  }
28065
28130
  return messages;
28066
28131
  }
28132
+ function fixTranslatedDuplicateSheetName(data, initialMessages) {
28133
+ const sheetNames = {};
28134
+ for (const sheet of data.sheets || []) {
28135
+ sheetNames[sheet.id] = sheet.name;
28136
+ }
28137
+ const messages = [];
28138
+ for (const message of initialMessages) {
28139
+ if (message.type === "REMOTE_REVISION") {
28140
+ const commands = [];
28141
+ for (const cmd of message.commands) {
28142
+ switch (cmd.type) {
28143
+ case "DUPLICATE_SHEET":
28144
+ cmd.sheetNameTo =
28145
+ cmd.sheetNameTo ??
28146
+ getDuplicateSheetName(sheetNames[cmd.sheetId], Object.values(sheetNames));
28147
+ break;
28148
+ case "CREATE_SHEET":
28149
+ case "RENAME_SHEET":
28150
+ sheetNames[cmd.sheetId] = cmd.name || getNextSheetName(Object.values(sheetNames));
28151
+ break;
28152
+ }
28153
+ commands.push(cmd);
28154
+ }
28155
+ messages.push({
28156
+ ...message,
28157
+ commands,
28158
+ });
28159
+ }
28160
+ else {
28161
+ messages.push(message);
28162
+ }
28163
+ }
28164
+ return initialMessages;
28165
+ }
28067
28166
  // -----------------------------------------------------------------------------
28068
28167
  // Helpers
28069
28168
  // -----------------------------------------------------------------------------
@@ -28860,12 +28959,11 @@ function canBeLinearChart(definition, dataSets, labelRange, getters) {
28860
28959
  }
28861
28960
  let missingTimeAdapterAlreadyWarned = false;
28862
28961
  function isLuxonTimeAdapterInstalled() {
28863
- const Chart = getChartJSConstructor();
28864
- if (!Chart) {
28962
+ if (!window.Chart) {
28865
28963
  return false;
28866
28964
  }
28867
28965
  // @ts-ignore
28868
- const adapter = new Chart._adapters._date({});
28966
+ const adapter = new window.Chart._adapters._date({});
28869
28967
  const isInstalled = adapter._id === "luxon";
28870
28968
  if (!isInstalled && !missingTimeAdapterAlreadyWarned) {
28871
28969
  missingTimeAdapterAlreadyWarned = true;
@@ -29503,6 +29601,9 @@ const INTERACTIVE_LEGEND_CONFIG = {
29503
29601
  target.style.cursor = "default";
29504
29602
  },
29505
29603
  onClick: (event, legendItem, legend) => {
29604
+ if (event.type !== "click") {
29605
+ return;
29606
+ }
29506
29607
  const index = legendItem.datasetIndex;
29507
29608
  if (!legend.legendItems || index === undefined) {
29508
29609
  return;
@@ -29583,7 +29684,7 @@ function getBarChartScales(definition, args) {
29583
29684
  };
29584
29685
  scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29585
29686
  ...scales.x,
29586
- offset: false,
29687
+ offset: true,
29587
29688
  display: false,
29588
29689
  };
29589
29690
  }
@@ -30303,9 +30404,6 @@ class BarChart extends AbstractChart {
30303
30404
  };
30304
30405
  }
30305
30406
  getDefinitionForExcel() {
30306
- // Excel does not support aggregating labels
30307
- if (this.aggregated)
30308
- return undefined;
30309
30407
  const dataSets = this.dataSets
30310
30408
  .map((ds) => toExcelDataset(this.getters, ds))
30311
30409
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -31020,9 +31118,6 @@ class LineChart extends AbstractChart {
31020
31118
  return new LineChart(definition, this.sheetId, this.getters);
31021
31119
  }
31022
31120
  getDefinitionForExcel() {
31023
- // Excel does not support aggregating labels
31024
- if (this.aggregated)
31025
- return undefined;
31026
31121
  const dataSets = this.dataSets
31027
31122
  .map((ds) => toExcelDataset(this.getters, ds))
31028
31123
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -31159,9 +31254,6 @@ class PieChart extends AbstractChart {
31159
31254
  return new PieChart(definition, sheetId, this.getters);
31160
31255
  }
31161
31256
  getDefinitionForExcel() {
31162
- // Excel does not support aggregating labels
31163
- if (this.aggregated)
31164
- return undefined;
31165
31257
  const dataSets = this.dataSets
31166
31258
  .map((ds) => toExcelDataset(this.getters, ds))
31167
31259
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -33411,10 +33503,13 @@ const duplicateSheet = {
33411
33503
  name: _t("Duplicate"),
33412
33504
  execute: (env) => {
33413
33505
  const sheetIdFrom = env.model.getters.getActiveSheetId();
33506
+ const sheetNameFrom = env.model.getters.getSheetName(sheetIdFrom);
33414
33507
  const sheetIdTo = env.model.uuidGenerator.smallUuid();
33508
+ const sheetNameTo = env.model.getters.getDuplicateSheetName(sheetNameFrom);
33415
33509
  env.model.dispatch("DUPLICATE_SHEET", {
33416
33510
  sheetId: sheetIdFrom,
33417
33511
  sheetIdTo,
33512
+ sheetNameTo,
33418
33513
  });
33419
33514
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
33420
33515
  },
@@ -33660,18 +33755,28 @@ function isBrowserFirefox() {
33660
33755
  function useInterval(callback, delay) {
33661
33756
  let intervalId;
33662
33757
  const { setInterval, clearInterval } = window;
33758
+ const pause = () => {
33759
+ clearInterval(intervalId);
33760
+ intervalId = undefined;
33761
+ };
33762
+ const safeCallback = () => {
33763
+ try {
33764
+ callback();
33765
+ }
33766
+ catch (e) {
33767
+ pause();
33768
+ throw e;
33769
+ }
33770
+ };
33663
33771
  owl.useEffect(() => {
33664
- intervalId = setInterval(callback, delay);
33772
+ intervalId = setInterval(safeCallback, delay);
33665
33773
  return () => clearInterval(intervalId);
33666
33774
  }, () => [delay]);
33667
33775
  return {
33668
- pause: () => {
33669
- clearInterval(intervalId);
33670
- intervalId = undefined;
33671
- },
33776
+ pause,
33672
33777
  resume: () => {
33673
33778
  if (intervalId === undefined) {
33674
- intervalId = setInterval(callback, delay);
33779
+ intervalId = setInterval(safeCallback, delay);
33675
33780
  }
33676
33781
  },
33677
33782
  };
@@ -38452,8 +38557,11 @@ class SelectionInput extends owl.Component {
38452
38557
  }
38453
38558
  removeInput(rangeId) {
38454
38559
  const index = this.store.selectionInputs.findIndex((range) => range.id === rangeId);
38455
- this.props.onSelectionRemoved?.(index);
38456
- this.props.onSelectionConfirmed?.();
38560
+ if (this.ranges.find((range) => range.id === rangeId)?.xc) {
38561
+ this.props.onSelectionRemoved?.(index);
38562
+ this.props.onSelectionConfirmed?.();
38563
+ }
38564
+ this.store.removeRange(rangeId);
38457
38565
  }
38458
38566
  onInputChanged(rangeId, ev) {
38459
38567
  const target = ev.target;
@@ -38604,7 +38712,7 @@ class GenericChartConfigPanel extends owl.Component {
38604
38712
  const cancelledReasons = [
38605
38713
  ...(this.state.datasetDispatchResult?.reasons || []),
38606
38714
  ...(this.state.labelsDispatchResult?.reasons || []),
38607
- ];
38715
+ ].filter((reason) => reason !== "NoChanges" /* CommandResult.NoChanges */);
38608
38716
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
38609
38717
  }
38610
38718
  get isDatasetInvalid() {
@@ -40826,6 +40934,13 @@ class Composer extends owl.Component {
40826
40934
  openAssistant() {
40827
40935
  this.assistant.forcedClosed = false;
40828
40936
  }
40937
+ onWheel(event) {
40938
+ // detect if scrollbar is available
40939
+ if (this.composerRef.el &&
40940
+ this.composerRef.el.scrollHeight > this.composerRef.el.clientHeight) {
40941
+ event.stopPropagation();
40942
+ }
40943
+ }
40829
40944
  // ---------------------------------------------------------------------------
40830
40945
  // Private
40831
40946
  // ---------------------------------------------------------------------------
@@ -46302,8 +46417,8 @@ function compareDimensionValues(dimension, a, b) {
46302
46417
 
46303
46418
  const NULL_SYMBOL = Symbol("NULL");
46304
46419
  function createDate(dimension, value, locale) {
46305
- const granularity = dimension.granularity;
46306
- if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
46420
+ const granularity = dimension.granularity || "month";
46421
+ if (!(granularity in MAP_VALUE_DIMENSION_DATE)) {
46307
46422
  throw new Error(`Unknown date granularity: ${granularity}`);
46308
46423
  }
46309
46424
  const keyInMap = typeof value === "number" || typeof value === "string" ? value : NULL_SYMBOL;
@@ -46322,6 +46437,9 @@ function createDate(dimension, value, locale) {
46322
46437
  case "month_number":
46323
46438
  number = date.getMonth() + 1;
46324
46439
  break;
46440
+ case "month":
46441
+ number = Math.floor(toNumber(value, locale));
46442
+ break;
46325
46443
  case "iso_week_number":
46326
46444
  number = date.getIsoWeek();
46327
46445
  break;
@@ -46415,6 +46533,10 @@ const MAP_VALUE_DIMENSION_DATE = {
46415
46533
  set: new Set(),
46416
46534
  values: {},
46417
46535
  },
46536
+ month: {
46537
+ set: new Set(),
46538
+ values: {},
46539
+ },
46418
46540
  iso_week_number: {
46419
46541
  set: new Set(),
46420
46542
  values: {},
@@ -46625,7 +46747,7 @@ class SpreadsheetPivot {
46625
46747
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
46626
46748
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
46627
46749
  if (dimension.type === "datetime") {
46628
- const adapter = pivotTimeAdapter(dimension.granularity);
46750
+ const adapter = pivotTimeAdapter((dimension.granularity || "month"));
46629
46751
  return adapter.toValueAndFormat(lastNode.value, this.getters.getLocale());
46630
46752
  }
46631
46753
  if (!finalCell) {
@@ -46743,7 +46865,7 @@ class SpreadsheetPivot {
46743
46865
  if (nonEmptyCells.length === 0) {
46744
46866
  return "integer";
46745
46867
  }
46746
- if (nonEmptyCells.every((cell) => cell.format && isDateTimeFormat(cell.format))) {
46868
+ if (nonEmptyCells.every((cell) => cell.type === CellValueType.number && cell.format && isDateTimeFormat(cell.format))) {
46747
46869
  return "datetime";
46748
46870
  }
46749
46871
  if (nonEmptyCells.every((cell) => cell.type === CellValueType.boolean)) {
@@ -46836,7 +46958,7 @@ class SpreadsheetPivot {
46836
46958
  for (const entry of dataEntries) {
46837
46959
  for (const dimension of dateDimensions) {
46838
46960
  const value = createDate(dimension, entry[dimension.fieldName]?.value || null, this.getters.getLocale());
46839
- const adapter = pivotTimeAdapter(dimension.granularity);
46961
+ const adapter = pivotTimeAdapter((dimension.granularity || "month"));
46840
46962
  const { format, value: valueToFormat } = adapter.toValueAndFormat(value, locale);
46841
46963
  entry[dimension.nameWithGranularity] = {
46842
46964
  value,
@@ -46856,6 +46978,7 @@ const dateGranularities = [
46856
46978
  "year",
46857
46979
  "quarter_number",
46858
46980
  "month_number",
46981
+ "month",
46859
46982
  "iso_week_number",
46860
46983
  "day_of_month",
46861
46984
  "day",
@@ -47106,7 +47229,7 @@ class PivotSidePanelStore extends SpreadsheetStore {
47106
47229
  : this.datetimeGranularities);
47107
47230
  }
47108
47231
  for (const field of dateFields) {
47109
- granularitiesPerFields[field.fieldName].delete(field.granularity);
47232
+ granularitiesPerFields[field.fieldName].delete(field.granularity || "month");
47110
47233
  }
47111
47234
  return granularitiesPerFields;
47112
47235
  }
@@ -49276,6 +49399,8 @@ class GridComposer extends owl.Component {
49276
49399
  }
49277
49400
  get composerProps() {
49278
49401
  const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
49402
+ // Remove the wrapper border width
49403
+ const maxHeight = this.props.gridDims.height - this.rect.y - 2 * COMPOSER_BORDER_WIDTH;
49279
49404
  return {
49280
49405
  rect: { ...this.rect },
49281
49406
  delimitation: {
@@ -49293,6 +49418,7 @@ class GridComposer extends owl.Component {
49293
49418
  }),
49294
49419
  onInputContextMenu: this.props.onInputContextMenu,
49295
49420
  composerStore: this.composerStore,
49421
+ inputStyle: `max-height: ${maxHeight}px;`,
49296
49422
  };
49297
49423
  }
49298
49424
  get containerStyle() {
@@ -50853,7 +50979,7 @@ css /* scss */ `
50853
50979
  position: absolute;
50854
50980
  top: 0;
50855
50981
  left: ${HEADER_WIDTH}px;
50856
- right: 0;
50982
+ right: ${SCROLLBAR_WIDTH}px;
50857
50983
  height: ${HEADER_HEIGHT}px;
50858
50984
  width: calc(100% - ${HEADER_WIDTH + SCROLLBAR_WIDTH}px);
50859
50985
  &.o-dragging {
@@ -51046,9 +51172,8 @@ css /* scss */ `
51046
51172
  position: absolute;
51047
51173
  top: ${HEADER_HEIGHT}px;
51048
51174
  left: 0;
51049
- right: 0;
51175
+ bottom: ${SCROLLBAR_WIDTH}px;
51050
51176
  width: ${HEADER_WIDTH}px;
51051
- height: calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px);
51052
51177
  &.o-dragging {
51053
51178
  cursor: grabbing;
51054
51179
  }
@@ -54556,7 +54681,7 @@ class ChartPlugin extends CorePlugin {
54556
54681
  case "CREATE_CHART":
54557
54682
  return this.checkValidations(cmd, this.chainValidations(this.validateChartDefinition, this.checkChartDuplicate));
54558
54683
  case "UPDATE_CHART":
54559
- return this.checkValidations(cmd, this.chainValidations(this.validateChartDefinition, this.checkChartExists));
54684
+ return this.checkValidations(cmd, this.chainValidations(this.validateChartDefinition, this.checkChartExists, this.checkChartChanged));
54560
54685
  default:
54561
54686
  return "Success" /* CommandResult.Success */;
54562
54687
  }
@@ -54711,9 +54836,12 @@ class ChartPlugin extends CorePlugin {
54711
54836
  : "Success" /* CommandResult.Success */;
54712
54837
  }
54713
54838
  checkChartExists(cmd) {
54714
- return this.getters.getFigureSheetId(cmd.id)
54715
- ? "Success" /* CommandResult.Success */
54716
- : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
54839
+ return this.isChartDefined(cmd.id) ? "Success" /* CommandResult.Success */ : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
54840
+ }
54841
+ checkChartChanged(cmd) {
54842
+ return deepEquals(this.getChartDefinition(cmd.id), cmd.definition)
54843
+ ? "NoChanges" /* CommandResult.NoChanges */
54844
+ : "Success" /* CommandResult.Success */;
54717
54845
  }
54718
54846
  }
54719
54847
 
@@ -57032,6 +57160,7 @@ class SheetPlugin extends CorePlugin {
57032
57160
  "getCommandZones",
57033
57161
  "getUnboundedZone",
57034
57162
  "checkElementsIncludeAllNonFrozenHeaders",
57163
+ "getDuplicateSheetName",
57035
57164
  ];
57036
57165
  sheetIdsMapName = {};
57037
57166
  orderedSheetIds = [];
@@ -57056,7 +57185,11 @@ class SheetPlugin extends CorePlugin {
57056
57185
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
57057
57186
  }
57058
57187
  case "DUPLICATE_SHEET": {
57059
- return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
57188
+ if (this.sheets[cmd.sheetIdTo])
57189
+ return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
57190
+ if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
57191
+ return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
57192
+ return "Success" /* CommandResult.Success */;
57060
57193
  }
57061
57194
  case "MOVE_SHEET":
57062
57195
  try {
@@ -57133,7 +57266,7 @@ class SheetPlugin extends CorePlugin {
57133
57266
  this.showSheet(cmd.sheetId);
57134
57267
  break;
57135
57268
  case "DUPLICATE_SHEET":
57136
- this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo);
57269
+ this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo, cmd.sheetNameTo);
57137
57270
  break;
57138
57271
  case "DELETE_SHEET":
57139
57272
  this.deleteSheet(this.sheets[cmd.sheetId]);
@@ -57340,10 +57473,7 @@ class SheetPlugin extends CorePlugin {
57340
57473
  }
57341
57474
  getNextSheetName(baseName = "Sheet") {
57342
57475
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
57343
- return getUniqueText(baseName, names, {
57344
- compute: (name, i) => `${name}${i}`,
57345
- computeFirstOne: true,
57346
- });
57476
+ return getNextSheetName(names, baseName);
57347
57477
  }
57348
57478
  getSheetSize(sheetId) {
57349
57479
  return {
@@ -57589,9 +57719,8 @@ class SheetPlugin extends CorePlugin {
57589
57719
  showSheet(sheetId) {
57590
57720
  this.history.update("sheets", sheetId, "isVisible", true);
57591
57721
  }
57592
- duplicateSheet(fromId, toId) {
57722
+ duplicateSheet(fromId, toId, toName) {
57593
57723
  const sheet = this.getSheet(fromId);
57594
- const toName = this.getDuplicateSheetName(sheet.name);
57595
57724
  const newSheet = deepCopy(sheet);
57596
57725
  newSheet.id = toId;
57597
57726
  newSheet.name = toName;
@@ -57624,8 +57753,7 @@ class SheetPlugin extends CorePlugin {
57624
57753
  }
57625
57754
  getDuplicateSheetName(sheetName) {
57626
57755
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
57627
- const baseName = _t("Copy of %s", sheetName);
57628
- return getUniqueText(baseName.toString(), names);
57756
+ return getDuplicateSheetName(sheetName, names);
57629
57757
  }
57630
57758
  deleteSheet(sheet) {
57631
57759
  const name = sheet.name;
@@ -59096,6 +59224,15 @@ function adaptPivotRange(range, applyChange) {
59096
59224
  }
59097
59225
  }
59098
59226
  class SpreadsheetPivotCorePlugin extends CorePlugin {
59227
+ allowDispatch(cmd) {
59228
+ switch (cmd.type) {
59229
+ case "ADD_PIVOT":
59230
+ case "UPDATE_PIVOT":
59231
+ const definition = cmd.pivot;
59232
+ return this.checkDataSetValidity(definition);
59233
+ }
59234
+ return "Success" /* CommandResult.Success */;
59235
+ }
59099
59236
  adaptRanges(applyChange) {
59100
59237
  for (const pivotId of this.getters.getPivotIds()) {
59101
59238
  const definition = this.getters.getPivotCoreDefinition(pivotId);
@@ -59114,6 +59251,16 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
59114
59251
  }
59115
59252
  }
59116
59253
  }
59254
+ checkDataSetValidity(definition) {
59255
+ if (definition.type === "SPREADSHEET" && definition.dataSet) {
59256
+ const { zone, sheetId } = definition.dataSet;
59257
+ if (!sheetId || !this.getters.tryGetSheet(sheetId) || !zone || !isZoneValid(zone)) {
59258
+ return "InvalidDataSet" /* CommandResult.InvalidDataSet */;
59259
+ }
59260
+ return this.getters.checkZonesExistInSheet(sheetId, [zone]);
59261
+ }
59262
+ return "Success" /* CommandResult.Success */;
59263
+ }
59117
59264
  }
59118
59265
 
59119
59266
  class TableStylePlugin extends CorePlugin {
@@ -60401,8 +60548,8 @@ class SpreadingRelation {
60401
60548
  const EMPTY_ARRAY = [];
60402
60549
 
60403
60550
  const MAX_ITERATION = 30;
60404
- const ERROR_CYCLE_CELL = createEvaluatedCell(new CircularDependencyError());
60405
- const EMPTY_CELL = createEvaluatedCell({ value: null });
60551
+ const ERROR_CYCLE_CELL = Object.freeze(createEvaluatedCell(new CircularDependencyError()));
60552
+ const EMPTY_CELL = Object.freeze(createEvaluatedCell({ value: null }));
60406
60553
  class Evaluator {
60407
60554
  context;
60408
60555
  getters;
@@ -61904,7 +62051,7 @@ class DynamicTablesPlugin extends CoreViewPlugin {
61904
62051
  tables = {};
61905
62052
  handle(cmd) {
61906
62053
  if (invalidateEvaluationCommands.has(cmd.type) ||
61907
- (cmd.type === "UPDATE_CELL" && "content" in cmd) ||
62054
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd)) ||
61908
62055
  cmd.type === "EVALUATE_CELLS") {
61909
62056
  this.tables = {};
61910
62057
  return;
@@ -65776,7 +65923,7 @@ class TableComputedStylePlugin extends UIPlugin {
65776
65923
  tableStyles = {};
65777
65924
  handle(cmd) {
65778
65925
  if (invalidateEvaluationCommands.has(cmd.type) ||
65779
- (cmd.type === "UPDATE_CELL" && "content" in cmd) ||
65926
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd)) ||
65780
65927
  cmd.type === "EVALUATE_CELLS") {
65781
65928
  this.tableStyles = {};
65782
65929
  return;
@@ -67737,6 +67884,8 @@ class GridSelectionPlugin extends UIPlugin {
67737
67884
  });
67738
67885
  this.selectCell(col, row);
67739
67886
  }
67887
+ const { col, row } = this.gridSelection.anchor.cell;
67888
+ this.moveClient({ sheetId: this.activeSheet.id, col, row });
67740
67889
  }
67741
67890
  /**
67742
67891
  * Ensure selections are not outside sheet boundaries.
@@ -68452,8 +68601,11 @@ class SheetViewPlugin extends UIPlugin {
68452
68601
  case "REMOVE_TABLE":
68453
68602
  case "UPDATE_TABLE":
68454
68603
  case "UPDATE_FILTER":
68455
- this.sheetsWithDirtyViewports.add(cmd.sheetId);
68456
- break;
68604
+ case "UNFREEZE_ROWS":
68605
+ case "UNFREEZE_COLUMNS":
68606
+ case "FREEZE_COLUMNS":
68607
+ case "FREEZE_ROWS":
68608
+ case "UNFREEZE_COLUMNS_ROWS":
68457
68609
  case "REMOVE_COLUMNS_ROWS":
68458
68610
  case "RESIZE_COLUMNS_ROWS":
68459
68611
  case "HIDE_COLUMNS_ROWS":
@@ -68466,11 +68618,9 @@ class SheetViewPlugin extends UIPlugin {
68466
68618
  case "FOLD_HEADER_GROUPS_IN_ZONE":
68467
68619
  case "UNFOLD_HEADER_GROUPS_IN_ZONE":
68468
68620
  case "UNFOLD_ALL_HEADER_GROUPS":
68469
- case "FOLD_ALL_HEADER_GROUPS": {
68470
- const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.getActiveSheetId();
68471
- this.sheetsWithDirtyViewports.add(sheetId);
68621
+ case "FOLD_ALL_HEADER_GROUPS":
68622
+ this.sheetsWithDirtyViewports.add(cmd.sheetId);
68472
68623
  break;
68473
- }
68474
68624
  case "UPDATE_CELL":
68475
68625
  // update cell content or format can change hidden rows because of data filters
68476
68626
  if ("content" in cmd || "format" in cmd || cmd.style?.fontSize !== undefined) {
@@ -68486,13 +68636,6 @@ class SheetViewPlugin extends UIPlugin {
68486
68636
  case "ACTIVATE_SHEET":
68487
68637
  this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
68488
68638
  break;
68489
- case "UNFREEZE_ROWS":
68490
- case "UNFREEZE_COLUMNS":
68491
- case "FREEZE_COLUMNS":
68492
- case "FREEZE_ROWS":
68493
- case "UNFREEZE_COLUMNS_ROWS":
68494
- this.resetViewports(this.getters.getActiveSheetId());
68495
- break;
68496
68639
  case "SCROLL_TO_CELL":
68497
68640
  this.refreshViewport(this.getters.getActiveSheetId(), { col: cmd.col, row: cmd.row });
68498
68641
  break;
@@ -69660,7 +69803,7 @@ class AggregateStatisticsStore extends SpreadsheetStore {
69660
69803
  }
69661
69804
  handle(cmd) {
69662
69805
  if (invalidateEvaluationCommands.has(cmd.type) ||
69663
- (cmd.type === "UPDATE_CELL" && "content" in cmd)) {
69806
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd))) {
69664
69807
  this.isDirty = true;
69665
69808
  }
69666
69809
  switch (cmd.type) {
@@ -71711,11 +71854,13 @@ class Spreadsheet extends owl.Component {
71711
71854
  this.checkViewportSize();
71712
71855
  stores.on("store-updated", this, render);
71713
71856
  resizeObserver.observe(this.spreadsheetRef.el);
71857
+ registerChartJSExtensions();
71714
71858
  });
71715
71859
  owl.onWillUnmount(() => {
71716
71860
  this.unbindModelEvents();
71717
71861
  stores.off("store-updated", this);
71718
71862
  resizeObserver.disconnect();
71863
+ unregisterChartJsExtensions();
71719
71864
  });
71720
71865
  owl.onPatched(() => {
71721
71866
  this.checkViewportSize();
@@ -76242,6 +76387,6 @@ exports.tokenColors = tokenColors;
76242
76387
  exports.tokenize = tokenize;
76243
76388
 
76244
76389
 
76245
- __info__.version = "18.2.9";
76246
- __info__.date = "2025-04-25T08:06:52.677Z";
76247
- __info__.hash = "3e88645";
76390
+ __info__.version = "18.2.11";
76391
+ __info__.date = "2025-05-12T05:25:59.138Z";
76392
+ __info__.hash = "eb87dca";