add different view types

This commit is contained in:
Géry Debongnie
2019-03-06 17:36:22 +01:00
parent 4fe7745a8a
commit 4b02b74440
13 changed files with 124 additions and 17 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
import { makeEnv } from "./env"; import { makeEnv } from "./env";
import { loadMenus, loadTemplates } from "./loaders"; import { loadMenus, loadTemplates } from "./loaders";
import { actionRegistry } from "./registries"; import { actionRegistry, viewRegistry } from "./registries";
import { rpc } from "./services/ajax"; import { rpc } from "./services/ajax";
import { Router } from "./services/router"; import { Router } from "./services/router";
import { Store } from "./store/store"; import { Store } from "./store/store";
@@ -20,7 +20,7 @@ document.addEventListener("DOMContentLoaded", async function() {
const templates = await loadTemplates(); const templates = await loadTemplates();
const menuInfo = loadMenus(); const menuInfo = loadMenus();
const store = new Store(services, menuInfo, actionRegistry); const store = new Store(services, menuInfo, actionRegistry, viewRegistry);
const env = makeEnv(store, templates); const env = makeEnv(store, templates);
// Creating root widget // Creating root widget
+18
View File
@@ -1,6 +1,24 @@
import { Registry } from "./core/registry"; import { Registry } from "./core/registry";
import { ControllerWidget } from "./store/store"; import { ControllerWidget } from "./store/store";
import { Discuss } from "./discuss/discuss"; import { Discuss } from "./discuss/discuss";
import { ListView } from "./views/list_view";
import { KanbanView } from "./views/kanban_view";
import { FormView } from "./views/form_view";
//------------------------------------------------------------------------------
// Views
//------------------------------------------------------------------------------
export const viewRegistry: Registry<ControllerWidget> = new Registry();
viewRegistry
.add("list", ListView)
.add("kanban", KanbanView)
.add("form", FormView);
//------------------------------------------------------------------------------
// Client Actions
//------------------------------------------------------------------------------
export const actionRegistry: Registry<ControllerWidget> = new Registry(); export const actionRegistry: Registry<ControllerWidget> = new Registry();
@@ -1,7 +1,6 @@
import { Type } from "../core/component"; import { Type } from "../core/component";
import { rpcMixin } from "./rpc_mixin"; import { rpcMixin } from "./rpc_mixin";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { View } from "../views/view";
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Types // Types
@@ -82,11 +81,21 @@ export function actionManagerMixin<T extends ReturnType<typeof rpcMixin>>(
} }
doActWindowAction(descr: ActWindowActionDescription) { doActWindowAction(descr: ActWindowActionDescription) {
const tag = descr.views[0][1];
let View = this.viewRegistry.get(tag);
if (!View) {
this.addNotification({
title: "Invalid View type",
type: "warning",
message: `Cannot find view of type '${tag}' in the view registry`
});
View = Widget;
}
return async function executor( return async function executor(
this: Controller, this: Controller,
parent: Widget<any, any> 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);
this.widget = widget; this.widget = widget;
+7 -3
View File
@@ -65,18 +65,21 @@ export class BaseStore extends EventBus {
menuInfo: MenuInfo; menuInfo: MenuInfo;
services: Services; services: Services;
actionRegistry: Registry<ControllerWidget>; actionRegistry: Registry<ControllerWidget>;
viewRegistry: Registry<ControllerWidget>;
currentQuery: Query; currentQuery: Query;
generateID = idGenerator(); generateID = idGenerator();
constructor( constructor(
services: Services, services: Services,
menuInfo: MenuInfo, menuInfo: MenuInfo,
actionRegistry: Registry<ControllerWidget> actionRegistry: Registry<ControllerWidget>,
viewRegistry: Registry<ControllerWidget>
) { ) {
super(); super();
this.services = services; this.services = services;
this.menuInfo = menuInfo; this.menuInfo = menuInfo;
this.actionRegistry = actionRegistry; this.actionRegistry = actionRegistry;
this.viewRegistry = viewRegistry;
this.currentQuery = {}; this.currentQuery = {};
} }
@@ -129,9 +132,10 @@ export class Store extends actionManagerMixin(rpcMixin(BaseStore)) {
constructor( constructor(
services: Services, services: Services,
menuInfo: MenuInfo, menuInfo: MenuInfo,
actionRegistry: Registry<ControllerWidget> actionRegistry: Registry<ControllerWidget>,
viewRegistry: Registry<ControllerWidget>
) { ) {
super(services, menuInfo, actionRegistry); super(services, menuInfo, actionRegistry, viewRegistry);
const query = this.services.router.getQuery(); const query = this.services.router.getQuery();
let { app, actionId } = this.getAppAndAction(query); let { app, actionId } = this.getAppAndAction(query);
this.state.currentApp = app; this.state.currentApp = app;
+5
View File
@@ -0,0 +1,5 @@
import { Widget } from "../widget";
export class FormView extends Widget<{}, { info: any }> {
inlineTemplate = `<div>form view: <span t-esc="props.info"/></div>`;
}
+5
View File
@@ -0,0 +1,5 @@
import { Widget } from "../widget";
export class KanbanView extends Widget<{}, { info: any }> {
inlineTemplate = `<div>kanban view: <span t-esc="props.info"/></div>`;
}
+5
View File
@@ -0,0 +1,5 @@
import { Widget } from "../widget";
export class ListView extends Widget<{}, { info: any }> {
inlineTemplate = `<div>list view: <span t-esc="props.info"/></div>`;
}
-5
View File
@@ -1,5 +0,0 @@
import { Widget } from "../widget";
export class View extends Widget<{}, { info: any }> {
inlineTemplate = `<div>some view: <span t-esc="props.info"/></div>`;
}
+8 -4
View File
@@ -1,6 +1,6 @@
import { readFile } from "fs"; import { readFile } from "fs";
import { BaseMenuItem, getMenuInfo } from "../../src/ts/loaders"; import { BaseMenuItem, getMenuInfo } from "../../src/ts/loaders";
import { actionRegistry } from "../../src/ts/registries"; import { actionRegistry, viewRegistry } from "../../src/ts/registries";
import { ActionDescription } from "../../src/ts/store/action_manager_mixin"; import { ActionDescription } from "../../src/ts/store/action_manager_mixin";
import { MenuInfo } from "../../src/ts/store/store"; import { MenuInfo } from "../../src/ts/store/store";
import { Registry } from "../../src/ts/core/registry"; import { Registry } from "../../src/ts/core/registry";
@@ -9,6 +9,7 @@ export interface TestData {
menuInfo: MenuInfo; menuInfo: MenuInfo;
actions: ActionDescription[]; actions: ActionDescription[];
actionRegistry: typeof actionRegistry; actionRegistry: typeof actionRegistry;
viewRegistry: typeof viewRegistry;
templates: string; templates: string;
} }
@@ -18,13 +19,16 @@ export async function makeTestData(): Promise<TestData> {
if (!templates) { if (!templates) {
templates = await loadTemplates(); templates = await loadTemplates();
} }
const registry: typeof actionRegistry = new Registry(); const _actionRegistry: typeof actionRegistry = new Registry();
(<any>registry).map = Object.assign({}, (<any>actionRegistry).map); (<any>_actionRegistry).map = Object.assign({}, (<any>actionRegistry).map);
const _viewRegistry: typeof actionRegistry = new Registry();
(<any>_viewRegistry).map = Object.assign({}, (<any>actionRegistry).map);
return { return {
menuInfo: makeMenuInfo(), menuInfo: makeMenuInfo(),
actions: makeActionData(), actions: makeActionData(),
actionRegistry: registry, actionRegistry: _actionRegistry,
viewRegistry: _viewRegistry,
templates templates
}; };
} }
+3 -1
View File
@@ -41,12 +41,14 @@ export function makeTestEnv(info: TestInfo = {}): TestEnv {
roots: [] roots: []
}; };
const actionRegistry = info.actionRegistry || new Registry(); const actionRegistry = info.actionRegistry || new Registry();
const viewRegistry = info.viewRegistry || new Registry();
const actions = info.actions || []; const actions = info.actions || [];
const data: TestData = { const data: TestData = {
menuInfo, menuInfo,
actions, actions,
actionRegistry, actionRegistry,
viewRegistry,
templates templates
}; };
@@ -63,7 +65,7 @@ export function makeTestEnv(info: TestInfo = {}): TestEnv {
router: info.router || new MockRouter() router: info.router || new MockRouter()
}; };
const store = new Store(services, menuInfo, actionRegistry); const store = new Store(services, menuInfo, actionRegistry, viewRegistry);
const env = makeEnv(store, templates); const env = makeEnv(store, templates);
const testEnv = Object.assign({ store }, env); const testEnv = Object.assign({ store }, env);
return testEnv; return testEnv;
@@ -38,3 +38,15 @@ test("display a warning if client action is not in registry", async () => {
expect(notifs.length).toBe(1); expect(notifs.length).toBe(1);
expect(notifs[0].type).toBe("warning"); expect(notifs[0].type).toBe("warning");
}); });
test("display a warning if view is not in registry", async () => {
const data = await makeTestData();
data.viewRegistry = new Registry();
const testEnv = makeTestEnv(data);
await testEnv.store.doAction(250);
const notifs = testEnv.store.state.notifications;
expect(notifs.length).toBe(1);
expect(notifs[0].type).toBe("warning");
});
@@ -118,6 +118,40 @@ exports[`if url has action_id, will render action and navigate to proper menu_id
</div>" </div>"
`; `;
exports[`open act window action with invalid viewtype => empty widget is rendered + warning 1`] = `
"<div class=\\"o_web_client\\">
<div class=\\"o_navbar\\">
<a aria-label=\\"Applications\\" class=\\"o_title fa fa-th\\" href=\\"#\\" title=\\"Applications\\" accesskey=\\"h\\"></a>
<a class=\\"o_menu_brand\\" href=\\"\\" role=\\"button\\">
Notes
</a>
<ul class=\\"o_menu_sections\\">
</ul>
</div>
<div class=\\"o_content\\"><div></div></div>
<div class=\\"o_notification_container\\">
<div class=\\"o_notification o_error\\">
<div class=\\"o_notification_title\\">
<span class=\\"o_icon fa fa-3x fa-exclamation\\" role=\\"img\\" aria-label=\\"Notification Invalid View type\\" title=\\"Notification Invalid View type\\"></span>
Invalid View type
</div>
<div class=\\"o_notification_content\\">
Cannot find view of type 'kanban' in the view registry
</div>
</div>
</div>
<div class=\\"o_loading d-none\\">Loading</div>
</div>"
`;
exports[`start with no action => clicks on client action => discuss is rendered 1`] = ` exports[`start with no action => clicks on client action => discuss is rendered 1`] = `
"<div class=\\"o_web_client\\"> "<div class=\\"o_web_client\\">
<div class=\\"o_navbar\\"> <div class=\\"o_navbar\\">
+14
View File
@@ -76,3 +76,17 @@ test("clicks on client action with invalid key => empty widget is rendered + war
expect(fixture.innerHTML).toMatchSnapshot(); expect(fixture.innerHTML).toMatchSnapshot();
}); });
test("open act window action with invalid viewtype => empty widget is rendered + warning", async () => {
const data = await makeTestData();
data.viewRegistry = new Registry();
const testEnv = makeTestEnv(data);
const root = new Root(testEnv, testEnv.store);
await root.mount(fixture);
// note menu item
await (<any>document.querySelector('[data-menu="205"]')).click();
await helpers.nextTick();
expect(fixture.innerHTML).toMatchSnapshot();
});