Skip to content

Commit dddcd89

Browse files
committed
[IMP] spreadsheet: add operators for global filters
This commit introduces operators to global filters. It's now possible to choose amount "in", "not in", "contains", etc. depending on the filter type (relation, text) closes odoo#215217 Task: 4797532 Related: odoo/enterprise#88160 Related: odoo/upgrade#7964 Signed-off-by: Lucas Lefèvre (lul) <[email protected]>
1 parent 739c776 commit dddcd89

File tree

25 files changed

+904
-601
lines changed

25 files changed

+904
-601
lines changed

addons/spreadsheet/static/src/@types/global_filter.d.ts

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,58 @@ declare module "@spreadsheet" {
6060
| RelativeDateValue
6161
| DateRangeValue;
6262

63+
interface SetValue {
64+
operator: "set" | "not_set";
65+
}
66+
67+
interface RelationIdsValue {
68+
operator: "in" | "not in" | "child_of";
69+
ids: number[];
70+
}
71+
72+
interface RelationContainsValue {
73+
operator: "ilike" | "not ilike" | "starts_with" | "ends_with";
74+
strings: string[];
75+
}
76+
77+
interface CurrentUser {
78+
operator: "in" | "not in";
79+
ids: "current_user";
80+
}
81+
82+
export type RelationValue = RelationIdsValue | SetValue | RelationContainsValue;
83+
type RelationDefaultValue = RelationValue | CurrentUser;
84+
85+
interface NumericUnaryValue {
86+
operator: "=" | "!=" | "<" | ">";
87+
operand: number;
88+
}
89+
90+
interface NumericRangeValue {
91+
operator: "between" | "not_between";
92+
min: number;
93+
max: number;
94+
}
95+
96+
export type NumericValue = NumericUnaryValue | NumericRangeValue | SetValue;
97+
98+
interface TextInValue {
99+
operator: "in" | "not in";
100+
strings: string[];
101+
}
102+
103+
interface TextContainsValue {
104+
operator: "ilike" | "not ilike" | "starts_with";
105+
text: string;
106+
}
107+
108+
export type TextValue = TextInValue | TextContainsValue | SetValue;
109+
110+
interface SelectionInValue {
111+
operator: "in" | "not in";
112+
selectionValues: string[];
113+
}
114+
63115
export interface FieldMatching {
64116
chain: string;
65117
type: string;
@@ -71,7 +123,7 @@ declare module "@spreadsheet" {
71123
id: string;
72124
label: string;
73125
rangesOfAllowedValues?: Range[];
74-
defaultValue?: string[];
126+
defaultValue?: TextValue;
75127
}
76128

77129
export interface SelectionGlobalFilter {
@@ -80,7 +132,7 @@ declare module "@spreadsheet" {
80132
label: string;
81133
resModel: string;
82134
selectionField: string;
83-
defaultValue?: string[];
135+
defaultValue?: SelectionInValue;
84136
}
85137

86138
export interface CmdTextGlobalFilter extends TextGlobalFilter {
@@ -100,15 +152,15 @@ declare module "@spreadsheet" {
100152
label: string;
101153
modelName: string;
102154
includeChildren: boolean;
103-
defaultValue?: "current_user" | number[];
155+
defaultValue?: RelationDefaultValue;
104156
domainOfAllowedValues?: DomainListRepr | string;
105157
}
106158

107159
export interface BooleanGlobalFilter {
108160
type: "boolean";
109161
id: string;
110162
label: string;
111-
defaultValue?: boolean[];
163+
defaultValue?: SetValue;
112164
}
113165

114166
export type GlobalFilter = TextGlobalFilter | DateGlobalFilter | RelationalGlobalFilter | BooleanGlobalFilter | SelectionGlobalFilter;

addons/spreadsheet/static/src/global_filters/components/boolean_multi_selector/boolean_multi_selector.js

Lines changed: 0 additions & 62 deletions
This file was deleted.

addons/spreadsheet/static/src/global_filters/components/boolean_multi_selector/boolean_multi_selector.xml

Lines changed: 0 additions & 12 deletions
This file was deleted.

addons/spreadsheet/static/src/global_filters/components/filter_value/filter_value.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ import { Domain } from "@web/core/domain";
1111
import { user } from "@web/core/user";
1212
import { TextFilterValue } from "../filter_text_value/filter_text_value";
1313
import { getFields, ModelNotFoundError } from "@spreadsheet/data_sources/data_source";
14-
import { BooleanMultiSelector } from "../boolean_multi_selector/boolean_multi_selector";
1514
import { SelectionFilterValue } from "../selection_filter_value/selection_filter_value";
15+
import {
16+
isTextualOperator,
17+
isSetOperator,
18+
getDefaultValue,
19+
} from "@spreadsheet/global_filters/helpers";
1620

1721
const { ValidationMessages } = components;
1822

@@ -22,7 +26,6 @@ export class FilterValue extends Component {
2226
TextFilterValue,
2327
DateFilterValue,
2428
MultiRecordSelector,
25-
BooleanMultiSelector,
2629
SelectionFilterValue,
2730
ValidationMessages,
2831
};
@@ -57,6 +60,14 @@ export class FilterValue extends Component {
5760
});
5861
}
5962

63+
get isTextualOperator() {
64+
return isTextualOperator(this.filterValue?.operator);
65+
}
66+
67+
get isSetOperator() {
68+
return isSetOperator(this.filterValue?.operator);
69+
}
70+
6071
get filter() {
6172
return this.props.filter;
6273
}
@@ -87,6 +98,10 @@ export class FilterValue extends Component {
8798
);
8899
}
89100

101+
getDefaultOperator() {
102+
return getDefaultValue(this.filter.type).operator;
103+
}
104+
90105
onDateInput(id, value) {
91106
this.props.setGlobalFilterValue(id, value);
92107
}
@@ -96,7 +111,8 @@ export class FilterValue extends Component {
96111
this.clear(id);
97112
return;
98113
}
99-
this.props.setGlobalFilterValue(id, value);
114+
const operator = this.filterValue?.operator ?? this.getDefaultOperator();
115+
this.props.setGlobalFilterValue(id, { operator, strings: value });
100116
}
101117

102118
onBooleanInput(id, value) {
@@ -112,15 +128,20 @@ export class FilterValue extends Component {
112128
this.clear(id);
113129
return;
114130
}
115-
this.props.setGlobalFilterValue(id, value);
131+
const operator = this.filterValue?.operator ?? this.getDefaultOperator();
132+
this.props.setGlobalFilterValue(id, { operator, selectionValues: value });
116133
}
117134

118135
async onTagSelected(id, resIds) {
119136
if (!resIds.length) {
120137
// force clear, even automatic default values
121138
this.clear(id);
122139
} else {
123-
this.props.setGlobalFilterValue(id, resIds);
140+
const operator = this.filterValue?.operator ?? this.getDefaultOperator();
141+
this.props.setGlobalFilterValue(
142+
id,
143+
{ operator, ids: resIds },
144+
);
124145
}
125146
}
126147

addons/spreadsheet/static/src/global_filters/components/filter_value/filter_value.xml

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,37 @@
22
<templates>
33
<t t-name="spreadsheet.FilterValue">
44
<div class="o-filter-value d-flex align-items-start w-100" t-att-title="props.showTitle and filter.label">
5-
<div t-if="filter.type === 'boolean'" class="w-100">
6-
<BooleanMultiSelector
7-
selectedValues="filterValue || []"
8-
update="(value) => this.onBooleanInput(filter.id, value)"
9-
/>
10-
</div>
11-
<div t-if="filter.type === 'text'" class="w-100">
5+
<div t-if="isSetOperator" class="w-100"></div>
6+
<div t-elif="isTextualOperator || filter.type === 'text'" class="w-100">
127
<TextFilterValue
13-
value="filterValue"
8+
value="filterValue?.strings"
149
options="textAllowedValues"
1510
onValueChanged="(value) => this.onTextInput(filter.id, value)"
1611
/>
1712
</div>
18-
<div t-if="filter.type === 'selection'" class="w-100">
13+
<div t-elif="filter.type === 'selection'" class="w-100">
1914
<SelectionFilterValue
2015
resModel="filter.resModel"
2116
field="filter.selectionField"
22-
value="filterValue"
17+
value="filterValue?.selectionValues ?? []"
2318
onValueChanged="(value) => this.onSelectionInput(filter.id, value)"
2419
/>
2520
</div>
26-
<span t-if="filter.type === 'relation'" class="w-100">
21+
<div t-elif="filter.type === 'date'" class="w-100">
22+
<DateFilterValue value="filterValue"
23+
update.bind="(value) => this.onDateInput(filter.id, value)"/>
24+
</div>
25+
<span t-elif="filter.type === 'relation'" class="w-100">
2726
<MultiRecordSelector
2827
t-if="isValid"
2928
resModel="filter.modelName"
30-
resIds="filterValue || []"
29+
resIds="filterValue?.ids ?? []"
3130
domain="relationalAllowedDomain"
3231
update="(resIds) => this.onTagSelected(filter.id, resIds)" />
3332
<ValidationMessages t-else="1"
3433
messages="[invalidModel]"
3534
msgType="'error'"/>
36-
3735
</span>
38-
<div t-if="filter.type === 'date'" class="w-100">
39-
<DateFilterValue value="filterValue"
40-
update.bind="(value) => this.onDateInput(filter.id, value)"/>
41-
</div>
4236
<i t-if="props.showClear and getters.isGlobalFilterActive(filter.id)"
4337
class="fa fa-times btn btn-link text-muted ms-1 mt-1"
4438
title="Clear"

0 commit comments

Comments
 (0)