1- import { Component , onWillUpdateProps , useState } from "@odoo/owl" ;
1+ import { Component , onWillUpdateProps } from "@odoo/owl" ;
22import { BUTTON_ACTIVE_BG } from "../../../constants" ;
3- import { deepEquals } from "../../../helpers" ;
3+ import { deepEquals , isDateTimeFormat } from "../../../helpers" ;
44import { interactiveSort } from "../../../helpers/sort" ;
5- import { Position , SortDirection , SpreadsheetChildEnv } from "../../../types" ;
5+ import { _t } from "../../../translation" ;
6+ import {
7+ CellValueType ,
8+ CriterionFilter ,
9+ DataFilterValue ,
10+ Position ,
11+ SortDirection ,
12+ SpreadsheetChildEnv ,
13+ filterDateCriterionOperators ,
14+ filterNumberCriterionOperators ,
15+ filterTextCriterionOperators ,
16+ } from "../../../types" ;
617import { CellPopoverComponent , PopoverBuilders } from "../../../types/cell_popovers" ;
718import { css } from "../../helpers/css" ;
19+ import { SidePanelCollapsible } from "../../side_panel/components/collapsible/side_panel_collapsible" ;
20+ import { FilterMenuCriterion } from "../filter_menu_criterion/filter_menu_criterion" ;
821import { FilterMenuValueList } from "../filter_menu_value_list/filter_menu_value_list" ;
922
10- const FILTER_MENU_HEIGHT = 295 ;
11-
1223css /* scss */ `
1324 .o-filter-menu {
14- padding : 8px 16px ;
15- height : ${ FILTER_MENU_HEIGHT } px;
16- line-height : 1 ;
25+ width : 245px ;
26+ padding : 8px 0 ;
27+ user-select : none;
28+
29+ .o-filter-menu-content {
30+ padding : 0 16px ;
31+ }
32+
33+ .o-sort-item {
34+ padding-left : 34px ;
35+ }
36+
37+ .o_side_panel_collapsible_title {
38+ font-size : inherit;
39+ padding : 0 0 4px 0 !important ;
40+ font-weight : 400 !important ;
41+
42+ .collapsor .o-icon {
43+ opacity : 0.8 ;
44+ }
45+
46+ .collapsor-arrow {
47+ transform-origin : 6px 8px ;
48+
49+ .o-icon {
50+ width : 12px ;
51+ height : 16px ;
52+ }
53+ }
54+ }
1755
1856 .o-filter-menu-item {
1957 display : flex;
2058 cursor : pointer;
2159 user-select : none;
60+ line-height : 1 ;
2261
2362 & .selected ,
2463 & : hover {
@@ -41,28 +80,27 @@ interface Props {
4180 onClosed ?: ( ) => void ;
4281}
4382
44- interface State {
45- updatedHiddenValue : string [ ] | undefined ;
46- }
83+ type CriterionCategory = "text" | "number" | "date" ;
4784
4885export class FilterMenu extends Component < Props , SpreadsheetChildEnv > {
4986 static template = "o-spreadsheet-FilterMenu" ;
5087 static props = {
5188 filterPosition : Object ,
5289 onClosed : { type : Function , optional : true } ,
5390 } ;
54- static components = { FilterMenuValueList } ;
91+ static components = { FilterMenuValueList, SidePanelCollapsible , FilterMenuCriterion } ;
5592
56- private state : State = useState ( {
57- updatedHiddenValue : undefined ,
58- } ) ;
93+ private criterionCategory : CriterionCategory = "text" ;
94+ private updatedCriterionValue : DataFilterValue | undefined ;
5995
6096 setup ( ) {
6197 onWillUpdateProps ( ( nextProps : Props ) => {
6298 if ( ! deepEquals ( nextProps . filterPosition , this . props . filterPosition ) ) {
63- this . state . updatedHiddenValue = undefined ;
99+ this . updatedCriterionValue = undefined ;
100+ this . criterionCategory = this . getCriterionCategory ( nextProps . filterPosition ) ;
64101 }
65102 } ) ;
103+ this . criterionCategory = this . getCriterionCategory ( this . props . filterPosition ) ;
66104 }
67105
68106 get isSortable ( ) {
@@ -82,24 +120,85 @@ export class FilterMenu extends Component<Props, SpreadsheetChildEnv> {
82120 return this . env . model . getters . getTable ( { sheetId, ...position } ) ;
83121 }
84122
123+ get filterValueType ( ) {
124+ const sheetId = this . env . model . getters . getActiveSheetId ( ) ;
125+ const position = this . props . filterPosition ;
126+ const filterValue = this . env . model . getters . getFilterValue ( { sheetId, ...position } ) ;
127+ return filterValue ?. filterType ;
128+ }
129+
130+ private getCriterionCategory ( position : Position ) : CriterionCategory {
131+ const sheetId = this . env . model . getters . getActiveSheetId ( ) ;
132+ const filter = this . env . model . getters . getFilter ( { sheetId, ...position } ) ;
133+ if ( ! filter || ! filter . filteredRange ) {
134+ return "text" ;
135+ }
136+
137+ const cellTypesCount : Record < CriterionCategory , number > = { text : 0 , number : 0 , date : 0 } ;
138+ const filteredZone = filter . filteredRange . zone ;
139+
140+ for ( let row = filteredZone . top ; row <= filteredZone . bottom ; row ++ ) {
141+ // 100 rows should be enough to determine the type, let's not loop on 10,000 rows for nothing
142+ if ( row > 100 ) {
143+ break ;
144+ }
145+ const cell = this . env . model . getters . getEvaluatedCell ( { sheetId, row, col : position . col } ) ;
146+ if ( cell . type === CellValueType . text || cell . type === CellValueType . boolean ) {
147+ cellTypesCount . text ++ ;
148+ } else if ( cell . type === CellValueType . number ) {
149+ if ( cell . format && isDateTimeFormat ( cell . format ) ) {
150+ cellTypesCount . date ++ ;
151+ } else {
152+ cellTypesCount . number ++ ;
153+ }
154+ }
155+ }
156+
157+ const max = Math . max ( cellTypesCount . text , cellTypesCount . number , cellTypesCount . date ) ;
158+ const type = Object . keys ( cellTypesCount ) . find ( ( key ) => cellTypesCount [ key ] === max ) ;
159+ return ( type || "text" ) as CriterionCategory ;
160+ }
161+
85162 onUpdateHiddenValues ( values : string [ ] ) {
86- this . state . updatedHiddenValue = values ;
163+ this . updatedCriterionValue = { filterType : "values" , hiddenValues : values } ;
164+ }
165+
166+ onCriterionChanged ( criterion : CriterionFilter ) {
167+ this . updatedCriterionValue = criterion ;
87168 }
88169
89170 confirm ( ) {
90- if ( ! this . state . updatedHiddenValue ) {
171+ if ( ! this . updatedCriterionValue ) {
91172 this . props . onClosed ?.( ) ;
92173 return ;
93174 }
94175 const position = this . props . filterPosition ;
95176 this . env . model . dispatch ( "UPDATE_FILTER" , {
96177 ...position ,
97178 sheetId : this . env . model . getters . getActiveSheetId ( ) ,
98- hiddenValues : this . state . updatedHiddenValue ,
179+ value : this . updatedCriterionValue ,
99180 } ) ;
100181 this . props . onClosed ?.( ) ;
101182 }
102183
184+ get criterionOperators ( ) {
185+ if ( this . criterionCategory === "date" ) {
186+ return filterDateCriterionOperators ;
187+ } else if ( this . criterionCategory === "number" ) {
188+ return filterNumberCriterionOperators ;
189+ }
190+ return filterTextCriterionOperators ;
191+ }
192+
193+ get criterionTitle ( ) {
194+ if ( this . criterionCategory === "date" ) {
195+ return _t ( "Filter by date" ) ;
196+ } else if ( this . criterionCategory === "number" ) {
197+ return _t ( "Filter by number" ) ;
198+ }
199+ return _t ( "Filter by text" ) ;
200+ }
201+
103202 cancel ( ) {
104203 this . props . onClosed ?.( ) ;
105204 }
0 commit comments