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

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.3
5
+ @date 2025-05-13T17:55:42.200Z
6
+ @hash 70ad365
7
7
  -->
8
8
  <odoo>
9
9
  <t t-name="o-spreadsheet-ValidationMessages">
@@ -849,7 +849,7 @@
849
849
  fields="props.unusedGroupableFields"
850
850
  />
851
851
  </div>
852
- <t t-foreach="props.definition.columns" t-as="col" t-key="col.nameWithGranularity">
852
+ <t t-foreach="props.definition.columns" t-as="col" t-key="col_index">
853
853
  <div
854
854
  t-on-pointerdown="(ev) => this.startDragAndDrop(col, ev)"
855
855
  t-att-style="dragAndDrop.itemsStyle[col.nameWithGranularity]"
@@ -875,7 +875,7 @@
875
875
  fields="props.unusedGroupableFields"
876
876
  />
877
877
  </div>
878
- <t t-foreach="props.definition.rows" t-as="row" t-key="row.nameWithGranularity">
878
+ <t t-foreach="props.definition.rows" t-as="row" t-key="row_index">
879
879
  <div
880
880
  t-on-pointerdown="(ev) => this.startDragAndDrop(row, ev)"
881
881
  t-att-style="dragAndDrop.itemsStyle[row.nameWithGranularity]"
@@ -1324,7 +1324,88 @@
1324
1324
  </div>
1325
1325
  </t>
1326
1326
 
1327
- <t t-name="o-spreadsheet-DataValidationValueInRangeCriterionForm">
1327
+ <t t-name="o-spreadsheet-CustomCurrencyPanel">
1328
+ <div class="o-custom-currency">
1329
+ <Section t-if="availableCurrencies.length > 1" title.translate="Currency">
1330
+ <select
1331
+ class="o-input o-available-currencies"
1332
+ t-on-change="(ev) => this.updateSelectCurrency(ev)">
1333
+ <t t-foreach="availableCurrencies" t-as="currency" t-key="currency_index">
1334
+ <option
1335
+ t-att-value="currency_index"
1336
+ t-esc="currencyDisplayName(currency)"
1337
+ t-att-selected="currency_index === state.selectedCurrencyIndex"
1338
+ />
1339
+ </t>
1340
+ </select>
1341
+ </Section>
1342
+ <Section>
1343
+ <div class="o-subsection-left">
1344
+ <div class="o-section-title">Code</div>
1345
+ <input
1346
+ type="text"
1347
+ class="o-input"
1348
+ t-model="state.currencyCode"
1349
+ placeholder="code"
1350
+ t-on-input="(ev) => this.updateCode(ev)"
1351
+ />
1352
+ </div>
1353
+ <div class="o-subsection-right">
1354
+ <div class="o-section-title">Symbol</div>
1355
+ <input
1356
+ type="text"
1357
+ class="o-input"
1358
+ placeholder="symbol"
1359
+ t-model="state.currencySymbol"
1360
+ t-on-input="(ev) => this.updateSymbol(ev)"
1361
+ />
1362
+ </div>
1363
+ </Section>
1364
+ <Section title.translate="Format">
1365
+ <select
1366
+ class="o-input o-format-proposals mb-1"
1367
+ t-on-change="(ev) => this.updateSelectFormat(ev)"
1368
+ t-att-disabled="!formatProposals.length">
1369
+ <t t-foreach="formatProposals" t-as="proposal" t-key="proposal_index">
1370
+ <option
1371
+ t-att-value="proposal_index"
1372
+ t-esc="proposal.example"
1373
+ t-att-selected="proposal_index === state.selectedFormatIndex"
1374
+ />
1375
+ </t>
1376
+ </select>
1377
+ <t t-set="accounting_format_label">Accounting format</t>
1378
+ <Checkbox
1379
+ name="'accountingFormat'"
1380
+ label="accounting_format_label"
1381
+ value="state.isAccountingFormat"
1382
+ onChange.bind="toggleAccountingFormat"
1383
+ />
1384
+ <div class="o-format-examples mt-4" t-if="selectedFormat">
1385
+ <table class="w-100">
1386
+ <t t-foreach="getFormatExamples()" t-as="example" t-key="example_index">
1387
+ <tr>
1388
+ <td class="w-25 pe-3 o-fw-bold" t-esc="example.label"/>
1389
+ <td class="w-75 text-truncate" t-esc="example.value"/>
1390
+ </tr>
1391
+ </t>
1392
+ </table>
1393
+ </div>
1394
+ </Section>
1395
+ <Section>
1396
+ <div class="o-sidePanelButtons">
1397
+ <button
1398
+ class="o-button primary"
1399
+ t-on-click="() => this.apply()"
1400
+ t-att-disabled="!formatProposals.length || isSameFormat">
1401
+ Apply
1402
+ </button>
1403
+ </div>
1404
+ </Section>
1405
+ </div>
1406
+ </t>
1407
+
1408
+ <t t-name="o-spreadsheet-ValueInRangeCriterionForm">
1328
1409
  <SelectionInput
1329
1410
  ranges="[props.criterion.values[0] || '']"
1330
1411
  onSelectionChanged="(ranges) => this.onRangeChanged(ranges[0])"
@@ -1341,16 +1422,17 @@
1341
1422
  </select>
1342
1423
  </t>
1343
1424
 
1344
- <t t-name="o-spreadsheet-DataValidationListCriterionForm">
1425
+ <t t-name="o-spreadsheet-ListCriterionForm">
1345
1426
  <t t-foreach="displayedValues" t-as="value" t-key="value_index">
1346
1427
  <div class="o-dv-list-values d-flex align-items-center">
1347
- <DataValidationInput
1428
+ <CriterionInput
1348
1429
  value="props.criterion.values[value_index]"
1349
1430
  onValueChanged="(v) => this.onValueChanged(v, value_index)"
1350
1431
  criterionType="props.criterion.type"
1351
1432
  onKeyDown="(ev) => this.onKeyDown(ev, value_index)"
1352
1433
  focused="value_index === state.focusedValueIndex"
1353
1434
  onBlur.bind="onBlurInput"
1435
+ disableFormulas="props.disableFormulas"
1354
1436
  />
1355
1437
  <div
1356
1438
  class="o-dv-list-item-delete ms-2 o-button-icon"
@@ -1373,56 +1455,27 @@
1373
1455
  </select>
1374
1456
  </t>
1375
1457
 
1376
- <t t-name="o-spreadsheet-DataValidationSingleInput">
1377
- <DataValidationInput
1458
+ <t t-name="o-spreadsheet-SingleInputCriterionForm">
1459
+ <CriterionInput
1378
1460
  value="props.criterion.values[0]"
1379
1461
  onValueChanged.bind="onValueChanged"
1380
1462
  criterionType="props.criterion.type"
1463
+ disableFormulas="props.disableFormulas"
1381
1464
  />
1382
1465
  </t>
1383
1466
 
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
1467
+ <t t-name="o-spreadsheet-DoubleInputCriterionForm">
1468
+ <CriterionInput
1416
1469
  value="props.criterion.values[0]"
1417
1470
  onValueChanged.bind="onFirstValueChanged"
1418
1471
  criterionType="props.criterion.type"
1472
+ disableFormulas="props.disableFormulas"
1419
1473
  />
1420
-
1421
- <div class="o-section-subtitle ms-1 my-2">and</div>
1422
- <DataValidationInput
1474
+ <CriterionInput
1423
1475
  value="props.criterion.values[1]"
1424
1476
  onValueChanged.bind="onSecondValueChanged"
1425
1477
  criterionType="props.criterion.type"
1478
+ disableFormulas="props.disableFormulas"
1426
1479
  />
1427
1480
  </t>
1428
1481
 
@@ -1438,92 +1491,42 @@
1438
1491
  />
1439
1492
  </select>
1440
1493
 
1441
- <DataValidationInput
1494
+ <CriterionInput
1442
1495
  t-if="props.criterion.dateValue === 'exactDate'"
1443
1496
  value="props.criterion.values[0]"
1444
1497
  onValueChanged.bind="onValueChanged"
1445
1498
  criterionType="props.criterion.type"
1499
+ disableFormulas="props.disableFormulas"
1446
1500
  />
1447
1501
  </t>
1448
1502
 
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"
1503
+ <t t-name="o-spreadsheet-CriterionInput">
1504
+ <div class="o-dv-input position-relative w-100 p-1">
1505
+ <t t-if="allowedValues === 'onlyLiterals'">
1506
+ <input
1507
+ type="text"
1508
+ t-ref="input"
1509
+ t-on-input="onInputValueChanged"
1510
+ t-att-value="props.value"
1511
+ class="o-input"
1512
+ t-att-class="{
1513
+ 'o-invalid border-danger position-relative': errorMessage,
1514
+ }"
1515
+ t-att-title="errorMessage"
1516
+ t-att-placeholder="placeholder"
1517
+ t-on-keydown="props.onKeyDown"
1518
+ t-on-blur="props.onBlur"
1505
1519
  />
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>
1520
+ </t>
1521
+ <t t-else="">
1522
+ <StandaloneComposer t-props="getDataValidationRuleInputComposerProps()"/>
1523
+ </t>
1524
+ <span
1525
+ t-if="errorMessage"
1526
+ class="error-icon text-danger position-absolute d-flex align-items-center"
1527
+ t-att-title="errorMessage">
1528
+ <t t-call="o-spreadsheet-Icon.ERROR"/>
1529
+ </span>
1527
1530
  </div>
1528
1531
  </t>
1529
1532
 
@@ -1937,27 +1940,20 @@
1937
1940
  <t t-set="text_color">Text Color</t>
1938
1941
  <div class="o-cf-cell-is-rule">
1939
1942
  <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>
1943
+ <SelectMenu
1944
+ class="'o-cell-is-operator o-input mb-2'"
1945
+ menuItems="cfCriterionMenuItems"
1946
+ selectedValue="selectedCriterionName"
1947
+ />
1948
+
1949
+ <t
1950
+ t-if="criterionComponent"
1951
+ t-component="criterionComponent"
1952
+ t-key="state.rules.cellIs.operator"
1953
+ criterion="genericCriterion"
1954
+ onCriterionChanged.bind="onRuleValuesChanged"
1955
+ />
1956
+
1961
1957
  <div class="o-section-subtitle pt-3">Formatting style</div>
1962
1958
 
1963
1959
  <t t-call="o-spreadsheet-CellIsRuleEditorPreview">
@@ -2531,6 +2527,9 @@
2531
2527
  onSelectionConfirmed.bind="onDataSeriesConfirmed"
2532
2528
  onSelectionReordered.bind="onDataSeriesReordered"
2533
2529
  onSelectionRemoved.bind="onDataSeriesRemoved"
2530
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
2531
+ datasetOrientation="datasetOrientation"
2532
+ onFlipAxis.bind="setDatasetOrientation"
2534
2533
  />
2535
2534
  <ChartLabelRange
2536
2535
  range="this.getLabelRange()"
@@ -2663,6 +2662,9 @@
2663
2662
  onSelectionConfirmed.bind="onDataSeriesConfirmed"
2664
2663
  onSelectionReordered.bind="onDataSeriesReordered"
2665
2664
  onSelectionRemoved.bind="onDataSeriesRemoved"
2665
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
2666
+ datasetOrientation="datasetOrientation"
2667
+ onFlipAxis.bind="setDatasetOrientation"
2666
2668
  />
2667
2669
  <ChartLabelRange
2668
2670
  range="this.getLabelRange()"
@@ -2801,6 +2803,9 @@
2801
2803
  onSelectionReordered.bind="onDataSeriesReordered"
2802
2804
  onSelectionRemoved.bind="onDataSeriesRemoved"
2803
2805
  maxNumberOfUsedRanges="maxNumberOfUsedRanges"
2806
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
2807
+ datasetOrientation="datasetOrientation"
2808
+ onFlipAxis.bind="setDatasetOrientation"
2804
2809
  />
2805
2810
  <ChartLabelRange
2806
2811
  range="this.getLabelRange()"
@@ -3668,6 +3673,7 @@
3668
3673
  value="option.value"
3669
3674
  onChange="option.onChange"
3670
3675
  className="'mt-2'"
3676
+ disabled="option.disabled"
3671
3677
  />
3672
3678
  </t>
3673
3679
  </Section>
@@ -3682,6 +3688,9 @@
3682
3688
  onSelectionReordered.bind="onDataSeriesReordered"
3683
3689
  onSelectionRemoved.bind="onDataSeriesRemoved"
3684
3690
  maxNumberOfUsedRanges="maxNumberOfUsedRanges"
3691
+ datasetOrientation="datasetOrientation"
3692
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
3693
+ onFlipAxis.bind="setDatasetOrientation"
3685
3694
  />
3686
3695
  <ChartLabelRange
3687
3696
  range="this.getLabelRange()"
@@ -3725,7 +3734,28 @@
3725
3734
  </t>
3726
3735
 
3727
3736
  <t t-name="o-spreadsheet.ChartDataSeries">
3728
- <Section class="'o-data-series'" title="title">
3737
+ <Section class="'o-data-series'">
3738
+ <t t-set-slot="title">
3739
+ <div class="d-flex flex-row justify-content-between">
3740
+ <t t-esc="title"/>
3741
+ <div t-if="props.onFlipAxis and props.canChangeDatasetOrientation" class="d-flex">
3742
+ <span
3743
+ t-if="props.datasetOrientation !== 'rows'"
3744
+ title="Split dataset by rows"
3745
+ t-on-click="(ev) => props.onFlipAxis('rows')"
3746
+ class="p-1 o-hoverable-button o-split-by-rows">
3747
+ <t t-call="o-spreadsheet-Icon.INSERT_ROW_BEFORE"/>
3748
+ </span>
3749
+ <span
3750
+ t-else=""
3751
+ title="Split dataset by columns"
3752
+ t-on-click="(ev) => props.onFlipAxis('columns')"
3753
+ class="p-1 o-hoverable-button o-split-by-columns">
3754
+ <t t-call="o-spreadsheet-Icon.INSERT_COL_BEFORE"/>
3755
+ </span>
3756
+ </div>
3757
+ </div>
3758
+ </t>
3729
3759
  <SelectionInput
3730
3760
  ranges="ranges"
3731
3761
  required="true"
@@ -3799,6 +3829,9 @@
3799
3829
  onSelectionConfirmed.bind="onDataSeriesConfirmed"
3800
3830
  onSelectionReordered.bind="onDataSeriesReordered"
3801
3831
  onSelectionRemoved.bind="onDataSeriesRemoved"
3832
+ canChangeDatasetOrientation="canChangeDatasetOrientation"
3833
+ datasetOrientation="datasetOrientation"
3834
+ onFlipAxis.bind="setDatasetOrientation"
3802
3835
  />
3803
3836
  <ChartLabelRange
3804
3837
  range="this.getLabelRange()"
@@ -3902,11 +3935,62 @@
3902
3935
  t-on-wheel="props.onMouseWheel"
3903
3936
  t-att-style="popoverStyle"
3904
3937
  t-on-click.stop="">
3905
- <t t-slot="default"/>
3938
+ <div class="o-popover-content" t-ref="popoverContent">
3939
+ <t t-slot="default"/>
3940
+ </div>
3906
3941
  </div>
3907
3942
  </t>
3908
3943
  </t>
3909
3944
 
3945
+ <t t-name="o_spreadsheet.PivotHTMLRenderer">
3946
+ <div class="o_pivot_html_renderer">
3947
+ <Checkbox
3948
+ name="'missing_values'"
3949
+ label.translate="Display missing cells only"
3950
+ value="state.showMissingValuesOnly"
3951
+ onChange.bind="(value) => this.state.showMissingValuesOnly = value"
3952
+ className="'m-2'"
3953
+ />
3954
+ <t t-set="tableData" t-value="getTableData()"/>
3955
+ <table
3956
+ class="o_pivot_html_renderer"
3957
+ t-if="tableData.values.length > 0 or tableData.rows.length > 0">
3958
+ <tr t-foreach="tableData.columns" t-as="row" t-key="row_index">
3959
+ <t t-if="row_index === 0">
3960
+ <th t-att-rowspan="tableData.columns.length"/>
3961
+ </t>
3962
+ <t t-foreach="row" t-as="cell" t-key="cell_index">
3963
+ <th
3964
+ t-att-colspan="cell.span"
3965
+ t-att-style="cell.style"
3966
+ t-att-class="{ o_missing_value: cell.isMissing }"
3967
+ t-on-click="() => props.onCellClicked(cell.formula)">
3968
+ <t t-esc="cell.value"/>
3969
+ </th>
3970
+ </t>
3971
+ </tr>
3972
+ <t t-foreach="tableData.rows" t-as="row" t-key="row_index">
3973
+ <tr>
3974
+ <th
3975
+ t-att-style="row.style"
3976
+ t-att-class="{ o_missing_value: row.isMissing }"
3977
+ t-on-click="() => props.onCellClicked(row.formula)">
3978
+ <t t-esc="row.value"/>
3979
+ </th>
3980
+ <t t-foreach="tableData.values" t-as="col" t-key="col_index">
3981
+ <td
3982
+ t-att-class="{ o_missing_value: col[row_index].isMissing }"
3983
+ t-on-click="() => props.onCellClicked(col[row_index].formula)">
3984
+ <t t-esc="col[row_index].value"/>
3985
+ </td>
3986
+ </t>
3987
+ </tr>
3988
+ </t>
3989
+ </table>
3990
+ <div class="alert alert-info" t-else="1">This pivot has no cell missing on this sheet</div>
3991
+ </div>
3992
+ </t>
3993
+
3910
3994
  <t t-name="o-spreadsheet-PaintFormatButton">
3911
3995
  <span
3912
3996
  class="o-menu-item-button"
@@ -5604,6 +5688,47 @@
5604
5688
  </div>
5605
5689
  </t>
5606
5690
 
5691
+ <t t-name="o-spreadsheet-FilterMenuValueList">
5692
+ <div class="o-filter-menu-actions d-flex">
5693
+ <div class="o-button-link me-4" t-on-click="selectAll">Select all</div>
5694
+ <div class="o-button-link me-4" t-on-click="clearAll">Clear</div>
5695
+ </div>
5696
+ <div class="position-relative">
5697
+ <input
5698
+ class="w-100 o-input my-2"
5699
+ t-ref="filterMenuSearchBar"
5700
+ type="text"
5701
+ t-model="state.textFilter"
5702
+ placeholder="Search..."
5703
+ t-on-keydown="onKeyDown"
5704
+ />
5705
+ <i class="o-search-icon position-absolute">
5706
+ <t t-call="o-spreadsheet-Icon.SEARCH"/>
5707
+ </i>
5708
+ </div>
5709
+ <div
5710
+ class="o-filter-menu-list d-flex flex-column"
5711
+ t-ref="filterValueList"
5712
+ t-on-click="this.clearScrolledToValue"
5713
+ t-on-scroll="this.clearScrolledToValue">
5714
+ <t t-foreach="displayedValues" t-as="value" t-key="value.string">
5715
+ <FilterMenuValueItem
5716
+ onClick="() => this.checkValue(value)"
5717
+ onMouseMove="() => this.onMouseMove(value)"
5718
+ value="value.string"
5719
+ isChecked="value.checked"
5720
+ isSelected="value.string === state.selectedValue"
5721
+ scrolledTo="value.scrolledTo"
5722
+ />
5723
+ </t>
5724
+ <div
5725
+ t-if="displayedValues.length === 0"
5726
+ class="o-filter-menu-no-values d-flex align-items-center justify-content-center w-100 h-100 ">
5727
+ No results
5728
+ </div>
5729
+ </div>
5730
+ </t>
5731
+
5607
5732
  <t t-name="o-spreadsheet-FilterMenuValueItem">
5608
5733
  <div
5609
5734
  t-on-pointermove="this.props.onMouseMove"
@@ -5625,61 +5750,72 @@
5625
5750
  </div>
5626
5751
  </t>
5627
5752
 
5753
+ <t t-name="o-spreadsheet-FilterMenuCriterion">
5754
+ <SelectMenu
5755
+ class="'o-filter-criterion-type o-input m-1 mb-2'"
5756
+ menuItems="criterionMenuItems"
5757
+ selectedValue="selectedCriterionName"
5758
+ />
5759
+
5760
+ <t
5761
+ t-if="criterionComponent"
5762
+ t-component="criterionComponent"
5763
+ t-key="selectedCriterionName"
5764
+ criterion="state.criterion"
5765
+ onCriterionChanged.bind="onCriterionChanged"
5766
+ disableFormulas="true"
5767
+ />
5768
+ </t>
5769
+
5628
5770
  <t t-name="o-spreadsheet-FilterMenu">
5629
5771
  <div class="o-filter-menu d-flex flex-column bg-white" t-on-wheel.stop="">
5630
5772
  <t t-if="isSortable">
5631
5773
  <div>
5632
- <div class="o-filter-menu-item my-2 mb-3" t-on-click="() => this.sortFilterZone('asc')">
5774
+ <div
5775
+ class="o-filter-menu-item o-sort-item py-2 mb-1"
5776
+ t-on-click="() => this.sortFilterZone('asc')">
5633
5777
  Sort ascending (A ⟶ Z)
5634
5778
  </div>
5635
- <div class="o-filter-menu-item my-2" t-on-click="() => this.sortFilterZone('desc')">
5779
+ <div
5780
+ class="o-filter-menu-item o-sort-item py-2"
5781
+ t-on-click="() => this.sortFilterZone('desc')">
5636
5782
  Sort descending (Z ⟶ A)
5637
5783
  </div>
5638
5784
  </div>
5639
- <div class="o-separator"/>
5640
5785
  </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
5786
+ <div class="o-filter-menu-content">
5787
+ <div class="o-separator"/>
5788
+ <SidePanelCollapsible
5789
+ isInitiallyCollapsed="filterValueType !== 'criterion'"
5790
+ title.translate="Filter by criterion">
5791
+ <t t-set-slot="content">
5792
+ <FilterMenuCriterion
5793
+ filterPosition="props.filterPosition"
5794
+ onCriterionChanged.bind="onCriterionChanged"
5795
+ criterionOperators="criterionOperators"
5796
+ />
5797
+ <div class="mb-3"/>
5798
+ </t>
5799
+ </SidePanelCollapsible>
5800
+
5801
+ <SidePanelCollapsible
5802
+ isInitiallyCollapsed="filterValueType === 'criterion'"
5803
+ title.translate="Filter by values">
5804
+ <t t-set-slot="content">
5805
+ <FilterMenuValueList
5806
+ filterPosition="props.filterPosition"
5807
+ onUpdateHiddenValues.bind="onUpdateHiddenValues"
5808
+ />
5809
+ </t>
5810
+ </SidePanelCollapsible>
5811
+
5812
+ <div class="o-filter-menu-buttons d-flex justify-content-end">
5813
+ <button class="o-button o-filter-menu-cancel me-2" t-on-click="cancel">Cancel</button>
5814
+ <button class="o-button primary o-filter-menu-confirm" t-on-click="confirm">
5815
+ Confirm
5816
+ </button>
5677
5817
  </div>
5678
5818
  </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
5819
  </div>
5684
5820
  </t>
5685
5821
 
@@ -6134,7 +6270,11 @@
6134
6270
  <div
6135
6271
  class="o-composer-assistant-container shadow position-absolute z-1"
6136
6272
  t-att-style="assistantContainerStyle"
6137
- t-if="props.focus !== 'inactive' and !assistant.forcedClosed and assistantIsAvailable">
6273
+ t-if="props.focus !== 'inactive' and !assistant.forcedClosed and assistantIsAvailable"
6274
+ t-on-wheel.stop=""
6275
+ t-on-pointerdown.prevent.stop=""
6276
+ t-on-pointerup.prevent.stop=""
6277
+ t-on-click.prevent.stop="">
6138
6278
  <span
6139
6279
  role="button"
6140
6280
  t-on-click="closeAssistant"
@@ -6142,13 +6282,7 @@
6142
6282
  <i class="fa fa-circle fa-stack-1x fa-inverse"/>
6143
6283
  <i class="fa fa-times-circle fa-stack-1x text-muted"/>
6144
6284
  </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="">
6285
+ <div class="o-composer-assistant overflow-auto" t-att-style="assistantStyle">
6152
6286
  <FunctionDescriptionProvider
6153
6287
  t-if="functionDescriptionState.showDescription"
6154
6288
  functionDescription="functionDescriptionState.functionDescription"