diff --git a/web_refresher/README.rst b/web_refresher/README.rst index 36b0c16bc..9e8ba0498 100644 --- a/web_refresher/README.rst +++ b/web_refresher/README.rst @@ -7,7 +7,7 @@ Web Refresher !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:4ef545bbf655053c91d43dc4f35993c3a7e5cbe1c0989e5ca8a6d25bab77851b + !! source digest: sha256:72dfc3fadb6b640422ed2786d2036e3c550c09a4a55fed57e92c3caeb4b1b176 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/web_refresher/__manifest__.py b/web_refresher/__manifest__.py index e9395c9ca..c398d33fa 100644 --- a/web_refresher/__manifest__.py +++ b/web_refresher/__manifest__.py @@ -9,13 +9,9 @@ "auto_install": False, "assets": { "web.assets_backend": [ - "web_refresher/static/src/scss/refresher.scss", - "web_refresher/static/src/js/refresher.esm.js", - "web_refresher/static/src/js/control_panel.esm.js", - "web_refresher/static/src/js/pager.esm.js", - "web_refresher/static/src/xml/refresher.xml", - "web_refresher/static/src/xml/control_panel.xml", - "web_refresher/static/src/xml/pager.xml", + "web_refresher/static/src/**/*.scss", + "web_refresher/static/src/**/*.esm.js", + "web_refresher/static/src/**/*.xml", ], }, } diff --git a/web_refresher/static/description/index.html b/web_refresher/static/description/index.html index 476f12858..05d40bc08 100644 --- a/web_refresher/static/description/index.html +++ b/web_refresher/static/description/index.html @@ -1,3 +1,4 @@ + @@ -366,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:4ef545bbf655053c91d43dc4f35993c3a7e5cbe1c0989e5ca8a6d25bab77851b +!! source digest: sha256:72dfc3fadb6b640422ed2786d2036e3c550c09a4a55fed57e92c3caeb4b1b176 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

Adds a button next to the pager (in trees/kanban views) to refresh the displayed list.

diff --git a/web_refresher/static/src/js/control_panel.esm.js b/web_refresher/static/src/js/control_panel.esm.js index 972d07784..2a63c2fd6 100644 --- a/web_refresher/static/src/js/control_panel.esm.js +++ b/web_refresher/static/src/js/control_panel.esm.js @@ -1,9 +1,27 @@ /** @odoo-module **/ -/* Copyright 2024 Tecnativa - Carlos Roca +/* Copyright 2022 Tecnativa - Alexandre D. Díaz + * Copyright 2022 Tecnativa - Carlos Roca + * Copyright 2023 Taras Shabaranskyi * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ + import {ControlPanel} from "@web/search/control_panel/control_panel"; import {Refresher} from "./refresher.esm"; +import {patch} from "@web/core/utils/patch"; ControlPanel.components = Object.assign({}, ControlPanel.components, { Refresher, }); + +patch(ControlPanel.prototype, "web_refresher.ControlPanel", { + setup() { + this._super(...arguments); + const {config, searchModel} = this.env; + const forbiddenSubType = ["base_settings"]; + if (!forbiddenSubType.includes(config.viewSubType)) { + this.refresherProps = { + searchModel: searchModel, + pagerProps: this.pagerProps, + }; + } + }, +}); diff --git a/web_refresher/static/src/js/pager.esm.js b/web_refresher/static/src/js/pager.esm.js deleted file mode 100644 index 06f9ec77c..000000000 --- a/web_refresher/static/src/js/pager.esm.js +++ /dev/null @@ -1,9 +0,0 @@ -/** @odoo-module **/ -/* Copyright 2022 Tecnativa - Carlos Roca - * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ -import {Pager} from "@web/core/pager/pager"; -import {Refresher} from "./refresher.esm"; - -Pager.components = Object.assign({}, Pager.components, { - Refresher, -}); diff --git a/web_refresher/static/src/js/refresher.esm.js b/web_refresher/static/src/js/refresher.esm.js index a006e0e4c..4a519eba5 100644 --- a/web_refresher/static/src/js/refresher.esm.js +++ b/web_refresher/static/src/js/refresher.esm.js @@ -1,36 +1,134 @@ /** @odoo-module **/ /* Copyright 2022 Tecnativa - Alexandre D. Díaz * Copyright 2022 Tecnativa - Carlos Roca + * Copyright 2023 Taras Shabaranskyi * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ -const {Component} = owl; +import {Component} from "@odoo/owl"; +import {useDebounced} from "@web/core/utils/timing"; import {useService} from "@web/core/utils/hooks"; +export function useRefreshAnimation(timeout) { + const refreshClass = "o_content__refresh"; + let timeoutId = null; + + /** + * @returns {DOMTokenList|null} + */ + function contentClassList() { + const content = document.querySelector(".o_content"); + return content ? content.classList : null; + } + + function clearAnimationTimeout() { + if (timeoutId) { + clearTimeout(timeoutId); + } + timeoutId = null; + } + + function animate() { + clearAnimationTimeout(); + contentClassList().add(refreshClass); + timeoutId = setTimeout(() => { + contentClassList().remove(refreshClass); + clearAnimationTimeout(); + }, timeout); + } + + return animate; +} + export class Refresher extends Component { setup() { super.setup(); this.action = useService("action"); + this.refreshAnimation = useRefreshAnimation(1000); + this.onClickRefresh = useDebounced(this.onClickRefresh, 200); } - async _doRefresh() { + + /** + * @returns {Boolean} + */ + get displayButton() { + const {searchModel, pagerProps, refresherReport} = this.props; + const hasSearchModel = searchModel && searchModel.search; + return Boolean( + refresherReport || hasSearchModel || (pagerProps && pagerProps.onUpdate) + ); + } + + /** + * @returns {Boolean} + * @private + */ + _searchModelRefresh() { + const {searchModel} = this.props; + if (searchModel && typeof searchModel.search === "function") { + searchModel.search(); + return true; + } + return false; + } + + /** + * @returns {Promise} + * @private + */ + async _pagerRefresh() { + const pagerProps = this.props.pagerProps; + if (pagerProps && typeof pagerProps.onUpdate === "function") { + const {limit, offset} = pagerProps; + await pagerProps.onUpdate({offset, limit}); + return true; + } + return false; + } + + /** + * @returns {Promise} + */ + async refresh() { + let updated = this._searchModelRefresh(); + if (!updated) { + updated = await this._pagerRefresh(); + } + return updated; + } + + /** + * Function to refresh the views that has not the props + * required by the refresher, like ir.actions.report or + * ir.actions.client. + */ + async refreshReport() { const viewAction = this.action.currentController.action; - // Allow refresh reports - if (["ir.actions.report", "ir.actions.client"].includes(viewAction.type)) { - const options = {}; - if (this.env.config.breadcrumbs.length > 1) { - const breadcrumb = this.env.config.breadcrumbs.slice(-1); - await this.action.restore(breadcrumb.jsId); - } else { - options.clearBreadcrumbs = true; - } - return this.action.doAction(viewAction, options); + const options = {}; + if (this.env.config.breadcrumbs.length > 1) { + const breadcrumb = this.env.config.breadcrumbs.slice(-1); + await this.action.restore(breadcrumb.jsId); + } else { + options.clearBreadcrumbs = true; } - // Note: here we use the pager props, see xml - const {limit, offset} = this.props; - if (!limit && !offset) { - return; + this.action.doAction(viewAction, options); + } + + async onClickRefresh() { + if (this.props.refresherReport) { + return this.refreshReport(); + } + const updated = await this.refresh(); + if (updated) { + this.refreshAnimation(); } - return this.props.onUpdate({offset, limit}); } } -Refresher.template = "web_refresher.Button"; +Object.assign(Refresher, { + template: "web_refresher.Button", + props: { + searchModel: {type: Object, optional: true}, + pagerProps: {type: Object, optional: true}, + refresherReport: {type: Boolean, optional: true}, + }, +}); diff --git a/web_refresher/static/src/scss/refresher.scss b/web_refresher/static/src/scss/refresher.scss index edc1102ca..ef59aa819 100644 --- a/web_refresher/static/src/scss/refresher.scss +++ b/web_refresher/static/src/scss/refresher.scss @@ -1,11 +1,23 @@ .oe_cp_refresher { - margin: auto 0 auto auto; - padding-left: 5px; - text-align: right; + margin: auto 0 auto 0; user-select: none; - flex-grow: 1; } -.o_cp_bottom_right.oe_cp_refresher { - display: flex; - flex-direction: row-reverse; + +.o_content { + &__refresh { + animation: web_refresh 0.6s ease; + } +} + +@keyframes web_refresh { + 0% { + opacity: 1; + } + 50% { + transform: translateY(10px); + opacity: 0.6; + } + 100% { + opacity: 1; + } } diff --git a/web_refresher/static/src/xml/control_panel.xml b/web_refresher/static/src/xml/control_panel.xml index 81aa4553a..0fb096f7c 100644 --- a/web_refresher/static/src/xml/control_panel.xml +++ b/web_refresher/static/src/xml/control_panel.xml @@ -8,14 +8,19 @@ t-inherit-mode="extension" owl="1" > - + + + + @@ -25,14 +30,41 @@ t-inherit-mode="extension" owl="1" > - + + + + + + + + + + + +
+
diff --git a/web_refresher/static/src/xml/pager.xml b/web_refresher/static/src/xml/pager.xml deleted file mode 100644 index 67ed8c952..000000000 --- a/web_refresher/static/src/xml/pager.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - diff --git a/web_refresher/static/src/xml/refresher.xml b/web_refresher/static/src/xml/refresher.xml index 5f44c1282..f52ff5c8a 100644 --- a/web_refresher/static/src/xml/refresher.xml +++ b/web_refresher/static/src/xml/refresher.xml @@ -3,16 +3,19 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->