Skip to content

Commit

Permalink
[ADD] web_m2x_options: display last selected records at first when se…
Browse files Browse the repository at this point in the history
…lecting a value in a many2one before the user types something
  • Loading branch information
benwillig committed Jan 8, 2025
1 parent af6a9b2 commit ec7a009
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 10 deletions.
17 changes: 17 additions & 0 deletions web_m2x_options/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ in the field's options dict

Deactivates the color picker on many2many_tags buttons to do nothing (ignored if open is set)

``search_mru`` *boolean* (Default: ``False``)

Allows to display to the user the 5 lasts records he selected for a given field. This list will be displayed
when the many2one field is focused and when the user didn't type anything to filter on. The values are stored in
the local storage of the browser and updated after a successful saved of the form. This features only works on form
views at the moment.

ir.config_parameter options
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -122,6 +129,15 @@ If you disable one option, you can enable it for particular field by setting "cr

Number of displayed lines on all One2many fields

``web_m2x_options.search_mru`` *boolean* (Default: default value is ``False``)

Enable MRU for all many2one fields (form view only).

``web_m2x_options.search_mru_max_length`` *int*

Changes the length of the records to store and show with MRU feature


To add these parameters go to Configuration -> Technical -> Parameters -> System Parameters and add new parameters like:

- web_m2x_options.create: False
Expand All @@ -130,6 +146,7 @@ To add these parameters go to Configuration -> Technical -> Parameters -> System
- web_m2x_options.limit: 10
- web_m2x_options.search_more: True
- web_m2x_options.field_limit_entries: 5
- web_m2x_options.search_mru: True


Example
Expand Down
7 changes: 6 additions & 1 deletion web_m2x_options/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
"website": "https://github.com/OCA/web",
"license": "AGPL-3",
"depends": ["web"],
"assets": {"web.assets_backend": ["web_m2x_options/static/src/components/*"]},
"assets": {
"web.assets_backend": [
"web_m2x_options/static/src/components/*",
"web_m2x_options/static/src/utils/mru.esm.js",
]
},
"installable": True,
}
2 changes: 2 additions & 0 deletions web_m2x_options/models/ir_config_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def get_web_m2x_options(self):
"web_m2x_options.search_more",
"web_m2x_options.m2o_dialog",
"web_m2x_options.field_limit_entries",
"web_m2x_options.search_mru",
"web_m2x_options.search_mru_max_length",
]
values = self.sudo().search_read([["key", "in", opts]], ["key", "value"])
return {res["key"]: res["value"] for res in values}
17 changes: 17 additions & 0 deletions web_m2x_options/readme/USAGE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ in the field's options dict

Deactivates the color picker on many2many_tags buttons to do nothing (ignored if open is set)

``search_mru`` *boolean* (Default: ``False``)

Allows to display to the user the 5 lasts records he selected for a given field. This list will be displayed
when the many2one field is focused and when the user didn't type anything to filter on. The values are stored in
the local storage of the browser and updated after a successful saved of the form. This features only works on form
views at the moment.

ir.config_parameter options
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -73,6 +80,15 @@ If you disable one option, you can enable it for particular field by setting "cr

Number of displayed lines on all One2many fields

``web_m2x_options.search_mru`` *boolean* (Default: default value is ``False``)

Enable MRU for all many2one fields (form view only).

``web_m2x_options.search_mru_max_length`` *int*

Changes the length of the records to store and show with MRU feature


To add these parameters go to Configuration -> Technical -> Parameters -> System Parameters and add new parameters like:

- web_m2x_options.create: False
Expand All @@ -81,6 +97,7 @@ To add these parameters go to Configuration -> Technical -> Parameters -> System
- web_m2x_options.limit: 10
- web_m2x_options.search_more: True
- web_m2x_options.field_limit_entries: 5
- web_m2x_options.search_mru: True


Example
Expand Down
60 changes: 60 additions & 0 deletions web_m2x_options/static/src/components/form.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import {
Many2ManyTagsFieldColorEditable,
} from "@web/views/fields/many2many_tags/many2many_tags_field";

import {
isMruGlobalOptionEnabled,
updateMruLocalStorageValues,
} from "@web_m2x_options/utils/mru.esm";

import {Dialog} from "@web/core/dialog/dialog";
import {FormController} from "@web/views/form/form_controller";
import {FormViewDialog} from "@web/views/view_dialogs/form_view_dialog";
Expand Down Expand Up @@ -159,6 +164,7 @@ patch(Many2OneField.prototype, "web_m2x_options.Many2OneField", {
this._super(...arguments);
this.ir_options = Component.env.session.web_m2x_options;
},

/**
* @override
*/
Expand All @@ -170,6 +176,7 @@ patch(Many2OneField.prototype, "web_m2x_options.Many2OneField", {
searchMore: this.props.searchMore,
canCreate: this.props.canCreate,
nodeOptions: this.props.nodeOptions,
fieldName: this.props.name,
};
},

Expand Down Expand Up @@ -401,4 +408,57 @@ patch(FormController.prototype, "web_m2x_options.FormController", {
}
}
},

async saveButtonClicked() {
const mruChanges = this.getUpdateMruLocalStorageValues();
const saved = this._super(...arguments);
updateMruLocalStorageValues(this.props.resModel, mruChanges);
return saved;
},

async beforeExecuteActionButton() {
const mruChanges = this.getUpdateMruLocalStorageValues();
const saved = this._super(...arguments);
updateMruLocalStorageValues(this.props.resModel, mruChanges);
return saved;
},

async beforeLeave() {
const mruChanges = this.getUpdateMruLocalStorageValues();
const saved = this._super(...arguments);
updateMruLocalStorageValues(this.props.resModel, mruChanges);
return saved;
},

async onPagerUpdate() {
const mruChanges = this.getUpdateMruLocalStorageValues();
const saved = this._super(...arguments);
updateMruLocalStorageValues(this.props.resModel, mruChanges);
return saved;
},

getUpdateMruLocalStorageValues() {
if (!this.model.root.isDirty) {
return {};
}
const model = this.model;
const changes = model.__bm__._generateChanges(
model.__bm__.localData[model.root.__bm_handle__],
{changesOnly: true}
);
const mruChanges = {};
let enableMru = false;
let nodeOptions = {};
Object.keys(changes).forEach(function (key) {
nodeOptions = model.__bm__.loadParams.fieldsInfo.form[key].options;
enableMru =
nodeOptions.search_mru !== undefined
? nodeOptions.search_mru
: isMruGlobalOptionEnabled();
if (enableMru) {
mruChanges[key] = changes[key];
}
});
return mruChanges;
},
});
56 changes: 47 additions & 9 deletions web_m2x_options/static/src/components/relational_utils.esm.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
/** @odoo-module **/

import {
getMruKey,
getMruValue,
isMruGlobalOptionEnabled,
} from "@web_m2x_options/utils/mru.esm";

import {Many2XAutocomplete} from "@web/views/fields/relational_utils";
import {patch} from "@web/core/utils/patch";
import {sprintf} from "@web/core/utils/strings";

const {Component} = owl;

export function is_option_set(option) {
Expand All @@ -16,6 +23,44 @@ patch(Many2XAutocomplete.prototype, "web_m2x_options.Many2XAutocomplete", {
setup() {
this._super(...arguments);
this.ir_options = Component.env.session.web_m2x_options;
const searchMruOption = this.props.nodeOptions.search_mru;
this.enableMru =
searchMruOption === undefined
? isMruGlobalOptionEnabled()
: this.props.nodeOptions.search_mru;
if (this.enableMru) {
this.mruKey = getMruKey(this.env.model.root.resModel, this.props.fieldName);
}
},

async loadRecords(request) {
const withMru = this.enableMru && Boolean(!request);
this.lastProm = this.orm.call(this.props.resModel, "name_search", [], {
name: request,
operator: "ilike",
args: this.getLoadRecordsDomain(withMru),
limit: this.props.searchLimit + 1,
context: this.props.context,
});
const records = await this.lastProm;

if (withMru) {
const cachedIds = getMruValue(this.mruKey);
records.sort((record1, record2) => {
return cachedIds.indexOf(record1[0]) > cachedIds.indexOf(record2[0]);
});
}

return records;
},

getLoadRecordsDomain(withMru) {
const domain = this.props.getDomain();
const mruValue = withMru ? getMruValue(this.mruKey) : false;
if (Boolean(mruValue) && mruValue.length > 0) {
domain.push(["id", "in", mruValue]);
}
return domain;
},

async loadOptionsSource(request) {
Expand All @@ -24,6 +69,7 @@ patch(Many2XAutocomplete.prototype, "web_m2x_options.Many2XAutocomplete", {
}
// Add options limit used to change number of selections record
// returned.

if (!_.isUndefined(this.ir_options["web_m2x_options.limit"])) {
this.props.searchLimit = parseInt(
this.ir_options["web_m2x_options.limit"],
Expand All @@ -41,15 +87,7 @@ patch(Many2XAutocomplete.prototype, "web_m2x_options.Many2XAutocomplete", {
this.field_color = this.props.nodeOptions.field_color;
this.colors = this.props.nodeOptions.colors;

this.lastProm = this.orm.call(this.props.resModel, "name_search", [], {
name: request,
operator: "ilike",
args: this.props.getDomain(),
limit: this.props.searchLimit + 1,
context: this.props.context,
});
const records = await this.lastProm;

const records = await this.loadRecords(request);
var options = records.map((result) => ({
value: result[0],
id: result[0],
Expand Down
62 changes: 62 additions & 0 deletions web_m2x_options/static/src/utils/mru.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/** @odoo-module **/
import {session} from "@web/session";

const LOCAL_STORAGE_NAME = "web_m2x_options_mru";

export function getMruMaxLength() {
return (
parseInt(session.web_m2x_options["web_m2x_options.search_mru_max_length"]) || 5
);
}

export function isMruGlobalOptionEnabled() {
return session.web_m2x_options["web_m2x_options.search_mru"] === "True";
}

export function getMruKey(modelName, fieldName) {
return session.db + "/" + modelName + "/" + fieldName;
}

export function getMruStorage() {
let data = localStorage.getItem(LOCAL_STORAGE_NAME);
if (!data) {
return {};
}
data = JSON.parse(data);
return data;
}

export function getMruValue(mruKey) {
const data = getMruStorage();
return mruKey in data ? data[mruKey] : [];
}

export function setMruValue(mruKey, value) {
const data = getMruStorage();
data[mruKey] = value;
localStorage.setItem(LOCAL_STORAGE_NAME, JSON.stringify(data));
}

export function updateMruIds(mruKey, recordId) {
if (!recordId) {
return;
}
const cachedIds = getMruValue(mruKey);
const currentIndex = cachedIds.indexOf(recordId);
if (currentIndex !== -1) {
cachedIds.splice(currentIndex, 1);
}
cachedIds.unshift(recordId);
const maxLength = getMruMaxLength();
if (cachedIds.length > maxLength) {
cachedIds.splice(maxLength, cachedIds.length);
}
setMruValue(mruKey, cachedIds);
}

export function updateMruLocalStorageValues(modelName, values) {
Object.keys(values).forEach(function (key) {
const mruKey = getMruKey(modelName, key);
updateMruIds(mruKey, values[key]);
});
}

0 comments on commit ec7a009

Please sign in to comment.