From 4b02b7444050807e53bdfff88c0b9c9fd7556bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Wed, 6 Mar 2019 17:36:22 +0100 Subject: [PATCH] add different view types --- web/static/src/ts/main.ts | 4 +-- web/static/src/ts/registries.ts | 18 ++++++++++ .../src/ts/store/action_manager_mixin.ts | 13 +++++-- web/static/src/ts/store/store.ts | 10 ++++-- web/static/src/ts/views/form_view.ts | 5 +++ web/static/src/ts/views/kanban_view.ts | 5 +++ web/static/src/ts/views/list_view.ts | 5 +++ web/static/src/ts/views/view.ts | 5 --- web/static/tests/helpers/test_data.ts | 12 ++++--- web/static/tests/helpers/test_env.ts | 4 ++- .../tests/store/action_manager_mixin_test.ts | 12 +++++++ .../tests/ui/__snapshots__/root.test.ts.snap | 34 +++++++++++++++++++ web/static/tests/ui/root.test.ts | 14 ++++++++ 13 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 web/static/src/ts/views/form_view.ts create mode 100644 web/static/src/ts/views/kanban_view.ts create mode 100644 web/static/src/ts/views/list_view.ts delete mode 100644 web/static/src/ts/views/view.ts diff --git a/web/static/src/ts/main.ts b/web/static/src/ts/main.ts index dc8f5d93..780b1583 100644 --- a/web/static/src/ts/main.ts +++ b/web/static/src/ts/main.ts @@ -2,7 +2,7 @@ import { makeEnv } from "./env"; import { loadMenus, loadTemplates } from "./loaders"; -import { actionRegistry } from "./registries"; +import { actionRegistry, viewRegistry } from "./registries"; import { rpc } from "./services/ajax"; import { Router } from "./services/router"; import { Store } from "./store/store"; @@ -20,7 +20,7 @@ document.addEventListener("DOMContentLoaded", async function() { const templates = await loadTemplates(); const menuInfo = loadMenus(); - const store = new Store(services, menuInfo, actionRegistry); + const store = new Store(services, menuInfo, actionRegistry, viewRegistry); const env = makeEnv(store, templates); // Creating root widget diff --git a/web/static/src/ts/registries.ts b/web/static/src/ts/registries.ts index 65449d69..2814f35f 100644 --- a/web/static/src/ts/registries.ts +++ b/web/static/src/ts/registries.ts @@ -1,6 +1,24 @@ import { Registry } from "./core/registry"; import { ControllerWidget } from "./store/store"; 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 = new Registry(); + +viewRegistry + .add("list", ListView) + .add("kanban", KanbanView) + .add("form", FormView); + +//------------------------------------------------------------------------------ +// Client Actions +//------------------------------------------------------------------------------ export const actionRegistry: Registry = new Registry(); diff --git a/web/static/src/ts/store/action_manager_mixin.ts b/web/static/src/ts/store/action_manager_mixin.ts index ddc81a15..86bcf7cf 100644 --- a/web/static/src/ts/store/action_manager_mixin.ts +++ b/web/static/src/ts/store/action_manager_mixin.ts @@ -1,7 +1,6 @@ import { Type } from "../core/component"; import { rpcMixin } from "./rpc_mixin"; import { Widget } from "../widget"; -import { View } from "../views/view"; //------------------------------------------------------------------------------ // Types @@ -82,11 +81,21 @@ export function actionManagerMixin>( } 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( this: Controller, parent: Widget ) { - 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"); await widget.mount(div); this.widget = widget; diff --git a/web/static/src/ts/store/store.ts b/web/static/src/ts/store/store.ts index 23a121f6..74970845 100644 --- a/web/static/src/ts/store/store.ts +++ b/web/static/src/ts/store/store.ts @@ -65,18 +65,21 @@ export class BaseStore extends EventBus { menuInfo: MenuInfo; services: Services; actionRegistry: Registry; + viewRegistry: Registry; currentQuery: Query; generateID = idGenerator(); constructor( services: Services, menuInfo: MenuInfo, - actionRegistry: Registry + actionRegistry: Registry, + viewRegistry: Registry ) { super(); this.services = services; this.menuInfo = menuInfo; this.actionRegistry = actionRegistry; + this.viewRegistry = viewRegistry; this.currentQuery = {}; } @@ -129,9 +132,10 @@ export class Store extends actionManagerMixin(rpcMixin(BaseStore)) { constructor( services: Services, menuInfo: MenuInfo, - actionRegistry: Registry + actionRegistry: Registry, + viewRegistry: Registry ) { - super(services, menuInfo, actionRegistry); + super(services, menuInfo, actionRegistry, viewRegistry); const query = this.services.router.getQuery(); let { app, actionId } = this.getAppAndAction(query); this.state.currentApp = app; diff --git a/web/static/src/ts/views/form_view.ts b/web/static/src/ts/views/form_view.ts new file mode 100644 index 00000000..47b06a97 --- /dev/null +++ b/web/static/src/ts/views/form_view.ts @@ -0,0 +1,5 @@ +import { Widget } from "../widget"; + +export class FormView extends Widget<{}, { info: any }> { + inlineTemplate = `
form view:
`; +} diff --git a/web/static/src/ts/views/kanban_view.ts b/web/static/src/ts/views/kanban_view.ts new file mode 100644 index 00000000..a205d495 --- /dev/null +++ b/web/static/src/ts/views/kanban_view.ts @@ -0,0 +1,5 @@ +import { Widget } from "../widget"; + +export class KanbanView extends Widget<{}, { info: any }> { + inlineTemplate = `
kanban view:
`; +} diff --git a/web/static/src/ts/views/list_view.ts b/web/static/src/ts/views/list_view.ts new file mode 100644 index 00000000..d0f12a06 --- /dev/null +++ b/web/static/src/ts/views/list_view.ts @@ -0,0 +1,5 @@ +import { Widget } from "../widget"; + +export class ListView extends Widget<{}, { info: any }> { + inlineTemplate = `
list view:
`; +} diff --git a/web/static/src/ts/views/view.ts b/web/static/src/ts/views/view.ts deleted file mode 100644 index a434e19b..00000000 --- a/web/static/src/ts/views/view.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Widget } from "../widget"; - -export class View extends Widget<{}, { info: any }> { - inlineTemplate = `
some view:
`; -} diff --git a/web/static/tests/helpers/test_data.ts b/web/static/tests/helpers/test_data.ts index 98cab580..1a7151c9 100644 --- a/web/static/tests/helpers/test_data.ts +++ b/web/static/tests/helpers/test_data.ts @@ -1,6 +1,6 @@ import { readFile } from "fs"; 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 { MenuInfo } from "../../src/ts/store/store"; import { Registry } from "../../src/ts/core/registry"; @@ -9,6 +9,7 @@ export interface TestData { menuInfo: MenuInfo; actions: ActionDescription[]; actionRegistry: typeof actionRegistry; + viewRegistry: typeof viewRegistry; templates: string; } @@ -18,13 +19,16 @@ export async function makeTestData(): Promise { if (!templates) { templates = await loadTemplates(); } - const registry: typeof actionRegistry = new Registry(); - (registry).map = Object.assign({}, (actionRegistry).map); + const _actionRegistry: typeof actionRegistry = new Registry(); + (_actionRegistry).map = Object.assign({}, (actionRegistry).map); + const _viewRegistry: typeof actionRegistry = new Registry(); + (_viewRegistry).map = Object.assign({}, (actionRegistry).map); return { menuInfo: makeMenuInfo(), actions: makeActionData(), - actionRegistry: registry, + actionRegistry: _actionRegistry, + viewRegistry: _viewRegistry, templates }; } diff --git a/web/static/tests/helpers/test_env.ts b/web/static/tests/helpers/test_env.ts index 2a6b7c55..c5e0fa3a 100644 --- a/web/static/tests/helpers/test_env.ts +++ b/web/static/tests/helpers/test_env.ts @@ -41,12 +41,14 @@ export function makeTestEnv(info: TestInfo = {}): TestEnv { roots: [] }; const actionRegistry = info.actionRegistry || new Registry(); + const viewRegistry = info.viewRegistry || new Registry(); const actions = info.actions || []; const data: TestData = { menuInfo, actions, actionRegistry, + viewRegistry, templates }; @@ -63,7 +65,7 @@ export function makeTestEnv(info: TestInfo = {}): TestEnv { 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 testEnv = Object.assign({ store }, env); return testEnv; diff --git a/web/static/tests/store/action_manager_mixin_test.ts b/web/static/tests/store/action_manager_mixin_test.ts index a1b28eed..89d41837 100644 --- a/web/static/tests/store/action_manager_mixin_test.ts +++ b/web/static/tests/store/action_manager_mixin_test.ts @@ -38,3 +38,15 @@ test("display a warning if client action is not in registry", async () => { expect(notifs.length).toBe(1); 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"); +}); diff --git a/web/static/tests/ui/__snapshots__/root.test.ts.snap b/web/static/tests/ui/__snapshots__/root.test.ts.snap index 397ef6de..97699ddb 100644 --- a/web/static/tests/ui/__snapshots__/root.test.ts.snap +++ b/web/static/tests/ui/__snapshots__/root.test.ts.snap @@ -118,6 +118,40 @@ exports[`if url has action_id, will render action and navigate to proper menu_id " `; +exports[`open act window action with invalid viewtype => empty widget is rendered + warning 1`] = ` +"
+
+ + + + Notes + +
    + + +
+ +
+ +
+
+ +
+ +
+ + Invalid View type +
+
+ Cannot find view of type 'kanban' in the view registry +
+
+ +
+
Loading
+
" +`; + exports[`start with no action => clicks on client action => discuss is rendered 1`] = ` "
diff --git a/web/static/tests/ui/root.test.ts b/web/static/tests/ui/root.test.ts index 3fa1872f..e1e03eba 100644 --- a/web/static/tests/ui/root.test.ts +++ b/web/static/tests/ui/root.test.ts @@ -76,3 +76,17 @@ test("clicks on client action with invalid key => empty widget is rendered + war 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 (document.querySelector('[data-menu="205"]')).click(); + await helpers.nextTick(); + + expect(fixture.innerHTML).toMatchSnapshot(); +});