@odoo/o-spreadsheet 18.4.0-alpha.7 → 18.4.0-alpha.8

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.4.0-alpha.7
6
- * @date 2025-06-06T09:32:44.285Z
7
- * @hash 2bfbe64
5
+ * @version 18.4.0-alpha.8
6
+ * @date 2025-06-12T09:53:48.133Z
7
+ * @hash 9b7a8d0
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -131,7 +131,7 @@
131
131
 
132
132
  const CANVAS_SHIFT = 0.5;
133
133
  // Colors
134
- const HIGHLIGHT_COLOR = "#37A850";
134
+ const HIGHLIGHT_COLOR = "#017E84";
135
135
  const BACKGROUND_GRAY_COLOR = "#f5f5f5";
136
136
  const BACKGROUND_HEADER_COLOR = "#F8F9FA";
137
137
  const BACKGROUND_HEADER_SELECTED_COLOR = "#E8EAED";
@@ -144,7 +144,7 @@
144
144
  const BACKGROUND_CHART_COLOR = "#FFFFFF";
145
145
  const DISABLED_TEXT_COLOR = "#CACACA";
146
146
  const DEFAULT_COLOR_SCALE_MIDPOINT_COLOR = 0xb6d7a8;
147
- const LINK_COLOR = "#017E84";
147
+ const LINK_COLOR = HIGHLIGHT_COLOR;
148
148
  const FILTERS_COLOR = "#188038";
149
149
  const SEPARATOR_COLOR = "#E0E2E4";
150
150
  const ICONS_COLOR = "#4A4F59";
@@ -173,7 +173,7 @@
173
173
  const BUTTON_HOVER_TEXT_COLOR = "#111827";
174
174
  const BUTTON_ACTIVE_BG = "#e6f2f3";
175
175
  const BUTTON_ACTIVE_TEXT_COLOR = "#111827";
176
- const ACTION_COLOR = "#017E84";
176
+ const ACTION_COLOR = HIGHLIGHT_COLOR;
177
177
  const ACTION_COLOR_HOVER = "#01585c";
178
178
  const ALERT_WARNING_BG = "#FBEBCC";
179
179
  const ALERT_WARNING_BORDER = "#F8E2B3";
@@ -1567,6 +1567,19 @@
1567
1567
  this.palette = getAlternatingColorsPalette(paletteSize).filter((c) => !preferredColors.includes(c));
1568
1568
  }
1569
1569
  }
1570
+ class AlternatingColorMap {
1571
+ availableColors;
1572
+ colors = {};
1573
+ constructor(paletteSize = 12) {
1574
+ this.availableColors = new AlternatingColorGenerator(paletteSize);
1575
+ }
1576
+ get(id) {
1577
+ if (!this.colors[id]) {
1578
+ this.colors[id] = this.availableColors.next();
1579
+ }
1580
+ return this.colors[id];
1581
+ }
1582
+ }
1570
1583
  /**
1571
1584
  * Returns a function that maps a value to a color using a color scale defined by the given
1572
1585
  * color/threshold values pairs.
@@ -5006,7 +5019,9 @@
5006
5019
  }
5007
5020
 
5008
5021
  function evaluateLiteral(literalCell, localeFormat) {
5009
- const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
5022
+ const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
5023
+ ? literalCell.content
5024
+ : literalCell.parsedValue;
5010
5025
  const functionResult = { value, format: localeFormat.format };
5011
5026
  return createEvaluatedCell(functionResult, localeFormat.locale);
5012
5027
  }
@@ -5055,6 +5070,9 @@
5055
5070
  if (isEvaluationError(value)) {
5056
5071
  return errorCell(value, message);
5057
5072
  }
5073
+ if (value === null) {
5074
+ return emptyCell(format);
5075
+ }
5058
5076
  if (isTextFormat(format)) {
5059
5077
  // TO DO:
5060
5078
  // with the next line, the value of the cell is transformed depending on the format.
@@ -5062,9 +5080,6 @@
5062
5080
  // to interpret the value as a number.
5063
5081
  return textCell(toString(value), format, formattedValue);
5064
5082
  }
5065
- if (value === null) {
5066
- return emptyCell(format);
5067
- }
5068
5083
  if (typeof value === "number") {
5069
5084
  if (isDateTimeFormat(format || "")) {
5070
5085
  return dateTimeCell(value, format, formattedValue);
@@ -19352,8 +19367,9 @@ stores.inject(MyMetaStore, storeInstance);
19352
19367
  arg("include_total (boolean, default=TRUE)", _t("Whether to include total/sub-totals or not.")),
19353
19368
  arg("include_column_titles (boolean, default=TRUE)", _t("Whether to include the column titles or not.")),
19354
19369
  arg("column_count (number, optional)", _t("number of columns")),
19370
+ arg("include_measure_titles (boolean, default=TRUE)", _t("Whether to include the measure titles row or not.")),
19355
19371
  ],
19356
- compute: function (pivotFormulaId, rowCount = { value: 10000 }, includeTotal = { value: true }, includeColumnHeaders = { value: true }, columnCount = { value: Number.MAX_VALUE }) {
19372
+ compute: function (pivotFormulaId, rowCount = { value: 10000 }, includeTotal = { value: true }, includeColumnHeaders = { value: true }, columnCount = { value: Number.MAX_VALUE }, includeMeasureTitles = { value: true }) {
19357
19373
  const _pivotFormulaId = toString(pivotFormulaId);
19358
19374
  const _rowCount = toNumber(rowCount, this.locale);
19359
19375
  if (_rowCount < 0) {
@@ -19363,8 +19379,11 @@ stores.inject(MyMetaStore, storeInstance);
19363
19379
  if (_columnCount < 0) {
19364
19380
  return new EvaluationError(_t("The number of columns must be positive."));
19365
19381
  }
19366
- const _includeColumnHeaders = toBoolean(includeColumnHeaders);
19367
- const _includedTotal = toBoolean(includeTotal);
19382
+ const visibilityOptions = {
19383
+ displayColumnHeaders: toBoolean(includeColumnHeaders),
19384
+ displayTotals: toBoolean(includeTotal),
19385
+ displayMeasuresRow: toBoolean(includeMeasureTitles),
19386
+ };
19368
19387
  const pivotId = getPivotId(_pivotFormulaId, this.getters);
19369
19388
  const pivot = this.getters.getPivot(pivotId);
19370
19389
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
@@ -19375,9 +19394,15 @@ stores.inject(MyMetaStore, storeInstance);
19375
19394
  return error;
19376
19395
  }
19377
19396
  const table = pivot.getCollapsedTableStructure();
19378
- const cells = table.getPivotCells(_includedTotal, _includeColumnHeaders);
19379
- const headerRows = _includeColumnHeaders ? table.columns.length : 0;
19380
- const pivotTitle = this.getters.getPivotDisplayName(pivotId);
19397
+ const cells = table.getPivotCells(visibilityOptions);
19398
+ let headerRows = 0;
19399
+ if (visibilityOptions.displayColumnHeaders) {
19400
+ headerRows = table.columns.length - 1;
19401
+ }
19402
+ if (visibilityOptions.displayMeasuresRow) {
19403
+ headerRows++;
19404
+ }
19405
+ const pivotTitle = this.getters.getPivotName(pivotId);
19381
19406
  const tableHeight = Math.min(headerRows + _rowCount, cells[0].length);
19382
19407
  if (tableHeight === 0) {
19383
19408
  return [[{ value: pivotTitle }]];
@@ -19405,7 +19430,7 @@ stores.inject(MyMetaStore, storeInstance);
19405
19430
  }
19406
19431
  }
19407
19432
  }
19408
- if (_includeColumnHeaders) {
19433
+ if (visibilityOptions.displayColumnHeaders || visibilityOptions.displayMeasuresRow) {
19409
19434
  result[0][0] = { value: pivotTitle };
19410
19435
  }
19411
19436
  return result;
@@ -21744,10 +21769,22 @@ stores.inject(MyMetaStore, storeInstance);
21744
21769
  const midAngle = (startAngle + endAngle) / 2;
21745
21770
  const midRadius = (innerRadius + outerRadius) / 2;
21746
21771
  const x = bar.x + midRadius * Math.cos(midAngle);
21747
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
21772
+ const y = bar.y + midRadius * Math.sin(midAngle);
21773
+ const displayValue = options.callback(value, dataset, i);
21774
+ const textHeight = 12; // ChartJS default
21775
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
21776
+ const radius = outerRadius - innerRadius;
21777
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
21778
+ if (textWidth >= radius || radius < textHeight) {
21779
+ continue;
21780
+ }
21781
+ const sliceAngle = endAngle - startAngle;
21782
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
21783
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
21784
+ continue;
21785
+ }
21748
21786
  ctx.fillStyle = chartFontColor(options.background);
21749
21787
  ctx.strokeStyle = options.background || "#ffffff";
21750
- const displayValue = options.callback(value, dataset, i);
21751
21788
  drawTextWithBackground(displayValue, x, y, ctx);
21752
21789
  }
21753
21790
  }
@@ -34940,17 +34977,22 @@ stores.inject(MyMetaStore, storeInstance);
34940
34977
  static components = { FilterMenuValueItem };
34941
34978
  state = owl.useState({
34942
34979
  values: [],
34980
+ displayedValues: [],
34943
34981
  textFilter: "",
34944
34982
  selectedValue: undefined,
34983
+ numberOfDisplayedValues: 50,
34984
+ hasMoreValues: false,
34945
34985
  });
34946
34986
  searchBar = owl.useRef("filterMenuSearchBar");
34947
34987
  setup() {
34948
34988
  owl.onWillUpdateProps((nextProps) => {
34949
34989
  if (!deepEquals(nextProps.filterPosition, this.props.filterPosition)) {
34950
34990
  this.state.values = this.getFilterHiddenValues(nextProps.filterPosition);
34991
+ this.computeDisplayedValues();
34951
34992
  }
34952
34993
  });
34953
34994
  this.state.values = this.getFilterHiddenValues(this.props.filterPosition);
34995
+ this.computeDisplayedValues();
34954
34996
  }
34955
34997
  getFilterHiddenValues(position) {
34956
34998
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -34968,21 +35010,28 @@ stores.inject(MyMetaStore, storeInstance);
34968
35010
  }
34969
35011
  const cellValues = cells.map((val) => val.cellValue);
34970
35012
  const filterValues = filterValue?.filterType === "values" ? filterValue.hiddenValues : [];
34971
- const strValues = [...cellValues, ...filterValues];
34972
- const normalizedFilteredValues = filterValues.map(toLowerCase);
34973
- // Set with lowercase values to avoid duplicates
34974
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
34975
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
34976
- return sortedValues.map((normalizedValue) => {
34977
- let checked = false;
34978
- if (filterValue?.filterType !== "criterion") {
34979
- checked = normalizedFilteredValues.findIndex((val) => val === normalizedValue) === -1;
35013
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
35014
+ const set = new Set();
35015
+ const values = [];
35016
+ const addValue = (value) => {
35017
+ const normalizedValue = toLowerCase(value);
35018
+ if (!set.has(normalizedValue)) {
35019
+ values.push({
35020
+ string: value || "",
35021
+ checked: filterValue?.filterType !== "criterion"
35022
+ ? !normalizedFilteredValues.has(normalizedValue)
35023
+ : false,
35024
+ normalizedValue,
35025
+ });
35026
+ set.add(normalizedValue);
34980
35027
  }
34981
- return {
34982
- checked,
34983
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
34984
- };
34985
- });
35028
+ };
35029
+ cellValues.forEach(addValue);
35030
+ filterValues.forEach(addValue);
35031
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
35032
+ numeric: true,
35033
+ sensitivity: "base",
35034
+ }));
34986
35035
  }
34987
35036
  checkValue(value) {
34988
35037
  this.state.selectedValue = value.string;
@@ -34994,25 +35043,37 @@ stores.inject(MyMetaStore, storeInstance);
34994
35043
  this.state.selectedValue = value.string;
34995
35044
  }
34996
35045
  selectAll() {
34997
- this.displayedValues.forEach((value) => (value.checked = true));
34998
- this.updateHiddenValues();
35046
+ this.state.displayedValues.forEach((value) => (value.checked = true));
35047
+ this.props.onUpdateHiddenValues([]);
34999
35048
  }
35000
35049
  clearAll() {
35001
- this.displayedValues.forEach((value) => (value.checked = false));
35002
- this.updateHiddenValues();
35050
+ this.state.displayedValues.forEach((value) => (value.checked = false));
35051
+ const hiddenValues = this.state.values.map((val) => val.string);
35052
+ this.props.onUpdateHiddenValues(hiddenValues);
35003
35053
  }
35004
35054
  updateHiddenValues() {
35005
35055
  const hiddenValues = this.state.values.filter((val) => !val.checked).map((val) => val.string);
35006
35056
  this.props.onUpdateHiddenValues(hiddenValues);
35007
35057
  }
35008
- get displayedValues() {
35009
- if (!this.state.textFilter) {
35010
- return this.state.values;
35011
- }
35012
- return fuzzyLookup(this.state.textFilter, this.state.values, (val) => val.string);
35058
+ updateSearch(ev) {
35059
+ const target = ev.target;
35060
+ this.state.textFilter = target.value;
35061
+ this.state.selectedValue = undefined;
35062
+ this.computeDisplayedValues();
35063
+ }
35064
+ computeDisplayedValues() {
35065
+ const values = !this.state.textFilter
35066
+ ? this.state.values
35067
+ : fuzzyLookup(this.state.textFilter, this.state.values, (val) => val.string);
35068
+ this.state.displayedValues = values.slice(0, this.state.numberOfDisplayedValues);
35069
+ this.state.hasMoreValues = values.length > this.state.numberOfDisplayedValues;
35070
+ }
35071
+ loadMoreValues() {
35072
+ this.state.numberOfDisplayedValues += 100;
35073
+ this.computeDisplayedValues();
35013
35074
  }
35014
35075
  onKeyDown(ev) {
35015
- const displayedValues = this.displayedValues;
35076
+ const displayedValues = this.state.displayedValues;
35016
35077
  if (displayedValues.length === 0)
35017
35078
  return;
35018
35079
  let selectedIndex = undefined;
@@ -38485,7 +38546,7 @@ stores.inject(MyMetaStore, storeInstance);
38485
38546
  */
38486
38547
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
38487
38548
  if (optionalArgs?.required) {
38488
- if (optionalArgs?.default) {
38549
+ if (optionalArgs?.default !== undefined) {
38489
38550
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
38490
38551
  }
38491
38552
  else {
@@ -48708,7 +48769,8 @@ stores.inject(MyMetaStore, storeInstance);
48708
48769
  input.o-font-size {
48709
48770
  outline: none;
48710
48771
  height: 20px;
48711
- width: 23px;
48772
+ width: 31px;
48773
+ text-align: center;
48712
48774
  }
48713
48775
  }
48714
48776
  .o-text-options > div {
@@ -53786,28 +53848,45 @@ stores.inject(MyMetaStore, storeInstance);
53786
53848
  getNumberOfDataColumns() {
53787
53849
  return this.columns.at(-1)?.length || 0;
53788
53850
  }
53789
- getPivotCells(includeTotal = true, includeColumnHeaders = true) {
53790
- const key = JSON.stringify({ includeTotal, includeColumnHeaders });
53851
+ getSkippedRows(visibilityOptions) {
53852
+ const skippedRows = new Set();
53853
+ if (!visibilityOptions.displayColumnHeaders) {
53854
+ for (let i = 0; i < this.columns.length - 1; i++) {
53855
+ skippedRows.add(i);
53856
+ }
53857
+ }
53858
+ if (!visibilityOptions.displayMeasuresRow) {
53859
+ skippedRows.add(this.columns.length - 1);
53860
+ }
53861
+ return skippedRows;
53862
+ }
53863
+ getPivotCells(visibilityOptions = {
53864
+ displayColumnHeaders: true,
53865
+ displayTotals: true,
53866
+ displayMeasuresRow: true,
53867
+ }) {
53868
+ const key = JSON.stringify(visibilityOptions);
53791
53869
  if (!this.pivotCells[key]) {
53870
+ const { displayTotals } = visibilityOptions;
53792
53871
  const numberOfDataRows = this.rows.length;
53793
53872
  const numberOfDataColumns = this.getNumberOfDataColumns();
53794
53873
  let pivotHeight = this.columns.length + numberOfDataRows;
53795
53874
  let pivotWidth = 1 /*(row headers)*/ + numberOfDataColumns;
53796
- if (!includeTotal && numberOfDataRows !== 1) {
53875
+ if (!displayTotals && numberOfDataRows !== 1) {
53797
53876
  pivotHeight -= 1;
53798
53877
  }
53799
- if (!includeTotal && numberOfDataColumns !== this.measures.length) {
53878
+ if (!displayTotals && numberOfDataColumns !== this.measures.length) {
53800
53879
  pivotWidth -= this.measures.length;
53801
53880
  }
53802
53881
  const domainArray = [];
53803
- const startRow = includeColumnHeaders ? 0 : this.columns.length;
53882
+ const skippedRows = this.getSkippedRows(visibilityOptions);
53804
53883
  for (let col = 0; col < pivotWidth; col++) {
53805
53884
  domainArray.push([]);
53806
- for (let row = startRow; row < pivotHeight; row++) {
53807
- if (!includeTotal && row === pivotHeight) {
53885
+ for (let row = 0; row < pivotHeight; row++) {
53886
+ if (skippedRows.has(row)) {
53808
53887
  continue;
53809
53888
  }
53810
- domainArray[col].push(this.getPivotCell(col, row, includeTotal));
53889
+ domainArray[col].push(this.getPivotCell(col, row, displayTotals));
53811
53890
  }
53812
53891
  }
53813
53892
  this.pivotCells[key] = domainArray;
@@ -61998,7 +62077,9 @@ stores.inject(MyMetaStore, storeInstance);
61998
62077
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
61999
62078
  const union = this.getters.getRangesUnion(ranges);
62000
62079
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
62001
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
62080
+ if (mergesInTarget.length) {
62081
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
62082
+ }
62002
62083
  const id = this.consumeNextId();
62003
62084
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
62004
62085
  const newTable = cmd.tableType === "dynamic"
@@ -62097,14 +62178,16 @@ stores.inject(MyMetaStore, storeInstance);
62097
62178
  const zoneToCheckIfEmpty = direction === "down"
62098
62179
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
62099
62180
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
62100
- for (const position of positions(zoneToCheckIfEmpty)) {
62101
- const cellPosition = { sheetId, ...position };
62102
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
62103
- const cellContent = this.getters.getCell(cellPosition)?.content;
62104
- if (cellContent ||
62105
- this.getters.isInMerge(cellPosition) ||
62106
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
62107
- return "none";
62181
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
62182
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
62183
+ const cellPosition = { sheetId, col, row };
62184
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
62185
+ const cellContent = this.getters.getCell(cellPosition)?.content;
62186
+ if (cellContent ||
62187
+ this.getters.isInMerge(cellPosition) ||
62188
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
62189
+ return "none";
62190
+ }
62108
62191
  }
62109
62192
  }
62110
62193
  return direction;
@@ -67257,10 +67340,15 @@ stores.inject(MyMetaStore, storeInstance);
67257
67340
  const includeTotal = toScalar(args[2]);
67258
67341
  const shouldIncludeTotal = includeTotal === undefined ? true : toBoolean(includeTotal);
67259
67342
  const includeColumnHeaders = toScalar(args[3]);
67343
+ const includeMeasures = toScalar(args[5]);
67344
+ const shouldIncludeMeasures = includeMeasures === undefined ? true : toBoolean(includeMeasures);
67260
67345
  const shouldIncludeColumnHeaders = includeColumnHeaders === undefined ? true : toBoolean(includeColumnHeaders);
67261
- const pivotCells = pivot
67262
- .getCollapsedTableStructure()
67263
- .getPivotCells(shouldIncludeTotal, shouldIncludeColumnHeaders);
67346
+ const visibilityOptions = {
67347
+ displayColumnHeaders: shouldIncludeColumnHeaders,
67348
+ displayTotals: shouldIncludeTotal,
67349
+ displayMeasuresRow: shouldIncludeMeasures,
67350
+ };
67351
+ const pivotCells = pivot.getCollapsedTableStructure().getPivotCells(visibilityOptions);
67264
67352
  const pivotCol = position.col - mainPosition.col;
67265
67353
  const pivotRow = position.row - mainPosition.row;
67266
67354
  return pivotCells[pivotCol][pivotRow];
@@ -69482,8 +69570,7 @@ stores.inject(MyMetaStore, storeInstance);
69482
69570
  "isFullySynchronized",
69483
69571
  ];
69484
69572
  static layers = ["Selection"];
69485
- availableColors = new AlternatingColorGenerator(12);
69486
- colors = {};
69573
+ colors = new AlternatingColorMap(12);
69487
69574
  session;
69488
69575
  constructor(config) {
69489
69576
  super(config);
@@ -69501,7 +69588,7 @@ stores.inject(MyMetaStore, storeInstance);
69501
69588
  }
69502
69589
  getConnectedClients() {
69503
69590
  return [...this.session.getConnectedClients()].map((client) => {
69504
- return { ...client, color: this.colors[client.id] };
69591
+ return { ...client, color: this.colors.get(client.id) };
69505
69592
  });
69506
69593
  }
69507
69594
  isFullySynchronized() {
@@ -69530,10 +69617,7 @@ stores.inject(MyMetaStore, storeInstance);
69530
69617
  client.position &&
69531
69618
  client.position.sheetId === sheetId &&
69532
69619
  this.isPositionValid(client.position)) {
69533
- if (!this.colors[client.id]) {
69534
- this.colors[client.id] = this.availableColors.next();
69535
- }
69536
- clients.push({ ...client, color: this.colors[client.id], position: client.position });
69620
+ clients.push({ ...client, position: client.position });
69537
69621
  }
69538
69622
  }
69539
69623
  return clients;
@@ -72407,9 +72491,10 @@ stores.inject(MyMetaStore, storeInstance);
72407
72491
  const filteredValues = filterValue.hiddenValues?.map(toLowerCase);
72408
72492
  if (!filteredValues)
72409
72493
  continue;
72494
+ const filteredValuesSet = new Set(filteredValues);
72410
72495
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
72411
72496
  const value = this.getCellValueAsString(sheetId, filter.col, row);
72412
- if (filteredValues.includes(value)) {
72497
+ if (filteredValuesSet.has(value)) {
72413
72498
  hiddenRows.add(row);
72414
72499
  }
72415
72500
  }
@@ -75091,7 +75176,7 @@ stores.inject(MyMetaStore, storeInstance);
75091
75176
  })
75092
75177
  .addChild("settings", ["file"], {
75093
75178
  name: _t("Settings"),
75094
- sequence: 100,
75179
+ sequence: 200,
75095
75180
  execute: (env) => env.openSidePanel("Settings"),
75096
75181
  isEnabled: (env) => !env.isSmall,
75097
75182
  icon: "o-spreadsheet-Icon.COG",
@@ -78000,7 +78085,7 @@ stores.inject(MyMetaStore, storeInstance);
78000
78085
 
78001
78086
  .o-spreadsheet-topbar {
78002
78087
  line-height: 1.2;
78003
- font-size: 13px;
78088
+ font-size: 14px;
78004
78089
  font-weight: 500;
78005
78090
  background-color: #fff;
78006
78091
 
@@ -83259,6 +83344,7 @@ stores.inject(MyMetaStore, storeInstance);
83259
83344
  exports.AbstractChart = AbstractChart;
83260
83345
  exports.AbstractFigureClipboardHandler = AbstractFigureClipboardHandler;
83261
83346
  exports.CellErrorType = CellErrorType;
83347
+ exports.ClientDisconnectedError = ClientDisconnectedError;
83262
83348
  exports.CorePlugin = CorePlugin;
83263
83349
  exports.CoreViewPlugin = CoreViewPlugin;
83264
83350
  exports.DispatchResult = DispatchResult;
@@ -83305,9 +83391,9 @@ stores.inject(MyMetaStore, storeInstance);
83305
83391
  exports.tokenize = tokenize;
83306
83392
 
83307
83393
 
83308
- __info__.version = "18.4.0-alpha.7";
83309
- __info__.date = "2025-06-06T09:32:44.285Z";
83310
- __info__.hash = "2bfbe64";
83394
+ __info__.version = "18.4.0-alpha.8";
83395
+ __info__.date = "2025-06-12T09:53:48.133Z";
83396
+ __info__.hash = "9b7a8d0";
83311
83397
 
83312
83398
 
83313
83399
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);