aboutsummaryrefslogtreecommitdiffstats
path: root/packages/renderer
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-01-23 17:12:47 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-02-08 21:43:17 +0100
commit044b2de8c7861504704468ba441d4a6a37eed8f7 (patch)
tree940d2b7946d07a0c69b5e3ad46c25c599cf2aca7 /packages/renderer
parentfeat: Add selected service field to SharedStore (diff)
downloadsophie-044b2de8c7861504704468ba441d4a6a37eed8f7.tar.gz
sophie-044b2de8c7861504704468ba441d4a6a37eed8f7.tar.zst
sophie-044b2de8c7861504704468ba441d4a6a37eed8f7.zip
refactor: Move runtime state into shared models
Now the runtime state lives inside the model (instead of being associated to the static settings via a map), which simplifies state management. Static settings are now located inside the runtime models, so we must create tests to make sure that the settings are being persisted correctly. The contents of the config file are now generated as a view of store (instead of a snapshot), which adds flexibility. Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/renderer')
-rw-r--r--packages/renderer/src/components/ServiceSwitcher.tsx4
-rw-r--r--packages/renderer/src/env/RendererEnv.ts4
-rw-r--r--packages/renderer/src/env/impl/RendererEnvImpl.ts55
-rw-r--r--packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts87
-rw-r--r--packages/renderer/src/stores/Config.ts32
-rw-r--r--packages/renderer/src/stores/RendererStore.ts24
-rw-r--r--packages/renderer/src/stores/Service.ts38
-rw-r--r--packages/renderer/src/stores/SharedStore.ts37
-rw-r--r--packages/renderer/src/stores/__tests__/Service.spec.ts63
9 files changed, 15 insertions, 329 deletions
diff --git a/packages/renderer/src/components/ServiceSwitcher.tsx b/packages/renderer/src/components/ServiceSwitcher.tsx
index 0786b71..167153f 100644
--- a/packages/renderer/src/components/ServiceSwitcher.tsx
+++ b/packages/renderer/src/components/ServiceSwitcher.tsx
@@ -78,8 +78,8 @@ export default observer(() => {
78 <ServiceSwitcherTab 78 <ServiceSwitcherTab
79 key={service.id} 79 key={service.id}
80 value={service.id} 80 value={service.id}
81 icon={<ServiceIcon name={service.name} />} 81 icon={<ServiceIcon name={service.settings.name} />}
82 aria-label={service.name} 82 aria-label={service.settings.name}
83 /> 83 />
84 ))} 84 ))}
85 </ServiceSwitcherRoot> 85 </ServiceSwitcherRoot>
diff --git a/packages/renderer/src/env/RendererEnv.ts b/packages/renderer/src/env/RendererEnv.ts
index 5ca2978..ba4c43e 100644
--- a/packages/renderer/src/env/RendererEnv.ts
+++ b/packages/renderer/src/env/RendererEnv.ts
@@ -18,10 +18,8 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import type { Action, RuntimeService } from '@sophie/shared'; 21import type { Action } from '@sophie/shared';
22 22
23export default interface RendererEnv { 23export default interface RendererEnv {
24 dispatchMainAction(action: Action): void; 24 dispatchMainAction(action: Action): void;
25
26 getRuntimeService(serviceId: string): RuntimeService | undefined;
27} 25}
diff --git a/packages/renderer/src/env/impl/RendererEnvImpl.ts b/packages/renderer/src/env/impl/RendererEnvImpl.ts
deleted file mode 100644
index 184d31b..0000000
--- a/packages/renderer/src/env/impl/RendererEnvImpl.ts
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import {
22 Action,
23 runtimeService,
24 RuntimeService,
25 SophieRenderer,
26} from '@sophie/shared';
27import type { IMSTMap } from 'mobx-state-tree';
28
29import type { RendererStore } from '../../stores/RendererStore';
30import type RendererEnv from '../RendererEnv';
31
32export default class RendererEnvImpl implements RendererEnv {
33 readonly #ipc: SophieRenderer;
34
35 #runtimeServices: IMSTMap<typeof runtimeService> | undefined;
36
37 constructor(ipc: SophieRenderer) {
38 this.#ipc = ipc;
39 }
40
41 setStore(store: RendererStore): void {
42 this.#runtimeServices = store.shared.runtimeServices;
43 }
44
45 dispatchMainAction(action: Action): void {
46 this.#ipc.dispatchAction(action);
47 }
48
49 getRuntimeService(serviceId: string): RuntimeService | undefined {
50 if (this.#runtimeServices === undefined) {
51 throw new Error('runtime services map is not yet set');
52 }
53 return this.#runtimeServices.get(serviceId);
54 }
55}
diff --git a/packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts b/packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts
deleted file mode 100644
index d36462c..0000000
--- a/packages/renderer/src/env/impl/__tests__/RendererEnvImpl.spec.ts
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { jest } from '@jest/globals';
22import {
23 Action,
24 runtimeService,
25 RuntimeService,
26 SophieRenderer,
27} from '@sophie/shared';
28
29import { rendererStore } from '../../../stores/RendererStore';
30import RendererEnvImpl from '../RendererEnvImpl';
31
32const ipc: SophieRenderer = {
33 dispatchAction: jest.fn(),
34 onSharedStoreChange: jest.fn(),
35};
36let sut: RendererEnvImpl;
37
38beforeEach(() => {
39 sut = new RendererEnvImpl(ipc);
40});
41
42describe('dispatchMainAction', () => {
43 it('should dispatch actions via the IPC', () => {
44 const action: Action = {
45 action: 'set-theme-source',
46 themeSource: 'dark',
47 };
48 sut.dispatchMainAction(action);
49 expect(ipc.dispatchAction).toHaveBeenCalledWith(action);
50 });
51});
52
53describe('getRuntimeService', () => {
54 describe('when no store was set', () => {
55 it('should throw an error', () => {
56 expect(() => sut.getRuntimeService('someId')).toThrow();
57 });
58 });
59
60 describe('when the store was set', () => {
61 let runtimeServiceStore: RuntimeService;
62
63 beforeEach(() => {
64 runtimeServiceStore = runtimeService.create({
65 state: 'loaded',
66 });
67 const store = rendererStore.create({
68 shared: {
69 runtimeServices: {
70 someId: runtimeServiceStore,
71 },
72 },
73 });
74 sut.setStore(store);
75 });
76
77 it('should return the runtime service for the given ID', () => {
78 const returnedStore = sut.getRuntimeService('someId');
79 expect(returnedStore).toBe(runtimeServiceStore);
80 });
81
82 it('should return undefined for an unknown ID', () => {
83 const returnedStore = sut.getRuntimeService('unknownId');
84 expect(returnedStore).toBeUndefined();
85 });
86 });
87});
diff --git a/packages/renderer/src/stores/Config.ts b/packages/renderer/src/stores/Config.ts
deleted file mode 100644
index 070c4ec..0000000
--- a/packages/renderer/src/stores/Config.ts
+++ /dev/null
@@ -1,32 +0,0 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { config as originalConfig } from '@sophie/shared';
22import { Instance, types } from 'mobx-state-tree';
23
24import { service } from './Service';
25
26export const config = originalConfig.props({
27 services: types.array(service),
28});
29
30export interface Config extends Instance<typeof config> {}
31
32export type { ConfigSnapshotIn, ConfigSnapshotOut } from '@sophie/shared';
diff --git a/packages/renderer/src/stores/RendererStore.ts b/packages/renderer/src/stores/RendererStore.ts
index 731ca28..a4e6197 100644
--- a/packages/renderer/src/stores/RendererStore.ts
+++ b/packages/renderer/src/stores/RendererStore.ts
@@ -18,17 +18,19 @@
18 * SPDX-License-Identifier: AGPL-3.0-only 18 * SPDX-License-Identifier: AGPL-3.0-only
19 */ 19 */
20 20
21import { BrowserViewBounds, SophieRenderer, ThemeSource } from '@sophie/shared'; 21import {
22 BrowserViewBounds,
23 sharedStore,
24 Service,
25 SophieRenderer,
26 ThemeSource,
27} from '@sophie/shared';
22import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree'; 28import { applySnapshot, applyPatch, Instance, types } from 'mobx-state-tree';
23 29
30import RendererEnv from '../env/RendererEnv';
24import getEnv from '../env/getEnv'; 31import getEnv from '../env/getEnv';
25import RendererEnvImpl from '../env/impl/RendererEnvImpl';
26import { getLogger } from '../utils/log'; 32import { getLogger } from '../utils/log';
27 33
28import type { Config } from './Config';
29import type { Service } from './Service';
30import { sharedStore } from './SharedStore';
31
32const log = getLogger('RendererStore'); 34const log = getLogger('RendererStore');
33 35
34export const rendererStore = types 36export const rendererStore = types
@@ -36,11 +38,8 @@ export const rendererStore = types
36 shared: types.optional(sharedStore, {}), 38 shared: types.optional(sharedStore, {}),
37 }) 39 })
38 .views((self) => ({ 40 .views((self) => ({
39 get config(): Config {
40 return self.shared.config;
41 },
42 get services(): Service[] { 41 get services(): Service[] {
43 return this.config.services; 42 return self.shared.services;
44 }, 43 },
45 get selectedService(): Service | undefined { 44 get selectedService(): Service | undefined {
46 return self.shared.selectedService; 45 return self.shared.selectedService;
@@ -87,9 +86,10 @@ export interface RendererStore extends Instance<typeof rendererStore> {}
87export function createAndConnectRendererStore( 86export function createAndConnectRendererStore(
88 ipc: SophieRenderer, 87 ipc: SophieRenderer,
89): RendererStore { 88): RendererStore {
90 const env = new RendererEnvImpl(ipc); 89 const env: RendererEnv = {
90 dispatchMainAction: ipc.dispatchAction,
91 };
91 const store = rendererStore.create({}, env); 92 const store = rendererStore.create({}, env);
92 env.setStore(store);
93 93
94 ipc 94 ipc
95 .onSharedStoreChange({ 95 .onSharedStoreChange({
diff --git a/packages/renderer/src/stores/Service.ts b/packages/renderer/src/stores/Service.ts
deleted file mode 100644
index 2f45106..0000000
--- a/packages/renderer/src/stores/Service.ts
+++ /dev/null
@@ -1,38 +0,0 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import {
22 runtimeService,
23 RuntimeService,
24 service as originalService,
25} from '@sophie/shared';
26import { Instance } from 'mobx-state-tree';
27
28import getEnv from '../env/getEnv';
29
30export const service = originalService.views((self) => ({
31 get runtime(): RuntimeService {
32 return getEnv(self).getRuntimeService(self.id) ?? runtimeService.create();
33 },
34}));
35
36export interface Service extends Instance<typeof service> {}
37
38export type { ServiceSnapshotIn, ServiceSnapshotOut } from '@sophie/shared';
diff --git a/packages/renderer/src/stores/SharedStore.ts b/packages/renderer/src/stores/SharedStore.ts
deleted file mode 100644
index 962f7e2..0000000
--- a/packages/renderer/src/stores/SharedStore.ts
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { sharedStore as originalSharedStore } from '@sophie/shared';
22import { Instance, types } from 'mobx-state-tree';
23
24import { config } from './Config';
25import { service } from './Service';
26
27export const sharedStore = originalSharedStore.props({
28 config: types.optional(config, {}),
29 selectedService: types.safeReference(service),
30});
31
32export interface SharedStore extends Instance<typeof sharedStore> {}
33
34export type {
35 SharedStoreSnapshotIn,
36 SharedStoreSnapshotOut,
37} from '@sophie/shared';
diff --git a/packages/renderer/src/stores/__tests__/Service.spec.ts b/packages/renderer/src/stores/__tests__/Service.spec.ts
deleted file mode 100644
index f835d41..0000000
--- a/packages/renderer/src/stores/__tests__/Service.spec.ts
+++ /dev/null
@@ -1,63 +0,0 @@
1/*
2 * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { jest } from '@jest/globals';
22import { runtimeService } from '@sophie/shared';
23import { mocked } from 'jest-mock';
24
25import type RendererEnv from '../../env/RendererEnv';
26import { service, Service } from '../Service';
27
28const env: RendererEnv = {
29 dispatchMainAction: jest.fn(),
30 getRuntimeService: jest.fn(),
31};
32let sut: Service;
33
34beforeEach(() => {
35 sut = service.create(
36 {
37 id: 'serviceId',
38 name: 'Foo',
39 url: 'https://example.com',
40 profile: 'profileId',
41 },
42 env,
43 );
44});
45
46describe('runtime', () => {
47 it('should return the runtime service with for the service ID', () => {
48 const runtimeServiceStore = runtimeService.create({}, env);
49 mocked(env.getRuntimeService).mockReturnValueOnce(runtimeServiceStore);
50 const returnedStore = sut.runtime;
51 expect(env.getRuntimeService).toHaveBeenCalledWith('serviceId');
52 expect(returnedStore).toBe(runtimeServiceStore);
53 });
54
55 it('should return a valid runtime service even if none exists in the environment', () => {
56 /*
57 eslint-disable-next-line unicorn/no-useless-undefined --
58 `mockReturnValueOnce` expects 1 parameter.
59 */
60 mocked(env.getRuntimeService).mockReturnValueOnce(undefined);
61 expect(sut.runtime).toHaveProperty('state', 'hibernated');
62 });
63});