[REF] spreadsheet, spreadsheet_dashboard: use MultiRecordSelector

This commit replaces the RecordsSelector component by the MultiRecordSelector
component in the global filters of the spreadsheet and the spreadsheet
dashboard. Thus, the RecordsSelector component is not used anymore and
can be removed.

Part of task-id 3433922

closes odoo/odoo#138464

Related: odoo/enterprise#48857
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Pierre Rousseau
2023-10-13 11:46:21 +00:00
parent 29e301fe32
commit cb5d5fe15a
7 changed files with 19 additions and 140 deletions
@@ -1,16 +1,18 @@
/** @odoo-module */
import { RecordsSelector } from "../records_selector/records_selector";
import { MultiRecordSelector } from "@web/core/record_selectors/multi_record_selector";
import { RELATIVE_DATE_RANGE_TYPES } from "@spreadsheet/helpers/constants";
import { DateFilterValue } from "../filter_date_value/filter_date_value";
import { Component } from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
import { useService } from "@web/core/utils/hooks";
export class FilterValue extends Component {
setup() {
this.getters = this.props.model.getters;
this.relativeDateRangesTypes = RELATIVE_DATE_RANGE_TYPES;
this.nameService = useService("name");
}
onDateInput(id, value) {
this.props.model.dispatch("SET_GLOBAL_FILTER_VALUE", { id, value });
@@ -20,15 +22,19 @@ export class FilterValue extends Component {
this.props.model.dispatch("SET_GLOBAL_FILTER_VALUE", { id, value });
}
onTagSelected(id, values) {
if (!values.length) {
async onTagSelected(id, resIds) {
if (!resIds.length) {
// force clear, even automatic default values
this.clear(id);
} else {
const displayNames = await this.nameService.loadDisplayNames(
this.props.filter.modelName,
resIds
);
this.props.model.dispatch("SET_GLOBAL_FILTER_VALUE", {
id,
value: values.map((record) => record.id),
displayNames: values.map((record) => record.display_name),
value: resIds,
displayNames: Object.values(displayNames),
});
}
}
@@ -42,7 +48,7 @@ export class FilterValue extends Component {
}
}
FilterValue.template = "spreadsheet_edition.FilterValue";
FilterValue.components = { RecordsSelector, DateFilterValue };
FilterValue.components = { DateFilterValue, MultiRecordSelector };
FilterValue.props = {
filter: Object,
model: Object,
@@ -6,7 +6,7 @@
<t t-set="filter"
t-value="props.filter"/>
<t t-set="filterValue"
t-value="getters.getGlobalFilterValue(filter.id)"/>
t-value="getters.getGlobalFilterValue(filter.id) || []"/>
<div t-if="filter.type === 'text'" class="w-100">
<input type="text"
class="o_input o-text-filter-input"
@@ -15,10 +15,11 @@
t-on-change="(e) => this.onTextInput(filter.id, e.target.value)"/>
</div>
<span t-if="filter.type === 'relation'" class="w-100">
<RecordsSelector placeholder="' ' + translate(filter.label)"
<MultiRecordSelector
placeholder="' ' + translate(filter.label)"
resModel="filter.modelName"
resIds="filterValue"
onValueChanged="(value) => this.onTagSelected(filter.id, value)" />
update="(resIds) => this.onTagSelected(filter.id, resIds)" />
</span>
<div t-if="filter.type === 'date'" class="w-100">
<DateFilterValue t-if="filter.rangeType !== 'relative'"
@@ -1,107 +0,0 @@
/** @odoo-module **/
import { Domain } from "@web/core/domain";
import { useService } from "@web/core/utils/hooks";
import { TagsList } from "@web/core/tags_list/tags_list";
import { Many2XAutocomplete } from "@web/views/fields/relational_utils";
import { Component, onWillStart, onWillUpdateProps } from "@odoo/owl";
export class RecordsSelector extends Component {
setup() {
/** @type {Record<number, string>} */
this.displayNames = {};
/** @type {import("@web/core/orm_service").ORM}*/
this.orm = useService("orm");
onWillStart(() => this.fetchMissingDisplayNames(this.props.resModel, this.props.resIds));
onWillUpdateProps((nextProps) =>
this.fetchMissingDisplayNames(nextProps.resModel, nextProps.resIds)
);
}
get tags() {
return this.props.resIds.map((id) => ({
text: this.displayNames[id],
onDelete: () => this.removeRecord(id),
}));
}
onKeydown(ev) {
if (this.props.resIds.length === 0) {
return;
}
if (ev.key.toUpperCase() === "BACKSPACE") {
this.removeRecord(this.props.resIds[this.props.resIds.length - 1]);
}
}
searchDomain() {
return Domain.not([["id", "in", this.props.resIds]]).toList();
}
/**
* @param {number} recordId
*/
removeRecord(recordId) {
delete this.displayNames[recordId];
this.notifyChange(this.props.resIds.filter((id) => id !== recordId));
}
/**
* @param {{ id: number; display_name?: string}[]} records
*/
update(records) {
for (const record of records.filter((record) => record.display_name)) {
this.displayNames[record.id] = record.display_name;
}
this.notifyChange(this.props.resIds.concat(records.map(({ id }) => id)));
}
/**
* @param {number[]} selectedIds
*/
notifyChange(selectedIds) {
this.props.onValueChanged(
selectedIds.map((id) => ({ id, display_name: this.displayNames[id] }))
);
}
/**
* @param {string} resModel
* @param {number[]} recordIds
*/
async fetchMissingDisplayNames(resModel, recordIds) {
const missingNameIds = recordIds.filter((id) => !(id in this.displayNames));
if (missingNameIds.length === 0) {
return;
}
const results = await this.orm.read(resModel, missingNameIds, ["display_name"]);
for (const { id, display_name } of results) {
this.displayNames[id] = display_name;
}
}
}
RecordsSelector.components = { TagsList, Many2XAutocomplete };
RecordsSelector.template = "spreadsheet.RecordsSelector";
RecordsSelector.props = {
/**
* Callback called when a record is selected or removed.
* (selectedRecords: Array<{ id: number; display_name: string }>) => void
**/
onValueChanged: Function,
resModel: String,
/**
* Array of selected record ids
*/
resIds: {
optional: true,
type: Array,
},
placeholder: {
optional: true,
type: String,
},
};
RecordsSelector.defaultProps = {
resIds: [],
};
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<templates>
<div t-name="spreadsheet.RecordsSelector" class="o_field_widget o_field_many2many_tags">
<div class="o_field_tags d-inline-flex flex-wrap mw-100 o_tags_input o_input w-100 gap-1">
<TagsList tags="tags"/>
<div
class="o_field_many2many_selection d-inline-flex w-100"
t-on-keydown="onKeydown">
<Many2XAutocomplete
placeholder="props.placeholder"
resModel="props.resModel"
fieldString="props.placeholder"
activeActions="{}"
update.bind="update"
getDomain.bind="searchDomain"
isToMany="true"
/>
</div>
</div>
</div>
</templates>
@@ -14,7 +14,7 @@
.o-selection-statistic {
background-color: #fff !important;
}
.o_field_tags .badge {
.o_multi_record_selector .badge {
background-color: #e6dddd !important;
color: #3c3c3c !important;
}
@@ -68,7 +68,7 @@
min-height: 25px;
min-width: 100px;
.o_field_many2many_tags {
.o_multi_record_selector {
width: 100%;
}
@@ -205,7 +205,7 @@ QUnit.test("Can delete record tag in the filter by hitting Backspace", async fun
const serverData = getServerData(spreadsheetData);
const fixture = getFixture();
await createSpreadsheetDashboard({ serverData });
const filter = fixture.querySelector(".o_control_panel_actions div.o_field_tags");
const filter = fixture.querySelector(".o_control_panel_actions div.o_multi_record_selector");
const autoCompleteInput = filter.querySelector(".o-autocomplete--input.o_input");
assert.equal(filter.querySelectorAll(".o_tag").length, 1);