work on action manager

This commit is contained in:
Géry Debongnie
2019-03-06 14:59:17 +01:00
parent 4145a5ebac
commit c0ea764481
5 changed files with 54 additions and 65 deletions
+2 -2
View File
@@ -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);
+35 -46
View File
@@ -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(),
executor, actionId: descr.id,
activate() { create: executor,
if (self.currentAction && self.currentAction.widget) { title: descr.name
self.currentAction.widget.destroy();
}
self.currentAction = action;
self.update({
inHome: false
});
document.title = descr.name + " - Odoo";
}
}; };
self.lastAction = action; self.lastController = action;
this.trigger("update_action", 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";
}
}; };
} }
+5 -5
View File
@@ -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();
+7 -7
View File
@@ -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);
} }
} }
} }
+2 -2
View File
@@ -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");