mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
203 lines
5.4 KiB
TypeScript
203 lines
5.4 KiB
TypeScript
import { EventBus } from "../core/event_bus";
|
|
import { Registry } from "../core/registry";
|
|
import { idGenerator } from "../core/utils";
|
|
import { RPC } from "../services/ajax";
|
|
import { IRouter, Query } from "../services/router";
|
|
import { actionManagerMixin, ControllerWidget } from "./action_manager_mixin";
|
|
import { rpcMixin } from "./rpc_mixin";
|
|
import { MenuItem } from "./store";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Types
|
|
//------------------------------------------------------------------------------
|
|
|
|
export { ControllerWidget } from "./action_manager_mixin";
|
|
export { RPC } from "./rpc_mixin";
|
|
|
|
export interface MenuItem {
|
|
id: number;
|
|
name: string;
|
|
parentId: number | false;
|
|
action: string | false;
|
|
icon: string | false;
|
|
|
|
// root menu id
|
|
app: MenuItem;
|
|
actionId: number;
|
|
children: MenuItem[];
|
|
}
|
|
|
|
export interface MenuInfo {
|
|
menus: { [key: number]: MenuItem | undefined };
|
|
|
|
actionMap: { [id: number]: MenuItem | undefined };
|
|
roots: number[];
|
|
}
|
|
|
|
export interface State {
|
|
inHome: boolean;
|
|
currentApp: MenuItem | null;
|
|
notifications: Notification[];
|
|
}
|
|
|
|
export interface Services {
|
|
rpc: RPC;
|
|
router: IRouter;
|
|
}
|
|
|
|
export interface Notification {
|
|
id: number;
|
|
title: string;
|
|
message: string;
|
|
type: "notification" | "warning";
|
|
sticky: boolean;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Store
|
|
//------------------------------------------------------------------------------
|
|
export class BaseStore extends EventBus {
|
|
state: State = {
|
|
inHome: false,
|
|
currentApp: null,
|
|
notifications: []
|
|
};
|
|
menuInfo: MenuInfo;
|
|
services: Services;
|
|
actionRegistry: Registry<ControllerWidget>;
|
|
currentQuery: Query;
|
|
generateID = idGenerator();
|
|
|
|
constructor(
|
|
services: Services,
|
|
menuInfo: MenuInfo,
|
|
actionRegistry: Registry<ControllerWidget>
|
|
) {
|
|
super();
|
|
this.services = services;
|
|
this.menuInfo = menuInfo;
|
|
this.actionRegistry = actionRegistry;
|
|
this.currentQuery = {};
|
|
}
|
|
|
|
update(nextState: Partial<State>) {
|
|
Object.assign(this.state, nextState);
|
|
this.trigger("state_updated", this.state);
|
|
}
|
|
|
|
toggleHomeMenu() {
|
|
if (this.state.inHome && !this.state.currentApp) {
|
|
return;
|
|
}
|
|
this.update({ inHome: !this.state.inHome });
|
|
if (this.state.inHome) {
|
|
this.services.router.navigate({ home: true });
|
|
} else {
|
|
this.updateQuery(this.currentQuery);
|
|
}
|
|
}
|
|
|
|
updateQuery(query: Query) {
|
|
this.currentQuery = query;
|
|
this.services.router.navigate(query);
|
|
}
|
|
|
|
addNotification(notif: Partial<Notification>): number {
|
|
const id = this.generateID();
|
|
const defaultVals = {
|
|
title: "",
|
|
message: "",
|
|
type: "notification",
|
|
sticky: false
|
|
};
|
|
const notification = Object.assign(defaultVals, notif, { id });
|
|
const notifs = this.state.notifications.concat(notification);
|
|
this.update({ notifications: notifs });
|
|
if (!notification.sticky) {
|
|
setTimeout(() => this.closeNotification(id), 2500);
|
|
}
|
|
return id;
|
|
}
|
|
|
|
closeNotification(id: number) {
|
|
const notifs = this.state.notifications.filter(n => n.id !== id);
|
|
this.update({ notifications: notifs });
|
|
}
|
|
}
|
|
|
|
export class Store extends actionManagerMixin(rpcMixin(BaseStore)) {
|
|
constructor(
|
|
services: Services,
|
|
menuInfo: MenuInfo,
|
|
actionRegistry: Registry<ControllerWidget>
|
|
) {
|
|
super(services, menuInfo, actionRegistry);
|
|
const query = this.services.router.getQuery();
|
|
let { app, actionId } = this.getAppAndAction(query);
|
|
this.state.currentApp = app;
|
|
if (!actionId) {
|
|
this.state.inHome = true;
|
|
this.services.router.navigate({ home: true });
|
|
}
|
|
this.services.router.on("query_changed", this, this.updateAction);
|
|
this.updateAction(this.services.router.getQuery());
|
|
}
|
|
|
|
private updateAction(query: Query) {
|
|
let { app, actionId } = this.getAppAndAction(query);
|
|
this.updateAppState(app, actionId);
|
|
}
|
|
|
|
activateMenuItem(menuId: number) {
|
|
const menu = this.menuInfo.menus[menuId];
|
|
if (!menu) {
|
|
throw new Error("Invalid menu id");
|
|
}
|
|
return this.updateAppState(menu.app, menu.actionId);
|
|
}
|
|
|
|
private async updateAppState(app: MenuItem | null, actionId: number | null) {
|
|
const newApp = app || this.state.currentApp;
|
|
if (actionId) {
|
|
const query: Query = { action_id: String(actionId) };
|
|
const menuId = newApp ? newApp.app.id : false;
|
|
if (menuId) {
|
|
query.menu_id = String(menuId);
|
|
}
|
|
if (app) {
|
|
this.update({ currentApp: app });
|
|
}
|
|
await this.doAction(actionId);
|
|
this.updateQuery(query);
|
|
} else {
|
|
this.update({ inHome: true, currentApp: newApp });
|
|
}
|
|
}
|
|
|
|
getAppAndAction(
|
|
query: Query
|
|
): { app: MenuItem | null; actionId: number | null } {
|
|
const menuInfo = this.menuInfo;
|
|
let app: MenuItem | null = null;
|
|
let actionId: number | null = null;
|
|
if (typeof query.action_id === "string") {
|
|
actionId = parseInt(query.action_id, 10);
|
|
if (menuInfo.actionMap[actionId]) {
|
|
const menu = menuInfo.actionMap[actionId]!;
|
|
app = menu.app;
|
|
}
|
|
}
|
|
if (typeof query.menu_id === "string") {
|
|
const menuId = parseInt(query.menu_id, 10);
|
|
const menu = menuInfo.menus[menuId];
|
|
if (menu) {
|
|
app = menu.app;
|
|
if (!actionId) {
|
|
actionId = menu.actionId;
|
|
}
|
|
}
|
|
}
|
|
return { app, actionId };
|
|
}
|
|
}
|