@odoo/o-spreadsheet 17.4.0-alpha.1 → 17.4.0-alpha.2

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.4.0-alpha.1
7
- * @date 2024-06-03T15:30:28.283Z
8
- * @hash cb56c37
6
+ * @version 17.4.0-alpha.2
7
+ * @date 2024-06-06T13:31:21.327Z
8
+ * @hash e07794d
9
9
  */
10
10
 
11
11
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -18375,6 +18375,131 @@ var logical = /*#__PURE__*/Object.freeze({
18375
18375
  const supportedPivotExplodedFormulaRegistry = new Registry();
18376
18376
  supportedPivotExplodedFormulaRegistry.add("SPREADSHEET", false);
18377
18377
 
18378
+ const AGGREGATOR_NAMES = {
18379
+ count: _t("Count"),
18380
+ count_distinct: _t("Count Distinct"),
18381
+ bool_and: _t("Boolean And"),
18382
+ bool_or: _t("Boolean Or"),
18383
+ max: _t("Maximum"),
18384
+ min: _t("Minimum"),
18385
+ avg: _t("Average"),
18386
+ sum: _t("Sum"),
18387
+ };
18388
+ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
18389
+ const AGGREGATORS_BY_FIELD_TYPE = {
18390
+ integer: NUMBER_CHAR_AGGREGATORS,
18391
+ char: NUMBER_CHAR_AGGREGATORS,
18392
+ //TODO Support for date and boolean
18393
+ };
18394
+ const AGGREGATORS = {};
18395
+ for (const type in AGGREGATORS_BY_FIELD_TYPE) {
18396
+ AGGREGATORS[type] = {};
18397
+ for (const aggregator of AGGREGATORS_BY_FIELD_TYPE[type]) {
18398
+ AGGREGATORS[type][aggregator] = AGGREGATOR_NAMES[aggregator];
18399
+ }
18400
+ }
18401
+ const AGGREGATORS_FN = {
18402
+ count: {
18403
+ fn: (args) => countAny([args]),
18404
+ format: () => "0",
18405
+ },
18406
+ count_distinct: {
18407
+ fn: (args) => countUnique([args]),
18408
+ format: () => "0",
18409
+ },
18410
+ bool_and: {
18411
+ fn: (args) => boolAnd([args]).result,
18412
+ format: () => undefined,
18413
+ },
18414
+ bool_or: {
18415
+ fn: (args) => boolOr([args]).result,
18416
+ format: () => undefined,
18417
+ },
18418
+ max: {
18419
+ fn: (args, locale) => max([args], locale),
18420
+ format: inferFormat,
18421
+ },
18422
+ min: {
18423
+ fn: (args, locale) => min([args], locale),
18424
+ format: inferFormat,
18425
+ },
18426
+ avg: {
18427
+ fn: (args, locale) => average([args], locale),
18428
+ format: inferFormat,
18429
+ },
18430
+ sum: {
18431
+ fn: (args, locale) => sum([args], locale),
18432
+ format: inferFormat,
18433
+ },
18434
+ };
18435
+ /**
18436
+ * Build a pivot formula expression
18437
+ */
18438
+ function makePivotFormula(formula, args) {
18439
+ return `=${formula}(${args
18440
+ .map((arg) => {
18441
+ const stringIsNumber = typeof arg == "string" && !isNaN(Number(arg)) && Number(arg).toString() === arg;
18442
+ const convertToNumber = typeof arg == "number" || stringIsNumber;
18443
+ return convertToNumber ? `${arg}` : `"${arg.toString().replace(/"/g, '\\"')}"`;
18444
+ })
18445
+ .join(",")})`;
18446
+ }
18447
+ /**
18448
+ * Given an object of form {"1": {...}, "2": {...}, ...} get the maximum ID used
18449
+ * in this object
18450
+ * If the object has no keys, return 0
18451
+ *
18452
+ */
18453
+ function getMaxObjectId(o) {
18454
+ const keys = Object.keys(o);
18455
+ if (!keys.length) {
18456
+ return 0;
18457
+ }
18458
+ const nums = keys.map((id) => parseInt(id, 10));
18459
+ const max = Math.max(...nums);
18460
+ return max;
18461
+ }
18462
+ const ALL_PERIODS = {
18463
+ year: _t("Year"),
18464
+ quarter: _t("Quarter"),
18465
+ month: _t("Month"),
18466
+ week: _t("Week"),
18467
+ day: _t("Day"),
18468
+ year_number: _t("Year"),
18469
+ quarter_number: _t("Quarter"),
18470
+ month_number: _t("Month"),
18471
+ iso_week_number: _t("Week"),
18472
+ day_of_month: _t("Day of Month"),
18473
+ };
18474
+ const DATE_FIELDS = ["date", "datetime"];
18475
+ /**
18476
+ * Parse a dimension string into a pivot dimension definition.
18477
+ * e.g "create_date:month" => { name: "create_date", granularity: "month" }
18478
+ */
18479
+ function parseDimension(dimension) {
18480
+ const [name, granularity] = dimension.split(":");
18481
+ if (granularity) {
18482
+ return { name, granularity };
18483
+ }
18484
+ return { name };
18485
+ }
18486
+ function isDateField(field) {
18487
+ return DATE_FIELDS.includes(field.type);
18488
+ }
18489
+ function toPivotDomain(domainStr) {
18490
+ if (domainStr.length % 2 !== 0) {
18491
+ throw new Error("Invalid domain: odd number of elements");
18492
+ }
18493
+ const domain = [];
18494
+ for (let i = 0; i < domainStr.length - 1; i += 2) {
18495
+ domain.push({ field: domainStr[i], value: domainStr[i + 1] });
18496
+ }
18497
+ return domain;
18498
+ }
18499
+ function flatPivotDomain(domain) {
18500
+ return domain.flatMap((arg) => [arg.field, arg.value]);
18501
+ }
18502
+
18378
18503
  /**
18379
18504
  * Get the pivot ID from the formula pivot ID.
18380
18505
  */
@@ -18854,13 +18979,13 @@ const PIVOT_VALUE = {
18854
18979
  arg("domain_field_name (string,optional,repeating)", _t("Field name.")),
18855
18980
  arg("domain_value (string,optional,repeating)", _t("Value.")),
18856
18981
  ],
18857
- compute: function (formulaId, measureName, ...domain) {
18982
+ compute: function (formulaId, measureName, ...domainArgs) {
18858
18983
  const _pivotFormulaId = toString(formulaId);
18859
- const measure = toString(measureName);
18860
- const domainArgs = domain.map(toString);
18984
+ const _measure = toString(measureName);
18985
+ const _domainArgs = domainArgs.map(toString);
18861
18986
  const pivotId = getPivotId(_pivotFormulaId, this.getters);
18862
- assertMeasureExist(pivotId, measure, this.getters);
18863
- assertDomainLength(domainArgs);
18987
+ assertMeasureExist(pivotId, _measure, this.getters);
18988
+ assertDomainLength(_domainArgs);
18864
18989
  const pivot = this.getters.getPivot(pivotId);
18865
18990
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18866
18991
  if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
@@ -18874,8 +18999,9 @@ const PIVOT_VALUE = {
18874
18999
  if (error) {
18875
19000
  return error;
18876
19001
  }
18877
- const { value, format } = pivot.getPivotCellValueAndFormat(measure, domainArgs);
18878
- if (!value && !this.getters.areDomainArgsFieldsValid(pivotId, domainArgs)) {
19002
+ const domain = toPivotDomain(_domainArgs);
19003
+ const { value, format } = pivot.getPivotCellValueAndFormat(_measure, domain);
19004
+ if (!value && !this.getters.areDomainArgsFieldsValid(pivotId, domain)) {
18879
19005
  return {
18880
19006
  value: CellErrorType.GenericError,
18881
19007
  message: _t("Dimensions don't match the pivot definition"),
@@ -18892,11 +19018,11 @@ const PIVOT_HEADER = {
18892
19018
  arg("domain_field_name (string,optional,repeating)", _t("Field name.")),
18893
19019
  arg("domain_value (string,optional,repeating)", _t("Value.")),
18894
19020
  ],
18895
- compute: function (pivotId, ...domain) {
19021
+ compute: function (pivotId, ...domainArgs) {
18896
19022
  const _pivotFormulaId = toString(pivotId);
18897
- const domainArgs = domain.map(toString);
19023
+ const _domainArgs = domainArgs.map(toString);
18898
19024
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
18899
- assertDomainLength(domainArgs);
19025
+ assertDomainLength(_domainArgs);
18900
19026
  const pivot = this.getters.getPivot(_pivotId);
18901
19027
  const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
18902
19028
  if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
@@ -18910,18 +19036,23 @@ const PIVOT_HEADER = {
18910
19036
  if (error) {
18911
19037
  return error;
18912
19038
  }
18913
- const fieldName = domainArgs.at(-2);
18914
- const valueArg = domainArgs.at(-1);
18915
- if (!this.getters.areDomainArgsFieldsValid(_pivotId, fieldName === "measure" ? domainArgs.slice(0, -2) : domainArgs)) {
19039
+ const domain = toPivotDomain(_domainArgs);
19040
+ const lastNode = domain.at(-1);
19041
+ if (!this.getters.areDomainArgsFieldsValid(_pivotId, lastNode?.field === "measure" ? domain.slice(0, -1) : domain)) {
18916
19042
  return {
18917
19043
  value: CellErrorType.GenericError,
18918
19044
  message: _t("Dimensions don't match the pivot definition"),
18919
19045
  };
18920
19046
  }
18921
- const { value, format } = pivot.getPivotHeaderValueAndFormat(domainArgs);
19047
+ if (lastNode?.field === "measure") {
19048
+ return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
19049
+ }
19050
+ const { value, format } = pivot.getPivotHeaderValueAndFormat(domain);
18922
19051
  return {
18923
19052
  value,
18924
- format: !fieldName || fieldName === "measure" || valueArg === "false" ? undefined : format,
19053
+ format: !lastNode || lastNode.field === "measure" || lastNode.value === "false"
19054
+ ? undefined
19055
+ : format,
18925
19056
  };
18926
19057
  },
18927
19058
  returns: ["NUMBER", "STRING"],
@@ -18934,11 +19065,14 @@ const PIVOT = {
18934
19065
  arg("include_total (boolean, default=TRUE)", _t("Whether to include total/sub-totals or not.")),
18935
19066
  arg("include_column_titles (boolean, default=TRUE)", _t("Whether to include the column titles or not.")),
18936
19067
  ],
18937
- compute: function (pivotId, rowCount = { value: 10000 }, includeTotal = { value: true }, includeColumnHeaders = { value: true }) {
18938
- const _pivotFormulaId = toString(pivotId);
18939
- const _pivotId = getPivotId(_pivotFormulaId, this.getters);
18940
- const pivot = this.getters.getPivot(_pivotId);
18941
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19068
+ compute: function (pivotFormulaId, rowCount = { value: 10000 }, includeTotal = { value: true }, includeColumnHeaders = { value: true }) {
19069
+ const _pivotFormulaId = toString(pivotFormulaId);
19070
+ const _rowCount = toNumber(rowCount, this.locale);
19071
+ const _includeColumnHeaders = toBoolean(includeColumnHeaders);
19072
+ const _includedTotal = toBoolean(includeTotal);
19073
+ const pivotId = getPivotId(_pivotFormulaId, this.getters);
19074
+ const pivot = this.getters.getPivot(pivotId);
19075
+ const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18942
19076
  addPivotDependencies(this, coreDefinition);
18943
19077
  pivot.init({ reload: pivot.needsReevaluation });
18944
19078
  const error = pivot.assertIsValid({ throwOnError: false });
@@ -18946,11 +19080,9 @@ const PIVOT = {
18946
19080
  return error;
18947
19081
  }
18948
19082
  const table = pivot.getTableStructure();
18949
- const _includeColumnHeaders = toBoolean(includeColumnHeaders);
18950
- const cells = table.getPivotCells(toBoolean(includeTotal), _includeColumnHeaders);
19083
+ const cells = table.getPivotCells(_includedTotal, _includeColumnHeaders);
18951
19084
  const headerRows = _includeColumnHeaders ? table.columns.length : 0;
18952
- const pivotTitle = this.getters.getPivotDisplayName(_pivotId);
18953
- const _rowCount = toNumber(rowCount, this.locale);
19085
+ const pivotTitle = this.getters.getPivotDisplayName(pivotId);
18954
19086
  if (_rowCount < 0) {
18955
19087
  throw new EvaluationError(_t("The number of rows must be positive."));
18956
19088
  }
@@ -18965,17 +19097,23 @@ const PIVOT = {
18965
19097
  result[col] = [];
18966
19098
  for (const row of tableRows) {
18967
19099
  const pivotCell = cells[col][row];
18968
- if (!pivotCell.domain) {
18969
- result[col].push({ value: "", format: undefined });
18970
- }
18971
- else if (pivotCell.isHeader) {
18972
- result[col].push(pivot.getPivotHeaderValueAndFormat(pivotCell.domain));
18973
- }
18974
- else {
18975
- if (!pivotCell.measure) {
18976
- throw new Error("Measure is missing");
18977
- }
18978
- result[col].push(pivot.getPivotCellValueAndFormat(pivotCell.measure, pivotCell.domain));
19100
+ switch (pivotCell.type) {
19101
+ case "EMPTY":
19102
+ result[col].push({ value: "" });
19103
+ break;
19104
+ case "HEADER":
19105
+ const domain = pivotCell.domain;
19106
+ const lastNode = domain.at(-1);
19107
+ if (lastNode?.field === "measure") {
19108
+ result[col].push(pivot.getPivotMeasureValue(toString(lastNode.value), domain));
19109
+ }
19110
+ else {
19111
+ result[col].push(pivot.getPivotHeaderValueAndFormat(domain));
19112
+ }
19113
+ break;
19114
+ case "VALUE":
19115
+ result[col].push(pivot.getPivotCellValueAndFormat(pivotCell.measure, pivotCell.domain));
19116
+ break;
18979
19117
  }
18980
19118
  }
18981
19119
  }
@@ -20900,8 +21038,15 @@ class Composer extends Component {
20900
21038
  }
20901
21039
  onPaste(ev) {
20902
21040
  if (this.composerStore.editionMode !== "inactive") {
21041
+ // let the browser clipboard work
20903
21042
  ev.stopPropagation();
20904
21043
  }
21044
+ else {
21045
+ // the user meant to paste in the sheet, not open the composer with the pasted content
21046
+ // While we're not editing, we still have the focus and should therefore prevent
21047
+ // the native "paste" to occur.
21048
+ ev.preventDefault();
21049
+ }
20905
21050
  }
20906
21051
  /*
20907
21052
  * Triggered automatically by the content-editable between the keydown and key up
@@ -20910,9 +21055,6 @@ class Composer extends Component {
20910
21055
  if (!this.shouldProcessInputEvents) {
20911
21056
  return;
20912
21057
  }
20913
- if (ev.inputType === "insertFromPaste" && this.composerStore.editionMode === "inactive") {
20914
- return;
20915
- }
20916
21058
  ev.stopPropagation();
20917
21059
  let content;
20918
21060
  if (this.composerStore.editionMode === "inactive") {
@@ -21565,132 +21707,8 @@ function getFunctionsFromAST(ast, functionNames) {
21565
21707
  }
21566
21708
 
21567
21709
  const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
21568
- const AGGREGATOR_NAMES = {
21569
- count: _t("Count"),
21570
- count_distinct: _t("Count Distinct"),
21571
- bool_and: _t("Boolean And"),
21572
- bool_or: _t("Boolean Or"),
21573
- max: _t("Maximum"),
21574
- min: _t("Minimum"),
21575
- avg: _t("Average"),
21576
- sum: _t("Sum"),
21577
- };
21578
- const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
21579
- const AGGREGATORS_BY_FIELD_TYPE = {
21580
- integer: NUMBER_CHAR_AGGREGATORS,
21581
- char: NUMBER_CHAR_AGGREGATORS,
21582
- //TODO Support for date and boolean
21583
- };
21584
- const AGGREGATORS = {};
21585
- for (const type in AGGREGATORS_BY_FIELD_TYPE) {
21586
- AGGREGATORS[type] = {};
21587
- for (const aggregator of AGGREGATORS_BY_FIELD_TYPE[type]) {
21588
- AGGREGATORS[type][aggregator] = AGGREGATOR_NAMES[aggregator];
21589
- }
21590
- }
21591
- const AGGREGATORS_FN = {
21592
- count: {
21593
- fn: (args) => countAny([args]),
21594
- format: () => "0",
21595
- },
21596
- count_distinct: {
21597
- fn: (args) => countUnique([args]),
21598
- format: () => "0",
21599
- },
21600
- bool_and: {
21601
- fn: (args) => boolAnd([args]).result,
21602
- format: () => undefined,
21603
- },
21604
- bool_or: {
21605
- fn: (args) => boolOr([args]).result,
21606
- format: () => undefined,
21607
- },
21608
- max: {
21609
- fn: (args, locale) => max([args], locale),
21610
- format: inferFormat,
21611
- },
21612
- min: {
21613
- fn: (args, locale) => min([args], locale),
21614
- format: inferFormat,
21615
- },
21616
- avg: {
21617
- fn: (args, locale) => average([args], locale),
21618
- format: inferFormat,
21619
- },
21620
- sum: {
21621
- fn: (args, locale) => sum([args], locale),
21622
- format: inferFormat,
21623
- },
21624
- };
21625
- /**
21626
- * Build a pivot formula expression
21627
- */
21628
- function makePivotFormula(formula, args) {
21629
- return `=${formula}(${args
21630
- .map((arg) => {
21631
- const stringIsNumber = typeof arg == "string" && !isNaN(Number(arg)) && Number(arg).toString() === arg;
21632
- const convertToNumber = typeof arg == "number" || stringIsNumber;
21633
- return convertToNumber ? `${arg}` : `"${arg.toString().replace(/"/g, '\\"')}"`;
21634
- })
21635
- .join(",")})`;
21636
- }
21637
- /**
21638
- * Given an object of form {"1": {...}, "2": {...}, ...} get the maximum ID used
21639
- * in this object
21640
- * If the object has no keys, return 0
21641
- *
21642
- */
21643
- function getMaxObjectId(o) {
21644
- const keys = Object.keys(o);
21645
- if (!keys.length) {
21646
- return 0;
21647
- }
21648
- const nums = keys.map((id) => parseInt(id, 10));
21649
- const max = Math.max(...nums);
21650
- return max;
21651
- }
21652
- /**
21653
- * Get the first Pivot function description of the given formula.
21654
- */
21655
- function getFirstPivotFunction(tokens) {
21656
- return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS)[0];
21657
- }
21658
- /**
21659
- * Parse a spreadsheet formula and detect the number of PIVOT functions that are
21660
- * present in the given formula.
21661
- */
21662
- function getNumberOfPivotFunctions(tokens) {
21663
- return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS).length;
21664
- }
21665
- const ALL_PERIODS = {
21666
- year: _t("Year"),
21667
- quarter: _t("Quarter"),
21668
- month: _t("Month"),
21669
- week: _t("Week"),
21670
- day: _t("Day"),
21671
- year_number: _t("Year"),
21672
- quarter_number: _t("Quarter"),
21673
- month_number: _t("Month"),
21674
- iso_week_number: _t("Week"),
21675
- day_of_month: _t("Day of Month"),
21676
- };
21677
- const DATE_FIELDS = ["date", "datetime"];
21678
- /**
21679
- * Parse a dimension string into a pivot dimension definition.
21680
- * e.g "create_date:month" => { name: "create_date", granularity: "month" }
21681
- */
21682
- function parseDimension(dimension) {
21683
- const [name, granularity] = dimension.split(":");
21684
- if (granularity) {
21685
- return { name, granularity };
21686
- }
21687
- return { name };
21688
- }
21689
- function isDateField(field) {
21690
- return DATE_FIELDS.includes(field.type);
21691
- }
21692
21710
  /**
21693
- * Create a proposal entry for the compose autocomplete
21711
+ * Create a proposal entry for the compose autowcomplete
21694
21712
  * to insert a field name string in a formula.
21695
21713
  */
21696
21714
  function makeFieldProposal(field, granularity) {
@@ -21746,15 +21764,18 @@ function extractFormulaIdFromToken(tokenAtCursor) {
21746
21764
  }
21747
21765
  return idAst.value;
21748
21766
  }
21749
- function toDomainArgs(domainStr) {
21750
- if (domainStr.length % 2 !== 0) {
21751
- throw new Error("Invalid domain: odd number of elements");
21752
- }
21753
- const domain = [];
21754
- for (let i = 0; i < domainStr.length - 1; i += 2) {
21755
- domain.push({ field: domainStr[i], value: domainStr[i + 1] });
21756
- }
21757
- return domain;
21767
+ /**
21768
+ * Get the first Pivot function description of the given formula.
21769
+ */
21770
+ function getFirstPivotFunction(tokens) {
21771
+ return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS)[0];
21772
+ }
21773
+ /**
21774
+ * Parse a spreadsheet formula and detect the number of PIVOT functions that are
21775
+ * present in the given formula.
21776
+ */
21777
+ function getNumberOfPivotFunctions(tokens) {
21778
+ return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS).length;
21758
21779
  }
21759
21780
 
21760
21781
  autoCompleteProviders.add("pivot_ids", {
@@ -32782,7 +32803,7 @@ css /* scss */ `
32782
32803
  vertical-align: middle;
32783
32804
  }
32784
32805
  .o_cf_radio_item {
32785
- margin-right: 10%;
32806
+ margin-right: 30px;
32786
32807
  }
32787
32808
  .radio input:checked {
32788
32809
  color: #e9ecef;
@@ -32802,6 +32823,9 @@ css /* scss */ `
32802
32823
  }
32803
32824
  margin-top: 10px;
32804
32825
  display: flex;
32826
+ .form-check {
32827
+ padding-left: 1rem;
32828
+ }
32805
32829
  }
32806
32830
  .o-section-subtitle:first-child {
32807
32831
  margin-top: 0px;
@@ -32810,7 +32834,7 @@ css /* scss */ `
32810
32834
  font-size: 12px;
32811
32835
  line-height: 1.5;
32812
32836
  .o-selection-cf {
32813
- margin-bottom: 3%;
32837
+ margin-bottom: 9px;
32814
32838
  }
32815
32839
  .o-cell-content {
32816
32840
  font-size: 12px;
@@ -32851,7 +32875,7 @@ css /* scss */ `
32851
32875
  width: 100%;
32852
32876
  }
32853
32877
  .o-threshold-value {
32854
- margin-left: 2%;
32878
+ margin-left: 6px;
32855
32879
  width: 20%;
32856
32880
  min-width: 0px; // input overflows in Firefox otherwise
32857
32881
  }
@@ -32880,8 +32904,8 @@ css /* scss */ `
32880
32904
  justify-content: space-between;
32881
32905
  .o-cf-icon {
32882
32906
  display: inline;
32883
- margin-left: 1%;
32884
- margin-right: 1%;
32907
+ margin-left: 3px;
32908
+ margin-right: 3px;
32885
32909
  }
32886
32910
  svg {
32887
32911
  vertical-align: baseline;
@@ -32904,7 +32928,7 @@ css /* scss */ `
32904
32928
  }
32905
32929
  table {
32906
32930
  table-layout: fixed;
32907
- margin-top: 2%;
32931
+ margin-top: 6px;
32908
32932
  display: table;
32909
32933
  text-align: left;
32910
32934
  font-size: 12px;
@@ -32934,8 +32958,8 @@ css /* scss */ `
32934
32958
  }
32935
32959
  }
32936
32960
  .o-cf-iconset-reverse {
32937
- margin-bottom: 2%;
32938
- margin-top: 2%;
32961
+ margin-bottom: 6px;
32962
+ margin-top: 6px;
32939
32963
  .o-cf-label {
32940
32964
  display: inline-block;
32941
32965
  vertical-align: bottom;
@@ -34642,6 +34666,10 @@ css /* scss */ `
34642
34666
  select > option {
34643
34667
  background-color: white;
34644
34668
  }
34669
+
34670
+ .pivot-dim-operator-label {
34671
+ min-width: 120px;
34672
+ }
34645
34673
  }
34646
34674
  `;
34647
34675
  class PivotDimension extends Component {
@@ -34882,7 +34910,7 @@ class PivotRuntimeDefinition {
34882
34910
  getMeasure(name) {
34883
34911
  const measure = this.measures.find((measure) => measure.name === name);
34884
34912
  if (!measure) {
34885
- throw new EvaluationError(_t("Field %s does not exist", name));
34913
+ throw new EvaluationError(_t("Field %s is not a measure", name));
34886
34914
  }
34887
34915
  return measure;
34888
34916
  }
@@ -35008,10 +35036,9 @@ class SpreadsheetPivotTable {
35008
35036
  columns;
35009
35037
  rows;
35010
35038
  measures;
35011
- rowTitle;
35012
35039
  maxIndent;
35013
35040
  pivotCells = {};
35014
- constructor(columns, rows, measures, rowTitle = "") {
35041
+ constructor(columns, rows, measures) {
35015
35042
  this.columns = columns.map((row) => {
35016
35043
  // offset in the pivot table
35017
35044
  // starts at 1 because the first column is the row title
@@ -35024,7 +35051,6 @@ class SpreadsheetPivotTable {
35024
35051
  });
35025
35052
  this.rows = rows;
35026
35053
  this.measures = measures;
35027
- this.rowTitle = rowTitle;
35028
35054
  this.maxIndent = Math.max(...this.rows.map((row) => row.indent));
35029
35055
  }
35030
35056
  /**
@@ -35066,26 +35092,23 @@ class SpreadsheetPivotTable {
35066
35092
  }
35067
35093
  getPivotCell(col, row, includeTotal = true) {
35068
35094
  const colHeadersHeight = this.columns.length;
35069
- if (col === 0 && row === colHeadersHeight - 1) {
35070
- return { content: this.rowTitle, isHeader: true };
35071
- }
35072
- else if (row <= colHeadersHeight - 1) {
35095
+ if (row <= colHeadersHeight - 1) {
35073
35096
  const domain = this.getColHeaderDomain(col, row);
35074
- return { domain, isHeader: true };
35097
+ return domain ? { type: "HEADER", domain } : { type: "EMPTY" };
35075
35098
  }
35076
35099
  else if (col === 0) {
35077
35100
  const rowIndex = row - colHeadersHeight;
35078
35101
  const domain = this.getRowDomain(rowIndex);
35079
- return { domain, isHeader: true };
35102
+ return { type: "HEADER", domain };
35080
35103
  }
35081
35104
  else {
35082
35105
  const rowIndex = row - colHeadersHeight;
35083
35106
  if (!includeTotal && this.isTotalRow(rowIndex)) {
35084
- return { isHeader: false };
35107
+ return { type: "EMPTY" };
35085
35108
  }
35086
35109
  const domain = [...this.getRowDomain(rowIndex), ...this.getColDomain(col)];
35087
35110
  const measure = this.getColMeasure(col);
35088
- return { domain, isHeader: false, measure };
35111
+ return { type: "VALUE", domain, measure };
35089
35112
  }
35090
35113
  }
35091
35114
  getColHeaderDomain(col, row) {
@@ -35098,24 +35121,32 @@ class SpreadsheetPivotTable {
35098
35121
  return undefined;
35099
35122
  }
35100
35123
  for (let i = 0; i < pivotCol.fields.length; i++) {
35101
- domain.push(pivotCol.fields[i]);
35102
- domain.push(pivotCol.values[i]);
35124
+ domain.push({
35125
+ field: pivotCol.fields[i],
35126
+ value: pivotCol.values[i],
35127
+ });
35103
35128
  }
35104
35129
  return domain;
35105
35130
  }
35106
35131
  getColDomain(col) {
35107
35132
  const domain = this.getColHeaderDomain(col, this.columns.length - 1);
35108
- return domain ? domain.slice(0, -2) : []; // slice: remove measure and value
35133
+ return domain ? domain.slice(0, -1) : []; // slice: remove measure and value
35109
35134
  }
35110
35135
  getColMeasure(col) {
35111
35136
  const domain = this.getColHeaderDomain(col, this.columns.length - 1);
35112
- return domain?.at(-1);
35137
+ const measure = domain?.at(-1)?.value;
35138
+ if (measure === undefined) {
35139
+ throw new Error("Measure isd missing");
35140
+ }
35141
+ return measure.toString();
35113
35142
  }
35114
35143
  getRowDomain(row) {
35115
35144
  const domain = [];
35116
35145
  for (let i = 0; i < this.rows[row].fields.length; i++) {
35117
- domain.push(this.rows[row].fields[i]);
35118
- domain.push(this.rows[row].values[i]);
35146
+ domain.push({
35147
+ field: this.rows[row].fields[i],
35148
+ value: this.rows[row].values[i],
35149
+ });
35119
35150
  }
35120
35151
  return domain;
35121
35152
  }
@@ -35124,7 +35155,6 @@ class SpreadsheetPivotTable {
35124
35155
  cols: this.columns,
35125
35156
  rows: this.rows,
35126
35157
  measures: this.measures,
35127
- rowTitle: this.rowTitle,
35128
35158
  };
35129
35159
  }
35130
35160
  }
@@ -35144,8 +35174,7 @@ function dataEntriesToSpreadsheetPivotTable(dataEntries, definition) {
35144
35174
  indent: 0,
35145
35175
  });
35146
35176
  const measureNames = definition.measures.map((m) => m.name);
35147
- const rowTitle = rows.length > 0 ? rows[0].values[0] : "";
35148
- return new SpreadsheetPivotTable(cols, rows, measureNames, rowTitle);
35177
+ return new SpreadsheetPivotTable(cols, rows, measureNames);
35149
35178
  }
35150
35179
  // -----------------------------------------------------------------------------
35151
35180
  // ROWS
@@ -35488,7 +35517,10 @@ class SpreadsheetPivot {
35488
35517
  }
35489
35518
  get definition() {
35490
35519
  if (!this._definition) {
35491
- throw new Error("Pivot not loaded yet");
35520
+ this.init();
35521
+ }
35522
+ if (!this._definition) {
35523
+ throw new Error("Pivot definition should be defined at this point.");
35492
35524
  }
35493
35525
  return this._definition;
35494
35526
  }
@@ -35537,15 +35569,16 @@ class SpreadsheetPivot {
35537
35569
  getMeasure(name) {
35538
35570
  return this.definition.getMeasure(name);
35539
35571
  }
35540
- getPivotHeaderValueAndFormat(domainStr) {
35541
- const domain = toDomainArgs(domainStr);
35572
+ getPivotMeasureValue(name) {
35573
+ return {
35574
+ value: this.getMeasure(name).displayName,
35575
+ };
35576
+ }
35577
+ getPivotHeaderValueAndFormat(domain) {
35542
35578
  const lastNode = domain.at(-1);
35543
35579
  if (!lastNode) {
35544
35580
  return { value: _t("Total") };
35545
35581
  }
35546
- if (lastNode.field === "measure") {
35547
- return { value: this.getMeasure(lastNode.value).displayName };
35548
- }
35549
35582
  const dimension = this.getDimension(lastNode.field);
35550
35583
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
35551
35584
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
@@ -35573,8 +35606,7 @@ class SpreadsheetPivot {
35573
35606
  format: finalCell.format,
35574
35607
  };
35575
35608
  }
35576
- getPivotCellValueAndFormat(measure, domainStr) {
35577
- const domain = toDomainArgs(domainStr);
35609
+ getPivotCellValueAndFormat(measure, domain) {
35578
35610
  const dataEntries = this.filterDataEntriesFromDomain(this.dataEntries, domain);
35579
35611
  if (dataEntries.length === 0) {
35580
35612
  return { value: "" };
@@ -35975,7 +36007,6 @@ class PivotSpreadsheetSidePanel extends Component {
35975
36007
  state;
35976
36008
  setup() {
35977
36009
  this.store = useLocalStore(PivotSidePanelStore, this.props.pivotId);
35978
- this.pivot.init();
35979
36010
  this.state = useState({
35980
36011
  range: undefined,
35981
36012
  rangeHasChanged: false,
@@ -36852,7 +36883,7 @@ css /* scss */ `
36852
36883
  }
36853
36884
 
36854
36885
  .o-table-style-list-item {
36855
- padding: 3px;
36886
+ padding: 3px 2px;
36856
36887
  margin: 2px 1px;
36857
36888
 
36858
36889
  .o-table-style-picker-preview {
@@ -36873,10 +36904,10 @@ class TableStylePicker extends Component {
36873
36904
  const styles = Object.keys(allStyles).filter((key) => allStyles[key].category === selectedStyleCategory);
36874
36905
  const selectedStyleIndex = styles.indexOf(this.props.table.config.styleId);
36875
36906
  if (selectedStyleIndex === -1) {
36876
- return styles.slice(0, 4);
36907
+ return selectedStyleIndex;
36877
36908
  }
36878
36909
  const index = Math.floor(selectedStyleIndex / 4) * 4;
36879
- return styles.slice(index, index + 4);
36910
+ return styles.slice(index);
36880
36911
  }
36881
36912
  onStylePicked(styleId) {
36882
36913
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -37916,10 +37947,7 @@ class GridComposer extends Component {
37916
37947
  }
37917
37948
  get containerStyle() {
37918
37949
  if (this.composerStore.editionMode === "inactive") {
37919
- return `
37920
- position: absolute;
37921
- z-index: -1000;
37922
- `;
37950
+ return `z-index: -1000;`;
37923
37951
  }
37924
37952
  const isFormula = this.composerStore.currentContent.startsWith("=");
37925
37953
  const cell = this.env.model.getters.getActiveCell();
@@ -40763,10 +40791,13 @@ class VerticalScrollBar extends Component {
40763
40791
  }
40764
40792
  }
40765
40793
 
40794
+ const DEFAULT_SIDE_PANEL_SIZE = 350;
40795
+ const MIN_SHEET_VIEW_WIDTH = 150;
40766
40796
  class SidePanelStore extends SpreadsheetStore {
40767
- mutators = ["open", "toggle", "close"];
40797
+ mutators = ["open", "toggle", "close", "changePanelSize", "resetPanelSize"];
40768
40798
  initialPanelProps = {};
40769
40799
  componentTag = "";
40800
+ panelSize = DEFAULT_SIDE_PANEL_SIZE;
40770
40801
  get isOpen() {
40771
40802
  if (!this.componentTag) {
40772
40803
  return false;
@@ -40811,6 +40842,20 @@ class SidePanelStore extends SpreadsheetStore {
40811
40842
  this.initialPanelProps = {};
40812
40843
  this.componentTag = "";
40813
40844
  }
40845
+ changePanelSize(size, spreadsheetElWidth) {
40846
+ if (size < DEFAULT_SIDE_PANEL_SIZE) {
40847
+ this.panelSize = DEFAULT_SIDE_PANEL_SIZE;
40848
+ }
40849
+ else if (size > spreadsheetElWidth - MIN_SHEET_VIEW_WIDTH) {
40850
+ this.panelSize = Math.max(spreadsheetElWidth - MIN_SHEET_VIEW_WIDTH, DEFAULT_SIDE_PANEL_SIZE);
40851
+ }
40852
+ else {
40853
+ this.panelSize = size;
40854
+ }
40855
+ }
40856
+ resetPanelSize() {
40857
+ this.panelSize = DEFAULT_SIDE_PANEL_SIZE;
40858
+ }
40814
40859
  computeState(componentTag, panelProps) {
40815
40860
  const customComputeState = sidePanelRegistry.get(componentTag).computeState;
40816
40861
  if (!customComputeState) {
@@ -41931,7 +41976,7 @@ class XLSXImportWarningManager {
41931
41976
  }
41932
41977
  }
41933
41978
 
41934
- const SUPPORTED_BORDER_STYLES = ["thin"];
41979
+ const SUPPORTED_BORDER_STYLES = ["thin", "medium", "thick", "dashed", "dotted"];
41935
41980
  const SUPPORTED_HORIZONTAL_ALIGNMENTS = [
41936
41981
  "general",
41937
41982
  "left",
@@ -51070,8 +51115,8 @@ class PivotCorePlugin extends CorePlugin {
51070
51115
  case "INSERT_PIVOT": {
51071
51116
  const { sheetId, col, row, pivotId, table } = cmd;
51072
51117
  const position = { sheetId, col, row };
51073
- const { cols, rows, measures, rowTitle } = table;
51074
- const spTable = new SpreadsheetPivotTable(cols, rows, measures, rowTitle);
51118
+ const { cols, rows, measures } = table;
51119
+ const spTable = new SpreadsheetPivotTable(cols, rows, measures);
51075
51120
  const formulaId = this.getPivotFormulaId(pivotId);
51076
51121
  this.insertPivot(position, formulaId, spTable);
51077
51122
  break;
@@ -51200,13 +51245,18 @@ class PivotCorePlugin extends CorePlugin {
51200
51245
  }
51201
51246
  }
51202
51247
  addPivotFormula(position, formulaId, pivotCell) {
51203
- const formula = pivotCell.isHeader ? "PIVOT.HEADER" : "PIVOT.VALUE";
51204
- const args = pivotCell.domain
51205
- ? [formulaId, pivotCell.measure, ...pivotCell.domain].filter(isDefined)
51206
- : undefined;
51248
+ let content = undefined;
51249
+ switch (pivotCell.type) {
51250
+ case "HEADER":
51251
+ content = makePivotFormula("PIVOT.HEADER", [formulaId, ...flatPivotDomain(pivotCell.domain)].filter(isDefined));
51252
+ break;
51253
+ case "VALUE":
51254
+ content = makePivotFormula("PIVOT.VALUE", [formulaId, pivotCell.measure, ...flatPivotDomain(pivotCell.domain)].filter(isDefined));
51255
+ break;
51256
+ }
51207
51257
  this.dispatch("UPDATE_CELL", {
51208
51258
  ...position,
51209
- content: pivotCell.content || (args ? makePivotFormula(formula, args) : undefined),
51259
+ content,
51210
51260
  });
51211
51261
  }
51212
51262
  getPivotCore(pivotId) {
@@ -51225,7 +51275,7 @@ class PivotCorePlugin extends CorePlugin {
51225
51275
  import(data) {
51226
51276
  if (data.pivots) {
51227
51277
  for (const [id, pivot] of Object.entries(data.pivots)) {
51228
- this.addPivot(id, deepCopy(pivot), pivot.formulaId);
51278
+ this.addPivot(id, pivot, pivot.formulaId);
51229
51279
  }
51230
51280
  }
51231
51281
  this.history.update("nextFormulaId", data.pivotNextId || getMaxObjectId(this.pivots) + 1);
@@ -54566,15 +54616,18 @@ class PivotUIPlugin extends UIPlugin {
54566
54616
  const pivotCol = position.col - mainPosition.col;
54567
54617
  const pivotRow = position.row - mainPosition.row;
54568
54618
  const pivotCell = pivotCells[pivotCol][pivotRow];
54619
+ if (pivotCell.type === "EMPTY") {
54620
+ return undefined;
54621
+ }
54569
54622
  const domain = pivotCell.domain;
54570
- if (domain?.at(-2) === "measure") {
54571
- return domain.slice(0, -2);
54623
+ if (domain.at(-1)?.field === "measure") {
54624
+ return domain.slice(0, -1);
54572
54625
  }
54573
54626
  return domain;
54574
54627
  }
54575
- const domain = args.slice(functionName === "PIVOT.VALUE" ? 2 : 1);
54576
- if (domain.at(-2) === "measure") {
54577
- return domain.slice(0, -2);
54628
+ const domain = toPivotDomain(args.slice(functionName === "PIVOT.VALUE" ? 2 : 1).map((x) => `${x}`));
54629
+ if (domain.at(-1)?.field === "measure") {
54630
+ return domain.slice(0, -1);
54578
54631
  }
54579
54632
  return domain;
54580
54633
  }
@@ -54589,9 +54642,9 @@ class PivotUIPlugin extends UIPlugin {
54589
54642
  * a pivot function are valid according to the pivot definition.
54590
54643
  * e.g. =PIVOT.VALUE(1,"revenue","country_id",...,"create_date:month",...,"source_id",...)
54591
54644
  */
54592
- areDomainArgsFieldsValid(pivotId, domainArgs) {
54593
- const dimensions = domainArgs
54594
- .filter((arg, index) => index % 2 === 0)
54645
+ areDomainArgsFieldsValid(pivotId, domain) {
54646
+ const dimensions = domain
54647
+ .map((node) => node.field)
54595
54648
  .map((name) => (name.startsWith("#") ? name.slice(1) : name));
54596
54649
  let argIndex = 0;
54597
54650
  let definitionIndex = 0;
@@ -61605,6 +61658,10 @@ css /* scss */ `
61605
61658
  }
61606
61659
  }
61607
61660
  }
61661
+ .o-sidePanelBody-container {
61662
+ /* This overwrites the min-height: auto; of flex. Without this, a flex div cannot be smaller than its children */
61663
+ min-height: 0;
61664
+ }
61608
61665
  .o-sidePanelBody {
61609
61666
  overflow: auto;
61610
61667
  width: 100%;
@@ -61683,24 +61740,6 @@ css /* scss */ `
61683
61740
  text-align: left;
61684
61741
  }
61685
61742
 
61686
- .o-inflection {
61687
- table {
61688
- table-layout: fixed;
61689
- margin-top: 2%;
61690
- display: table;
61691
- text-align: left;
61692
- font-size: 12px;
61693
- line-height: 18px;
61694
- width: 100%;
61695
- }
61696
- input,
61697
- select {
61698
- width: 100%;
61699
- height: 100%;
61700
- box-sizing: border-box;
61701
- }
61702
- }
61703
-
61704
61743
  .o-sidePanel-tools {
61705
61744
  color: #333;
61706
61745
  font-size: 13px;
@@ -61719,12 +61758,25 @@ css /* scss */ `
61719
61758
  }
61720
61759
  }
61721
61760
  }
61761
+
61762
+ .o-sidePanel-handle-container {
61763
+ width: 8px;
61764
+ }
61765
+ .o-sidePanel-handle {
61766
+ cursor: col-resize;
61767
+ color: #a9a9a9;
61768
+ .o-icon {
61769
+ height: 25px;
61770
+ margin-left: -5px;
61771
+ }
61772
+ }
61722
61773
  }
61723
61774
  `;
61724
61775
  class SidePanel extends Component {
61725
61776
  static template = "o-spreadsheet-SidePanel";
61726
61777
  static props = {};
61727
61778
  sidePanelStore;
61779
+ spreadsheetRect = useSpreadsheetRect();
61728
61780
  setup() {
61729
61781
  this.sidePanelStore = useStore(SidePanelStore);
61730
61782
  useEffect((isOpen) => {
@@ -61745,6 +61797,20 @@ class SidePanel extends Component {
61745
61797
  ? panel.title(this.env, this.sidePanelStore.panelProps)
61746
61798
  : panel.title;
61747
61799
  }
61800
+ startHandleDrag(ev) {
61801
+ const startingCursor = document.body.style.cursor;
61802
+ const startSize = this.sidePanelStore.panelSize;
61803
+ const startPosition = ev.clientX;
61804
+ const onMouseMove = (ev) => {
61805
+ document.body.style.cursor = "col-resize";
61806
+ const newSize = startSize + startPosition - ev.clientX;
61807
+ this.sidePanelStore.changePanelSize(newSize, this.spreadsheetRect.width);
61808
+ };
61809
+ const cleanUp = () => {
61810
+ document.body.style.cursor = startingCursor;
61811
+ };
61812
+ startDnd(onMouseMove, cleanUp);
61813
+ }
61748
61814
  }
61749
61815
 
61750
61816
  css /* scss */ `
@@ -62528,7 +62594,6 @@ css /* scss */ `
62528
62594
  .o-spreadsheet {
62529
62595
  position: relative;
62530
62596
  display: grid;
62531
- grid-template-columns: auto 350px;
62532
62597
  color: #333;
62533
62598
  font-size: 14px;
62534
62599
 
@@ -62726,6 +62791,7 @@ class Spreadsheet extends Component {
62726
62791
  };
62727
62792
  sidePanel;
62728
62793
  spreadsheetRef = useRef("spreadsheet");
62794
+ spreadsheetRect = useSpreadsheetRect();
62729
62795
  _focusGrid;
62730
62796
  keyDownMapping;
62731
62797
  isViewportTooSmall = false;
@@ -62735,10 +62801,15 @@ class Spreadsheet extends Component {
62735
62801
  return this.props.model;
62736
62802
  }
62737
62803
  getStyle() {
62804
+ const properties = {};
62738
62805
  if (this.env.isDashboard()) {
62739
- return `grid-template-rows: auto;`;
62806
+ properties["grid-template-rows"] = `auto`;
62740
62807
  }
62741
- return `grid-template-rows: ${TOPBAR_HEIGHT}px auto ${BOTTOMBAR_HEIGHT + 1}px`;
62808
+ else {
62809
+ properties["grid-template-rows"] = `${TOPBAR_HEIGHT}px auto ${BOTTOMBAR_HEIGHT + 1}px`;
62810
+ }
62811
+ properties["grid-template-columns"] = `auto ${this.sidePanel.panelSize}px`;
62812
+ return cssPropertiesToCss(properties);
62742
62813
  }
62743
62814
  setup() {
62744
62815
  const stores = useStoreProvider();
@@ -62798,14 +62869,19 @@ class Spreadsheet extends Component {
62798
62869
  onMounted(() => {
62799
62870
  this.checkViewportSize();
62800
62871
  stores.on("store-updated", this, render);
62872
+ resizeObserver.observe(this.spreadsheetRef.el);
62801
62873
  });
62802
62874
  onWillUnmount(() => {
62803
62875
  this.unbindModelEvents();
62804
62876
  stores.off("store-updated", this);
62877
+ resizeObserver.disconnect();
62805
62878
  });
62806
62879
  onPatched(() => {
62807
62880
  this.checkViewportSize();
62808
62881
  });
62882
+ const resizeObserver = new ResizeObserver(() => {
62883
+ this.sidePanel.changePanelSize(this.sidePanel.panelSize, this.spreadsheetRect.width);
62884
+ });
62809
62885
  }
62810
62886
  bindModelEvents() {
62811
62887
  this.model.on("update", this, () => this.render(true));
@@ -66860,6 +66936,8 @@ const helpers = {
66860
66936
  insertTokenAfterLeftParenthesis,
66861
66937
  mergeContiguousZones,
66862
66938
  getPivotHighlights,
66939
+ toPivotDomain,
66940
+ flatPivotDomain,
66863
66941
  pivotTimeAdapter,
66864
66942
  UNDO_REDO_PIVOT_COMMANDS,
66865
66943
  };
@@ -66944,6 +67022,6 @@ const constants = {
66944
67022
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
66945
67023
 
66946
67024
 
66947
- __info__.version = "17.4.0-alpha.1";
66948
- __info__.date = "2024-06-03T15:30:28.283Z";
66949
- __info__.hash = "cb56c37";
67025
+ __info__.version = "17.4.0-alpha.2";
67026
+ __info__.date = "2024-06-06T13:31:21.327Z";
67027
+ __info__.hash = "e07794d";