From d24734ac4cd1c6ddda5ba39f033ce9eaa4dcda01 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 20 Jan 2022 18:06:23 +0100 Subject: feat: Add RuntimeService store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stores transient state for services shared between the main and renderer processes. Signed-off-by: Kristóf Marussy --- packages/main/src/stores/RuntimeService.ts | 74 ++++++++++++++++++ packages/main/src/stores/SharedStore.ts | 2 + packages/renderer/jest.config.js | 7 ++ packages/renderer/package.json | 5 ++ packages/renderer/src/env/RendererEnv.ts | 27 +++++++ packages/renderer/src/env/getEnv.ts | 34 +++++++++ packages/renderer/src/env/impl/RendererEnvImpl.ts | 55 ++++++++++++++ .../src/env/impl/__tests__/RendererEnvImpl.spec.ts | 87 ++++++++++++++++++++++ packages/renderer/src/stores/Config.ts | 32 ++++++++ packages/renderer/src/stores/RendererEnv.ts | 37 --------- packages/renderer/src/stores/RendererStore.ts | 21 ++---- packages/renderer/src/stores/Service.ts | 38 ++++++++++ packages/renderer/src/stores/SharedStore.ts | 35 +++++++++ .../renderer/src/stores/__tests__/Service.spec.ts | 63 ++++++++++++++++ packages/renderer/tsconfig.json | 3 +- packages/shared/src/index.ts | 7 ++ packages/shared/src/stores/RuntimeService.ts | 47 ++++++++++++ packages/shared/src/stores/SharedStore.ts | 2 + yarn.lock | 5 ++ 19 files changed, 530 insertions(+), 51 deletions(-) create mode 100644 packages/main/src/stores/RuntimeService.ts create mode 100644 packages/renderer/jest.config.js create mode 100644 packages/renderer/src/env/RendererEnv.ts create mode 100644 packages/renderer/src/env/getEnv.ts create mode 100644 packages/renderer/src/env/impl/RendererEnvImpl.ts create mode 100644 packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts create mode 100644 packages/renderer/src/stores/Config.ts delete mode 100644 packages/renderer/src/stores/RendererEnv.ts create mode 100644 packages/renderer/src/stores/Service.ts create mode 100644 packages/renderer/src/stores/SharedStore.ts create mode 100644 packages/renderer/src/stores/__tests__/Service.spec.ts create mode 100644 packages/shared/src/stores/RuntimeService.ts diff --git a/packages/main/src/stores/RuntimeService.ts b/packages/main/src/stores/RuntimeService.ts new file mode 100644 index 0000000..ecb1942 --- /dev/null +++ b/packages/main/src/stores/RuntimeService.ts @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { UnreadCount } from '@sophie/service-shared'; +import { runtimeService as originalRuntimeService } from '@sophie/shared'; +import { Instance } from 'mobx-state-tree'; + +export const runtimeService = originalRuntimeService.actions((self) => ({ + setLocation({ + url, + canGoBack, + canGoForward, + }: { + url: string; + canGoBack: boolean; + canGoForward: boolean; + }): void { + self.url = url; + self.canGoBack = canGoBack; + self.canGoForward = canGoForward; + }, + setTitle(title: string): void { + self.title = title; + }, + hibernated(): void { + self.canGoBack = false; + self.canGoForward = false; + self.state = 'hibernated'; + }, + startedLoading(): void { + self.state = 'loading'; + }, + finishedLoading(): void { + if (self.state === 'loading') { + // Do not overwrite crashed state if the service haven't been reloaded yet. + self.state = 'loaded'; + } + }, + crashed(): void { + self.state = 'crashed'; + }, + setUnreadCount({ direct, indirect }: UnreadCount): void { + if (direct !== undefined) { + self.directMessageCount = direct; + } + if (indirect !== undefined) { + self.indirectMessageCount = indirect; + } + }, +})); + +export interface RuntimeService extends Instance {} + +export type { + RuntimeServiceSnapshotIn, + RuntimeServiceSnapshotOut, +} from '@sophie/shared'; diff --git a/packages/main/src/stores/SharedStore.ts b/packages/main/src/stores/SharedStore.ts index 73245cd..76ce05c 100644 --- a/packages/main/src/stores/SharedStore.ts +++ b/packages/main/src/stores/SharedStore.ts @@ -22,6 +22,7 @@ import { sharedStore as originalSharedStore } from '@sophie/shared'; import { Instance, types } from 'mobx-state-tree'; import { config } from './Config'; +import { runtimeService } from './RuntimeService'; export type { SharedStoreSnapshotIn, @@ -30,6 +31,7 @@ export type { export const sharedStore = originalSharedStore.props({ config: types.optional(config, {}), + runtimeServices: types.map(runtimeService), }); export interface SharedStore extends Instance {} diff --git a/packages/renderer/jest.config.js b/packages/renderer/jest.config.js new file mode 100644 index 0000000..27af475 --- /dev/null +++ b/packages/renderer/jest.config.js @@ -0,0 +1,7 @@ +import rootConfig from '../../config/jest.config.base.js'; + +/** @type {import('@jest/types').Config.InitialOptions} */ +export default { + ...rootConfig, + testEnvironment: 'jsdom', +}; diff --git a/packages/renderer/package.json b/packages/renderer/package.json index 9e84159..cfd6e4b 100644 --- a/packages/renderer/package.json +++ b/packages/renderer/package.json @@ -24,10 +24,15 @@ "react-dom": "^17.0.2" }, "devDependencies": { + "@jest/globals": "^27.4.6", + "@types/jest": "^27.4.0", "@types/lodash-es": "^4.17.5", "@types/react": "^17.0.38", "@types/react-dom": "^17.0.11", "@vitejs/plugin-react": "^1.1.4", + "jest": "^27.4.7", + "jest-mock": "^27.4.6", + "jsdom": "^19.0.0", "mst-middlewares": "^5.1.0", "remotedev": "^0.2.9", "vite": "^2.7.13" diff --git a/packages/renderer/src/env/RendererEnv.ts b/packages/renderer/src/env/RendererEnv.ts new file mode 100644 index 0000000..5ca2978 --- /dev/null +++ b/packages/renderer/src/env/RendererEnv.ts @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021-2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import type { Action, RuntimeService } from '@sophie/shared'; + +export default interface RendererEnv { + dispatchMainAction(action: Action): void; + + getRuntimeService(serviceId: string): RuntimeService | undefined; +} diff --git a/packages/renderer/src/env/getEnv.ts b/packages/renderer/src/env/getEnv.ts new file mode 100644 index 0000000..4f7357a --- /dev/null +++ b/packages/renderer/src/env/getEnv.ts @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { getEnv as getAnyEnv, IAnyStateTreeNode } from 'mobx-state-tree'; + +import type RendererEnv from './RendererEnv'; + +/** + * Gets a well-typed environment from `model`. + * + * Only useable inside state trees created by `createAndConnectRootStore`. + * + * @param model The state tree node. + */ +export default function getEnv(model: IAnyStateTreeNode): RendererEnv { + return getAnyEnv(model); +} diff --git a/packages/renderer/src/env/impl/RendererEnvImpl.ts b/packages/renderer/src/env/impl/RendererEnvImpl.ts new file mode 100644 index 0000000..184d31b --- /dev/null +++ b/packages/renderer/src/env/impl/RendererEnvImpl.ts @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { + Action, + runtimeService, + RuntimeService, + SophieRenderer, +} from '@sophie/shared'; +import type { IMSTMap } from 'mobx-state-tree'; + +import type { RendererStore } from '../../stores/RendererStore'; +import type RendererEnv from '../RendererEnv'; + +export default class RendererEnvImpl implements RendererEnv { + readonly #ipc: SophieRenderer; + + #runtimeServices: IMSTMap | undefined; + + constructor(ipc: SophieRenderer) { + this.#ipc = ipc; + } + + setStore(store: RendererStore): void { + this.#runtimeServices = store.shared.runtimeServices; + } + + dispatchMainAction(action: Action): void { + this.#ipc.dispatchAction(action); + } + + getRuntimeService(serviceId: string): RuntimeService | undefined { + if (this.#runtimeServices === undefined) { + throw new Error('runtime services map is not yet set'); + } + return this.#runtimeServices.get(serviceId); + } +} diff --git a/packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts b/packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts new file mode 100644 index 0000000..d36462c --- /dev/null +++ b/packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { jest } from '@jest/globals'; +import { + Action, + runtimeService, + RuntimeService, + SophieRenderer, +} from '@sophie/shared'; + +import { rendererStore } from '../../../stores/RendererStore'; +import RendererEnvImpl from '../RendererEnvImpl'; + +const ipc: SophieRenderer = { + dispatchAction: jest.fn(), + onSharedStoreChange: jest.fn(), +}; +let sut: RendererEnvImpl; + +beforeEach(() => { + sut = new RendererEnvImpl(ipc); +}); + +describe('dispatchMainAction', () => { + it('should dispatch actions via the IPC', () => { + const action: Action = { + action: 'set-theme-source', + themeSource: 'dark', + }; + sut.dispatchMainAction(action); + expect(ipc.dispatchAction).toHaveBeenCalledWith(action); + }); +}); + +describe('getRuntimeService', () => { + describe('when no store was set', () => { + it('should throw an error', () => { + expect(() => sut.getRuntimeService('someId')).toThrow(); + }); + }); + + describe('when the store was set', () => { + let runtimeServiceStore: RuntimeService; + + beforeEach(() => { + runtimeServiceStore = runtimeService.create({ + state: 'loaded', + }); + const store = rendererStore.create({ + shared: { + runtimeServices: { + someId: runtimeServiceStore, + }, + }, + }); + sut.setStore(store); + }); + + it('should return the runtime service for the given ID', () => { + const returnedStore = sut.getRuntimeService('someId'); + expect(returnedStore).toBe(runtimeServiceStore); + }); + + it('should return undefined for an unknown ID', () => { + const returnedStore = sut.getRuntimeService('unknownId'); + expect(returnedStore).toBeUndefined(); + }); + }); +}); diff --git a/packages/renderer/src/stores/Config.ts b/packages/renderer/src/stores/Config.ts new file mode 100644 index 0000000..070c4ec --- /dev/null +++ b/packages/renderer/src/stores/Config.ts @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { config as originalConfig } from '@sophie/shared'; +import { Instance, types } from 'mobx-state-tree'; + +import { service } from './Service'; + +export const config = originalConfig.props({ + services: types.array(service), +}); + +export interface Config extends Instance {} + +export type { ConfigSnapshotIn, ConfigSnapshotOut } from '@sophie/shared'; diff --git a/packages/renderer/src/stores/RendererEnv.ts b/packages/renderer/src/stores/RendererEnv.ts deleted file mode 100644 index f0a5a51..0000000 --- a/packages/renderer/src/stores/RendererEnv.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2021-2022 Kristóf Marussy - * - * This file is part of Sophie. - * - * Sophie is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import type { Action } from '@sophie/shared'; -import { getEnv as getAnyEnv, IAnyStateTreeNode } from 'mobx-state-tree'; - -export default interface RendererEnv { - dispatchMainAction(action: Action): void; -} - -/** - * Gets a well-typed environment from `model`. - * - * Only useable inside state trees created by `createAndConnectRootStore`. - * - * @param model The state tree node. - */ -export function getEnv(model: IAnyStateTreeNode): RendererEnv { - return getAnyEnv(model); -} diff --git a/packages/renderer/src/stores/RendererStore.ts b/packages/renderer/src/stores/RendererStore.ts index f1915c9..d0e7843 100644 --- a/packages/renderer/src/stores/RendererStore.ts +++ b/packages/renderer/src/stores/RendererStore.ts @@ -18,20 +18,16 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { - BrowserViewBounds, - Config, - Service, - sharedStore, - SophieRenderer, - ThemeSource, -} from '@sophie/shared'; +import { BrowserViewBounds, SophieRenderer, ThemeSource } from '@sophie/shared'; import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree'; +import getEnv from '../env/getEnv'; +import RendererEnvImpl from '../env/impl/RendererEnvImpl'; import { getLogger } from '../utils/log'; -import type RendererEnv from './RendererEnv'; -import { getEnv } from './RendererEnv'; +import type { Config } from './Config'; +import type { Service } from './Service'; +import { sharedStore } from './SharedStore'; const log = getLogger('RendererStore'); @@ -82,10 +78,9 @@ export interface RendererStore extends Instance {} export function createAndConnectRendererStore( ipc: SophieRenderer, ): RendererStore { - const env: RendererEnv = { - dispatchMainAction: ipc.dispatchAction, - }; + const env = new RendererEnvImpl(ipc); const store = rendererStore.create({}, env); + env.setStore(store); ipc .onSharedStoreChange({ diff --git a/packages/renderer/src/stores/Service.ts b/packages/renderer/src/stores/Service.ts new file mode 100644 index 0000000..2f45106 --- /dev/null +++ b/packages/renderer/src/stores/Service.ts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { + runtimeService, + RuntimeService, + service as originalService, +} from '@sophie/shared'; +import { Instance } from 'mobx-state-tree'; + +import getEnv from '../env/getEnv'; + +export const service = originalService.views((self) => ({ + get runtime(): RuntimeService { + return getEnv(self).getRuntimeService(self.id) ?? runtimeService.create(); + }, +})); + +export interface Service extends Instance {} + +export type { ServiceSnapshotIn, ServiceSnapshotOut } from '@sophie/shared'; diff --git a/packages/renderer/src/stores/SharedStore.ts b/packages/renderer/src/stores/SharedStore.ts new file mode 100644 index 0000000..baaf061 --- /dev/null +++ b/packages/renderer/src/stores/SharedStore.ts @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { sharedStore as originalSharedStore } from '@sophie/shared'; +import { Instance, types } from 'mobx-state-tree'; + +import { config } from './Config'; + +export const sharedStore = originalSharedStore.props({ + config: types.optional(config, {}), +}); + +export interface SharedStore extends Instance {} + +export type { + SharedStoreSnapshotIn, + SharedStoreSnapshotOut, +} from '@sophie/shared'; diff --git a/packages/renderer/src/stores/__tests__/Service.spec.ts b/packages/renderer/src/stores/__tests__/Service.spec.ts new file mode 100644 index 0000000..f835d41 --- /dev/null +++ b/packages/renderer/src/stores/__tests__/Service.spec.ts @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { jest } from '@jest/globals'; +import { runtimeService } from '@sophie/shared'; +import { mocked } from 'jest-mock'; + +import type RendererEnv from '../../env/RendererEnv'; +import { service, Service } from '../Service'; + +const env: RendererEnv = { + dispatchMainAction: jest.fn(), + getRuntimeService: jest.fn(), +}; +let sut: Service; + +beforeEach(() => { + sut = service.create( + { + id: 'serviceId', + name: 'Foo', + url: 'https://example.com', + profile: 'profileId', + }, + env, + ); +}); + +describe('runtime', () => { + it('should return the runtime service with for the service ID', () => { + const runtimeServiceStore = runtimeService.create({}, env); + mocked(env.getRuntimeService).mockReturnValueOnce(runtimeServiceStore); + const returnedStore = sut.runtime; + expect(env.getRuntimeService).toHaveBeenCalledWith('serviceId'); + expect(returnedStore).toBe(runtimeServiceStore); + }); + + it('should return a valid runtime service even if none exists in the environment', () => { + /* + eslint-disable-next-line unicorn/no-useless-undefined -- + `mockReturnValueOnce` expects 1 parameter. + */ + mocked(env.getRuntimeService).mockReturnValueOnce(undefined); + expect(sut.runtime).toHaveProperty('state', 'hibernated'); + }); +}); diff --git a/packages/renderer/tsconfig.json b/packages/renderer/tsconfig.json index 5453330..4fe3896 100644 --- a/packages/renderer/tsconfig.json +++ b/packages/renderer/tsconfig.json @@ -4,7 +4,7 @@ "noEmit": true, "jsx": "react", "lib": ["dom", "dom.iterable", "esnext"], - "types": ["vite/client"] + "types": ["@types/jest", "vite/client"] }, "references": [ { @@ -16,6 +16,7 @@ "src/**/*.tsx", "types/**/*.d.ts", ".eslintrc.cjs", + "jest.config.js", "vite.config.js" ] } diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 9f4e9b3..df02854 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -39,6 +39,13 @@ export type { } from './stores/Profile'; export { profile } from './stores/Profile'; +export type { + RuntimeService, + RuntimeServiceSnapshotIn, + RuntimeServiceSnapshotOut, +} from './stores/RuntimeService'; +export { runtimeService } from './stores/RuntimeService'; + export type { Service, ServiceSnapshotIn, diff --git a/packages/shared/src/stores/RuntimeService.ts b/packages/shared/src/stores/RuntimeService.ts new file mode 100644 index 0000000..c5b9031 --- /dev/null +++ b/packages/shared/src/stores/RuntimeService.ts @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 Kristóf Marussy + * + * This file is part of Sophie. + * + * Sophie is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Instance, types, SnapshotIn, SnapshotOut } from 'mobx-state-tree'; + +export const runtimeService = types.model({ + url: types.maybe(types.string), + canGoBack: false, + canGoForward: false, + title: types.maybe(types.string), + state: types.optional( + types.enumeration('ServiceState', [ + 'hibernated', + 'loading', + 'loaded', + 'crashed', + ]), + 'hibernated', + ), + directMessageCount: 0, + indirectMessageCount: 0, +}); + +export interface RuntimeService extends Instance {} + +export interface RuntimeServiceSnapshotIn + extends SnapshotIn {} + +export interface RuntimeServiceSnapshotOut + extends SnapshotOut {} diff --git a/packages/shared/src/stores/SharedStore.ts b/packages/shared/src/stores/SharedStore.ts index cb14394..ffa387f 100644 --- a/packages/shared/src/stores/SharedStore.ts +++ b/packages/shared/src/stores/SharedStore.ts @@ -27,10 +27,12 @@ import { } from 'mobx-state-tree'; import { config } from './Config'; +import { runtimeService } from './RuntimeService'; export const sharedStore = types.model('SharedStore', { config: types.optional(config, {}), shouldUseDarkColors: false, + runtimeServices: types.map(runtimeService), }); export interface SharedStore extends Instance {} diff --git a/yarn.lock b/yarn.lock index e6f05ba..8a0bf4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1291,13 +1291,18 @@ __metadata: "@emotion/react": ^11.7.1 "@emotion/styled": ^11.6.0 "@fontsource/roboto": ^4.5.2 + "@jest/globals": ^27.4.6 "@mui/icons-material": ^5.3.1 "@mui/material": ^5.3.1 "@sophie/shared": "workspace:*" + "@types/jest": ^27.4.0 "@types/lodash-es": ^4.17.5 "@types/react": ^17.0.38 "@types/react-dom": ^17.0.11 "@vitejs/plugin-react": ^1.1.4 + jest: ^27.4.7 + jest-mock: ^27.4.6 + jsdom: ^19.0.0 lodash-es: ^4.17.21 loglevel: ^1.8.0 loglevel-plugin-prefix: ^0.8.4 -- cgit v1.2.3-54-g00ecf