implement store, refactoring

This commit is contained in:
Géry Debongnie
2019-02-19 20:47:21 +01:00
parent 6ce1af636d
commit 7f3886ebba
20 changed files with 376 additions and 467 deletions
-105
View File
@@ -1,105 +0,0 @@
import { IAjax } from "./ajax";
import { Type } from "../core/component";
import { EventBus } from "../core/event_bus";
import { Registry } from "../core/registry";
import { Widget } from "../widgets/widget";
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
export type ActionRequest = string | number;
export type Context = { [key: string]: any };
export interface CommonActionInfo {
id: number;
context: Context;
title: string;
target: "current" | "new";
}
export type ActionWidget = Type<Widget<{}, {}>>;
export interface ClientActionInfo extends CommonActionInfo {
type: "client";
name: string;
Widget: ActionWidget;
}
export interface ActWindowInfo extends CommonActionInfo {
type: "act_window";
view: string;
}
export interface ActionDescription {
id: number;
type: "ir.actions.act_window" | "ir.actions.client";
target: "current";
}
export type ActionInfo = ClientActionInfo | ActWindowInfo;
export type ActionStack = ActionInfo[];
export type ActionEvent = "action_stack_updated";
type Callback = (stack: ActionStack) => void;
export interface IActionManager {
doAction(request: ActionRequest): void;
on(event: ActionEvent, owner: any, callback: Callback): void;
getStack(): ActionStack;
}
//------------------------------------------------------------------------------
// Action Manager
//------------------------------------------------------------------------------
export class ActionManager extends EventBus implements IActionManager {
registry: Registry<ActionWidget>;
ajax: IAjax;
stack: ActionStack;
constructor(registry: Registry<ActionWidget>, ajax: IAjax) {
super();
this.registry = registry;
this.ajax = ajax;
this.stack = [];
}
doAction(request: ActionRequest) {
if (typeof request === "number") {
this.loadAction(request);
// this is an action ID
let name = request === 131 ? "discuss" : "crm";
let title =
request === 131 ? "Discuss" : request === 250 ? "Notes" : "CRM";
let Widget = this.registry.get(name);
this.stack = [
{
id: 1,
context: {},
target: "current",
type: "client",
name,
title,
Widget: Widget
}
];
this.trigger("action_stack_updated", this.stack);
}
}
private loadAction(id: number) {
this.ajax.rpc({
route: "web/action/load",
params: {
action_id: id
}
});
}
getStack(): ActionStack {
return [];
}
}
-84
View File
@@ -1,84 +0,0 @@
import { EventBus } from "../core/event_bus";
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
export interface RPCModelQuery {
model: string;
method: string;
args?: any[];
kwargs?: { [key: string]: any };
context?: { [key: string]: any };
}
export interface RPCControllerQuery {
route: string;
params: { [key: string]: any };
}
export type RPCQuery = RPCModelQuery | RPCControllerQuery;
type AjaxStatus = "loading" | "notloading";
export interface IAjax {
rpc(rpc: RPCQuery): Promise<any>;
on(event: "rpc_status", owner: any, callback: (status: AjaxStatus) => void);
}
interface RequestParameters {
route: string;
params: { [key: string]: any };
}
export type FetchMethod = (route: string, params: any) => Promise<any>;
//------------------------------------------------------------------------------
// Ajax
//------------------------------------------------------------------------------
export class Ajax extends EventBus implements IAjax {
fetch: FetchMethod;
counter: number = 0;
constructor(fetch: FetchMethod) {
super();
this.fetch = fetch;
}
async rpc(rpc: RPCQuery): Promise<any> {
const request = this.prepareRequest(rpc);
if (this.counter === 0) {
this.trigger("rpc_status", "loading");
}
this.counter++;
const result = await this.fetch(request.route, request.params);
this.counter--;
if (this.counter === 0) {
this.trigger("rpc_status", "notloading");
}
return result;
}
private prepareRequest(query: RPCQuery): RequestParameters {
let route: string;
let params = "params" in query ? query.params : {};
if ("route" in query) {
route = query.route;
} else if ("model" in query && "method" in query) {
route = `/web/dataset/call_kw/${query.model}/${query.method}`;
params.args = query.args || [];
params.model = query.model;
params.method = query.method;
params.kwargs = Object.assign(params.kwargs || {}, query.kwargs);
params.kwargs.context =
query.context || params.context || params.kwargs.context;
} else {
throw new Error("Invalid Query");
}
// doing this remove empty keys, and undefined stuff
const sanitizedParams = JSON.parse(JSON.stringify(params));
return { route, params: sanitizedParams };
}
}
-55
View File
@@ -1,55 +0,0 @@
import { EventBus as Bus } from "../core/event_bus";
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
export interface INotification {
id: number;
title: string;
message: string;
type: "notification" | "warning";
sticky: boolean;
}
export interface INotificationManager {
add(notif: Partial<INotification>): number;
close(id: number): void;
on(
event: "notification_added",
owner: any,
callback: (notif: INotification) => void
): void;
on(
event: "notification_closed",
owner: any,
callback: (id: number) => void
): void;
}
//------------------------------------------------------------------------------
// Notification Manager
//------------------------------------------------------------------------------
export class NotificationManager extends Bus implements INotificationManager {
nextID = 1;
add(notif: Partial<INotification>): number {
const id = this.nextID++;
const defaultVals = {
title: "",
message: "",
type: "notification",
sticky: false
};
const notification = Object.assign(defaultVals, notif, { id });
this.trigger("notification_added", notification);
if (!notification.sticky) {
setTimeout(() => this.close(id), 2500);
}
return id;
}
close(id: number) {
this.trigger("notification_closed", id);
}
}
-67
View File
@@ -1,67 +0,0 @@
import { EventBus, Callback } from "../core/event_bus";
//------------------------------------------------------------------------------
// Types and helpers
//------------------------------------------------------------------------------
export type Query = { [key: string]: string };
function clearSlashes(s: string): string {
return s.replace(/\/$/, "").replace(/^\//, "");
}
export type RouterEvent = "query_changed";
export interface IRouter {
navigate(query: Query): void;
on(event: RouterEvent, owner: any, callback: Callback): void;
getQuery(): Query;
formatURL(path: string, query: Query): string;
}
//------------------------------------------------------------------------------
// Router
//------------------------------------------------------------------------------
export class Router extends EventBus implements IRouter {
currentQuery: Query;
constructor() {
super();
this.currentQuery = this.getQuery();
window.onhashchange = () => {
this.currentQuery = this.getQuery();
this.trigger("query_changed", this.currentQuery);
};
}
/**
* @param {Query} query
*/
navigate(query: Query) {
const url = this.formatURL("", query);
window.history.replaceState(null, document.title, url);
}
formatQuery(query: Query): string {
let parts: string[] = [];
for (let key in query) {
parts.push(`${key}=${query[key]}`);
}
return parts.join("&");
}
formatURL(path: string, query: Query): string {
let url = clearSlashes(path);
return `/${url}#${this.formatQuery(query)}`;
}
getQuery(): Query {
const query = {};
for (let part of window.location.hash.slice(1).split("&")) {
let [key, value] = part.split("=");
query[key] = value;
}
return query;
}
}