@odoo/o-spreadsheet 18.4.0-alpha.2 → 18.4.0-alpha.4

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.
@@ -1,9 +1,9 @@
1
1
  <!--
2
2
  This file is generated by o-spreadsheet build tools. Do not edit it.
3
3
  @see https://github.com/odoo/o-spreadsheet
4
- @version 18.4.0-alpha.2
5
- @date 2025-05-12T05:28:52.249Z
6
- @hash a11158e
4
+ @version 18.4.0-alpha.4
5
+ @date 2025-05-20T05:58:32.778Z
6
+ @hash 5c28bca
7
7
  -->
8
8
  <odoo>
9
9
  <t t-name="o-spreadsheet-ValidationMessages">
@@ -352,6 +352,7 @@
352
352
  <div class="o-spreadsheet h-100 w-100" t-ref="spreadsheet" t-att-style="getStyle()">
353
353
  <t t-if="env.isDashboard()">
354
354
  <SpreadsheetDashboard/>
355
+ <FullScreenChart/>
355
356
  </t>
356
357
  <t t-else="">
357
358
  <TopBar onClick="() => this.focusGrid()" dropdownMaxHeight="gridHeight"/>
@@ -849,7 +850,7 @@
849
850
  fields="props.unusedGroupableFields"
850
851
  />
851
852
  </div>
852
- <t t-foreach="props.definition.columns" t-as="col" t-key="col.nameWithGranularity">
853
+ <t t-foreach="props.definition.columns" t-as="col" t-key="col_index">
853
854
  <div
854
855
  t-on-pointerdown="(ev) => this.startDragAndDrop(col, ev)"
855
856
  t-att-style="dragAndDrop.itemsStyle[col.nameWithGranularity]"
@@ -875,7 +876,7 @@
875
876
  fields="props.unusedGroupableFields"
876
877
  />
877
878
  </div>
878
- <t t-foreach="props.definition.rows" t-as="row" t-key="row.nameWithGranularity">
879
+ <t t-foreach="props.definition.rows" t-as="row" t-key="row_index">
879
880
  <div
880
881
  t-on-pointerdown="(ev) => this.startDragAndDrop(row, ev)"
881
882
  t-att-style="dragAndDrop.itemsStyle[row.nameWithGranularity]"
@@ -971,6 +972,7 @@
971
972
  defaultRangeSheetId="measure.computedBy.sheetId"
972
973
  contextualAutocomplete="getMeasureAutocomplete()"
973
974
  getContextualColoredSymbolToken.bind="getColoredSymbolToken"
975
+ invalid="isCalculatedMeasureInvalid"
974
976
  />
975
977
  </div>
976
978
  </div>
@@ -1324,7 +1326,88 @@
1324
1326
  </div>
1325
1327
  </t>
1326
1328
 
1327
- <t t-name="o-spreadsheet-DataValidationValueInRangeCriterionForm">
1329
+ <t t-name="o-spreadsheet-CustomCurrencyPanel">
1330
+ <div class="o-custom-currency">
1331
+ <Section t-if="availableCurrencies.length > 1" title.translate="Currency">
1332
+ <select
1333
+ class="o-input o-available-currencies"
1334
+ t-on-change="(ev) => this.updateSelectCurrency(ev)">
1335
+ <t t-foreach="availableCurrencies" t-as="currency" t-key="currency_index">
1336
+ <option
1337
+ t-att-value="currency_index"
1338
+ t-esc="currencyDisplayName(currency)"
1339
+ t-att-selected="currency_index === state.selectedCurrencyIndex"
1340
+ />
1341
+ </t>
1342
+ </select>
1343
+ </Section>
1344
+ <Section>
1345
+ <div class="o-subsection-left">
1346
+ <div class="o-section-title">Code</div>
1347
+ <input
1348
+ type="text"
1349
+ class="o-input"
1350
+ t-model="state.currencyCode"
1351
+ placeholder="code"
1352
+ t-on-input="(ev) => this.updateCode(ev)"
1353
+ />
1354
+ </div>
1355
+ <div class="o-subsection-right">
1356
+ <div class="o-section-title">Symbol</div>
1357
+ <input
1358
+ type="text"
1359
+ class="o-input"
1360
+ placeholder="symbol"
1361
+ t-model="state.currencySymbol"
1362
+ t-on-input="(ev) => this.updateSymbol(ev)"
1363
+ />
1364
+ </div>
1365
+ </Section>
1366
+ <Section title.translate="Format">
1367
+ <select
1368
+ class="o-input o-format-proposals mb-1"
1369
+ t-on-change="(ev) => this.updateSelectFormat(ev)"
1370
+ t-att-disabled="!formatProposals.length">
1371
+ <t t-foreach="formatProposals" t-as="proposal" t-key="proposal_index">
1372
+ <option
1373
+ t-att-value="proposal_index"
1374
+ t-esc="proposal.example"
1375
+ t-att-selected="proposal_index === state.selectedFormatIndex"
1376
+ />
1377
+ </t>
1378
+ </select>
1379
+ <t t-set="accounting_format_label">Accounting format</t>
1380
+ <Checkbox
1381
+ name="'accountingFormat'"
1382
+ label="accounting_format_label"
1383
+ value="state.isAccountingFormat"
1384
+ onChange.bind="toggleAccountingFormat"
1385
+ />
1386
+ <div class="o-format-examples mt-4" t-if="selectedFormat">
1387
+ <table class="w-100">
1388
+ <t t-foreach="getFormatExamples()" t-as="example" t-key="example_index">
1389
+ <tr>
1390
+ <td class="w-25 pe-3 o-fw-bold" t-esc="example.label"/>
1391
+ <td class="w-75 text-truncate" t-esc="example.value"/>
1392
+ </tr>
1393
+ </t>
1394
+ </table>
1395
+ </div>
1396
+ </Section>
1397
+ <Section>
1398
+ <div class="o-sidePanelButtons">
1399
+ <button
1400
+ class="o-button primary"
1401
+ t-on-click="() => this.apply()"
1402
+ t-att-disabled="!formatProposals.length || isSameFormat">
1403
+ Apply
1404
+ </button>
1405
+ </div>
1406
+ </Section>
1407
+ </div>
1408
+ </t>
1409
+
1410
+ <t t-name="o-spreadsheet-ValueInRangeCriterionForm">
1328
1411
  <SelectionInput
1329
1412
  ranges="[props.criterion.values[0] || '']"
1330
1413
  onSelectionChanged="(ranges) => this.onRangeChanged(ranges[0])"
@@ -1341,16 +1424,17 @@
1341
1424
  </select>
1342
1425
  </t>
1343
1426
 
1344
- <t t-name="o-spreadsheet-DataValidationListCriterionForm">
1427
+ <t t-name="o-spreadsheet-ListCriterionForm">
1345
1428
  <t t-foreach="displayedValues" t-as="value" t-key="value_index">
1346
1429
  <div class="o-dv-list-values d-flex align-items-center">
1347
- <DataValidationInput
1430
+ <CriterionInput
1348
1431
  value="props.criterion.values[value_index]"
1349
1432
  onValueChanged="(v) => this.onValueChanged(v, value_index)"
1350
1433
  criterionType="props.criterion.type"
1351
1434
  onKeyDown="(ev) => this.onKeyDown(ev, value_index)"
1352
1435
  focused="value_index === state.focusedValueIndex"
1353
1436
  onBlur.bind="onBlurInput"
1437
+ disableFormulas="props.disableFormulas"
1354
1438
  />
1355
1439
  <div
1356
1440
  class="o-dv-list-item-delete ms-2 o-button-icon"
@@ -1373,56 +1457,27 @@
1373
1457
  </select>
1374
1458
  </t>
1375
1459
 
1376
- <t t-name="o-spreadsheet-DataValidationSingleInput">
1377
- <DataValidationInput
1460
+ <t t-name="o-spreadsheet-SingleInputCriterionForm">
1461
+ <CriterionInput
1378
1462
  value="props.criterion.values[0]"
1379
1463
  onValueChanged.bind="onValueChanged"
1380
1464
  criterionType="props.criterion.type"
1465
+ disableFormulas="props.disableFormulas"
1381
1466
  />
1382
1467
  </t>
1383
1468
 
1384
- <t t-name="o-spreadsheet-DataValidationInput">
1385
- <div class="o-dv-input position-relative w-100 p-1">
1386
- <t t-if="allowedValues === 'onlyLiterals'">
1387
- <input
1388
- type="text"
1389
- t-ref="input"
1390
- t-on-input="onInputValueChanged"
1391
- t-att-value="props.value"
1392
- class="o-input"
1393
- t-att-class="{
1394
- 'o-invalid border-danger position-relative': errorMessage,
1395
- }"
1396
- t-att-title="errorMessage"
1397
- t-att-placeholder="placeholder"
1398
- t-on-keydown="props.onKeyDown"
1399
- t-on-blur="props.onBlur"
1400
- />
1401
- </t>
1402
- <t t-else="">
1403
- <StandaloneComposer t-props="getDataValidationRuleInputComposerProps()"/>
1404
- </t>
1405
- <span
1406
- t-if="errorMessage"
1407
- class="error-icon text-danger position-absolute d-flex align-items-center"
1408
- t-att-title="errorMessage">
1409
- <t t-call="o-spreadsheet-Icon.ERROR"/>
1410
- </span>
1411
- </div>
1412
- </t>
1413
-
1414
- <t t-name="o-spreadsheet-DataValidationDoubleInput">
1415
- <DataValidationInput
1469
+ <t t-name="o-spreadsheet-DoubleInputCriterionForm">
1470
+ <CriterionInput
1416
1471
  value="props.criterion.values[0]"
1417
1472
  onValueChanged.bind="onFirstValueChanged"
1418
1473
  criterionType="props.criterion.type"
1474
+ disableFormulas="props.disableFormulas"
1419
1475
  />
1420
-
1421
- <div class="o-section-subtitle ms-1 my-2">and</div>
1422
- <DataValidationInput
1476
+ <CriterionInput
1423
1477
  value="props.criterion.values[1]"
1424
1478
  onValueChanged.bind="onSecondValueChanged"
1425
1479
  criterionType="props.criterion.type"
1480
+ disableFormulas="props.disableFormulas"
1426
1481
  />
1427
1482
  </t>
1428
1483
 
@@ -1438,92 +1493,42 @@
1438
1493
  />
1439
1494
  </select>
1440
1495
 
1441
- <DataValidationInput
1496
+ <CriterionInput
1442
1497
  t-if="props.criterion.dateValue === 'exactDate'"
1443
1498
  value="props.criterion.values[0]"
1444
1499
  onValueChanged.bind="onValueChanged"
1445
1500
  criterionType="props.criterion.type"
1501
+ disableFormulas="props.disableFormulas"
1446
1502
  />
1447
1503
  </t>
1448
1504
 
1449
- <t t-name="o-spreadsheet-CustomCurrencyPanel">
1450
- <div class="o-custom-currency">
1451
- <Section t-if="availableCurrencies.length > 1" title.translate="Currency">
1452
- <select
1453
- class="o-input o-available-currencies"
1454
- t-on-change="(ev) => this.updateSelectCurrency(ev)">
1455
- <t t-foreach="availableCurrencies" t-as="currency" t-key="currency_index">
1456
- <option
1457
- t-att-value="currency_index"
1458
- t-esc="currencyDisplayName(currency)"
1459
- t-att-selected="currency_index === state.selectedCurrencyIndex"
1460
- />
1461
- </t>
1462
- </select>
1463
- </Section>
1464
- <Section>
1465
- <div class="o-subsection-left">
1466
- <div class="o-section-title">Code</div>
1467
- <input
1468
- type="text"
1469
- class="o-input"
1470
- t-model="state.currencyCode"
1471
- placeholder="code"
1472
- t-on-input="(ev) => this.updateCode(ev)"
1473
- />
1474
- </div>
1475
- <div class="o-subsection-right">
1476
- <div class="o-section-title">Symbol</div>
1477
- <input
1478
- type="text"
1479
- class="o-input"
1480
- placeholder="symbol"
1481
- t-model="state.currencySymbol"
1482
- t-on-input="(ev) => this.updateSymbol(ev)"
1483
- />
1484
- </div>
1485
- </Section>
1486
- <Section title.translate="Format">
1487
- <select
1488
- class="o-input o-format-proposals mb-1"
1489
- t-on-change="(ev) => this.updateSelectFormat(ev)"
1490
- t-att-disabled="!formatProposals.length">
1491
- <t t-foreach="formatProposals" t-as="proposal" t-key="proposal_index">
1492
- <option
1493
- t-att-value="proposal_index"
1494
- t-esc="proposal.example"
1495
- t-att-selected="proposal_index === state.selectedFormatIndex"
1496
- />
1497
- </t>
1498
- </select>
1499
- <t t-set="accounting_format_label">Accounting format</t>
1500
- <Checkbox
1501
- name="'accountingFormat'"
1502
- label="accounting_format_label"
1503
- value="state.isAccountingFormat"
1504
- onChange.bind="toggleAccountingFormat"
1505
+ <t t-name="o-spreadsheet-CriterionInput">
1506
+ <div class="o-dv-input position-relative w-100 p-1">
1507
+ <t t-if="allowedValues === 'onlyLiterals'">
1508
+ <input
1509
+ type="text"
1510
+ t-ref="input"
1511
+ t-on-input="onInputValueChanged"
1512
+ t-att-value="props.value"
1513
+ class="o-input"
1514
+ t-att-class="{
1515
+ 'o-invalid border-danger position-relative': errorMessage,
1516
+ }"
1517
+ t-att-title="errorMessage"
1518
+ t-att-placeholder="placeholder"
1519
+ t-on-keydown="props.onKeyDown"
1520
+ t-on-blur="props.onBlur"
1505
1521
  />
1506
- <div class="o-format-examples mt-4" t-if="selectedFormat">
1507
- <table class="w-100">
1508
- <t t-foreach="getFormatExamples()" t-as="example" t-key="example_index">
1509
- <tr>
1510
- <td class="w-25 pe-3 o-fw-bold" t-esc="example.label"/>
1511
- <td class="w-75 text-truncate" t-esc="example.value"/>
1512
- </tr>
1513
- </t>
1514
- </table>
1515
- </div>
1516
- </Section>
1517
- <Section>
1518
- <div class="o-sidePanelButtons">
1519
- <button
1520
- class="o-button primary"
1521
- t-on-click="() => this.apply()"
1522
- t-att-disabled="!formatProposals.length || isSameFormat">
1523
- Apply
1524
- </button>
1525
- </div>
1526
- </Section>
1522
+ </t>
1523
+ <t t-else="">
1524
+ <StandaloneComposer t-props="getDataValidationRuleInputComposerProps()"/>
1525
+ </t>
1526
+ <span
1527
+ t-if="errorMessage"
1528
+ class="error-icon text-danger position-absolute d-flex align-items-center"
1529
+ t-att-title="errorMessage">
1530
+ <t t-call="o-spreadsheet-Icon.ERROR"/>
1531
+ </span>
1527
1532
  </div>
1528
1533
  </t>
1529
1534
 
@@ -1937,27 +1942,20 @@
1937
1942
  <t t-set="text_color">Text Color</t>
1938
1943
  <div class="o-cf-cell-is-rule">
1939
1944
  <div class="o-section-subtitle">Format cells if...</div>
1940
- <select
1941
- class="o-input o-cell-is-operator mb-3"
1942
- t-on-change="(ev) => this.editOperator(ev.target.value)">
1943
- <t t-foreach="cellIsOperators" t-as="op" t-key="op_index">
1944
- <option
1945
- t-att-value="op"
1946
- t-esc="cellIsOperators[op]"
1947
- t-att-selected="rule.operator === op"
1948
- />
1949
- </t>
1950
- </select>
1951
- <t t-if="rule.operator !== 'IsEmpty' and rule.operator !== 'IsNotEmpty'">
1952
- <div class="o-cell-is-value mb-3">
1953
- <StandaloneComposer t-props="getCellIsRuleComposerProps(0)"/>
1954
- </div>
1955
- <t t-if="rule.operator === 'Between' || rule.operator === 'NotBetween'">
1956
- <div class="o-cell-is-value o-secondary-value mb-3">
1957
- <StandaloneComposer t-props="getCellIsRuleComposerProps(1)"/>
1958
- </div>
1959
- </t>
1960
- </t>
1945
+ <SelectMenu
1946
+ class="'o-cell-is-operator o-input mb-2'"
1947
+ menuItems="cfCriterionMenuItems"
1948
+ selectedValue="selectedCriterionName"
1949
+ />
1950
+
1951
+ <t
1952
+ t-if="criterionComponent"
1953
+ t-component="criterionComponent"
1954
+ t-key="state.rules.cellIs.operator"
1955
+ criterion="genericCriterion"
1956
+ onCriterionChanged.bind="onRuleValuesChanged"
1957
+ />
1958
+
1961
1959
  <div class="o-section-subtitle pt-3">Formatting style</div>
1962
1960
 
1963
1961
  <t t-call="o-spreadsheet-CellIsRuleEditorPreview">
@@ -2453,17 +2451,24 @@
2453
2451
  </Section>
2454
2452
  </t>
2455
2453
  </GeneralDesignEditor>
2454
+ <ChartTitle
2455
+ title="this.props.definition.keyDescr?.text ?? ''"
2456
+ updateTitle="(text) => this.setKeyText(text)"
2457
+ name.translate="Key Value Style"
2458
+ placeholder.translate="Add a key value description"
2459
+ updateStyle.bind="updateKeyStyle"
2460
+ style="keyStyle"
2461
+ />
2456
2462
  <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="Baseline">
2457
2463
  <t t-set-slot="content">
2458
- <Section class="'pt-0'" title.translate="Baseline description">
2459
- <input
2460
- type="text"
2461
- t-att-value="translate(props.definition.baselineDescr)"
2462
- t-on-change="updateBaselineDescr"
2463
- class="o-input"
2464
- placeholder="Baseline description"
2465
- />
2466
- </Section>
2464
+ <ChartTitle
2465
+ title="this.props.definition.baselineDescr?.text ?? ''"
2466
+ updateTitle="(text) => this.setBaselineText(text)"
2467
+ name.translate="Baseline Style"
2468
+ placeholder.translate="Add a baseline description"
2469
+ updateStyle.bind="updateBaselineStyle"
2470
+ style="baselineStyle"
2471
+ />
2467
2472
  <Section class="'o-chart-baseline-color pt-0'" title="colorsSectionTitle">
2468
2473
  <div class="d-flex align-items-center mb-2">
2469
2474
  <RoundColorPicker
@@ -2531,6 +2536,9 @@
2531
2536
  onSelectionConfirmed.bind="onDataSeriesConfirmed"
2532
2537
  onSelectionReordered.bind="onDataSeriesReordered"
2533
2538
  onSelectionRemoved.bind="onDataSeriesRemoved"
2539
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
2540
+ datasetOrientation="datasetOrientation"
2541
+ onFlipAxis.bind="setDatasetOrientation"
2534
2542
  />
2535
2543
  <ChartLabelRange
2536
2544
  range="this.getLabelRange()"
@@ -2663,6 +2671,9 @@
2663
2671
  onSelectionConfirmed.bind="onDataSeriesConfirmed"
2664
2672
  onSelectionReordered.bind="onDataSeriesReordered"
2665
2673
  onSelectionRemoved.bind="onDataSeriesRemoved"
2674
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
2675
+ datasetOrientation="datasetOrientation"
2676
+ onFlipAxis.bind="setDatasetOrientation"
2666
2677
  />
2667
2678
  <ChartLabelRange
2668
2679
  range="this.getLabelRange()"
@@ -2801,6 +2812,9 @@
2801
2812
  onSelectionReordered.bind="onDataSeriesReordered"
2802
2813
  onSelectionRemoved.bind="onDataSeriesRemoved"
2803
2814
  maxNumberOfUsedRanges="maxNumberOfUsedRanges"
2815
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
2816
+ datasetOrientation="datasetOrientation"
2817
+ onFlipAxis.bind="setDatasetOrientation"
2804
2818
  />
2805
2819
  <ChartLabelRange
2806
2820
  range="this.getLabelRange()"
@@ -3668,6 +3682,7 @@
3668
3682
  value="option.value"
3669
3683
  onChange="option.onChange"
3670
3684
  className="'mt-2'"
3685
+ disabled="option.disabled"
3671
3686
  />
3672
3687
  </t>
3673
3688
  </Section>
@@ -3682,6 +3697,9 @@
3682
3697
  onSelectionReordered.bind="onDataSeriesReordered"
3683
3698
  onSelectionRemoved.bind="onDataSeriesRemoved"
3684
3699
  maxNumberOfUsedRanges="maxNumberOfUsedRanges"
3700
+ datasetOrientation="datasetOrientation"
3701
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
3702
+ onFlipAxis.bind="setDatasetOrientation"
3685
3703
  />
3686
3704
  <ChartLabelRange
3687
3705
  range="this.getLabelRange()"
@@ -3696,7 +3714,6 @@
3696
3714
  </t>
3697
3715
 
3698
3716
  <t t-name="o-spreadsheet-GeneralDesignEditor">
3699
- <t t-set="chart_title">Chart title</t>
3700
3717
  <SidePanelCollapsible isInitiallyCollapsed="false" title.translate="General">
3701
3718
  <t t-set-slot="content">
3702
3719
  <Section class="'o-chart-background-color pt-0 pb-0'" title.translate="Background color">
@@ -3708,7 +3725,8 @@
3708
3725
  <ChartTitle
3709
3726
  title="title.text"
3710
3727
  updateTitle.bind="updateTitle"
3711
- name="chart_title"
3728
+ name.translate="Chart title"
3729
+ placeholder.translate="Add a Title"
3712
3730
  updateStyle.bind="updateChartTitleStyle"
3713
3731
  style="title"
3714
3732
  defaultStyle="{align: 'left', fontSize: this.props.defaultChartTitleFontSize}"
@@ -3725,7 +3743,28 @@
3725
3743
  </t>
3726
3744
 
3727
3745
  <t t-name="o-spreadsheet.ChartDataSeries">
3728
- <Section class="'o-data-series'" title="title">
3746
+ <Section class="'o-data-series'">
3747
+ <t t-set-slot="title">
3748
+ <div class="d-flex flex-row justify-content-between">
3749
+ <t t-esc="title"/>
3750
+ <div t-if="props.onFlipAxis and props.canChangeDatasetOrientation" class="d-flex">
3751
+ <span
3752
+ t-if="props.datasetOrientation !== 'rows'"
3753
+ title="Split dataset by rows"
3754
+ t-on-click="(ev) => props.onFlipAxis('rows')"
3755
+ class="p-1 o-hoverable-button o-split-by-rows">
3756
+ <t t-call="o-spreadsheet-Icon.INSERT_ROW_BEFORE"/>
3757
+ </span>
3758
+ <span
3759
+ t-else=""
3760
+ title="Split dataset by columns"
3761
+ t-on-click="(ev) => props.onFlipAxis('columns')"
3762
+ class="p-1 o-hoverable-button o-split-by-columns">
3763
+ <t t-call="o-spreadsheet-Icon.INSERT_COL_BEFORE"/>
3764
+ </span>
3765
+ </div>
3766
+ </div>
3767
+ </t>
3729
3768
  <SelectionInput
3730
3769
  ranges="ranges"
3731
3770
  required="true"
@@ -3742,18 +3781,13 @@
3742
3781
  </t>
3743
3782
 
3744
3783
  <t t-name="o-spreadsheet.ChartTitle">
3745
- <t t-set="placeholder">Add a title</t>
3746
- <t t-set="title">
3747
- <t t-if="props.name" t-esc="props.name"/>
3748
- <t t-else="">Title</t>
3749
- </t>
3750
- <Section class="'o-chart-title'" title="title.toString()">
3784
+ <Section class="'o-chart-title'" title="props.name">
3751
3785
  <input
3752
3786
  type="text"
3753
3787
  class="o-input"
3754
3788
  t-att-value="props.title"
3755
3789
  t-on-change="updateTitle"
3756
- t-att-placeholder="placeholder"
3790
+ t-att-placeholder="props.placeholder"
3757
3791
  />
3758
3792
  <TextStyler
3759
3793
  style="props.style"
@@ -3799,6 +3833,9 @@
3799
3833
  onSelectionConfirmed.bind="onDataSeriesConfirmed"
3800
3834
  onSelectionReordered.bind="onDataSeriesReordered"
3801
3835
  onSelectionRemoved.bind="onDataSeriesRemoved"
3836
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
3837
+ datasetOrientation="datasetOrientation"
3838
+ onFlipAxis.bind="setDatasetOrientation"
3802
3839
  />
3803
3840
  <ChartLabelRange
3804
3841
  range="this.getLabelRange()"
@@ -3902,11 +3939,71 @@
3902
3939
  t-on-wheel="props.onMouseWheel"
3903
3940
  t-att-style="popoverStyle"
3904
3941
  t-on-click.stop="">
3905
- <t t-slot="default"/>
3942
+ <div class="o-popover-content" t-ref="popoverContent">
3943
+ <t t-slot="default"/>
3944
+ </div>
3906
3945
  </div>
3907
3946
  </t>
3908
3947
  </t>
3909
3948
 
3949
+ <t t-name="o_spreadsheet.PivotHTMLRenderer">
3950
+ <div class="o_pivot_html_renderer">
3951
+ <Checkbox
3952
+ name="'missing_values'"
3953
+ label.translate="Display missing cells only"
3954
+ value="state.showMissingValuesOnly"
3955
+ onChange.bind="(value) => this.state.showMissingValuesOnly = value"
3956
+ className="'m-2'"
3957
+ />
3958
+ <t t-set="tableData" t-value="getTableData()"/>
3959
+ <table
3960
+ class="o_pivot_html_renderer"
3961
+ t-if="tableData.values.length > 0 or tableData.rows.length > 0">
3962
+ <tr t-foreach="tableData.columns" t-as="row" t-key="row_index">
3963
+ <t t-if="row_index === 0">
3964
+ <th t-att-rowspan="tableData.columns.length"/>
3965
+ </t>
3966
+ <t t-foreach="row" t-as="cell" t-key="cell_index">
3967
+ <th
3968
+ t-att-colspan="cell.span"
3969
+ t-att-style="cell.style"
3970
+ t-att-class="{ o_missing_value: cell.isMissing }"
3971
+ t-on-click="() => props.onCellClicked(cell.formula)">
3972
+ <t t-esc="cell.value"/>
3973
+ </th>
3974
+ </t>
3975
+ </tr>
3976
+ <t t-foreach="tableData.rows" t-as="row" t-key="row_index">
3977
+ <tr>
3978
+ <th
3979
+ t-att-style="row.style"
3980
+ t-att-class="{ o_missing_value: row.isMissing }"
3981
+ t-on-click="() => props.onCellClicked(row.formula)">
3982
+ <t t-esc="row.value"/>
3983
+ </th>
3984
+ <t t-foreach="tableData.values" t-as="col" t-key="col_index">
3985
+ <td
3986
+ t-att-class="{ o_missing_value: col[row_index].isMissing }"
3987
+ t-on-click="() => props.onCellClicked(col[row_index].formula)">
3988
+ <t t-esc="col[row_index].value"/>
3989
+ </td>
3990
+ </t>
3991
+ </tr>
3992
+ </t>
3993
+ </table>
3994
+ <div class="alert alert-info" t-else="1">This pivot has no cell missing on this sheet</div>
3995
+ </div>
3996
+ </t>
3997
+
3998
+ <t t-name="o-spreadsheet-PivotCollapseIcon">
3999
+ <div
4000
+ class="o-pivot-collapse-icon o-hoverable-button d-flex align-items-center justify-content-center"
4001
+ t-on-click="onClick">
4002
+ <t t-if="isCollapsed" t-call="o-spreadsheet-Icon.PLUS"/>
4003
+ <t t-else="" t-call="o-spreadsheet-Icon.MINUS"/>
4004
+ </div>
4005
+ </t>
4006
+
3910
4007
  <t t-name="o-spreadsheet-PaintFormatButton">
3911
4008
  <span
3912
4009
  class="o-menu-item-button"
@@ -5454,8 +5551,7 @@
5454
5551
  t-on-pointerdown="onMouseDown"
5455
5552
  t-on-dblclick.self="onDoubleClick"
5456
5553
  t-on-contextmenu.stop.prevent="onContextMenu">
5457
- <DataValidationOverlay/>
5458
- <FilterIconsOverlay/>
5554
+ <GridCellIconOverlay/>
5459
5555
  <GridAddRowsFooter
5460
5556
  t-if="!env.model.getters.isReadonly()"
5461
5557
  t-key="env.model.getters.getActiveSheetId()"
@@ -5465,10 +5561,18 @@
5465
5561
  </div>
5466
5562
  </t>
5467
5563
 
5564
+ <t t-name="o-spreadsheet-GridCellIconOverlay">
5565
+ <t t-foreach="icons" t-as="icon" t-key="icon_index">
5566
+ <GridCellIcon icon="icon">
5567
+ <t t-component="icon.component" cellPosition="icon.position"/>
5568
+ </GridCellIcon>
5569
+ </t>
5570
+ </t>
5571
+
5468
5572
  <t t-name="o-spreadsheet-GridCellIcon">
5469
5573
  <div
5470
5574
  class="o-grid-cell-icon position-absolute overflow-hidden"
5471
- t-if="isPositionVisible(this.props.cellPosition)"
5575
+ t-if="isPositionVisible(this.props.icon.position)"
5472
5576
  t-att-style="iconStyle">
5473
5577
  <t t-slot="default"/>
5474
5578
  </div>
@@ -5524,6 +5628,7 @@
5524
5628
  onInputContextMenu.bind="onInputContextMenu"
5525
5629
  />
5526
5630
  <canvas t-ref="canvas"/>
5631
+ <t t-set="focused" t-value="focusedClients"/>
5527
5632
  <t
5528
5633
  t-foreach="env.model.getters.getClientsToDisplay()"
5529
5634
  t-as="client"
@@ -5533,7 +5638,7 @@
5533
5638
  color="client.color"
5534
5639
  col="client.position.col"
5535
5640
  row="client.position.row"
5536
- active="isCellHovered(client.position.col, client.position.row)"
5641
+ active="isCellHovered(client.position.col, client.position.row) || focused.has(client.id)"
5537
5642
  />
5538
5643
  </t>
5539
5644
  <GridPopover
@@ -5566,6 +5671,37 @@
5566
5671
  </div>
5567
5672
  </t>
5568
5673
 
5674
+ <t t-name="o-spreadsheet-FullScreenChart">
5675
+ <div
5676
+ class="position-absolute o-fullscreen-chart-overlay w-100 h-100 d-flex"
5677
+ t-if="figureUI"
5678
+ t-on-click="exitFullScreen">
5679
+ <button
5680
+ class="o-exit top-0 end-0 position-absolute o-button primary m-1"
5681
+ t-on-click="exitFullScreen">
5682
+ Exit fullscreen
5683
+ </button>
5684
+ <div class="flex-fill">
5685
+ <div
5686
+ class="o-fullscreen-chart o-figure position-relative"
5687
+ tabindex="1"
5688
+ t-ref="fullScreenChart"
5689
+ t-on-click.stop=""
5690
+ t-on-keydown="(ev) => this.onKeyDown(ev)">
5691
+ <t
5692
+ t-component="chartComponent"
5693
+ figureUI="this.figureUI"
5694
+ isFullScreen="true"
5695
+ t-key="this.figureUI.id"
5696
+ />
5697
+ <div class="position-absolute top-0 end-0">
5698
+ <ChartDashboardMenu figureUI="figureUI"/>
5699
+ </div>
5700
+ </div>
5701
+ </div>
5702
+ </div>
5703
+ </t>
5704
+
5569
5705
  <t t-name="o-spreadsheet-FontSizeEditor">
5570
5706
  <div class="o-dropdown" t-ref="FontSizeEditor">
5571
5707
  <div
@@ -5604,6 +5740,47 @@
5604
5740
  </div>
5605
5741
  </t>
5606
5742
 
5743
+ <t t-name="o-spreadsheet-FilterMenuValueList">
5744
+ <div class="o-filter-menu-actions d-flex">
5745
+ <div class="o-button-link me-4" t-on-click="selectAll">Select all</div>
5746
+ <div class="o-button-link me-4" t-on-click="clearAll">Clear</div>
5747
+ </div>
5748
+ <div class="position-relative">
5749
+ <input
5750
+ class="w-100 o-input my-2"
5751
+ t-ref="filterMenuSearchBar"
5752
+ type="text"
5753
+ t-model="state.textFilter"
5754
+ placeholder="Search..."
5755
+ t-on-keydown="onKeyDown"
5756
+ />
5757
+ <i class="o-search-icon position-absolute">
5758
+ <t t-call="o-spreadsheet-Icon.SEARCH"/>
5759
+ </i>
5760
+ </div>
5761
+ <div
5762
+ class="o-filter-menu-list d-flex flex-column"
5763
+ t-ref="filterValueList"
5764
+ t-on-click="this.clearScrolledToValue"
5765
+ t-on-scroll="this.clearScrolledToValue">
5766
+ <t t-foreach="displayedValues" t-as="value" t-key="value.string">
5767
+ <FilterMenuValueItem
5768
+ onClick="() => this.checkValue(value)"
5769
+ onMouseMove="() => this.onMouseMove(value)"
5770
+ value="value.string"
5771
+ isChecked="value.checked"
5772
+ isSelected="value.string === state.selectedValue"
5773
+ scrolledTo="value.scrolledTo"
5774
+ />
5775
+ </t>
5776
+ <div
5777
+ t-if="displayedValues.length === 0"
5778
+ class="o-filter-menu-no-values d-flex align-items-center justify-content-center w-100 h-100 ">
5779
+ No results
5780
+ </div>
5781
+ </div>
5782
+ </t>
5783
+
5607
5784
  <t t-name="o-spreadsheet-FilterMenuValueItem">
5608
5785
  <div
5609
5786
  t-on-pointermove="this.props.onMouseMove"
@@ -5625,75 +5802,75 @@
5625
5802
  </div>
5626
5803
  </t>
5627
5804
 
5805
+ <t t-name="o-spreadsheet-FilterMenuCriterion">
5806
+ <SelectMenu
5807
+ class="'o-filter-criterion-type o-input m-1 mb-2'"
5808
+ menuItems="criterionMenuItems"
5809
+ selectedValue="selectedCriterionName"
5810
+ />
5811
+
5812
+ <t
5813
+ t-if="criterionComponent"
5814
+ t-component="criterionComponent"
5815
+ t-key="selectedCriterionName"
5816
+ criterion="state.criterion"
5817
+ onCriterionChanged.bind="onCriterionChanged"
5818
+ disableFormulas="true"
5819
+ />
5820
+ </t>
5821
+
5628
5822
  <t t-name="o-spreadsheet-FilterMenu">
5629
5823
  <div class="o-filter-menu d-flex flex-column bg-white" t-on-wheel.stop="">
5630
5824
  <t t-if="isSortable">
5631
5825
  <div>
5632
- <div class="o-filter-menu-item my-2 mb-3" t-on-click="() => this.sortFilterZone('asc')">
5826
+ <div
5827
+ class="o-filter-menu-item o-sort-item py-2 mb-1"
5828
+ t-on-click="() => this.sortFilterZone('asc')">
5633
5829
  Sort ascending (A ⟶ Z)
5634
5830
  </div>
5635
- <div class="o-filter-menu-item my-2" t-on-click="() => this.sortFilterZone('desc')">
5831
+ <div
5832
+ class="o-filter-menu-item o-sort-item py-2"
5833
+ t-on-click="() => this.sortFilterZone('desc')">
5636
5834
  Sort descending (Z ⟶ A)
5637
5835
  </div>
5638
5836
  </div>
5639
- <div class="o-separator"/>
5640
5837
  </t>
5641
- <div class="o-filter-menu-actions d-flex">
5642
- <div class="o-button-link me-4" t-on-click="selectAll">Select all</div>
5643
- <div class="o-button-link me-4" t-on-click="clearAll">Clear</div>
5644
- </div>
5645
- <div class="position-relative">
5646
- <input
5647
- class="w-100 o-input my-2"
5648
- t-ref="filterMenuSearchBar"
5649
- type="text"
5650
- t-model="state.textFilter"
5651
- placeholder="Search..."
5652
- t-on-keydown="onKeyDown"
5653
- />
5654
- <i class="o-search-icon position-absolute">
5655
- <t t-call="o-spreadsheet-Icon.SEARCH"/>
5656
- </i>
5657
- </div>
5658
- <div
5659
- class="o-filter-menu-list d-flex flex-column"
5660
- t-ref="filterValueList"
5661
- t-on-click="this.clearScrolledToValue"
5662
- t-on-scroll="this.clearScrolledToValue">
5663
- <t t-foreach="displayedValues" t-as="value" t-key="value.string">
5664
- <FilterMenuValueItem
5665
- onClick="() => this.checkValue(value)"
5666
- onMouseMove="() => this.onMouseMove(value)"
5667
- value="value.string"
5668
- isChecked="value.checked"
5669
- isSelected="value.string === state.selectedValue"
5670
- scrolledTo="value.scrolledTo"
5671
- />
5672
- </t>
5673
- <div
5674
- t-if="displayedValues.length === 0"
5675
- class="o-filter-menu-no-values d-flex align-items-center justify-content-center w-100 h-100 ">
5676
- No results
5838
+ <div class="o-filter-menu-content">
5839
+ <div class="o-separator"/>
5840
+ <SidePanelCollapsible
5841
+ isInitiallyCollapsed="filterValueType !== 'criterion'"
5842
+ title.translate="Filter by criterion">
5843
+ <t t-set-slot="content">
5844
+ <FilterMenuCriterion
5845
+ filterPosition="props.filterPosition"
5846
+ onCriterionChanged.bind="onCriterionChanged"
5847
+ criterionOperators="criterionOperators"
5848
+ />
5849
+ <div class="mb-3"/>
5850
+ </t>
5851
+ </SidePanelCollapsible>
5852
+
5853
+ <SidePanelCollapsible
5854
+ isInitiallyCollapsed="filterValueType === 'criterion'"
5855
+ title.translate="Filter by values">
5856
+ <t t-set-slot="content">
5857
+ <FilterMenuValueList
5858
+ filterPosition="props.filterPosition"
5859
+ onUpdateHiddenValues.bind="onUpdateHiddenValues"
5860
+ />
5861
+ </t>
5862
+ </SidePanelCollapsible>
5863
+
5864
+ <div class="o-filter-menu-buttons d-flex justify-content-end">
5865
+ <button class="o-button o-filter-menu-cancel me-2" t-on-click="cancel">Cancel</button>
5866
+ <button class="o-button primary o-filter-menu-confirm" t-on-click="confirm">
5867
+ Confirm
5868
+ </button>
5677
5869
  </div>
5678
5870
  </div>
5679
- <div class="o-filter-menu-buttons d-flex justify-content-end">
5680
- <button class="o-button o-filter-menu-cancel me-2" t-on-click="cancel">Cancel</button>
5681
- <button class="o-button primary o-filter-menu-confirm" t-on-click="confirm">Confirm</button>
5682
- </div>
5683
5871
  </div>
5684
5872
  </t>
5685
5873
 
5686
- <t t-name="o-spreadsheet-FilterIconsOverlay">
5687
- <t
5688
- t-foreach="getFilterHeadersPositions()"
5689
- t-as="position"
5690
- t-key="'filter'+position.col + '_' + position.row">
5691
- <GridCellIcon cellPosition="position" horizontalAlign="'right'">
5692
- <FilterIcon cellPosition="position"/>
5693
- </GridCellIcon>
5694
- </t>
5695
- </t>
5696
-
5697
5874
  <t t-name="o-spreadsheet-FilterIcon">
5698
5875
  <div class="o-filter-icon" t-att-class="iconClass" t-on-click="onClick">
5699
5876
  <t t-if="isFilterActive" t-call="o-spreadsheet-Icon.FILTER_ICON_ACTIVE"/>
@@ -5853,13 +6030,13 @@
5853
6030
  <t t-name="spreadsheet.ChartDashboardMenu">
5854
6031
  <div class="o-dashboard-chart-select position-absolute top-0 end-0" t-on-click.stop="">
5855
6032
  <div class="d-flex flex-row px-1" t-att-style="backgroundColor">
5856
- <t t-foreach="getAvailableTypes()" t-as="type" t-key="type.chartSubtype">
6033
+ <t t-foreach="getMenuItems()" t-as="item" t-key="item.id">
5857
6034
  <button
5858
- t-attf-class=" {{type.icon}} {{type.chartType === selectedChartType ? 'active' : ''}}"
6035
+ t-attf-class=" {{item.iconClass}} {{item.isSelected ? 'active' : ''}}"
5859
6036
  class="o-chart-dashboard-item btn mt-1 me-1 p-1 "
5860
- t-att-title="type.displayName"
5861
- t-on-click="() => this.onTypeChange(type.chartSubtype)"
5862
- t-att-data-id="type.chartSubtype"
6037
+ t-att-title="item.label"
6038
+ t-on-click="item.onClick"
6039
+ t-att-data-id="item.id"
5863
6040
  />
5864
6041
  </t>
5865
6042
  <button
@@ -5906,20 +6083,6 @@
5906
6083
  </div>
5907
6084
  </t>
5908
6085
 
5909
- <t t-name="o-spreadsheet-DataValidationOverlay">
5910
- <t t-foreach="checkBoxCellPositions" t-as="position" t-key="'checkbox'+position_index">
5911
- <GridCellIcon cellPosition="position">
5912
- <DataValidationCheckbox cellPosition="position"/>
5913
- </GridCellIcon>
5914
- </t>
5915
-
5916
- <t t-foreach="listIconsCellPositions" t-as="position" t-key="'list'+position_index">
5917
- <GridCellIcon cellPosition="position" horizontalAlign="'right'">
5918
- <DataValidationListIcon cellPosition="position"/>
5919
- </GridCellIcon>
5920
- </t>
5921
- </t>
5922
-
5923
6086
  <t t-name="o-spreadsheet-DataValidationListIcon">
5924
6087
  <div
5925
6088
  class="o-dv-list-icon d-flex align-items-center justify-content-center"
@@ -6134,7 +6297,11 @@
6134
6297
  <div
6135
6298
  class="o-composer-assistant-container shadow position-absolute z-1"
6136
6299
  t-att-style="assistantContainerStyle"
6137
- t-if="props.focus !== 'inactive' and !assistant.forcedClosed and assistantIsAvailable">
6300
+ t-if="props.focus !== 'inactive' and !assistant.forcedClosed and assistantIsAvailable"
6301
+ t-on-wheel.stop=""
6302
+ t-on-pointerdown.prevent.stop=""
6303
+ t-on-pointerup.prevent.stop=""
6304
+ t-on-click.prevent.stop="">
6138
6305
  <span
6139
6306
  role="button"
6140
6307
  t-on-click="closeAssistant"
@@ -6142,13 +6309,7 @@
6142
6309
  <i class="fa fa-circle fa-stack-1x fa-inverse"/>
6143
6310
  <i class="fa fa-times-circle fa-stack-1x text-muted"/>
6144
6311
  </span>
6145
- <div
6146
- class="o-composer-assistant overflow-auto"
6147
- t-att-style="assistantStyle"
6148
- t-on-wheel.stop=""
6149
- t-on-pointerdown.prevent.stop=""
6150
- t-on-click.prevent.stop=""
6151
- t-on-pointerup.prevent.stop="">
6312
+ <div class="o-composer-assistant overflow-auto" t-att-style="assistantStyle">
6152
6313
  <FunctionDescriptionProvider
6153
6314
  t-if="functionDescriptionState.showDescription"
6154
6315
  functionDescription="functionDescriptionState.functionDescription"