[REF] web, *: change dialog service api
* iap, web_tour This commit changes the API of the dialog service. Before, the API gave 2 functions: "open" and "close". Now, there is only one function "add" which is the same as "open" but returning a callback that does the close. closes odoo-dev/odoo#940 Related: odoo-dev/enterprise#171 Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
This commit is contained in:
committed by
Aaron Bohy
parent
d1b260b424
commit
580533ecfb
@@ -41,7 +41,7 @@ function insufficientCreditHandler(env, error, originalError) {
|
||||
}
|
||||
const { data } = originalError;
|
||||
if (data && data.name === "odoo.addons.iap.tools.iap_tools.InsufficientCreditError") {
|
||||
env.services.dialog.open(InsufficientCreditDialog, {
|
||||
env.services.dialog.add(InsufficientCreditDialog, {
|
||||
errorData: JSON.parse(data.message),
|
||||
});
|
||||
return true;
|
||||
|
||||
@@ -24,6 +24,7 @@ ConfirmationDialog.props = {
|
||||
body: String,
|
||||
confirm: Function,
|
||||
cancel: Function,
|
||||
close: Function,
|
||||
};
|
||||
|
||||
ConfirmationDialog.bodyTemplate = "web.ConfirmationDialogBody";
|
||||
|
||||
@@ -15,7 +15,6 @@ export class Dialog extends Component {
|
||||
);
|
||||
}
|
||||
this.modalRef = useRef("modal");
|
||||
this.dialogService = useService("dialog");
|
||||
useActiveElement("modal");
|
||||
useHotkey(
|
||||
"escape",
|
||||
@@ -33,7 +32,6 @@ export class Dialog extends Component {
|
||||
this.size = this.constructor.size;
|
||||
this.technical = this.constructor.technical;
|
||||
this.title = this.constructor.title;
|
||||
this.__id = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +39,7 @@ export class Dialog extends Component {
|
||||
* @private
|
||||
*/
|
||||
close() {
|
||||
this.dialogService.close(this.__id);
|
||||
this.props.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,37 +16,31 @@ ErrorHandler.template = tags.xml`<t t-component="props.dialog.class" t-props="pr
|
||||
export class DialogContainer extends Component {
|
||||
setup() {
|
||||
this.dialogs = {};
|
||||
this.props.bus.on("ADD", this, (dialog) => {
|
||||
this.dialogs[dialog.id] = dialog;
|
||||
this.render();
|
||||
});
|
||||
this.props.bus.on("CLOSE", this, (id) => {
|
||||
this.closeDialog(id);
|
||||
});
|
||||
this.props.bus.on("ADD", this, this.add);
|
||||
this.props.bus.on("REMOVE", this, this.remove);
|
||||
}
|
||||
__destroy() {
|
||||
this.props.bus.off("ADD", this);
|
||||
this.props.bus.off("REMOVE", this);
|
||||
super.__destroy();
|
||||
}
|
||||
|
||||
onDialogClosed(id) {
|
||||
this.closeDialog(id);
|
||||
add(params) {
|
||||
this.dialogs[params.id] = params;
|
||||
this.render();
|
||||
}
|
||||
|
||||
closeDialog(id) {
|
||||
remove(id) {
|
||||
if (this.dialogs[id]) {
|
||||
if (this.dialogs[id].options && this.dialogs[id].options.onCloseCallback) {
|
||||
this.dialogs[id].options.onCloseCallback();
|
||||
}
|
||||
delete this.dialogs[id];
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
errorCallBack(id) {
|
||||
return () => this.closeDialog(id);
|
||||
onDialogClosed(id) {
|
||||
this.remove(id);
|
||||
}
|
||||
|
||||
__destroy() {
|
||||
this.props.bus.off("ADD", this);
|
||||
this.props.bus.off("CLOSE", this);
|
||||
super.__destroy();
|
||||
errorCallBack(id) {
|
||||
return () => this.remove(id);
|
||||
}
|
||||
}
|
||||
DialogContainer.components = { ErrorHandler };
|
||||
|
||||
@@ -7,40 +7,56 @@ import { DialogContainer } from "./dialog_container";
|
||||
const { core } = owl;
|
||||
const { EventBus } = core;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* onClose?(): void;
|
||||
* }} DialogServiceInterfaceAddOptions
|
||||
*/
|
||||
/**
|
||||
* @typedef {{
|
||||
* add(
|
||||
* Component: any,
|
||||
* props: {},
|
||||
* options?: DialogServiceInterfaceAddOptions
|
||||
* ): () => void;
|
||||
* }} DialogServiceInterface
|
||||
*/
|
||||
|
||||
export const dialogService = {
|
||||
/** @returns {DialogServiceInterface} */
|
||||
start() {
|
||||
const bus = new EventBus();
|
||||
let dialogId = 0;
|
||||
function open(dialogClass, props, options) {
|
||||
if (!(dialogClass.prototype instanceof Dialog)) {
|
||||
throw new Error(dialogClass.name + " must be a subclass of Dialog");
|
||||
}
|
||||
const id = ++dialogId;
|
||||
class dialogController extends dialogClass {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.__id = id;
|
||||
}
|
||||
}
|
||||
const dialog = {
|
||||
id,
|
||||
class: dialogController,
|
||||
props,
|
||||
options,
|
||||
};
|
||||
bus.trigger("ADD", dialog);
|
||||
return id;
|
||||
}
|
||||
function close(id) {
|
||||
bus.trigger("CLOSE", id);
|
||||
}
|
||||
|
||||
registry.category("main_components").add("DialogContainer", {
|
||||
Component: DialogContainer,
|
||||
props: { bus },
|
||||
});
|
||||
|
||||
return { open, close };
|
||||
function add(dialogClass, props, options = {}) {
|
||||
if (!(dialogClass.prototype instanceof Dialog)) {
|
||||
throw new Error(`${dialogClass.name} must be a subclass of Dialog`);
|
||||
}
|
||||
|
||||
const id = ++dialogId;
|
||||
function close() {
|
||||
if (options.onClose) {
|
||||
options.onClose();
|
||||
}
|
||||
bus.trigger("REMOVE", id);
|
||||
}
|
||||
|
||||
const dialog = {
|
||||
id,
|
||||
class: dialogClass,
|
||||
props: { ...props, close },
|
||||
};
|
||||
bus.trigger("ADD", dialog);
|
||||
|
||||
return close;
|
||||
}
|
||||
|
||||
return { add };
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ const errorDialogRegistry = registry.category("error_dialogs");
|
||||
*/
|
||||
function corsErrorHandler(env, error) {
|
||||
if (error instanceof UncaughtCorsError) {
|
||||
env.services.dialog.open(NetworkErrorDialog, {
|
||||
env.services.dialog.add(NetworkErrorDialog, {
|
||||
traceback: error.traceback,
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
@@ -51,7 +51,7 @@ errorHandlerRegistry.add("corsErrorHandler", corsErrorHandler, { sequence: 95 })
|
||||
*/
|
||||
function clientErrorHandler(env, error) {
|
||||
if (error instanceof UncaughtClientError) {
|
||||
env.services.dialog.open(ClientErrorDialog, {
|
||||
env.services.dialog.add(ClientErrorDialog, {
|
||||
traceback: error.traceback,
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
@@ -90,7 +90,7 @@ function rpcErrorHandler(env, error, originalError) {
|
||||
ErrorComponent = errorDialogRegistry.get(exceptionName);
|
||||
}
|
||||
|
||||
env.services.dialog.open(ErrorComponent || RPCErrorDialog, {
|
||||
env.services.dialog.add(ErrorComponent || RPCErrorDialog, {
|
||||
traceback: error.traceback,
|
||||
message: originalError.message,
|
||||
name: originalError.name,
|
||||
@@ -170,7 +170,7 @@ function emptyRejectionErrorHandler(env, error) {
|
||||
if (!(error instanceof UncaughtPromiseError)) {
|
||||
return false;
|
||||
}
|
||||
env.services.dialog.open(ClientErrorDialog, {
|
||||
env.services.dialog.add(ClientErrorDialog, {
|
||||
traceback: error.traceback,
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
@@ -191,7 +191,7 @@ errorHandlerRegistry.add("emptyRejectionErrorHandler", emptyRejectionErrorHandle
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function defaultHandler(env, error) {
|
||||
env.services.dialog.open(ErrorDialog, {
|
||||
env.services.dialog.add(ErrorDialog, {
|
||||
traceback: error.traceback,
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
|
||||
@@ -103,7 +103,7 @@ class ActionAdapter extends ComponentAdapter {
|
||||
}
|
||||
}
|
||||
WarningDialog.bodyTemplate = tags.xml`<t t-esc="props.message"/>`;
|
||||
this.dialogs.open(WarningDialog, {
|
||||
this.dialogs.add(WarningDialog, {
|
||||
title: payload.title,
|
||||
message: payload.message,
|
||||
});
|
||||
|
||||
@@ -190,7 +190,10 @@ function viewRecordRules({ accessRights, action, env }) {
|
||||
}
|
||||
|
||||
class FieldViewGetDialog extends Dialog {}
|
||||
FieldViewGetDialog.props = Object.assign({}, Dialog.props, { arch: { type: String } });
|
||||
FieldViewGetDialog.props = Object.assign({}, Dialog.props, {
|
||||
arch: { type: String },
|
||||
close: Function,
|
||||
});
|
||||
FieldViewGetDialog.bodyTemplate = tags.xml`<pre t-esc="props.arch"/>`;
|
||||
FieldViewGetDialog.title = _lt("Fields View Get");
|
||||
|
||||
@@ -390,7 +393,7 @@ function fieldsViewGet({ component, env }) {
|
||||
const props = {
|
||||
arch: component.props.viewInfo.arch,
|
||||
};
|
||||
env.services.dialog.open(FieldViewGetDialog, props);
|
||||
env.services.dialog.add(FieldViewGetDialog, props);
|
||||
},
|
||||
sequence: 340,
|
||||
};
|
||||
@@ -435,7 +438,7 @@ function setDefaults({ action, component, env }) {
|
||||
type: "item",
|
||||
description: env._t("Set Defaults"),
|
||||
callback: () => {
|
||||
env.services.dialog.open(SetDefaultDialog, {
|
||||
env.services.dialog.add(SetDefaultDialog, {
|
||||
res_model: action.res_model,
|
||||
component,
|
||||
});
|
||||
@@ -453,7 +456,7 @@ function viewMetadata({ action, component, env }) {
|
||||
type: "item",
|
||||
description: env._t("View Metadata"),
|
||||
callback: () => {
|
||||
env.services.dialog.open(GetMetadataDialog, {
|
||||
env.services.dialog.add(GetMetadataDialog, {
|
||||
res_model: action.res_model,
|
||||
selectedIds,
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ function legacyRPCErrorHandler(env, error, originalError) {
|
||||
ErrorComponent = errorDialogRegistry.get(exceptionName);
|
||||
}
|
||||
|
||||
env.services.dialog.open(ErrorComponent || RPCErrorDialog, {
|
||||
env.services.dialog.add(ErrorComponent || RPCErrorDialog, {
|
||||
traceback: originalError.traceback || originalError.stack,
|
||||
message: originalError.message,
|
||||
name: originalError.name,
|
||||
|
||||
@@ -32,6 +32,7 @@ ActionDialog.props = {
|
||||
ActionComponent: { optional: true },
|
||||
actionProps: { optional: true },
|
||||
title: { optional: true },
|
||||
close: Function,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -550,14 +550,14 @@ function makeActionManager(env) {
|
||||
}
|
||||
|
||||
const { onClose } = dialog;
|
||||
const oldDialogId = dialog.id;
|
||||
if (oldDialogId) {
|
||||
const removeOldDialog = dialog.remove;
|
||||
if (removeOldDialog) {
|
||||
dialog = {};
|
||||
env.services.dialog.close(oldDialogId);
|
||||
removeOldDialog();
|
||||
}
|
||||
const dialogId = env.services.dialog.open(ActionDialog, actionDialogProps, {
|
||||
onCloseCallback: () => {
|
||||
if (dialog.id) {
|
||||
const removeDialog = env.services.dialog.add(ActionDialog, actionDialogProps, {
|
||||
onClose: () => {
|
||||
if (dialog.remove) {
|
||||
if (dialog.onClose) {
|
||||
dialog.onClose();
|
||||
}
|
||||
@@ -566,7 +566,7 @@ function makeActionManager(env) {
|
||||
},
|
||||
});
|
||||
dialog = {
|
||||
id: dialogId,
|
||||
remove: removeDialog,
|
||||
onClose: onClose || options.onClose,
|
||||
};
|
||||
return currentActionProm;
|
||||
@@ -923,11 +923,11 @@ function makeActionManager(env) {
|
||||
async function _executeCloseAction(params = {}) {
|
||||
cleanDomFromBootstrap();
|
||||
let onClose;
|
||||
const dialogId = dialog.id;
|
||||
if (dialogId) {
|
||||
const removeDialog = dialog.remove;
|
||||
if (removeDialog) {
|
||||
onClose = dialog.onClose;
|
||||
dialog = {};
|
||||
env.services.dialog.close(dialogId);
|
||||
removeDialog();
|
||||
} else {
|
||||
onClose = params.onClose;
|
||||
}
|
||||
|
||||
@@ -34,4 +34,5 @@ CommandPaletteDialog.bodyTemplate = "web.CommandPaletteDialogBody";
|
||||
CommandPaletteDialog.components = Object.assign({}, Dialog.components, { CommandPalette });
|
||||
CommandPaletteDialog.props = {
|
||||
commands: { type: Array, element: { type: Object } },
|
||||
close: Function,
|
||||
};
|
||||
|
||||
@@ -67,11 +67,11 @@ export const commandService = {
|
||||
|
||||
// Open palette dialog
|
||||
isPaletteOpened = true;
|
||||
dialog.open(
|
||||
dialog.add(
|
||||
CommandPaletteDialog,
|
||||
{ commands },
|
||||
{
|
||||
onCloseCallback: () => {
|
||||
onClose: () => {
|
||||
isPaletteOpened = false;
|
||||
},
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ function shortCutsItem(env) {
|
||||
hide: env.isSmall,
|
||||
description: env._t("Shortcuts"),
|
||||
callback: () => {
|
||||
env.services.dialog.open(ShortCutsDialog);
|
||||
env.services.dialog.add(ShortCutsDialog);
|
||||
},
|
||||
sequence: 30,
|
||||
};
|
||||
|
||||
@@ -123,7 +123,11 @@ QUnit.module("DebugMenu", (hooks) => {
|
||||
|
||||
QUnit.test("Don't display the DebugMenu if debug mode is disabled", async (assert) => {
|
||||
const env = await makeTestEnv(testConfig);
|
||||
const actionDialog = await mount(ActionDialog, { env, target, props: {} });
|
||||
const actionDialog = await mount(ActionDialog, {
|
||||
env,
|
||||
target,
|
||||
props: { close: () => {} },
|
||||
});
|
||||
registerCleanup(() => {
|
||||
actionDialog.destroy();
|
||||
});
|
||||
@@ -173,9 +177,10 @@ QUnit.module("DebugMenu", (hooks) => {
|
||||
useSubEnv({ inDialog: true });
|
||||
useDebugMenu("custom", { customKey: "abc" });
|
||||
}
|
||||
close() {}
|
||||
}
|
||||
Parent.components = { ActionDialog };
|
||||
Parent.template = tags.xml`<ActionDialog/>`;
|
||||
Parent.template = tags.xml`<ActionDialog close="close"/>`;
|
||||
patchWithCleanup(odoo, { debug: "1" });
|
||||
const env = await makeTestEnv(testConfig);
|
||||
const actionDialog = await mount(Parent, { env, target });
|
||||
|
||||
@@ -57,7 +57,7 @@ QUnit.test("Simple rendering with a single dialog", async (assert) => {
|
||||
CustomDialog.title = "Welcome";
|
||||
pseudoWebClient = await mount(PseudoWebClient, { env, target });
|
||||
assert.containsNone(target, ".o_dialog_container .o_dialog");
|
||||
env.services.dialog.open(CustomDialog);
|
||||
env.services.dialog.add(CustomDialog);
|
||||
await nextTick();
|
||||
assert.containsOnce(target, ".o_dialog_container .o_dialog");
|
||||
assert.strictEqual(target.querySelector("header .modal-title").textContent, "Welcome");
|
||||
@@ -74,18 +74,18 @@ QUnit.test("Simple rendering and close a single dialog", async (assert) => {
|
||||
pseudoWebClient = await mount(PseudoWebClient, { env, target });
|
||||
assert.containsNone(target, ".o_dialog_container .o_dialog");
|
||||
|
||||
const dialogId = env.services.dialog.open(CustomDialog);
|
||||
const removeDialog = env.services.dialog.add(CustomDialog);
|
||||
await nextTick();
|
||||
assert.containsOnce(target, ".o_dialog_container .o_dialog");
|
||||
assert.strictEqual(target.querySelector("header .modal-title").textContent, "Welcome");
|
||||
|
||||
env.services.dialog.close(dialogId);
|
||||
removeDialog();
|
||||
await nextTick();
|
||||
assert.containsNone(target, ".o_dialog_container .o_dialog");
|
||||
|
||||
// Call a second time, the close on the dialog.
|
||||
// As the dialog is already close, this call is just ignored. No error should be raised.
|
||||
env.services.dialog.close(dialogId);
|
||||
removeDialog();
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
@@ -99,11 +99,11 @@ QUnit.test("rendering with two dialogs", async (assert) => {
|
||||
}
|
||||
pseudoWebClient = await mount(PseudoWebClient, { env, target });
|
||||
assert.containsNone(target, ".o_dialog_container .o_dialog");
|
||||
env.services.dialog.open(CustomDialog, { title: "Hello" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Hello" });
|
||||
await nextTick();
|
||||
assert.containsOnce(target, ".o_dialog_container .o_dialog");
|
||||
assert.strictEqual(target.querySelector("header .modal-title").textContent, "Hello");
|
||||
env.services.dialog.open(CustomDialog, { title: "Sauron" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Sauron" });
|
||||
await nextTick();
|
||||
assert.containsN(target, ".o_dialog_container .o_dialog", 2);
|
||||
assert.deepEqual(
|
||||
@@ -125,7 +125,7 @@ QUnit.test("multiple dialogs can become the UI active element", async (assert) =
|
||||
}
|
||||
pseudoWebClient = await mount(PseudoWebClient, { env, target });
|
||||
|
||||
env.services.dialog.open(CustomDialog, { title: "Hello" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Hello" });
|
||||
await nextTick();
|
||||
let dialogModal = target.querySelector(
|
||||
".o_dialog_container .o_dialog .modal:not(.o_inactive_modal)"
|
||||
@@ -133,7 +133,7 @@ QUnit.test("multiple dialogs can become the UI active element", async (assert) =
|
||||
|
||||
assert.strictEqual(dialogModal, env.services.ui.activeElement);
|
||||
|
||||
env.services.dialog.open(CustomDialog, { title: "Sauron" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Sauron" });
|
||||
await nextTick();
|
||||
dialogModal = target.querySelector(
|
||||
".o_dialog_container .o_dialog .modal:not(.o_inactive_modal)"
|
||||
@@ -141,7 +141,7 @@ QUnit.test("multiple dialogs can become the UI active element", async (assert) =
|
||||
|
||||
assert.strictEqual(dialogModal, env.services.ui.activeElement);
|
||||
|
||||
env.services.dialog.open(CustomDialog, { title: "Rafiki" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Rafiki" });
|
||||
await nextTick();
|
||||
dialogModal = target.querySelector(
|
||||
".o_dialog_container .o_dialog .modal:not(.o_inactive_modal)"
|
||||
@@ -170,11 +170,11 @@ QUnit.test("Interactions between multiple dialogs", async (assert) => {
|
||||
}
|
||||
pseudoWebClient = await mount(PseudoWebClient, { env, target });
|
||||
|
||||
env.services.dialog.open(CustomDialog, { title: "Hello" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Hello" });
|
||||
await nextTick();
|
||||
env.services.dialog.open(CustomDialog, { title: "Sauron" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Sauron" });
|
||||
await nextTick();
|
||||
env.services.dialog.open(CustomDialog, { title: "Rafiki" });
|
||||
env.services.dialog.add(CustomDialog, { title: "Rafiki" });
|
||||
await nextTick();
|
||||
|
||||
let modals = document.querySelectorAll(".modal");
|
||||
@@ -248,7 +248,7 @@ QUnit.test("dialog component crashes", async (assert) => {
|
||||
|
||||
pseudoWebClient = await mount(PseudoWebClient, { env, target });
|
||||
|
||||
env.services.dialog.open(FailingDialog);
|
||||
env.services.dialog.add(FailingDialog);
|
||||
await prom;
|
||||
assert.verifySteps(["error"]);
|
||||
assert.containsOnce(pseudoWebClient, ".modal");
|
||||
|
||||
@@ -110,67 +110,48 @@ QUnit.module("Components", (hooks) => {
|
||||
|
||||
QUnit.test("click on the button x triggers the service close", async function (assert) {
|
||||
assert.expect(3);
|
||||
serviceRegistry.add(
|
||||
"dialog",
|
||||
makeFakeDialogService({
|
||||
close: (id) => {
|
||||
assert.step("close with id: " + id);
|
||||
},
|
||||
}),
|
||||
{ force: true }
|
||||
);
|
||||
const env = await makeTestEnv();
|
||||
class MyDialog extends SimpleDialog {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.__id = 666;
|
||||
class MyDialog extends SimpleDialog {}
|
||||
class Parent extends owl.Component {
|
||||
close() {
|
||||
assert.step("close");
|
||||
}
|
||||
}
|
||||
class Parent extends owl.Component {}
|
||||
|
||||
Parent.template = owl.tags.xml`
|
||||
<MyDialog>
|
||||
Hello!
|
||||
</MyDialog>
|
||||
`;
|
||||
<MyDialog close="close">
|
||||
Hello!
|
||||
</MyDialog>
|
||||
`;
|
||||
Parent.components = { MyDialog };
|
||||
parent = await mount(Parent, { env, target });
|
||||
assert.containsOnce(target, ".o_dialog");
|
||||
await click(target, ".o_dialog header button.close");
|
||||
assert.verifySteps(["close with id: 666"]);
|
||||
assert.verifySteps(["close"]);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"click on the default footer button triggers the service close",
|
||||
async function (assert) {
|
||||
serviceRegistry.add(
|
||||
"dialog",
|
||||
makeFakeDialogService({
|
||||
close: (id) => {
|
||||
assert.step("close with id: " + id);
|
||||
},
|
||||
}),
|
||||
{ force: true }
|
||||
);
|
||||
const env = await makeTestEnv();
|
||||
assert.expect(3);
|
||||
class MyDialog extends SimpleDialog {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.__id = 777;
|
||||
class MyDialog extends SimpleDialog {}
|
||||
class Parent extends owl.Component {
|
||||
close() {
|
||||
assert.step("close");
|
||||
}
|
||||
}
|
||||
class Parent extends owl.Component {}
|
||||
|
||||
Parent.template = owl.tags.xml`
|
||||
<MyDialog>
|
||||
<MyDialog close="close">
|
||||
Hello!
|
||||
</MyDialog>
|
||||
`;
|
||||
`;
|
||||
Parent.components = { MyDialog };
|
||||
parent = await mount(Parent, { env, target });
|
||||
assert.containsOnce(target, ".o_dialog");
|
||||
await click(target, ".o_dialog footer button");
|
||||
assert.verifySteps(["close with id: 777"]);
|
||||
assert.verifySteps(["close"]);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -201,16 +201,10 @@ QUnit.test("WarningDialog", async (assert) => {
|
||||
});
|
||||
|
||||
QUnit.test("RedirectWarningDialog", async (assert) => {
|
||||
serviceRegistry.add(
|
||||
"dialog",
|
||||
makeFakeDialogService({
|
||||
close: () => {
|
||||
assert.step("dialog-closed");
|
||||
},
|
||||
}),
|
||||
{ force: true }
|
||||
);
|
||||
assert.expect(10);
|
||||
|
||||
class CloseRedirectWarningDialog extends RedirectWarningDialog {}
|
||||
|
||||
class Parent extends Component {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
@@ -222,9 +216,12 @@ QUnit.test("RedirectWarningDialog", async (assert) => {
|
||||
],
|
||||
};
|
||||
}
|
||||
close() {
|
||||
assert.step("dialog-closed");
|
||||
}
|
||||
}
|
||||
Parent.components = { RedirectWarningDialog };
|
||||
Parent.template = tags.xml`<RedirectWarningDialog data="data"/>`;
|
||||
Parent.components = { RedirectWarningDialog: CloseRedirectWarningDialog };
|
||||
Parent.template = tags.xml`<RedirectWarningDialog data="data" close="close"/>`;
|
||||
const faceActionService = {
|
||||
name: "action",
|
||||
start() {
|
||||
|
||||
@@ -58,7 +58,7 @@ QUnit.test("handle RPC_ERROR of type='server' and no associated dialog class", a
|
||||
error.message = "Some strange error occured";
|
||||
error.data = { debug: "somewhere" };
|
||||
error.subType = "strange_error";
|
||||
function open(dialogClass, props) {
|
||||
function addDialog(dialogClass, props) {
|
||||
assert.strictEqual(dialogClass, RPCErrorDialog);
|
||||
assert.deepEqual(props, {
|
||||
name: "RPC_ERROR",
|
||||
@@ -73,7 +73,7 @@ QUnit.test("handle RPC_ERROR of type='server' and no associated dialog class", a
|
||||
traceback: error.stack,
|
||||
});
|
||||
}
|
||||
serviceRegistry.add("dialog", makeFakeDialogService({ open: open }), { force: true });
|
||||
serviceRegistry.add("dialog", makeFakeDialogService(addDialog), { force: true });
|
||||
await makeTestEnv();
|
||||
const errorEvent = new PromiseRejectionEvent("error", { reason: error, promise: null });
|
||||
await unhandledRejectionCb(errorEvent);
|
||||
@@ -90,7 +90,7 @@ QUnit.test(
|
||||
error.code = 701;
|
||||
error.message = "Some strange error occured";
|
||||
error.exceptionName = "strange_error";
|
||||
function open(dialogClass, props) {
|
||||
function addDialog(dialogClass, props) {
|
||||
assert.strictEqual(dialogClass, CustomDialog);
|
||||
assert.deepEqual(props, {
|
||||
name: "RPC_ERROR",
|
||||
@@ -103,7 +103,7 @@ QUnit.test(
|
||||
traceback: error.stack,
|
||||
});
|
||||
}
|
||||
serviceRegistry.add("dialog", makeFakeDialogService({ open: open }), { force: true });
|
||||
serviceRegistry.add("dialog", makeFakeDialogService(addDialog), { force: true });
|
||||
await makeTestEnv();
|
||||
errorDialogRegistry.add("strange_error", CustomDialog);
|
||||
const errorEvent = new PromiseRejectionEvent("error", { reason: error, promise: null });
|
||||
@@ -176,7 +176,7 @@ QUnit.test("handle uncaught promise errors", async (assert) => {
|
||||
error.message = "This is an error test";
|
||||
error.name = "TestError";
|
||||
|
||||
function open(dialogClass, props) {
|
||||
function addDialog(dialogClass, props) {
|
||||
assert.strictEqual(dialogClass, ClientErrorDialog);
|
||||
assert.deepEqual(props, {
|
||||
name: "UncaughtPromiseError > TestError",
|
||||
@@ -184,7 +184,7 @@ QUnit.test("handle uncaught promise errors", async (assert) => {
|
||||
traceback: error.stack,
|
||||
});
|
||||
}
|
||||
serviceRegistry.add("dialog", makeFakeDialogService({ open: open }), { force: true });
|
||||
serviceRegistry.add("dialog", makeFakeDialogService(addDialog), { force: true });
|
||||
await makeTestEnv();
|
||||
|
||||
const errorEvent = new PromiseRejectionEvent("error", { reason: error, promise: null });
|
||||
@@ -197,12 +197,12 @@ QUnit.test("handle uncaught client errors", async (assert) => {
|
||||
error.message = "This is an error test";
|
||||
error.name = "TestError";
|
||||
|
||||
function open(dialogClass, props) {
|
||||
function addDialog(dialogClass, props) {
|
||||
assert.strictEqual(dialogClass, ClientErrorDialog);
|
||||
assert.strictEqual(props.name, "UncaughtClientError > TestError");
|
||||
assert.strictEqual(props.message, "Uncaught Javascript Error > This is an error test");
|
||||
}
|
||||
serviceRegistry.add("dialog", makeFakeDialogService({ open: open }), { force: true });
|
||||
serviceRegistry.add("dialog", makeFakeDialogService(addDialog), { force: true });
|
||||
await makeTestEnv();
|
||||
|
||||
const errorEvent = new ErrorEvent("error", {
|
||||
@@ -220,11 +220,11 @@ QUnit.test("handle uncaught CORS errors", async (assert) => {
|
||||
error.message = "This is a cors error";
|
||||
error.name = "CORS error";
|
||||
|
||||
function open(dialogClass, props) {
|
||||
function addDialog(dialogClass, props) {
|
||||
assert.strictEqual(dialogClass, NetworkErrorDialog);
|
||||
assert.strictEqual(props.message, "Uncaught CORS Error");
|
||||
}
|
||||
serviceRegistry.add("dialog", makeFakeDialogService({ open: open }), { force: true });
|
||||
serviceRegistry.add("dialog", makeFakeDialogService(addDialog), { force: true });
|
||||
await makeTestEnv();
|
||||
|
||||
// CORS error event has no colno, no lineno and no filename
|
||||
|
||||
@@ -203,15 +203,11 @@ export function makeFakeNotificationService(mock) {
|
||||
};
|
||||
}
|
||||
|
||||
export function makeFakeDialogService(values = {}) {
|
||||
const open = values.open || (() => {});
|
||||
const close = values.close || (() => {});
|
||||
export function makeFakeDialogService(addDialog) {
|
||||
return {
|
||||
name: "dialog",
|
||||
start() {
|
||||
return {
|
||||
open,
|
||||
close,
|
||||
add: addDialog || (() => () => {}),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -278,30 +278,23 @@ odoo.define('web.owl_dialog_tests', function (require) {
|
||||
|
||||
QUnit.test("Interactions between legacy owl dialogs and new owl dialogs", async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const serviceRegistry = registry.category("services");
|
||||
serviceRegistry.add("dialog", makeFakeDialogService({
|
||||
close: (id) => {
|
||||
assert.step(`dialog_${id}_closed`);
|
||||
parent.dialogs.splice(parent.dialogs.findIndex(d => d.id === id), 1);
|
||||
},
|
||||
})
|
||||
);
|
||||
const { legacyEnv, env } = await makeLegacyDialogMappingTestEnv();
|
||||
|
||||
let id = 1;
|
||||
// OwlDialog env
|
||||
patchWithCleanup(Dialog.prototype, {
|
||||
class OwlDialogWrapper extends owl.Component {
|
||||
setup() {
|
||||
this.env = legacyEnv;
|
||||
this._super();
|
||||
}
|
||||
});
|
||||
let id = 1;
|
||||
}
|
||||
OwlDialogWrapper.template = xml`
|
||||
<Dialog t-on-dialog-closed="props.close()" />
|
||||
`;
|
||||
OwlDialogWrapper.components = { Dialog };
|
||||
class WowlDialogSubClass extends WowlDialog{
|
||||
setup(){
|
||||
super.setup();
|
||||
this.contentClass = this.props.contentClass;
|
||||
this.__id = id;
|
||||
}
|
||||
}
|
||||
class Parent extends Component {
|
||||
@@ -311,8 +304,10 @@ odoo.define('web.owl_dialog_tests', function (require) {
|
||||
}
|
||||
// Handlers
|
||||
_onDialogClosed(id) {
|
||||
assert.step(`dialog_${id}_closed`);
|
||||
this.dialogs.splice(this.dialogs.findIndex(d => d.id === id), 1);
|
||||
return () => {
|
||||
assert.step(`dialog_${id}_closed`);
|
||||
this.dialogs.splice(this.dialogs.findIndex(d => d.id === id), 1);
|
||||
};
|
||||
}
|
||||
}
|
||||
Parent.template = xml`
|
||||
@@ -320,14 +315,15 @@ odoo.define('web.owl_dialog_tests', function (require) {
|
||||
<div class="o_dialog_container"/>
|
||||
<t t-foreach="dialogs" t-as="dialog" t-key="dialog.id" t-component="dialog.class"
|
||||
contentClass="'dialog_' + dialog.id"
|
||||
t-on-dialog-closed="_onDialogClosed(dialog.id)" />
|
||||
close="_onDialogClosed(dialog.id)"
|
||||
/>
|
||||
</div>`;
|
||||
const parent = await mount(Parent, { env, target: getFixture() });
|
||||
|
||||
parent.dialogs.push({ id: 1, class: WowlDialogSubClass });
|
||||
await nextTick();
|
||||
id ++;
|
||||
parent.dialogs.push({ id: 2, class: Dialog });
|
||||
parent.dialogs.push({ id: 2, class: OwlDialogWrapper });
|
||||
await nextTick();
|
||||
id ++;
|
||||
parent.dialogs.push({ id: 3, class: WowlDialogSubClass });
|
||||
|
||||
@@ -35,7 +35,7 @@ function startTour({ env }) {
|
||||
type: "item",
|
||||
description: env._t("Start Tour"),
|
||||
callback: async () => {
|
||||
env.services.dialog.open(ToursDialog);
|
||||
env.services.dialog.add(ToursDialog);
|
||||
},
|
||||
sequence: 60,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user