diff --git a/web/static/src/ts/core/event_bus.ts b/web/static/src/ts/core/event_bus.ts index 5a224f87..bcbd9fb6 100644 --- a/web/static/src/ts/core/event_bus.ts +++ b/web/static/src/ts/core/event_bus.ts @@ -22,7 +22,7 @@ export interface Subscription { //------------------------------------------------------------------------------ export class EventBus { - private subscriptions: { [eventType: string]: Subscription[] } = {}; + subscriptions: { [eventType: string]: Subscription[] } = {}; /** * Add a listener for the 'eventType' events. diff --git a/web/static/src/ts/env.ts b/web/static/src/ts/env.ts index fdb64f52..c9aae2c9 100644 --- a/web/static/src/ts/env.ts +++ b/web/static/src/ts/env.ts @@ -1,7 +1,7 @@ import { WEnv } from "./core/component"; import { QWeb } from "./core/qweb_vdom"; import { idGenerator } from "./core/utils"; -import { INotification, RPC, Services, Store } from "./store"; +import { INotification, RPC, Services, Store } from "./store/store"; //------------------------------------------------------------------------------ // Types diff --git a/web/static/src/ts/loaders.ts b/web/static/src/ts/loaders.ts index 696808a2..7bc3570d 100644 --- a/web/static/src/ts/loaders.ts +++ b/web/static/src/ts/loaders.ts @@ -1,5 +1,5 @@ import { findInTree } from "./core/utils"; -import { MenuInfo, MenuItem } from "./store"; +import { MenuInfo, MenuItem } from "./store/store"; //------------------------------------------------------------------------------ // Templates diff --git a/web/static/src/ts/main.ts b/web/static/src/ts/main.ts index cb5711cc..c9e204dd 100644 --- a/web/static/src/ts/main.ts +++ b/web/static/src/ts/main.ts @@ -5,7 +5,7 @@ import { loadMenus, loadTemplates } from "./loaders"; import { actionRegistry } from "./registries"; import { rpc } from "./services/ajax"; import { Router } from "./services/router"; -import { Store } from "./store"; +import { Store } from "./store/store"; import { Root } from "./widgets/root"; //------------------------------------------------------------------------------ diff --git a/web/static/src/ts/registries.ts b/web/static/src/ts/registries.ts index 774f7545..287284c3 100644 --- a/web/static/src/ts/registries.ts +++ b/web/static/src/ts/registries.ts @@ -1,5 +1,5 @@ import { Registry } from "./core/registry"; -import { ActionWidget } from "./store"; +import { ActionWidget } from "./store/store"; import { CRM } from "./widgets/crm"; import { Discuss } from "./widgets/discuss"; diff --git a/web/static/src/ts/store.ts b/web/static/src/ts/store.ts deleted file mode 100644 index 3da1894e..00000000 --- a/web/static/src/ts/store.ts +++ /dev/null @@ -1,336 +0,0 @@ -import { Type } from "./core/component"; -import { EventBus } from "./core/event_bus"; -import { Registry } from "./core/registry"; -import { RPC } from "./services/ajax"; -import { IRouter, Query } from "./services/router"; -import { Widget } from "./widgets/widget"; -import { idGenerator } from "./core/utils"; - -//------------------------------------------------------------------------------ -// Types -//------------------------------------------------------------------------------ - -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 { - stack: ActionStack; - inHome: boolean; - currentApp: MenuItem | null; -} - -export interface Services { - rpc: RPC; - router: IRouter; -} - -export type Context = { [key: string]: any }; - -export interface CommonActionInfo { - id: number; - context: Context; - title: string; - target: "current" | "new"; -} - -export type ActionRequest = string | number; - -export type ActionWidget = Type>; - -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[]; - -//------------------------------------------------------------------------------ -// Store -//------------------------------------------------------------------------------ -class BaseStore extends EventBus { - state: State = { - stack: [], - inHome: false, - currentApp: null - }; - menuInfo: MenuInfo; - services: Services; - actionRegistry: Registry; - - constructor( - services: Services, - menuInfo: MenuInfo, - actionRegistry: Registry - ) { - super(); - this.services = services; - this.menuInfo = menuInfo; - this.actionRegistry = actionRegistry; - } - - update(nextState: Partial) { - 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 }); - } -} - -export class Store extends actionManagerMixin( - rpcMixin(notificationMixin(BaseStore)) -) {} - -//------------------------------------------------------------------------------ -// RPC Mixin -//------------------------------------------------------------------------------ - -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; - -export type RPC = (rpc: RPCQuery) => Promise; - -interface RequestParameters { - route: string; - params: { [key: string]: any }; -} - -function rpcMixin>(Base: T) { - return class extends Base { - counter: number = 0; - - async rpc(rpc: RPCQuery): Promise { - const request = this.prepareRequest(rpc); - if (this.counter === 0) { - this.trigger("rpc_status", "loading"); - } - this.counter++; - const result = await this.services.rpc(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 }; - } - }; -} - -//------------------------------------------------------------------------------ -// Notifications Mixin -//------------------------------------------------------------------------------ -export interface INotification { - id: number; - title: string; - message: string; - type: "notification" | "warning"; - sticky: boolean; -} - -function notificationMixin>(Base: T) { - return class extends Base { - private generateID = idGenerator(); - - addNotification(notif: Partial): number { - const id = this.generateID(); - 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.closeNotification(id), 2500); - } - return id; - } - - closeNotification(id: number) { - this.trigger("notification_closed", id); - } - }; -} - -//------------------------------------------------------------------------------ -// Action Manager Mixin -//------------------------------------------------------------------------------ - -function actionManagerMixin>(Base: T) { - return class extends Base { - constructor(...args) { - super(...args); - 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.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 }); - } - this.services.router.navigate(query); - return this.doAction(actionId); - } else { - this.update({ inHome: true, currentApp: newApp }); - } - } - - private getAppAndAction( - query: Query - ): { app: MenuItem | null; actionId: number | null } { - const menuInfo = this.menuInfo; - let app: MenuItem | null = null; - let actionId: number | null = null; - if ("action_id" in query) { - actionId = parseInt(query.action_id, 10); - if (menuInfo.actionMap[actionId]) { - const menu = menuInfo.actionMap[actionId]!; - app = menu.app; - } - } - if ("menu_id" in query) { - 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 }; - } - - async doAction(request: ActionRequest) { - if (typeof request === "number") { - await 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.actionRegistry.get(name); - this.update({ - inHome: false, - stack: [ - { - id: 1, - context: {}, - target: "current", - type: "client", - name, - title, - Widget: Widget - } - ] - }); - } - } - - private loadAction(id: number) { - return this.rpc({ - route: "web/action/load", - params: { - action_id: id - } - }); - } - }; -} diff --git a/web/static/src/ts/store/action_manager_mixin.ts b/web/static/src/ts/store/action_manager_mixin.ts new file mode 100644 index 00000000..42b061e8 --- /dev/null +++ b/web/static/src/ts/store/action_manager_mixin.ts @@ -0,0 +1,80 @@ +import { Type } from "../core/component"; +import { rpcMixin } from "./rpc_mixin"; +import { Widget } from "../widgets/widget"; + +export type Context = { [key: string]: any }; + +export interface CommonActionInfo { + id: number; + context: Context; + title: string; + target: "current" | "new"; +} + +export type ActionRequest = string | number; + +export type ActionWidget = Type>; + +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[]; + +//------------------------------------------------------------------------------ +// Action Manager Mixin +//------------------------------------------------------------------------------ + +export function actionManagerMixin>( + Base: T +) { + return class extends Base { + async doAction(request: ActionRequest) { + if (typeof request === "number") { + await 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.actionRegistry.get(name); + this.update({ + inHome: false, + stack: [ + { + id: 1, + context: {}, + target: "current", + type: "client", + name, + title, + Widget: Widget + } + ] + }); + } + } + + loadAction(id: number) { + return this.rpc({ + route: "web/action/load", + params: { + action_id: id + } + }); + } + }; +} diff --git a/web/static/src/ts/store/notification_mixin.ts b/web/static/src/ts/store/notification_mixin.ts new file mode 100644 index 00000000..4fdd4c35 --- /dev/null +++ b/web/static/src/ts/store/notification_mixin.ts @@ -0,0 +1,40 @@ +import { Type } from "../core/component"; +import { BaseStore } from "./store"; +import { idGenerator } from "../core/utils"; + +//------------------------------------------------------------------------------ +// Notifications Mixin +//------------------------------------------------------------------------------ +export interface INotification { + id: number; + title: string; + message: string; + type: "notification" | "warning"; + sticky: boolean; +} + +export function notificationMixin>(Base: T) { + return class extends Base { + generateID = idGenerator(); + + addNotification(notif: Partial): number { + const id = this.generateID(); + 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.closeNotification(id), 2500); + } + return id; + } + + closeNotification(id: number) { + this.trigger("notification_closed", id); + } + }; +} diff --git a/web/static/src/ts/store/rpc_mixin.ts b/web/static/src/ts/store/rpc_mixin.ts new file mode 100644 index 00000000..6708ae85 --- /dev/null +++ b/web/static/src/ts/store/rpc_mixin.ts @@ -0,0 +1,74 @@ +import { Type } from "../core/component"; +import { BaseStore } from "./store"; + +//------------------------------------------------------------------------------ +// 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; + +export type RPC = (rpc: RPCQuery) => Promise; + +export interface RequestParameters { + route: string; + params: { [key: string]: any }; +} + +//------------------------------------------------------------------------------ +// rpc Mixin +//------------------------------------------------------------------------------ + +export function rpcMixin>(Base: T) { + return class extends Base { + counter: number = 0; + + async rpc(rpc: RPCQuery): Promise { + const request = this.prepareRequest(rpc); + if (this.counter === 0) { + this.trigger("rpc_status", "loading"); + } + this.counter++; + const result = await this.services.rpc(request.route, request.params); + this.counter--; + if (this.counter === 0) { + this.trigger("rpc_status", "notloading"); + } + return result; + } + + 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 }; + } + }; +} diff --git a/web/static/src/ts/store/store.ts b/web/static/src/ts/store/store.ts new file mode 100644 index 00000000..6bfd493e --- /dev/null +++ b/web/static/src/ts/store/store.ts @@ -0,0 +1,166 @@ +import { EventBus } from "../core/event_bus"; +import { Registry } from "../core/registry"; +import { RPC } from "../services/ajax"; +import { IRouter, Query } from "../services/router"; +import { + actionManagerMixin, + ActionStack, + ActionWidget +} from "./action_manager_mixin"; +import { notificationMixin } from "./notification_mixin"; +import { rpcMixin } from "./rpc_mixin"; +import { MenuItem } from "./store"; + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +export { ActionStack, ActionWidget } from "./action_manager_mixin"; +export { INotification } from "./notification_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 { + stack: ActionStack; + inHome: boolean; + currentApp: MenuItem | null; +} + +export interface Services { + rpc: RPC; + router: IRouter; +} + +//------------------------------------------------------------------------------ +// Store +//------------------------------------------------------------------------------ +export class BaseStore extends EventBus { + state: State = { + stack: [], + inHome: false, + currentApp: null + }; + menuInfo: MenuInfo; + services: Services; + actionRegistry: Registry; + + constructor( + services: Services, + menuInfo: MenuInfo, + actionRegistry: Registry + ) { + super(); + this.services = services; + this.menuInfo = menuInfo; + this.actionRegistry = actionRegistry; + } + + update(nextState: Partial) { + 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 }); + } +} + +export class Store extends actionManagerMixin( + rpcMixin(notificationMixin(BaseStore)) +) { + constructor( + services: Services, + menuInfo: MenuInfo, + actionRegistry: Registry + ) { + 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.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 }); + } + this.services.router.navigate(query); + return this.doAction(actionId); + } 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 ("action_id" in query) { + actionId = parseInt(query.action_id, 10); + if (menuInfo.actionMap[actionId]) { + const menu = menuInfo.actionMap[actionId]!; + app = menu.app; + } + } + if ("menu_id" in query) { + 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 }; + } +} diff --git a/web/static/src/ts/widgets/Navbar.ts b/web/static/src/ts/widgets/Navbar.ts index ef1ab483..1dd41818 100644 --- a/web/static/src/ts/widgets/Navbar.ts +++ b/web/static/src/ts/widgets/Navbar.ts @@ -1,4 +1,4 @@ -import { MenuItem } from "../store"; +import { MenuItem } from "../store/store"; import { PureWidget } from "./widget"; //------------------------------------------------------------------------------ diff --git a/web/static/src/ts/widgets/action_container.ts b/web/static/src/ts/widgets/action_container.ts index 7a0aa589..8f9b7059 100644 --- a/web/static/src/ts/widgets/action_container.ts +++ b/web/static/src/ts/widgets/action_container.ts @@ -1,4 +1,4 @@ -import { ActionStack } from "../store"; +import { ActionStack } from "../store/store"; import { Widget } from "./widget"; //------------------------------------------------------------------------------ diff --git a/web/static/src/ts/widgets/home_menu.ts b/web/static/src/ts/widgets/home_menu.ts index 1fcda647..543f5e36 100644 --- a/web/static/src/ts/widgets/home_menu.ts +++ b/web/static/src/ts/widgets/home_menu.ts @@ -1,4 +1,4 @@ -import { MenuInfo, MenuItem } from "../store"; +import { MenuInfo, MenuItem } from "../store/store"; import { Widget } from "./widget"; //------------------------------------------------------------------------------ diff --git a/web/static/src/ts/widgets/notification.ts b/web/static/src/ts/widgets/notification.ts index cd3a11af..1b5947c1 100644 --- a/web/static/src/ts/widgets/notification.ts +++ b/web/static/src/ts/widgets/notification.ts @@ -1,4 +1,4 @@ -import { INotification } from "../store"; +import { INotification } from "../store/store"; import { Widget } from "./widget"; export class Notification extends Widget { diff --git a/web/static/src/ts/widgets/root.ts b/web/static/src/ts/widgets/root.ts index c12d9f92..2aba1659 100644 --- a/web/static/src/ts/widgets/root.ts +++ b/web/static/src/ts/widgets/root.ts @@ -1,6 +1,6 @@ import { debounce } from "../core/utils"; import { Env } from "../env"; -import { State, Store } from "../store"; +import { State, Store } from "../store/store"; import { ActionContainer } from "./action_container"; import { HomeMenu } from "./home_menu"; import { Navbar } from "./navbar"; diff --git a/web/static/tests/helpers.ts b/web/static/tests/helpers.ts index 6be9228d..976e468a 100644 --- a/web/static/tests/helpers.ts +++ b/web/static/tests/helpers.ts @@ -6,7 +6,7 @@ import { idGenerator } from "../src/ts/core/utils"; import { getMenuInfo } from "../src/ts/loaders"; import { actionRegistry } from "../src/ts/registries"; import { IRouter, Query, RouterEvent } from "../src/ts/services/router"; -import { MenuInfo, Services, Store } from "../src/ts/store"; +import { MenuInfo, Services, Store } from "../src/ts/store/store"; export function makeTestFixture() { let fixture = document.createElement("div"); diff --git a/web/static/tests/widgets/action_container.test.ts b/web/static/tests/widgets/action_container.test.ts index e3f22c80..2e567ba2 100644 --- a/web/static/tests/widgets/action_container.test.ts +++ b/web/static/tests/widgets/action_container.test.ts @@ -1,5 +1,5 @@ import { Env, makeEnv } from "../../src/ts/env"; -import { ActionStack, Store } from "../../src/ts/store"; +import { ActionStack, Store } from "../../src/ts/store/store"; import { ActionContainer, Props } from "../../src/ts/widgets/action_container"; import { Widget } from "../../src/ts/widgets/widget"; import * as helpers from "../helpers"; diff --git a/web/static/tests/widgets/home_menu.test.ts b/web/static/tests/widgets/home_menu.test.ts index 420b3177..c8bc0eed 100644 --- a/web/static/tests/widgets/home_menu.test.ts +++ b/web/static/tests/widgets/home_menu.test.ts @@ -1,5 +1,5 @@ import { Env, makeEnv } from "../../src/ts/env"; -import { Store } from "../../src/ts/store"; +import { Store } from "../../src/ts/store/store"; import { HomeMenu, Props } from "../../src/ts/widgets/home_menu"; import * as helpers from "../helpers"; diff --git a/web/static/tests/widgets/navbar.test.ts b/web/static/tests/widgets/navbar.test.ts index c7d06cc4..378e39d9 100644 --- a/web/static/tests/widgets/navbar.test.ts +++ b/web/static/tests/widgets/navbar.test.ts @@ -1,5 +1,5 @@ import { Env, makeEnv } from "../../src/ts/env"; -import { MenuInfo, Store } from "../../src/ts/store"; +import { MenuInfo, Store } from "../../src/ts/store/store"; import { Navbar, Props } from "../../src/ts/widgets/navbar"; import * as helpers from "../helpers"; diff --git a/web/static/tests/widgets/notification.test.ts b/web/static/tests/widgets/notification.test.ts index c3639a35..b4deb466 100644 --- a/web/static/tests/widgets/notification.test.ts +++ b/web/static/tests/widgets/notification.test.ts @@ -1,5 +1,5 @@ import { Env, makeEnv } from "../../src/ts/env"; -import { INotification, Store } from "../../src/ts/store"; +import { INotification, Store } from "../../src/ts/store/store"; import { Notification } from "../../src/ts/widgets/notification"; import * as helpers from "../helpers"; diff --git a/web/static/tests/widgets/root.test.ts b/web/static/tests/widgets/root.test.ts index bcc8b504..8c862956 100644 --- a/web/static/tests/widgets/root.test.ts +++ b/web/static/tests/widgets/root.test.ts @@ -1,5 +1,5 @@ import { Env, makeEnv } from "../../src/ts/env"; -import { Store } from "../../src/ts/store"; +import { Store } from "../../src/ts/store/store"; import { Root } from "../../src/ts/widgets/root"; import * as helpers from "../helpers";