[IMP] web: expose before and after execute action on controllers
Make it possible to override both before and after execute actions on all view controllers using `useViewButtons`. This avoids having to change a value in the env to override the function being called when clicking on a button. closes odoo/odoo#101310 X-original-commit: 9f6c2b8e969635f35786d58ee89ca767ff57144d Related: odoo/enterprise#31860 Signed-off-by: William Braeckman (wbr) <wbr@odoo.com>
This commit is contained in:
@@ -7,35 +7,35 @@ import { formView } from "@web/views/form/form_view";
|
||||
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
|
||||
const { useSubEnv } = owl;
|
||||
|
||||
export class ExpenseFormController extends FormController {
|
||||
setup() {
|
||||
super.setup();
|
||||
const dialogService = useService("dialog");
|
||||
const orm = useService("orm");
|
||||
const t = this.env._t;
|
||||
const previousOnClickViewButton = this.env.onClickViewButton;
|
||||
useSubEnv({
|
||||
async onClickViewButton(params) {
|
||||
const record = this.model.root;
|
||||
if (
|
||||
params.clickParams.name === "action_submit_expenses" &&
|
||||
record.data.duplicate_expense_ids.count
|
||||
) {
|
||||
dialogService.add(ConfirmationDialog, {
|
||||
body: t("An expense of same category, amount and date already exists."),
|
||||
confirm: async () => {
|
||||
orm.call("hr.expense", "action_approve_duplicates", [record.resId]);
|
||||
previousOnClickViewButton(params);
|
||||
},
|
||||
cancel: () => {},
|
||||
});
|
||||
} else {
|
||||
previousOnClickViewButton(params);
|
||||
}
|
||||
},
|
||||
});
|
||||
this.dialogService = useService("dialog");
|
||||
this.orm = useService("orm");
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async beforeExecuteActionButton(clickParams) {
|
||||
const record = this.model.root;
|
||||
if (
|
||||
clickParams.name === "action_submit_expenses" &&
|
||||
record.data.duplicate_expense_ids.count
|
||||
) {
|
||||
return new Promise((resolve) => {
|
||||
this.dialogService.add(ConfirmationDialog, {
|
||||
body: this.env._t("An expense of same category, amount and date already exists."),
|
||||
confirm: async () => {
|
||||
await this.orm.call("hr.expense", "action_approve_duplicates", [record.resId]);
|
||||
resolve(true);
|
||||
},
|
||||
}, {
|
||||
onClose: resolve.bind(null, false),
|
||||
});
|
||||
});
|
||||
}
|
||||
return super.beforeExecuteActionButton(...arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { PortalWizardUserListRenderer } from "../list/portal_wizard_user_list_renderer";
|
||||
import { PortalWizardUserListController } from "../list/portal_wizard_user_list_controller";
|
||||
import { X2ManyField } from "@web/views/fields/x2many/x2many_field";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
export class PortalUserX2ManyField extends X2ManyField {}
|
||||
PortalUserX2ManyField.components = {
|
||||
...X2ManyField.components,
|
||||
ListRenderer: PortalWizardUserListRenderer,
|
||||
Controller: PortalWizardUserListController,
|
||||
};
|
||||
|
||||
registry.category("fields").add("portal_wizard_user_one2many", PortalUserX2ManyField);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ListController } from "@web/views/list/list_controller";
|
||||
|
||||
export class PortalWizardUserListController extends ListController {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.isPortalActionOngoing = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async beforeExecuteActionButton(clickParams) {
|
||||
if (clickParams.name === 'action_refresh_modal' || this.isPortalActionOngoing) {
|
||||
return false;
|
||||
}
|
||||
this.isPortalActionOngoing = true;
|
||||
return super.beforeExecuteActionButton(clickParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async afterExecuteActionButton(clickParams) {
|
||||
this.isPortalActionOngoing = false;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ListRenderer } from "@web/views/list/list_renderer";
|
||||
|
||||
const { useSubEnv } = owl;
|
||||
|
||||
export class PortalWizardUserListRenderer extends ListRenderer {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.isPortalActionOngoing = false;
|
||||
const defaultOnClickViewButton = this.env.onClickViewButton;
|
||||
useSubEnv({
|
||||
onClickViewButton: async (params) => {
|
||||
if (params.clickParams.name === 'action_refresh_modal' || this.isPortalActionOngoing) {
|
||||
return false;
|
||||
}
|
||||
this.isPortalActionOngoing = true;
|
||||
await defaultOnClickViewButton(params);
|
||||
this.isPortalActionOngoing = false;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -172,20 +172,11 @@ export class FormController extends Component {
|
||||
this.archInfo.arch = this.archInfo.xmlDoc.outerHTML;
|
||||
}
|
||||
|
||||
const beforeExecuteAction = (clickParams) => {
|
||||
if (clickParams.special !== "cancel") {
|
||||
return this.model.root.save({ stayInEdition: true }).then((saved) => {
|
||||
if (saved && this.props.onSave) {
|
||||
this.props.onSave(this.model.root);
|
||||
}
|
||||
return saved;
|
||||
});
|
||||
} else if (this.props.onDiscard) {
|
||||
this.props.onDiscard(this.model.root);
|
||||
}
|
||||
};
|
||||
const rootRef = useRef("root");
|
||||
useViewButtons(this.model, rootRef, { beforeExecuteAction });
|
||||
useViewButtons(this.model, rootRef, {
|
||||
beforeExecuteAction: this.beforeExecuteActionButton.bind(this),
|
||||
afterExecuteAction: this.afterExecuteActionButton.bind(this),
|
||||
});
|
||||
useSetupView({
|
||||
rootRef,
|
||||
beforeLeave: () => {
|
||||
@@ -354,6 +345,21 @@ export class FormController extends Component {
|
||||
this.state.isDisabled = false;
|
||||
}
|
||||
|
||||
async beforeExecuteActionButton(clickParams) {
|
||||
if (clickParams.special !== "cancel") {
|
||||
return this.model.root.save({ stayInEdition: true }).then((saved) => {
|
||||
if (saved && this.props.onSave) {
|
||||
this.props.onSave(this.model.root);
|
||||
}
|
||||
return saved;
|
||||
});
|
||||
} else if (this.props.onDiscard) {
|
||||
this.props.onDiscard(this.model.root);
|
||||
}
|
||||
}
|
||||
|
||||
async afterExecuteActionButton(clickParams) {}
|
||||
|
||||
async edit() {
|
||||
await this.model.root.switchMode("edit");
|
||||
}
|
||||
|
||||
@@ -35,7 +35,10 @@ export class KanbanController extends Component {
|
||||
});
|
||||
|
||||
const rootRef = useRef("root");
|
||||
useViewButtons(this.model, rootRef);
|
||||
useViewButtons(this.model, rootRef, {
|
||||
beforeExecuteAction: this.beforeExecuteActionButton.bind(this),
|
||||
afterExecuteAction: this.afterExecuteActionButton.bind(this),
|
||||
});
|
||||
useSetupView({
|
||||
rootRef,
|
||||
getGlobalState: () => {
|
||||
@@ -110,6 +113,10 @@ export class KanbanController extends Component {
|
||||
}
|
||||
return list.isGrouped ? list.groups.length > 0 || !groupCreate : true;
|
||||
}
|
||||
|
||||
async beforeExecuteActionButton(clickParams) {}
|
||||
|
||||
async afterExecuteActionButton(clickParams) {}
|
||||
}
|
||||
|
||||
KanbanController.template = `web.KanbanView`;
|
||||
|
||||
@@ -86,7 +86,10 @@ export class ListController extends Component {
|
||||
? !fields.x_active.readonly
|
||||
: false;
|
||||
useSubEnv({ model: this.model }); // do this in useModel?
|
||||
useViewButtons(this.model, this.rootRef);
|
||||
useViewButtons(this.model, this.rootRef, {
|
||||
beforeExecuteAction: this.beforeExecuteActionButton.bind(this),
|
||||
afterExecuteAction: this.afterExecuteActionButton.bind(this),
|
||||
});
|
||||
useSetupView({
|
||||
rootRef: this.rootRef,
|
||||
beforeLeave: async () => {
|
||||
@@ -451,6 +454,10 @@ export class ListController extends Component {
|
||||
record.toggleSelection(false);
|
||||
});
|
||||
}
|
||||
|
||||
async beforeExecuteActionButton(clickParams) {}
|
||||
|
||||
async afterExecuteActionButton(clickParams) {}
|
||||
}
|
||||
|
||||
ListController.template = `web.ListView`;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { useAutofocus } from "@web/core/utils/hooks";
|
||||
import { pick } from "@web/core/utils/objects";
|
||||
import { formView } from "@web/views/form/form_view";
|
||||
import { useViewButtons } from "@web/views/view_button/view_button_hook";
|
||||
import { SettingsConfirmationDialog } from "./settings_confirmation_dialog";
|
||||
import { SettingsFormRenderer } from "./settings_form_renderer";
|
||||
|
||||
@@ -12,46 +11,6 @@ const { useSubEnv, useState, useRef, useEffect } = owl;
|
||||
export class SettingsFormController extends formView.Controller {
|
||||
setup() {
|
||||
super.setup();
|
||||
const beforeExecuteAction = async (clickParams) => {
|
||||
if (clickParams.name === "cancel") {
|
||||
return true;
|
||||
}
|
||||
let _continue = true;
|
||||
if (
|
||||
this.model.root.isDirty &&
|
||||
!["execute"].includes(clickParams.name) &&
|
||||
!clickParams.noSaveDialog
|
||||
) {
|
||||
const message = this.env._t("Would you like to save your changes?");
|
||||
await new Promise((resolve) => {
|
||||
this.dialogService.add(SettingsConfirmationDialog, {
|
||||
body: message,
|
||||
confirm: async () => {
|
||||
await this.model.root.save({ stayInEdition: true });
|
||||
await this.save();
|
||||
// It doesn't make sense to do the action of the button
|
||||
// as the res.config.settings `execute` method will trigger a reload.
|
||||
_continue = false;
|
||||
resolve();
|
||||
},
|
||||
cancel: async () => {
|
||||
await this.model.root.discard();
|
||||
await this.model.root.save({ stayInEdition: true });
|
||||
_continue = true;
|
||||
resolve();
|
||||
},
|
||||
stayHere: () => {
|
||||
_continue = false;
|
||||
resolve();
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
_continue = await this.model.root.save({ stayInEdition: true });
|
||||
}
|
||||
return _continue;
|
||||
};
|
||||
useViewButtons(this.model, useRef("root"), { beforeExecuteAction });
|
||||
useAutofocus();
|
||||
this.state = useState({ displayNoContent: false });
|
||||
this.searchState = useState({ value: "" });
|
||||
@@ -84,6 +43,49 @@ export class SettingsFormController extends formView.Controller {
|
||||
this.initialApp = "module" in this.props.context && this.props.context.module;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async beforeExecuteActionButton(clickParams) {
|
||||
if (clickParams.name === "cancel") {
|
||||
return true;
|
||||
}
|
||||
let _continue = true;
|
||||
if (
|
||||
this.model.root.isDirty &&
|
||||
!["execute"].includes(clickParams.name) &&
|
||||
!clickParams.noSaveDialog
|
||||
) {
|
||||
const message = this.env._t("Would you like to save your changes?");
|
||||
await new Promise((resolve) => {
|
||||
this.dialogService.add(SettingsConfirmationDialog, {
|
||||
body: message,
|
||||
confirm: async () => {
|
||||
await this.model.root.save({ stayInEdition: true });
|
||||
await this.save();
|
||||
// It doesn't make sense to do the action of the button
|
||||
// as the res.config.settings `execute` method will trigger a reload.
|
||||
_continue = false;
|
||||
resolve();
|
||||
},
|
||||
cancel: async () => {
|
||||
await this.model.root.discard();
|
||||
await this.model.root.save({ stayInEdition: true });
|
||||
_continue = true;
|
||||
resolve();
|
||||
},
|
||||
stayHere: () => {
|
||||
_continue = false;
|
||||
resolve();
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
_continue = await this.model.root.save({ stayInEdition: true });
|
||||
}
|
||||
return _continue;
|
||||
}
|
||||
|
||||
displayName() {
|
||||
return this.env._t("Settings");
|
||||
}
|
||||
|
||||
@@ -2807,10 +2807,10 @@ QUnit.module("Views", (hooks) => {
|
||||
assert.verifySteps(["read1", "willStart"]);
|
||||
|
||||
await click(target.querySelector(".o_form_statusbar button.p"));
|
||||
assert.verifySteps(["read2", "willUpdateProps", "willUpdateProps"]);
|
||||
assert.verifySteps(["willUpdateProps", "read2", "willUpdateProps", "willUpdateProps"]);
|
||||
|
||||
await click(target.querySelector(".o_form_statusbar button.p"));
|
||||
assert.verifySteps(["willUpdateProps", "read3", "willUpdateProps", "willUpdateProps"]);
|
||||
assert.verifySteps(["willUpdateProps", "willUpdateProps", "read3", "willUpdateProps", "willUpdateProps"]);
|
||||
});
|
||||
|
||||
QUnit.test("buttons in form view, new record", async function (assert) {
|
||||
|
||||
Reference in New Issue
Block a user