@odoo/o-spreadsheet 18.1.17 → 18.1.19

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.1.17
6
- * @date 2025-04-25T08:08:46.599Z
7
- * @hash a63687f
5
+ * @version 18.1.19
6
+ * @date 2025-05-12T05:26:05.861Z
7
+ * @hash 44cc170
8
8
  */
9
9
 
10
10
  'use strict';
@@ -3762,6 +3762,7 @@ exports.CommandResult = void 0;
3762
3762
  CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
3763
3763
  CommandResult["InvalidDefinition"] = "InvalidDefinition";
3764
3764
  CommandResult["InvalidColor"] = "InvalidColor";
3765
+ CommandResult["InvalidPivotDataSet"] = "InvalidPivotDataSet";
3765
3766
  })(exports.CommandResult || (exports.CommandResult = {}));
3766
3767
 
3767
3768
  const DEFAULT_LOCALES = [
@@ -6272,6 +6273,25 @@ function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
6272
6273
  })
6273
6274
  .filter(isDefined);
6274
6275
  }
6276
+ function getNextSheetName(existingNames, baseName = "Sheet") {
6277
+ let i = 1;
6278
+ let name = `${baseName}${i}`;
6279
+ while (existingNames.includes(name)) {
6280
+ name = `${baseName}${i}`;
6281
+ i++;
6282
+ }
6283
+ return name;
6284
+ }
6285
+ function getDuplicateSheetName(nameToDuplicate, existingNames) {
6286
+ let i = 1;
6287
+ const baseName = _t("Copy of %s", nameToDuplicate);
6288
+ let name = baseName.toString();
6289
+ while (existingNames.includes(name)) {
6290
+ name = `${baseName} (${i})`;
6291
+ i++;
6292
+ }
6293
+ return name;
6294
+ }
6275
6295
 
6276
6296
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
6277
6297
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
@@ -7970,6 +7990,24 @@ const monthNumberAdapter = {
7970
7990
  return `${normalizedValue}`;
7971
7991
  },
7972
7992
  };
7993
+ /**
7994
+ * normalizes month number + year
7995
+ */
7996
+ const monthAdapter = {
7997
+ normalizeFunctionValue(value) {
7998
+ const date = toNumber(value, DEFAULT_LOCALE);
7999
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
8000
+ },
8001
+ toValueAndFormat(normalizedValue) {
8002
+ return {
8003
+ value: toNumber(normalizedValue, DEFAULT_LOCALE),
8004
+ format: "mmmm yyyy",
8005
+ };
8006
+ },
8007
+ toFunctionValue(normalizedValue) {
8008
+ return `"${normalizedValue}"`;
8009
+ },
8010
+ };
7973
8011
  /**
7974
8012
  * normalizes quarter number
7975
8013
  */
@@ -8100,6 +8138,7 @@ pivotTimeAdapterRegistry
8100
8138
  .add("day_of_month", nullHandlerDecorator(dayOfMonthAdapter))
8101
8139
  .add("iso_week_number", nullHandlerDecorator(isoWeekNumberAdapter))
8102
8140
  .add("month_number", nullHandlerDecorator(monthNumberAdapter))
8141
+ .add("month", nullHandlerDecorator(monthAdapter))
8103
8142
  .add("quarter_number", nullHandlerDecorator(quarterNumberAdapter))
8104
8143
  .add("day_of_week", nullHandlerDecorator(dayOfWeekAdapter))
8105
8144
  .add("hour_number", nullHandlerDecorator(hourNumberAdapter))
@@ -8279,10 +8318,7 @@ function toNormalizedPivotValue(dimension, groupValue) {
8279
8318
  return normalizer(groupValueString, dimension.granularity);
8280
8319
  }
8281
8320
  function normalizeDateTime(value, granularity) {
8282
- if (!granularity) {
8283
- throw new Error("Missing granularity");
8284
- }
8285
- return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
8321
+ return pivotTimeAdapter(granularity ?? "month").normalizeFunctionValue(value);
8286
8322
  }
8287
8323
  function toFunctionPivotValue(value, dimension) {
8288
8324
  if (value === null) {
@@ -8294,10 +8330,7 @@ function toFunctionPivotValue(value, dimension) {
8294
8330
  return pivotToFunctionValueRegistry.get(dimension.type)(value, dimension.granularity);
8295
8331
  }
8296
8332
  function toFunctionValueDateTime(value, granularity) {
8297
- if (!granularity) {
8298
- throw new Error("Missing granularity");
8299
- }
8300
- return pivotTimeAdapter(granularity).toFunctionValue(value);
8333
+ return pivotTimeAdapter(granularity ?? "month").toFunctionValue(value);
8301
8334
  }
8302
8335
  const pivotNormalizationValueRegistry = new Registry();
8303
8336
  pivotNormalizationValueRegistry
@@ -9612,12 +9645,24 @@ class ComposerFocusStore extends SpreadsheetStore {
9612
9645
  }
9613
9646
 
9614
9647
  const chartJsExtensionRegistry = new Registry();
9615
- /** Return window.Chart, making sure all our extensions are loaded in ChartJS */
9616
- function getChartJSConstructor() {
9617
- if (window.Chart && !window.Chart?.registry.plugins.get("chartShowValuesPlugin")) {
9618
- window.Chart.register(...chartJsExtensionRegistry.getAll());
9648
+ function areChartJSExtensionsLoaded() {
9649
+ return !!window.Chart.registry.plugins.get("chartShowValuesPlugin");
9650
+ }
9651
+ function registerChartJSExtensions() {
9652
+ if (!window.Chart || areChartJSExtensionsLoaded()) {
9653
+ return;
9654
+ }
9655
+ for (const registryItem of chartJsExtensionRegistry.getAll()) {
9656
+ registryItem.register(window.Chart);
9657
+ }
9658
+ }
9659
+ function unregisterChartJsExtensions() {
9660
+ if (!window.Chart) {
9661
+ return;
9662
+ }
9663
+ for (const registryItem of chartJsExtensionRegistry.getAll()) {
9664
+ registryItem.unregister(window.Chart);
9619
9665
  }
9620
- return window.Chart;
9621
9666
  }
9622
9667
 
9623
9668
  const TREND_LINE_XAXIS_ID = "x1";
@@ -10009,7 +10054,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
10009
10054
  const yMin = chart.chartArea.top;
10010
10055
  const textsPositions = {};
10011
10056
  for (const dataset of chart._metasets) {
10012
- if (isTrendLineAxis(dataset.axisID) || dataset.hidden) {
10057
+ if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
10013
10058
  continue;
10014
10059
  }
10015
10060
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10052,7 +10097,7 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
10052
10097
  const xMin = chart.chartArea.left;
10053
10098
  const textsPositions = {};
10054
10099
  for (const dataset of chart._metasets) {
10055
- if (isTrendLineAxis(dataset.axisID)) {
10100
+ if (isTrendLineAxis(dataset.xAxisID)) {
10056
10101
  return; // ignore trend lines
10057
10102
  }
10058
10103
  for (let i = 0; i < dataset._parsed.length; i++) {
@@ -10158,8 +10203,14 @@ function getNextNonEmptyBar(bars, startIndex) {
10158
10203
  return bars.find((bar, i) => i > startIndex && bar.height !== 0);
10159
10204
  }
10160
10205
 
10161
- chartJsExtensionRegistry.add("chartShowValuesPlugin", chartShowValuesPlugin);
10162
- chartJsExtensionRegistry.add("waterfallLinesPlugin", waterfallLinesPlugin);
10206
+ chartJsExtensionRegistry.add("chartShowValuesPlugin", {
10207
+ register: (Chart) => Chart.register(chartShowValuesPlugin),
10208
+ unregister: (Chart) => Chart.unregister(chartShowValuesPlugin),
10209
+ });
10210
+ chartJsExtensionRegistry.add("waterfallLinesPlugin", {
10211
+ register: (Chart) => Chart.register(waterfallLinesPlugin),
10212
+ unregister: (Chart) => Chart.unregister(waterfallLinesPlugin),
10213
+ });
10163
10214
  class ChartJsComponent extends owl.Component {
10164
10215
  static template = "o-spreadsheet-ChartJsComponent";
10165
10216
  static props = {
@@ -10168,6 +10219,7 @@ class ChartJsComponent extends owl.Component {
10168
10219
  canvas = owl.useRef("graphContainer");
10169
10220
  chart;
10170
10221
  currentRuntime;
10222
+ currentDevicePixelRatio = window.devicePixelRatio;
10171
10223
  get background() {
10172
10224
  return this.chartRuntime.background;
10173
10225
  }
@@ -10201,13 +10253,16 @@ class ChartJsComponent extends owl.Component {
10201
10253
  }
10202
10254
  this.currentRuntime = runtime;
10203
10255
  }
10256
+ else if (this.currentDevicePixelRatio !== window.devicePixelRatio) {
10257
+ this.currentDevicePixelRatio = window.devicePixelRatio;
10258
+ this.updateChartJs(deepCopy(this.currentRuntime.chartJsConfig));
10259
+ }
10204
10260
  });
10205
10261
  }
10206
10262
  createChart(chartData) {
10207
10263
  const canvas = this.canvas.el;
10208
10264
  const ctx = canvas.getContext("2d");
10209
- const Chart = getChartJSConstructor();
10210
- this.chart = new Chart(ctx, chartData);
10265
+ this.chart = new window.Chart(ctx, chartData);
10211
10266
  }
10212
10267
  updateChartJs(chartData) {
10213
10268
  if (chartData.data && chartData.data.datasets) {
@@ -10456,9 +10511,11 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
10456
10511
  };
10457
10512
  function drawScoreChart(structure, canvas) {
10458
10513
  const ctx = canvas.getContext("2d");
10459
- canvas.width = structure.canvas.width;
10460
- const availableWidth = canvas.width - CHART_PADDING$1 * 2;
10461
- canvas.height = structure.canvas.height;
10514
+ const dpr = window.devicePixelRatio || 1;
10515
+ canvas.width = dpr * structure.canvas.width;
10516
+ canvas.height = dpr * structure.canvas.height;
10517
+ ctx.scale(dpr, dpr);
10518
+ const availableWidth = structure.canvas.width - CHART_PADDING$1 * 2;
10462
10519
  ctx.fillStyle = structure.canvas.backgroundColor;
10463
10520
  ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
10464
10521
  if (structure.title) {
@@ -10821,7 +10878,7 @@ class ScorecardChart extends owl.Component {
10821
10878
  owl.useEffect(this.createChart.bind(this), () => {
10822
10879
  const canvas = this.canvas.el;
10823
10880
  const rect = canvas.getBoundingClientRect();
10824
- return [rect.width, rect.height, this.runtime, this.canvas.el];
10881
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
10825
10882
  });
10826
10883
  }
10827
10884
  createChart() {
@@ -18337,7 +18394,7 @@ const IF = {
18337
18394
  return { value: "" };
18338
18395
  }
18339
18396
  if (result.value === null) {
18340
- result.value = "";
18397
+ return { ...result, value: "" };
18341
18398
  }
18342
18399
  return result;
18343
18400
  },
@@ -18358,7 +18415,7 @@ const IFERROR = {
18358
18415
  return { value: "" };
18359
18416
  }
18360
18417
  if (result.value === null) {
18361
- result.value = "";
18418
+ return { ...result, value: "" };
18362
18419
  }
18363
18420
  return result;
18364
18421
  },
@@ -18379,7 +18436,7 @@ const IFNA = {
18379
18436
  return { value: "" };
18380
18437
  }
18381
18438
  if (result.value === null) {
18382
- result.value = "";
18439
+ return { ...result, value: "" };
18383
18440
  }
18384
18441
  return result;
18385
18442
  },
@@ -18405,7 +18462,7 @@ const IFS = {
18405
18462
  return { value: "" };
18406
18463
  }
18407
18464
  if (result.value === null) {
18408
- result.value = "";
18465
+ return { ...result, value: "" };
18409
18466
  }
18410
18467
  return result;
18411
18468
  }
@@ -18523,6 +18580,11 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
18523
18580
  if (range === undefined || range.invalidXc || range.invalidSheetName) {
18524
18581
  throw new InvalidReferenceError();
18525
18582
  }
18583
+ if (evalContext.__originCellPosition &&
18584
+ range.sheetId === evalContext.__originSheetId &&
18585
+ isZoneInside(positionToZone(evalContext.__originCellPosition), zone)) {
18586
+ throw new CircularDependencyError();
18587
+ }
18526
18588
  dependencies.push(range);
18527
18589
  }
18528
18590
  for (const measure of forMeasures) {
@@ -22410,9 +22472,11 @@ const GAUGE_INFLECTION_LABEL_BOTTOM_MARGIN = 6;
22410
22472
  const GAUGE_TITLE_SECTION_HEIGHT = 25;
22411
22473
  function drawGaugeChart(canvas, runtime) {
22412
22474
  const canvasBoundingRect = canvas.getBoundingClientRect();
22413
- canvas.width = canvasBoundingRect.width;
22414
- canvas.height = canvasBoundingRect.height;
22475
+ const dpr = window.devicePixelRatio || 1;
22476
+ canvas.width = dpr * canvasBoundingRect.width;
22477
+ canvas.height = dpr * canvasBoundingRect.height;
22415
22478
  const ctx = canvas.getContext("2d");
22479
+ ctx.scale(dpr, dpr);
22416
22480
  const config = getGaugeRenderingConfig(canvasBoundingRect, runtime, ctx);
22417
22481
  drawBackground(ctx, config);
22418
22482
  drawGauge(ctx, config);
@@ -22747,7 +22811,7 @@ class GaugeChartComponent extends owl.Component {
22747
22811
  owl.useEffect(() => drawGaugeChart(this.canvas.el, this.runtime), () => {
22748
22812
  const canvas = this.canvas.el;
22749
22813
  const rect = canvas.getBoundingClientRect();
22750
- return [rect.width, rect.height, this.runtime, this.canvas.el];
22814
+ return [rect.width, rect.height, this.runtime, this.canvas.el, window.devicePixelRatio];
22751
22815
  });
22752
22816
  }
22753
22817
  }
@@ -22782,6 +22846,7 @@ const CHART_COMMON_OPTIONS = {
22782
22846
  },
22783
22847
  },
22784
22848
  animation: false,
22849
+ events: ["mousemove", "mouseout", "click", "touchstart", "touchmove", "mouseup"],
22785
22850
  };
22786
22851
  function truncateLabel(label) {
22787
22852
  if (!label) {
@@ -22807,8 +22872,7 @@ function chartToImage(runtime, figure, type) {
22807
22872
  if ("chartJsConfig" in runtime) {
22808
22873
  const config = deepCopy(runtime.chartJsConfig);
22809
22874
  config.plugins = [backgroundColorChartJSPlugin];
22810
- const Chart = getChartJSConstructor();
22811
- const chart = new Chart(canvas, config);
22875
+ const chart = new window.Chart(canvas, config);
22812
22876
  const imgContent = chart.toBase64Image();
22813
22877
  chart.destroy();
22814
22878
  div.remove();
@@ -27940,6 +28004,7 @@ function repairInitialMessages(data, initialMessages) {
27940
28004
  initialMessages = dropCommands(initialMessages, "SORT_CELLS");
27941
28005
  initialMessages = dropCommands(initialMessages, "SET_DECIMAL");
27942
28006
  initialMessages = fixChartDefinitions(data, initialMessages);
28007
+ initialMessages = fixTranslatedDuplicateSheetName(data, initialMessages);
27943
28008
  return initialMessages;
27944
28009
  }
27945
28010
  /**
@@ -28039,6 +28104,40 @@ function fixChartDefinitions(data, initialMessages) {
28039
28104
  }
28040
28105
  return messages;
28041
28106
  }
28107
+ function fixTranslatedDuplicateSheetName(data, initialMessages) {
28108
+ const sheetNames = {};
28109
+ for (const sheet of data.sheets || []) {
28110
+ sheetNames[sheet.id] = sheet.name;
28111
+ }
28112
+ const messages = [];
28113
+ for (const message of initialMessages) {
28114
+ if (message.type === "REMOTE_REVISION") {
28115
+ const commands = [];
28116
+ for (const cmd of message.commands) {
28117
+ switch (cmd.type) {
28118
+ case "DUPLICATE_SHEET":
28119
+ cmd.sheetNameTo =
28120
+ cmd.sheetNameTo ??
28121
+ getDuplicateSheetName(sheetNames[cmd.sheetId], Object.values(sheetNames));
28122
+ break;
28123
+ case "CREATE_SHEET":
28124
+ case "RENAME_SHEET":
28125
+ sheetNames[cmd.sheetId] = cmd.name || getNextSheetName(Object.values(sheetNames));
28126
+ break;
28127
+ }
28128
+ commands.push(cmd);
28129
+ }
28130
+ messages.push({
28131
+ ...message,
28132
+ commands,
28133
+ });
28134
+ }
28135
+ else {
28136
+ messages.push(message);
28137
+ }
28138
+ }
28139
+ return initialMessages;
28140
+ }
28042
28141
  // -----------------------------------------------------------------------------
28043
28142
  // Helpers
28044
28143
  // -----------------------------------------------------------------------------
@@ -28836,12 +28935,11 @@ function canBeLinearChart(definition, dataSets, labelRange, getters) {
28836
28935
  }
28837
28936
  let missingTimeAdapterAlreadyWarned = false;
28838
28937
  function isLuxonTimeAdapterInstalled() {
28839
- const Chart = getChartJSConstructor();
28840
- if (!Chart) {
28938
+ if (!window.Chart) {
28841
28939
  return false;
28842
28940
  }
28843
28941
  // @ts-ignore
28844
- const adapter = new Chart._adapters._date({});
28942
+ const adapter = new window.Chart._adapters._date({});
28845
28943
  const isInstalled = adapter._id === "luxon";
28846
28944
  if (!isInstalled && !missingTimeAdapterAlreadyWarned) {
28847
28945
  missingTimeAdapterAlreadyWarned = true;
@@ -29479,6 +29577,9 @@ const INTERACTIVE_LEGEND_CONFIG = {
29479
29577
  target.style.cursor = "default";
29480
29578
  },
29481
29579
  onClick: (event, legendItem, legend) => {
29580
+ if (event.type !== "click") {
29581
+ return;
29582
+ }
29482
29583
  const index = legendItem.datasetIndex;
29483
29584
  if (!legend.legendItems || index === undefined) {
29484
29585
  return;
@@ -29559,7 +29660,7 @@ function getBarChartScales(definition, args) {
29559
29660
  };
29560
29661
  scales[MOVING_AVERAGE_TREND_LINE_XAXIS_ID] = {
29561
29662
  ...scales.x,
29562
- offset: false,
29663
+ offset: true,
29563
29664
  display: false,
29564
29665
  };
29565
29666
  }
@@ -30156,9 +30257,6 @@ class BarChart extends AbstractChart {
30156
30257
  };
30157
30258
  }
30158
30259
  getDefinitionForExcel() {
30159
- // Excel does not support aggregating labels
30160
- if (this.aggregated)
30161
- return undefined;
30162
30260
  const dataSets = this.dataSets
30163
30261
  .map((ds) => toExcelDataset(this.getters, ds))
30164
30262
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -30839,9 +30937,6 @@ class LineChart extends AbstractChart {
30839
30937
  return new LineChart(definition, this.sheetId, this.getters);
30840
30938
  }
30841
30939
  getDefinitionForExcel() {
30842
- // Excel does not support aggregating labels
30843
- if (this.aggregated)
30844
- return undefined;
30845
30940
  const dataSets = this.dataSets
30846
30941
  .map((ds) => toExcelDataset(this.getters, ds))
30847
30942
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -30978,9 +31073,6 @@ class PieChart extends AbstractChart {
30978
31073
  return new PieChart(definition, sheetId, this.getters);
30979
31074
  }
30980
31075
  getDefinitionForExcel() {
30981
- // Excel does not support aggregating labels
30982
- if (this.aggregated)
30983
- return undefined;
30984
31076
  const dataSets = this.dataSets
30985
31077
  .map((ds) => toExcelDataset(this.getters, ds))
30986
31078
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -33213,10 +33305,13 @@ const duplicateSheet = {
33213
33305
  name: _t("Duplicate"),
33214
33306
  execute: (env) => {
33215
33307
  const sheetIdFrom = env.model.getters.getActiveSheetId();
33308
+ const sheetNameFrom = env.model.getters.getSheetName(sheetIdFrom);
33216
33309
  const sheetIdTo = env.model.uuidGenerator.smallUuid();
33310
+ const sheetNameTo = env.model.getters.getDuplicateSheetName(sheetNameFrom);
33217
33311
  env.model.dispatch("DUPLICATE_SHEET", {
33218
33312
  sheetId: sheetIdFrom,
33219
33313
  sheetIdTo,
33314
+ sheetNameTo,
33220
33315
  });
33221
33316
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
33222
33317
  },
@@ -33456,18 +33551,28 @@ function isCtrlKey(ev) {
33456
33551
  function useInterval(callback, delay) {
33457
33552
  let intervalId;
33458
33553
  const { setInterval, clearInterval } = window;
33554
+ const pause = () => {
33555
+ clearInterval(intervalId);
33556
+ intervalId = undefined;
33557
+ };
33558
+ const safeCallback = () => {
33559
+ try {
33560
+ callback();
33561
+ }
33562
+ catch (e) {
33563
+ pause();
33564
+ throw e;
33565
+ }
33566
+ };
33459
33567
  owl.useEffect(() => {
33460
- intervalId = setInterval(callback, delay);
33568
+ intervalId = setInterval(safeCallback, delay);
33461
33569
  return () => clearInterval(intervalId);
33462
33570
  }, () => [delay]);
33463
33571
  return {
33464
- pause: () => {
33465
- clearInterval(intervalId);
33466
- intervalId = undefined;
33467
- },
33572
+ pause,
33468
33573
  resume: () => {
33469
33574
  if (intervalId === undefined) {
33470
- intervalId = setInterval(callback, delay);
33575
+ intervalId = setInterval(safeCallback, delay);
33471
33576
  }
33472
33577
  },
33473
33578
  };
@@ -41026,6 +41131,13 @@ class Composer extends owl.Component {
41026
41131
  openAssistant() {
41027
41132
  this.assistant.forcedClosed = false;
41028
41133
  }
41134
+ onWheel(event) {
41135
+ // detect if scrollbar is available
41136
+ if (this.composerRef.el &&
41137
+ this.composerRef.el.scrollHeight > this.composerRef.el.clientHeight) {
41138
+ event.stopPropagation();
41139
+ }
41140
+ }
41029
41141
  // ---------------------------------------------------------------------------
41030
41142
  // Private
41031
41143
  // ---------------------------------------------------------------------------
@@ -45963,8 +46075,8 @@ function compareDimensionValues(dimension, a, b) {
45963
46075
 
45964
46076
  const NULL_SYMBOL = Symbol("NULL");
45965
46077
  function createDate(dimension, value, locale) {
45966
- const granularity = dimension.granularity;
45967
- if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
46078
+ const granularity = dimension.granularity || "month";
46079
+ if (!(granularity in MAP_VALUE_DIMENSION_DATE)) {
45968
46080
  throw new Error(`Unknown date granularity: ${granularity}`);
45969
46081
  }
45970
46082
  const keyInMap = typeof value === "number" || typeof value === "string" ? value : NULL_SYMBOL;
@@ -45983,6 +46095,9 @@ function createDate(dimension, value, locale) {
45983
46095
  case "month_number":
45984
46096
  number = date.getMonth() + 1;
45985
46097
  break;
46098
+ case "month":
46099
+ number = Math.floor(toNumber(value, locale));
46100
+ break;
45986
46101
  case "iso_week_number":
45987
46102
  number = date.getIsoWeek();
45988
46103
  break;
@@ -46076,6 +46191,10 @@ const MAP_VALUE_DIMENSION_DATE = {
46076
46191
  set: new Set(),
46077
46192
  values: {},
46078
46193
  },
46194
+ month: {
46195
+ set: new Set(),
46196
+ values: {},
46197
+ },
46079
46198
  iso_week_number: {
46080
46199
  set: new Set(),
46081
46200
  values: {},
@@ -46286,7 +46405,7 @@ class SpreadsheetPivot {
46286
46405
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
46287
46406
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
46288
46407
  if (dimension.type === "datetime") {
46289
- const adapter = pivotTimeAdapter(dimension.granularity);
46408
+ const adapter = pivotTimeAdapter((dimension.granularity || "month"));
46290
46409
  return adapter.toValueAndFormat(lastNode.value, this.getters.getLocale());
46291
46410
  }
46292
46411
  if (!finalCell) {
@@ -46404,7 +46523,7 @@ class SpreadsheetPivot {
46404
46523
  if (nonEmptyCells.length === 0) {
46405
46524
  return "integer";
46406
46525
  }
46407
- if (nonEmptyCells.every((cell) => cell.format && isDateTimeFormat(cell.format))) {
46526
+ if (nonEmptyCells.every((cell) => cell.type === CellValueType.number && cell.format && isDateTimeFormat(cell.format))) {
46408
46527
  return "datetime";
46409
46528
  }
46410
46529
  if (nonEmptyCells.every((cell) => cell.type === CellValueType.boolean)) {
@@ -46499,7 +46618,7 @@ class SpreadsheetPivot {
46499
46618
  for (const entry of dataEntries) {
46500
46619
  for (const dimension of dateDimensions) {
46501
46620
  const value = createDate(dimension, entry[dimension.fieldName]?.value || null, this.getters.getLocale());
46502
- const adapter = pivotTimeAdapter(dimension.granularity);
46621
+ const adapter = pivotTimeAdapter((dimension.granularity || "month"));
46503
46622
  const { format, value: valueToFormat } = adapter.toValueAndFormat(value, locale);
46504
46623
  entry[dimension.nameWithGranularity] = {
46505
46624
  value,
@@ -46519,6 +46638,7 @@ const dateGranularities = [
46519
46638
  "year",
46520
46639
  "quarter_number",
46521
46640
  "month_number",
46641
+ "month",
46522
46642
  "iso_week_number",
46523
46643
  "day_of_month",
46524
46644
  "day",
@@ -46766,7 +46886,7 @@ class PivotSidePanelStore extends SpreadsheetStore {
46766
46886
  : this.datetimeGranularities);
46767
46887
  }
46768
46888
  for (const field of dateFields) {
46769
- granularitiesPerFields[field.fieldName].delete(field.granularity);
46889
+ granularitiesPerFields[field.fieldName].delete(field.granularity || "month");
46770
46890
  }
46771
46891
  return granularitiesPerFields;
46772
46892
  }
@@ -48941,6 +49061,8 @@ class GridComposer extends owl.Component {
48941
49061
  }
48942
49062
  get composerProps() {
48943
49063
  const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
49064
+ // Remove the wrapper border width
49065
+ const maxHeight = this.props.gridDims.height - this.rect.y - 2 * COMPOSER_BORDER_WIDTH;
48944
49066
  return {
48945
49067
  rect: { ...this.rect },
48946
49068
  delimitation: {
@@ -48958,6 +49080,7 @@ class GridComposer extends owl.Component {
48958
49080
  }),
48959
49081
  onInputContextMenu: this.props.onInputContextMenu,
48960
49082
  composerStore: this.composerStore,
49083
+ inputStyle: `max-height: ${maxHeight}px;`,
48961
49084
  };
48962
49085
  }
48963
49086
  get containerStyle() {
@@ -50456,7 +50579,7 @@ css /* scss */ `
50456
50579
  position: absolute;
50457
50580
  top: 0;
50458
50581
  left: ${HEADER_WIDTH}px;
50459
- right: 0;
50582
+ right: ${SCROLLBAR_WIDTH}px;
50460
50583
  height: ${HEADER_HEIGHT}px;
50461
50584
  &.o-dragging {
50462
50585
  cursor: grabbing;
@@ -50622,9 +50745,8 @@ css /* scss */ `
50622
50745
  position: absolute;
50623
50746
  top: ${HEADER_HEIGHT}px;
50624
50747
  left: 0;
50625
- right: 0;
50748
+ bottom: ${SCROLLBAR_WIDTH}px;
50626
50749
  width: ${HEADER_WIDTH}px;
50627
- height: calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px);
50628
50750
  &.o-dragging {
50629
50751
  cursor: grabbing;
50630
50752
  }
@@ -54249,9 +54371,7 @@ class ChartPlugin extends CorePlugin {
54249
54371
  : "Success" /* CommandResult.Success */;
54250
54372
  }
54251
54373
  checkChartExists(cmd) {
54252
- return this.getters.getFigureSheetId(cmd.id)
54253
- ? "Success" /* CommandResult.Success */
54254
- : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
54374
+ return this.isChartDefined(cmd.id) ? "Success" /* CommandResult.Success */ : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
54255
54375
  }
54256
54376
  }
54257
54377
 
@@ -56536,6 +56656,7 @@ class SheetPlugin extends CorePlugin {
56536
56656
  "getCommandZones",
56537
56657
  "getUnboundedZone",
56538
56658
  "checkElementsIncludeAllNonFrozenHeaders",
56659
+ "getDuplicateSheetName",
56539
56660
  ];
56540
56661
  sheetIdsMapName = {};
56541
56662
  orderedSheetIds = [];
@@ -56560,7 +56681,11 @@ class SheetPlugin extends CorePlugin {
56560
56681
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
56561
56682
  }
56562
56683
  case "DUPLICATE_SHEET": {
56563
- return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
56684
+ if (this.sheets[cmd.sheetIdTo])
56685
+ return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
56686
+ if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
56687
+ return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
56688
+ return "Success" /* CommandResult.Success */;
56564
56689
  }
56565
56690
  case "MOVE_SHEET":
56566
56691
  try {
@@ -56637,7 +56762,7 @@ class SheetPlugin extends CorePlugin {
56637
56762
  this.showSheet(cmd.sheetId);
56638
56763
  break;
56639
56764
  case "DUPLICATE_SHEET":
56640
- this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo);
56765
+ this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo, cmd.sheetNameTo);
56641
56766
  break;
56642
56767
  case "DELETE_SHEET":
56643
56768
  this.deleteSheet(this.sheets[cmd.sheetId]);
@@ -56843,14 +56968,8 @@ class SheetPlugin extends CorePlugin {
56843
56968
  return dimension === "COL" ? this.getNumberCols(sheetId) : this.getNumberRows(sheetId);
56844
56969
  }
56845
56970
  getNextSheetName(baseName = "Sheet") {
56846
- let i = 1;
56847
56971
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
56848
- let name = `${baseName}${i}`;
56849
- while (names.includes(name)) {
56850
- name = `${baseName}${i}`;
56851
- i++;
56852
- }
56853
- return name;
56972
+ return getNextSheetName(names, baseName);
56854
56973
  }
56855
56974
  getSheetSize(sheetId) {
56856
56975
  return {
@@ -57096,9 +57215,8 @@ class SheetPlugin extends CorePlugin {
57096
57215
  showSheet(sheetId) {
57097
57216
  this.history.update("sheets", sheetId, "isVisible", true);
57098
57217
  }
57099
- duplicateSheet(fromId, toId) {
57218
+ duplicateSheet(fromId, toId, toName) {
57100
57219
  const sheet = this.getSheet(fromId);
57101
- const toName = this.getDuplicateSheetName(sheet.name);
57102
57220
  const newSheet = deepCopy(sheet);
57103
57221
  newSheet.id = toId;
57104
57222
  newSheet.name = toName;
@@ -57130,15 +57248,8 @@ class SheetPlugin extends CorePlugin {
57130
57248
  this.history.update("sheetIdsMapName", sheetIdsMapName);
57131
57249
  }
57132
57250
  getDuplicateSheetName(sheetName) {
57133
- let i = 1;
57134
57251
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
57135
- const baseName = _t("Copy of %s", sheetName);
57136
- let name = baseName.toString();
57137
- while (names.includes(name)) {
57138
- name = `${baseName} (${i})`;
57139
- i++;
57140
- }
57141
- return name;
57252
+ return getDuplicateSheetName(sheetName, names);
57142
57253
  }
57143
57254
  deleteSheet(sheet) {
57144
57255
  const name = sheet.name;
@@ -58625,6 +58736,15 @@ function adaptPivotRange(range, applyChange) {
58625
58736
  }
58626
58737
  }
58627
58738
  class SpreadsheetPivotCorePlugin extends CorePlugin {
58739
+ allowDispatch(cmd) {
58740
+ switch (cmd.type) {
58741
+ case "ADD_PIVOT":
58742
+ case "UPDATE_PIVOT":
58743
+ const definition = cmd.pivot;
58744
+ return this.checkDataSetValidity(definition);
58745
+ }
58746
+ return "Success" /* CommandResult.Success */;
58747
+ }
58628
58748
  adaptRanges(applyChange) {
58629
58749
  for (const pivotId of this.getters.getPivotIds()) {
58630
58750
  const definition = this.getters.getPivotCoreDefinition(pivotId);
@@ -58643,6 +58763,16 @@ class SpreadsheetPivotCorePlugin extends CorePlugin {
58643
58763
  }
58644
58764
  }
58645
58765
  }
58766
+ checkDataSetValidity(definition) {
58767
+ if (definition.type === "SPREADSHEET" && definition.dataSet) {
58768
+ const { zone, sheetId } = definition.dataSet;
58769
+ if (!sheetId || !this.getters.tryGetSheet(sheetId) || !zone || !isZoneValid(zone)) {
58770
+ return "InvalidDataSet" /* CommandResult.InvalidDataSet */;
58771
+ }
58772
+ return this.getters.checkZonesExistInSheet(sheetId, [zone]);
58773
+ }
58774
+ return "Success" /* CommandResult.Success */;
58775
+ }
58646
58776
  }
58647
58777
 
58648
58778
  class TableStylePlugin extends CorePlugin {
@@ -59946,8 +60076,8 @@ class SpreadingRelation {
59946
60076
  const EMPTY_ARRAY = [];
59947
60077
 
59948
60078
  const MAX_ITERATION = 30;
59949
- const ERROR_CYCLE_CELL = createEvaluatedCell(new CircularDependencyError());
59950
- const EMPTY_CELL = createEvaluatedCell({ value: null });
60079
+ const ERROR_CYCLE_CELL = Object.freeze(createEvaluatedCell(new CircularDependencyError()));
60080
+ const EMPTY_CELL = Object.freeze(createEvaluatedCell({ value: null }));
59951
60081
  class Evaluator {
59952
60082
  context;
59953
60083
  getters;
@@ -61442,7 +61572,7 @@ class DynamicTablesPlugin extends UIPlugin {
61442
61572
  tables = {};
61443
61573
  handle(cmd) {
61444
61574
  if (invalidateEvaluationCommands.has(cmd.type) ||
61445
- (cmd.type === "UPDATE_CELL" && "content" in cmd) ||
61575
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd)) ||
61446
61576
  cmd.type === "EVALUATE_CELLS") {
61447
61577
  this.tables = {};
61448
61578
  return;
@@ -65299,7 +65429,7 @@ class TableComputedStylePlugin extends UIPlugin {
65299
65429
  tableStyles = {};
65300
65430
  handle(cmd) {
65301
65431
  if (invalidateEvaluationCommands.has(cmd.type) ||
65302
- (cmd.type === "UPDATE_CELL" && "content" in cmd) ||
65432
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd)) ||
65303
65433
  cmd.type === "EVALUATE_CELLS") {
65304
65434
  this.tableStyles = {};
65305
65435
  return;
@@ -67263,6 +67393,8 @@ class GridSelectionPlugin extends UIPlugin {
67263
67393
  });
67264
67394
  this.selectCell(col, row);
67265
67395
  }
67396
+ const { col, row } = this.gridSelection.anchor.cell;
67397
+ this.moveClient({ sheetId: this.activeSheet.id, col, row });
67266
67398
  }
67267
67399
  /**
67268
67400
  * Ensure selections are not outside sheet boundaries.
@@ -68002,8 +68134,11 @@ class SheetViewPlugin extends UIPlugin {
68002
68134
  case "REMOVE_TABLE":
68003
68135
  case "UPDATE_TABLE":
68004
68136
  case "UPDATE_FILTER":
68005
- this.sheetsWithDirtyViewports.add(cmd.sheetId);
68006
- break;
68137
+ case "UNFREEZE_ROWS":
68138
+ case "UNFREEZE_COLUMNS":
68139
+ case "FREEZE_COLUMNS":
68140
+ case "FREEZE_ROWS":
68141
+ case "UNFREEZE_COLUMNS_ROWS":
68007
68142
  case "REMOVE_COLUMNS_ROWS":
68008
68143
  case "RESIZE_COLUMNS_ROWS":
68009
68144
  case "HIDE_COLUMNS_ROWS":
@@ -68016,11 +68151,9 @@ class SheetViewPlugin extends UIPlugin {
68016
68151
  case "FOLD_HEADER_GROUPS_IN_ZONE":
68017
68152
  case "UNFOLD_HEADER_GROUPS_IN_ZONE":
68018
68153
  case "UNFOLD_ALL_HEADER_GROUPS":
68019
- case "FOLD_ALL_HEADER_GROUPS": {
68020
- const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.getActiveSheetId();
68021
- this.sheetsWithDirtyViewports.add(sheetId);
68154
+ case "FOLD_ALL_HEADER_GROUPS":
68155
+ this.sheetsWithDirtyViewports.add(cmd.sheetId);
68022
68156
  break;
68023
- }
68024
68157
  case "UPDATE_CELL":
68025
68158
  // update cell content or format can change hidden rows because of data filters
68026
68159
  if ("content" in cmd || "format" in cmd || cmd.style?.fontSize !== undefined) {
@@ -68036,13 +68169,6 @@ class SheetViewPlugin extends UIPlugin {
68036
68169
  case "ACTIVATE_SHEET":
68037
68170
  this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
68038
68171
  break;
68039
- case "UNFREEZE_ROWS":
68040
- case "UNFREEZE_COLUMNS":
68041
- case "FREEZE_COLUMNS":
68042
- case "FREEZE_ROWS":
68043
- case "UNFREEZE_COLUMNS_ROWS":
68044
- this.resetViewports(this.getters.getActiveSheetId());
68045
- break;
68046
68172
  case "SCROLL_TO_CELL":
68047
68173
  this.refreshViewport(this.getters.getActiveSheetId(), { col: cmd.col, row: cmd.row });
68048
68174
  break;
@@ -69220,7 +69346,7 @@ class AggregateStatisticsStore extends SpreadsheetStore {
69220
69346
  }
69221
69347
  handle(cmd) {
69222
69348
  if (invalidateEvaluationCommands.has(cmd.type) ||
69223
- (cmd.type === "UPDATE_CELL" && "content" in cmd)) {
69349
+ (cmd.type === "UPDATE_CELL" && ("content" in cmd || "format" in cmd))) {
69224
69350
  this.isDirty = true;
69225
69351
  }
69226
69352
  switch (cmd.type) {
@@ -71283,11 +71409,13 @@ class Spreadsheet extends owl.Component {
71283
71409
  this.checkViewportSize();
71284
71410
  stores.on("store-updated", this, render);
71285
71411
  resizeObserver.observe(this.spreadsheetRef.el);
71412
+ registerChartJSExtensions();
71286
71413
  });
71287
71414
  owl.onWillUnmount(() => {
71288
71415
  this.unbindModelEvents();
71289
71416
  stores.off("store-updated", this);
71290
71417
  resizeObserver.disconnect();
71418
+ unregisterChartJsExtensions();
71291
71419
  });
71292
71420
  owl.onPatched(() => {
71293
71421
  this.checkViewportSize();
@@ -75781,6 +75909,6 @@ exports.tokenColors = tokenColors;
75781
75909
  exports.tokenize = tokenize;
75782
75910
 
75783
75911
 
75784
- __info__.version = "18.1.17";
75785
- __info__.date = "2025-04-25T08:08:46.599Z";
75786
- __info__.hash = "a63687f";
75912
+ __info__.version = "18.1.19";
75913
+ __info__.date = "2025-05-12T05:26:05.861Z";
75914
+ __info__.hash = "44cc170";