mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
work on action manager
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Registry } from "./core/registry";
|
import { Registry } from "./core/registry";
|
||||||
import { ActionWidget } from "./store/store";
|
import { ControllerWidget } from "./store/store";
|
||||||
import { Discuss } from "./discuss/discuss";
|
import { Discuss } from "./discuss/discuss";
|
||||||
|
|
||||||
export const actionRegistry: Registry<ActionWidget> = new Registry();
|
export const actionRegistry: Registry<ControllerWidget> = new Registry();
|
||||||
|
|
||||||
actionRegistry.add("mail.discuss", Discuss);
|
actionRegistry.add("mail.discuss", Discuss);
|
||||||
|
|||||||
@@ -7,28 +7,12 @@ import { View } from "../views/view";
|
|||||||
// Types
|
// Types
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
export type Context = { [key: string]: any };
|
// Miscellaneous
|
||||||
|
|
||||||
export interface CommonActionInfo {
|
|
||||||
id: number;
|
|
||||||
context: Context;
|
|
||||||
title: string;
|
|
||||||
target: "current" | "new";
|
|
||||||
Widget: ActionWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ActionRequest = number;
|
export type ActionRequest = number;
|
||||||
|
|
||||||
export type ActionWidget = Type<Widget<{}, {}>>;
|
export type ControllerWidget = Type<Widget<{}, {}>>;
|
||||||
|
|
||||||
export interface ClientActionInfo extends CommonActionInfo {
|
|
||||||
type: "client";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActWindowInfo extends CommonActionInfo {
|
|
||||||
type: "act_window";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Action Description
|
||||||
interface BaseActionDescription {
|
interface BaseActionDescription {
|
||||||
id: number;
|
id: number;
|
||||||
target: "current";
|
target: "current";
|
||||||
@@ -52,13 +36,13 @@ export type ActionDescription =
|
|||||||
| ClientActionDescription
|
| ClientActionDescription
|
||||||
| ActWindowActionDescription;
|
| ActWindowActionDescription;
|
||||||
|
|
||||||
export type ActionInfo = ClientActionInfo | ActWindowInfo;
|
// Controller
|
||||||
|
export interface Controller {
|
||||||
export interface Action {
|
|
||||||
id: number;
|
id: number;
|
||||||
|
actionId: number;
|
||||||
widget?: Widget<any, any>;
|
widget?: Widget<any, any>;
|
||||||
executor(parent: Widget<any, any>): Promise<Widget<any, any> | null>;
|
create(parent: Widget<any, any>): Promise<Widget<any, any> | null>;
|
||||||
activate(): void;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -70,8 +54,8 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
|
|||||||
) {
|
) {
|
||||||
return class extends Base {
|
return class extends Base {
|
||||||
actionCache: { [key: number]: Promise<ActionDescription> } = {};
|
actionCache: { [key: number]: Promise<ActionDescription> } = {};
|
||||||
currentAction?: Action;
|
currentController?: Controller;
|
||||||
lastAction?: Action;
|
lastController?: Controller;
|
||||||
|
|
||||||
async doAction(request: ActionRequest) {
|
async doAction(request: ActionRequest) {
|
||||||
const self = this;
|
const self = this;
|
||||||
@@ -87,28 +71,21 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
|
|||||||
default:
|
default:
|
||||||
throw new Error("unhandled action");
|
throw new Error("unhandled action");
|
||||||
}
|
}
|
||||||
if (executor) {
|
const action: Controller = {
|
||||||
const action: Action = {
|
id: this.generateID(),
|
||||||
id: this.generateID(),
|
actionId: descr.id,
|
||||||
executor,
|
create: executor,
|
||||||
activate() {
|
title: descr.name
|
||||||
if (self.currentAction && self.currentAction.widget) {
|
};
|
||||||
self.currentAction.widget.destroy();
|
self.lastController = action;
|
||||||
}
|
this.trigger("update_action", action);
|
||||||
self.currentAction = action;
|
|
||||||
self.update({
|
|
||||||
inHome: false
|
|
||||||
});
|
|
||||||
document.title = descr.name + " - Odoo";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.lastAction = action;
|
|
||||||
this.trigger("update_action", action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doActWindowAction(descr: ActWindowActionDescription) {
|
doActWindowAction(descr: ActWindowActionDescription) {
|
||||||
return async function executor(this: Action, parent: Widget<any, any>) {
|
return async function executor(
|
||||||
|
this: Controller,
|
||||||
|
parent: Widget<any, any>
|
||||||
|
) {
|
||||||
const widget = new View(parent, { info: descr.views[0][1] });
|
const widget = new View(parent, { info: descr.views[0][1] });
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
await widget.mount(div);
|
await widget.mount(div);
|
||||||
@@ -117,9 +94,7 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
doClientAction(
|
doClientAction(descr: ClientActionDescription): Controller["create"] {
|
||||||
descr: ClientActionDescription
|
|
||||||
): Action["executor"] | undefined {
|
|
||||||
let key = descr.tag;
|
let key = descr.tag;
|
||||||
let ActionWidget = this.actionRegistry.get(key);
|
let ActionWidget = this.actionRegistry.get(key);
|
||||||
if (!ActionWidget) {
|
if (!ActionWidget) {
|
||||||
@@ -130,7 +105,10 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
|
|||||||
});
|
});
|
||||||
ActionWidget = Widget;
|
ActionWidget = Widget;
|
||||||
}
|
}
|
||||||
return async function executor(this: Action, parent: Widget<any, any>) {
|
return async function executor(
|
||||||
|
this: Controller,
|
||||||
|
parent: Widget<any, any>
|
||||||
|
) {
|
||||||
const widget = new ActionWidget!(parent, {});
|
const widget = new ActionWidget!(parent, {});
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
await widget.mount(div);
|
await widget.mount(div);
|
||||||
@@ -150,5 +128,16 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activateController(controller: Controller) {
|
||||||
|
if (this.currentController && this.currentController.widget) {
|
||||||
|
this.currentController.widget.destroy();
|
||||||
|
}
|
||||||
|
this.currentController = controller;
|
||||||
|
this.update({
|
||||||
|
inHome: false
|
||||||
|
});
|
||||||
|
document.title = controller.title + " - Odoo";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Registry } from "../core/registry";
|
|||||||
import { idGenerator } from "../core/utils";
|
import { idGenerator } from "../core/utils";
|
||||||
import { RPC } from "../services/ajax";
|
import { RPC } from "../services/ajax";
|
||||||
import { IRouter, Query } from "../services/router";
|
import { IRouter, Query } from "../services/router";
|
||||||
import { actionManagerMixin, ActionWidget } from "./action_manager_mixin";
|
import { actionManagerMixin, ControllerWidget } from "./action_manager_mixin";
|
||||||
import { rpcMixin } from "./rpc_mixin";
|
import { rpcMixin } from "./rpc_mixin";
|
||||||
import { MenuItem } from "./store";
|
import { MenuItem } from "./store";
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import { MenuItem } from "./store";
|
|||||||
// Types
|
// Types
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
export { ActionWidget } from "./action_manager_mixin";
|
export { ControllerWidget } from "./action_manager_mixin";
|
||||||
export { RPC } from "./rpc_mixin";
|
export { RPC } from "./rpc_mixin";
|
||||||
|
|
||||||
export interface MenuItem {
|
export interface MenuItem {
|
||||||
@@ -64,14 +64,14 @@ export class BaseStore extends EventBus {
|
|||||||
};
|
};
|
||||||
menuInfo: MenuInfo;
|
menuInfo: MenuInfo;
|
||||||
services: Services;
|
services: Services;
|
||||||
actionRegistry: Registry<ActionWidget>;
|
actionRegistry: Registry<ControllerWidget>;
|
||||||
currentQuery: Query;
|
currentQuery: Query;
|
||||||
generateID = idGenerator();
|
generateID = idGenerator();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
services: Services,
|
services: Services,
|
||||||
menuInfo: MenuInfo,
|
menuInfo: MenuInfo,
|
||||||
actionRegistry: Registry<ActionWidget>
|
actionRegistry: Registry<ControllerWidget>
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.services = services;
|
this.services = services;
|
||||||
@@ -129,7 +129,7 @@ export class Store extends actionManagerMixin(rpcMixin(BaseStore)) {
|
|||||||
constructor(
|
constructor(
|
||||||
services: Services,
|
services: Services,
|
||||||
menuInfo: MenuInfo,
|
menuInfo: MenuInfo,
|
||||||
actionRegistry: Registry<ActionWidget>
|
actionRegistry: Registry<ControllerWidget>
|
||||||
) {
|
) {
|
||||||
super(services, menuInfo, actionRegistry);
|
super(services, menuInfo, actionRegistry);
|
||||||
const query = this.services.router.getQuery();
|
const query = this.services.router.getQuery();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { HomeMenu } from "./home_menu";
|
|||||||
import { Navbar } from "./navbar";
|
import { Navbar } from "./navbar";
|
||||||
import { Notification } from "./notification";
|
import { Notification } from "./notification";
|
||||||
import { Widget } from "../widget";
|
import { Widget } from "../widget";
|
||||||
import { Action } from "../store/action_manager_mixin";
|
import { Controller } from "../store/action_manager_mixin";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Root Widget
|
// Root Widget
|
||||||
@@ -26,9 +26,9 @@ export class Root extends Widget<Store, State> {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.store.on("state_updated", this, this.updateState);
|
this.store.on("state_updated", this, this.updateState);
|
||||||
this.store.on("rpc_status", this, this.toggleLoadingIndicator);
|
this.store.on("rpc_status", this, this.toggleLoadingIndicator);
|
||||||
this.store.on("update_action", this, this.applyAction);
|
this.store.on("update_action", this, this.applyController);
|
||||||
if (this.store.lastAction) {
|
if (this.store.lastController) {
|
||||||
this.applyAction(this.store.lastAction);
|
this.applyController(this.store.lastController);
|
||||||
}
|
}
|
||||||
|
|
||||||
// adding reactiveness to mobile/non mobile
|
// adding reactiveness to mobile/non mobile
|
||||||
@@ -50,13 +50,13 @@ export class Root extends Widget<Store, State> {
|
|||||||
(<any>this.refs.loading_indicator).classList[method]("d-none");
|
(<any>this.refs.loading_indicator).classList[method]("d-none");
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyAction(action: Action) {
|
async applyController(controller: Controller) {
|
||||||
const widget = await action.executor(this);
|
const widget = await controller.create(this);
|
||||||
if (widget) {
|
if (widget) {
|
||||||
// to do: call some public method of widget instead...
|
// to do: call some public method of widget instead...
|
||||||
(<HTMLElement>this.refs.content).appendChild(widget.el!);
|
(<HTMLElement>this.refs.content).appendChild(widget.el!);
|
||||||
widget.__mount();
|
widget.__mount();
|
||||||
action.activate();
|
this.store.activateController(controller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ describe("state transitions", () => {
|
|||||||
expect(store.services.router.getQuery()).toEqual({ home: true });
|
expect(store.services.router.getQuery()).toEqual({ home: true });
|
||||||
|
|
||||||
await promise;
|
await promise;
|
||||||
store.lastAction!.activate();
|
store.activateController(store.lastController!);
|
||||||
expect(store.state.inHome).toBe(false);
|
expect(store.state.inHome).toBe(false);
|
||||||
expect(store.services.router.getQuery()).toEqual({
|
expect(store.services.router.getQuery()).toEqual({
|
||||||
action_id: "131",
|
action_id: "131",
|
||||||
@@ -128,7 +128,7 @@ describe("state transitions", () => {
|
|||||||
const promise = store.activateMenuItem(96);
|
const promise = store.activateMenuItem(96);
|
||||||
expect(document.title).toBe("Odoo");
|
expect(document.title).toBe("Odoo");
|
||||||
await promise;
|
await promise;
|
||||||
store.lastAction!.activate();
|
store.activateController(store.lastController!);
|
||||||
|
|
||||||
expect(document.title).toBe("Discuss - Odoo");
|
expect(document.title).toBe("Discuss - Odoo");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user