From c8ecbce009d3ea77c52fac454582e34b6cb53712 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Wed, 17 Jan 2024 16:26:29 +0100 Subject: [PATCH 1/6] Add reset function --- .../src/web-views/hello-world-2.web-view.tsx | 20 +++++++++++++++---- lib/papi-dts/papi.d.ts | 8 +++++++- src/renderer/global-this.model.ts | 5 ++++- src/renderer/hooks/use-web-view-state.hook.ts | 17 +++++++++++++--- .../services/web-view-state.service.ts | 13 ++++++++++++ .../services/web-view.service-host.ts | 4 +++- src/shared/global-this.model.ts | 2 ++ src/shared/models/web-view.model.ts | 6 +++++- 8 files changed, 64 insertions(+), 11 deletions(-) diff --git a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx index 4751d36e73..a69a51a6b8 100644 --- a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx +++ b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx @@ -1,15 +1,17 @@ import papi from '@papi/frontend'; import { useEvent, Button } from 'platform-bible-react'; -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import type { HelloWorldEvent } from 'hello-world'; +import { WebViewProps } from '@papi/core'; -globalThis.webViewComponent = function HelloWorld2() { - const [clicks, setClicks] = useState(0); +globalThis.webViewComponent = function HelloWorld2({ useWebViewState }: WebViewProps) { + const [clicks, setClicks] = useWebViewState('clicks', 0); + const [clicks2, setClicks2, resetClicks2] = useWebViewState('newClicks', 0); // Update the clicks when we are informed helloWorld has been run useEvent( papi.network.getNetworkEvent('helloWorld.onHelloWorld'), - useCallback(({ times }: HelloWorldEvent) => setClicks(times), []), + useCallback(({ times }: HelloWorldEvent) => setClicks(times), [setClicks]), ); return ( @@ -27,6 +29,16 @@ globalThis.webViewComponent = function HelloWorld2() { Hello World {clicks} +
+ + +
); }; diff --git a/lib/papi-dts/papi.d.ts b/lib/papi-dts/papi.d.ts index 1a49c1cd9e..045bddc7de 100644 --- a/lib/papi-dts/papi.d.ts +++ b/lib/papi-dts/papi.d.ts @@ -201,7 +201,11 @@ declare module 'shared/models/web-view.model' { export type UseWebViewStateHook = ( stateKey: string, defaultStateValue: NonNullable, - ) => [webViewState: NonNullable, setWebViewState: Dispatch>>]; + ) => [ + webViewState: NonNullable, + setWebViewState: Dispatch>>, + resetWebViewState: () => void, + ]; /** * * Gets the updatable properties on this WebView's WebView definition @@ -372,6 +376,8 @@ declare module 'shared/global-this.model' { var getWebViewState: (stateKey: string) => T | undefined; /** Set the value for a given key in the web view state. */ var setWebViewState: (stateKey: string, stateValue: NonNullable) => void; + /** Remove the value for a given key in the web view state */ + var resetWebViewState: (stateKey: string) => void; var getWebViewDefinitionUpdatablePropertiesById: ( webViewId: string, ) => WebViewDefinitionUpdatableProperties | undefined; diff --git a/src/renderer/global-this.model.ts b/src/renderer/global-this.model.ts index c43ddefd35..a2d6c24adb 100644 --- a/src/renderer/global-this.model.ts +++ b/src/renderer/global-this.model.ts @@ -12,6 +12,7 @@ import { getModuleSimilarApiMessage } from '@shared/utils/util'; import { getWebViewStateById, setWebViewStateById, + resetWebViewStateById, } from '@renderer/services/web-view-state.service'; import useWebViewState from '@renderer/hooks/use-web-view-state.hook'; import * as papiReact from '@renderer/services/papi-frontend-react.service'; @@ -81,6 +82,7 @@ declare global { // Web view state functions are used in the default imports for each webview in web-view.service.ts var getWebViewStateById: (id: string, stateKey: string) => T | undefined; var setWebViewStateById: (id: string, stateKey: string, stateValue: NonNullable) => void; + var resetWebViewStateById: (id: string, stateKey: string) => void; } /* eslint-enable */ @@ -105,9 +107,10 @@ globalThis.ReactDOMClient = ReactDOMClient; globalThis.createRoot = ReactDOMClient.createRoot; globalThis.SillsdevScripture = SillsdevScripture; globalThis.webViewRequire = webViewRequire; -// We don't expose get/setWebViewStateById in PAPI because web views don't have access to IDs +// We don't expose get/setWebViewStateById/resetWebViewStateById in PAPI because web views don't have access to IDs globalThis.getWebViewStateById = getWebViewStateById; globalThis.setWebViewStateById = setWebViewStateById; +globalThis.resetWebViewStateById = resetWebViewStateById; // We store the hook reference because we need it to bind it to the webview's iframe 'window' context globalThis.useWebViewState = useWebViewState; diff --git a/src/renderer/hooks/use-web-view-state.hook.ts b/src/renderer/hooks/use-web-view-state.hook.ts index da1b8dd182..b799ab3a76 100644 --- a/src/renderer/hooks/use-web-view-state.hook.ts +++ b/src/renderer/hooks/use-web-view-state.hook.ts @@ -6,16 +6,27 @@ export default function useWebViewState( this: { getWebViewState: (stateKey: string) => T | undefined; setWebViewState: (stateKey: string, stateValue: NonNullable) => void; + resetWebViewState: (stateKey: string) => void; }, stateKey: string, defaultStateValue: NonNullable, -): [webViewState: NonNullable, setWebViewState: Dispatch>>] { +): [ + webViewState: NonNullable, + setWebViewState: Dispatch>>, + resetWebViewState: () => void, +] { const [state, setState] = useState(() => this.getWebViewState(stateKey) ?? defaultStateValue); // Whenever the state changes, save the updated value useEffect(() => { + if (state === defaultStateValue) return; this.setWebViewState(stateKey, state); - }, [stateKey, state]); + }, [defaultStateValue, state, stateKey]); - return [state, setState]; + const resetState = () => { + setState(defaultStateValue); + this.resetWebViewState(stateKey); + }; + + return [state, setState, resetState]; } diff --git a/src/renderer/services/web-view-state.service.ts b/src/renderer/services/web-view-state.service.ts index 7e9daaba56..fb28ea09a1 100644 --- a/src/renderer/services/web-view-state.service.ts +++ b/src/renderer/services/web-view-state.service.ts @@ -97,6 +97,19 @@ export function setWebViewStateById(id: string, stateKey: string, stateValue: save(); } +/** + * Remove the web view state object associated with the given ID + * + * @param id ID of the web view + * @param stateKey Key for the associated state + */ +export function resetWebViewStateById(id: string, stateKey: string): void { + if (!id || !stateKey) throw new Error('id and stateKey must be provided to remove webview state'); + const state = getRecord(id); + delete state[stateKey]; + save(); +} + /** * Purge any web view state that hasn't been touched since the process has been running. Only call * this once all web views have been loaded. diff --git a/src/renderer/services/web-view.service-host.ts b/src/renderer/services/web-view.service-host.ts index 0a74591902..ff9d935ce3 100644 --- a/src/renderer/services/web-view.service-host.ts +++ b/src/renderer/services/web-view.service-host.ts @@ -839,7 +839,7 @@ export const getWebView = async ( // The web view provider might have updated the web view state, so save it setFullWebViewStateById(webView.id, webView.state); - // `webViewRequire`, `getWebViewStateById`, and `setWebViewStateById` below are defined in `src\renderer\global-this.model.ts` + // `webViewRequire`, `getWebViewStateById`, `setWebViewStateById` and `resetWebViewStateById` below are defined in `src\renderer\global-this.model.ts` // `useWebViewState` below is defined in `src\shared\global-this.model.ts` // We have to bind `useWebViewState` to the current `window` context because calls within PAPI don't have access to a webview's `window` context /** @@ -862,8 +862,10 @@ export const getWebView = async ( var require = window.parent.webViewRequire; var getWebViewStateById = window.parent.getWebViewStateById; var setWebViewStateById = window.parent.setWebViewStateById; + var resetWebViewStateById = window.parent.resetWebViewStateById; window.getWebViewState = (stateKey) => { return getWebViewStateById('${webView.id}', stateKey) }; window.setWebViewState = (stateKey, stateValue) => { setWebViewStateById('${webView.id}', stateKey, stateValue) }; + window.resetWebViewState = (stateKey) => { resetWebViewStateById('${webView.id}', stateKey) }; window.useWebViewState = window.parent.useWebViewState.bind(window); var getWebViewDefinitionUpdatablePropertiesById = window.parent.getWebViewDefinitionUpdatablePropertiesById; window.getWebViewDefinitionUpdatableProperties = () => { return getWebViewDefinitionUpdatablePropertiesById('${webView.id}')} diff --git a/src/shared/global-this.model.ts b/src/shared/global-this.model.ts index 0dd78b8a84..6210864e1d 100644 --- a/src/shared/global-this.model.ts +++ b/src/shared/global-this.model.ts @@ -38,6 +38,8 @@ declare global { var getWebViewState: (stateKey: string) => T | undefined; /** Set the value for a given key in the web view state. */ var setWebViewState: (stateKey: string, stateValue: NonNullable) => void; + /** Remove the value for a given key in the web view state */ + var resetWebViewState: (stateKey: string) => void; // Web view "by id" functions are used in the default imports for each webview in web-view.service.ts // but probably wouldn't be used in a webview // TODO: Find a way to move this to `@renderer/global-this.model.ts` without causing an error on diff --git a/src/shared/models/web-view.model.ts b/src/shared/models/web-view.model.ts index cc96977b9e..212e789f22 100644 --- a/src/shared/models/web-view.model.ts +++ b/src/shared/models/web-view.model.ts @@ -221,7 +221,11 @@ export type WebViewDefinitionUpdateInfo = Partial( stateKey: string, defaultStateValue: NonNullable, -) => [webViewState: NonNullable, setWebViewState: Dispatch>>]; +) => [ + webViewState: NonNullable, + setWebViewState: Dispatch>>, + resetWebViewState: () => void, +]; // Note: the following comment uses @, not the actual @ character, to hackily provide @param and // such on this type. It seem that, for some reason, JSDoc does not carry these annotations on From 016bf13c2813fc6d7a8270b16a9cfb972c7a8291 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Wed, 17 Jan 2024 16:30:58 +0100 Subject: [PATCH 2/6] Use useState for clicks counter --- .../src/hello-world/src/web-views/hello-world-2.web-view.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx index a69a51a6b8..5dd6259289 100644 --- a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx +++ b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx @@ -1,11 +1,11 @@ import papi from '@papi/frontend'; import { useEvent, Button } from 'platform-bible-react'; -import { useCallback } from 'react'; +import { useCallback, useState } from 'react'; import type { HelloWorldEvent } from 'hello-world'; import { WebViewProps } from '@papi/core'; globalThis.webViewComponent = function HelloWorld2({ useWebViewState }: WebViewProps) { - const [clicks, setClicks] = useWebViewState('clicks', 0); + const [clicks, setClicks] = useState(0); const [clicks2, setClicks2, resetClicks2] = useWebViewState('newClicks', 0); // Update the clicks when we are informed helloWorld has been run From 362083815340e19816dd1889bbe0c5191296da92 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Wed, 17 Jan 2024 17:48:48 +0100 Subject: [PATCH 3/6] Remove NonNullable --- lib/papi-dts/papi.d.ts | 8 ++++---- src/renderer/global-this.model.ts | 2 +- src/renderer/hooks/use-web-view-state.hook.ts | 10 +++------- src/shared/global-this.model.ts | 2 +- src/shared/models/web-view.model.ts | 8 ++------ 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/papi-dts/papi.d.ts b/lib/papi-dts/papi.d.ts index 045bddc7de..12c59774d1 100644 --- a/lib/papi-dts/papi.d.ts +++ b/lib/papi-dts/papi.d.ts @@ -200,10 +200,10 @@ declare module 'shared/models/web-view.model' { */ export type UseWebViewStateHook = ( stateKey: string, - defaultStateValue: NonNullable, + defaultStateValue: T, ) => [ - webViewState: NonNullable, - setWebViewState: Dispatch>>, + webViewState: T, + setWebViewState: Dispatch>, resetWebViewState: () => void, ]; /** @@ -375,7 +375,7 @@ declare module 'shared/global-this.model' { /** Retrieve the value from web view state with the given 'stateKey', if it exists. */ var getWebViewState: (stateKey: string) => T | undefined; /** Set the value for a given key in the web view state. */ - var setWebViewState: (stateKey: string, stateValue: NonNullable) => void; + var setWebViewState: (stateKey: string, stateValue: T) => void; /** Remove the value for a given key in the web view state */ var resetWebViewState: (stateKey: string) => void; var getWebViewDefinitionUpdatablePropertiesById: ( diff --git a/src/renderer/global-this.model.ts b/src/renderer/global-this.model.ts index a2d6c24adb..f8bd8cdba9 100644 --- a/src/renderer/global-this.model.ts +++ b/src/renderer/global-this.model.ts @@ -81,7 +81,7 @@ declare global { var webViewRequire: WebViewRequire; // Web view state functions are used in the default imports for each webview in web-view.service.ts var getWebViewStateById: (id: string, stateKey: string) => T | undefined; - var setWebViewStateById: (id: string, stateKey: string, stateValue: NonNullable) => void; + var setWebViewStateById: (id: string, stateKey: string, stateValue: T) => void; var resetWebViewStateById: (id: string, stateKey: string) => void; } /* eslint-enable */ diff --git a/src/renderer/hooks/use-web-view-state.hook.ts b/src/renderer/hooks/use-web-view-state.hook.ts index b799ab3a76..a83faa1279 100644 --- a/src/renderer/hooks/use-web-view-state.hook.ts +++ b/src/renderer/hooks/use-web-view-state.hook.ts @@ -5,16 +5,12 @@ import { useState, useEffect, Dispatch, SetStateAction } from 'react'; export default function useWebViewState( this: { getWebViewState: (stateKey: string) => T | undefined; - setWebViewState: (stateKey: string, stateValue: NonNullable) => void; + setWebViewState: (stateKey: string, stateValue: T) => void; resetWebViewState: (stateKey: string) => void; }, stateKey: string, - defaultStateValue: NonNullable, -): [ - webViewState: NonNullable, - setWebViewState: Dispatch>>, - resetWebViewState: () => void, -] { + defaultStateValue: T, +): [webViewState: T, setWebViewState: Dispatch>, resetWebViewState: () => void] { const [state, setState] = useState(() => this.getWebViewState(stateKey) ?? defaultStateValue); // Whenever the state changes, save the updated value diff --git a/src/shared/global-this.model.ts b/src/shared/global-this.model.ts index 6210864e1d..e9dc784b0b 100644 --- a/src/shared/global-this.model.ts +++ b/src/shared/global-this.model.ts @@ -37,7 +37,7 @@ declare global { /** Retrieve the value from web view state with the given 'stateKey', if it exists. */ var getWebViewState: (stateKey: string) => T | undefined; /** Set the value for a given key in the web view state. */ - var setWebViewState: (stateKey: string, stateValue: NonNullable) => void; + var setWebViewState: (stateKey: string, stateValue: T) => void; /** Remove the value for a given key in the web view state */ var resetWebViewState: (stateKey: string) => void; // Web view "by id" functions are used in the default imports for each webview in web-view.service.ts diff --git a/src/shared/models/web-view.model.ts b/src/shared/models/web-view.model.ts index 212e789f22..140d7f76ac 100644 --- a/src/shared/models/web-view.model.ts +++ b/src/shared/models/web-view.model.ts @@ -220,12 +220,8 @@ export type WebViewDefinitionUpdateInfo = Partial( stateKey: string, - defaultStateValue: NonNullable, -) => [ - webViewState: NonNullable, - setWebViewState: Dispatch>>, - resetWebViewState: () => void, -]; + defaultStateValue: T, +) => [webViewState: T, setWebViewState: Dispatch>, resetWebViewState: () => void]; // Note: the following comment uses @, not the actual @ character, to hackily provide @param and // such on this type. It seem that, for some reason, JSDoc does not carry these annotations on From 677d330d8adf1fd6a3e2f4288d375921015fd88b Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Wed, 17 Jan 2024 17:52:23 +0100 Subject: [PATCH 4/6] Remove generic specification --- .../src/hello-world/src/web-views/hello-world-2.web-view.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx index 5dd6259289..f47b179f4e 100644 --- a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx +++ b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx @@ -5,8 +5,8 @@ import type { HelloWorldEvent } from 'hello-world'; import { WebViewProps } from '@papi/core'; globalThis.webViewComponent = function HelloWorld2({ useWebViewState }: WebViewProps) { - const [clicks, setClicks] = useState(0); - const [clicks2, setClicks2, resetClicks2] = useWebViewState('newClicks', 0); + const [clicks, setClicks] = useState(0); + const [clicks2, setClicks2, resetClicks2] = useWebViewState('newClicks', 0); // Update the clicks when we are informed helloWorld has been run useEvent( From 4efa3b584cb007dd1e4bb39032b9c9f0857f7864 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Thu, 18 Jan 2024 12:39:55 +0100 Subject: [PATCH 5/6] Processed review comments --- .../src/web-views/hello-world-2.web-view.tsx | 24 ++++++++++---- lib/papi-dts/papi.d.ts | 12 ++++--- src/renderer/global-this.model.ts | 2 +- src/renderer/hooks/use-web-view-state.hook.ts | 32 +++++++++++++------ .../services/web-view-state.service.ts | 7 ++-- .../services/web-view.service-host.ts | 2 +- src/shared/global-this.model.ts | 7 ++-- src/shared/models/web-view.model.ts | 4 +-- src/shared/services/settings.service.ts | 10 ++---- 9 files changed, 62 insertions(+), 38 deletions(-) diff --git a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx index f47b179f4e..b9a3fafd88 100644 --- a/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx +++ b/extensions/src/hello-world/src/web-views/hello-world-2.web-view.tsx @@ -4,14 +4,22 @@ import { useCallback, useState } from 'react'; import type { HelloWorldEvent } from 'hello-world'; import { WebViewProps } from '@papi/core'; +const randomInt = () => { + return Math.floor(Math.random() * 100); +}; + globalThis.webViewComponent = function HelloWorld2({ useWebViewState }: WebViewProps) { const [clicks, setClicks] = useState(0); - const [clicks2, setClicks2, resetClicks2] = useWebViewState('newClicks', 0); + const [defaultClicks, setDefaultClicks] = useState(randomInt()); + const [webViewStateClicks, setWebViewStateClicks, resetWebViewStateClicks] = useWebViewState( + 'webViewStateClicks', + defaultClicks, + ); // Update the clicks when we are informed helloWorld has been run useEvent( papi.network.getNetworkEvent('helloWorld.onHelloWorld'), - useCallback(({ times }: HelloWorldEvent) => setClicks(times), [setClicks]), + useCallback(({ times }: HelloWorldEvent) => setClicks(times), []), ); return ( @@ -26,18 +34,22 @@ globalThis.webViewComponent = function HelloWorld2({ useWebViewState }: WebViewP setClicks(clicks + 1); }} > - Hello World {clicks} + use-Event Clicks: {clicks} +
+ + -
); diff --git a/lib/papi-dts/papi.d.ts b/lib/papi-dts/papi.d.ts index 12c59774d1..95928f99f0 100644 --- a/lib/papi-dts/papi.d.ts +++ b/lib/papi-dts/papi.d.ts @@ -372,8 +372,11 @@ declare module 'shared/global-this.model' { * ``` */ var useWebViewState: UseWebViewStateHook; - /** Retrieve the value from web view state with the given 'stateKey', if it exists. */ - var getWebViewState: (stateKey: string) => T | undefined; + /** + * Retrieve the value from web view state with the given 'stateKey', if it exists. Otherwise + * return default value + */ + var getWebViewState: (stateKey: string, defaultValue: T) => T; /** Set the value for a given key in the web view state. */ var setWebViewState: (stateKey: string, stateValue: T) => void; /** Remove the value for a given key in the web view state */ @@ -3778,9 +3781,8 @@ declare module 'shared/services/settings.service' { * * @param key The string id of the setting for which the value is being retrieved * @param defaultSetting The default value used for the setting if no value is available for the key - * @returns The value of the specified setting, parsed to an object. Returns `undefined` if setting - * is not present or no value is available - * @throws When defaultSetting is required but not provided + * @returns The value of the specified setting, parsed to an object. Returns default setting if + * setting does not exist */ const getSetting: ( key: SettingName, diff --git a/src/renderer/global-this.model.ts b/src/renderer/global-this.model.ts index f8bd8cdba9..4710e7a6af 100644 --- a/src/renderer/global-this.model.ts +++ b/src/renderer/global-this.model.ts @@ -80,7 +80,7 @@ declare global { var SillsdevScripture: SillsdevScriptureType; var webViewRequire: WebViewRequire; // Web view state functions are used in the default imports for each webview in web-view.service.ts - var getWebViewStateById: (id: string, stateKey: string) => T | undefined; + var getWebViewStateById: (id: string, stateKey: string, defaultValue: T) => T; var setWebViewStateById: (id: string, stateKey: string, stateValue: T) => void; var resetWebViewStateById: (id: string, stateKey: string) => void; } diff --git a/src/renderer/hooks/use-web-view-state.hook.ts b/src/renderer/hooks/use-web-view-state.hook.ts index a83faa1279..1088c2c8c0 100644 --- a/src/renderer/hooks/use-web-view-state.hook.ts +++ b/src/renderer/hooks/use-web-view-state.hook.ts @@ -1,28 +1,40 @@ -import { useState, useEffect, Dispatch, SetStateAction } from 'react'; +import { useState, useCallback, useEffect } from 'react'; // We don't add this to PAPI directly like other hooks because `this` has to be bound to a web view's iframe context /** See `web-view.model.ts` for normal hook documentation */ export default function useWebViewState( this: { - getWebViewState: (stateKey: string) => T | undefined; + getWebViewState: (stateKey: string, defaultValue: T) => T; setWebViewState: (stateKey: string, stateValue: T) => void; resetWebViewState: (stateKey: string) => void; }, stateKey: string, defaultStateValue: T, -): [webViewState: T, setWebViewState: Dispatch>, resetWebViewState: () => void] { - const [state, setState] = useState(() => this.getWebViewState(stateKey) ?? defaultStateValue); +): [webViewState: T, setWebViewState: (newStateValue: T) => void, resetWebViewState: () => void] { + const [state, setStateInternal] = useState(() => + this.getWebViewState(stateKey, defaultStateValue), + ); - // Whenever the state changes, save the updated value useEffect(() => { - if (state === defaultStateValue) return; - this.setWebViewState(stateKey, state); + if ( + this.getWebViewState(stateKey, defaultStateValue) === defaultStateValue && + state !== defaultStateValue + ) + setStateInternal(defaultStateValue); }, [defaultStateValue, state, stateKey]); - const resetState = () => { - setState(defaultStateValue); + const setState = useCallback( + (newStateValue: T) => { + setStateInternal(newStateValue); + this.setWebViewState(stateKey, newStateValue); + }, + [stateKey], + ); + + const resetState = useCallback(() => { + setStateInternal(defaultStateValue); this.resetWebViewState(stateKey); - }; + }, [defaultStateValue, stateKey]); return [state, setState, resetState]; } diff --git a/src/renderer/services/web-view-state.service.ts b/src/renderer/services/web-view-state.service.ts index fb28ea09a1..6b2ca6a04a 100644 --- a/src/renderer/services/web-view-state.service.ts +++ b/src/renderer/services/web-view-state.service.ts @@ -69,14 +69,15 @@ export function setFullWebViewStateById(id: string, state: Record(id: string, stateKey: string): T | undefined { +export function getWebViewStateById(id: string, stateKey: string, defaultValue: T): T { if (!id || !stateKey) throw new Error('id and stateKey must be provided to get webview state'); const state = getRecord(id); // We don't have any way to know what type this is, so just type assert for convenience // eslint-disable-next-line no-type-assertion/no-type-assertion - return state[stateKey] as T | undefined; + return stateKey in state ? (state[stateKey] as T) : defaultValue; } /** diff --git a/src/renderer/services/web-view.service-host.ts b/src/renderer/services/web-view.service-host.ts index ff9d935ce3..e0eb013763 100644 --- a/src/renderer/services/web-view.service-host.ts +++ b/src/renderer/services/web-view.service-host.ts @@ -863,7 +863,7 @@ export const getWebView = async ( var getWebViewStateById = window.parent.getWebViewStateById; var setWebViewStateById = window.parent.setWebViewStateById; var resetWebViewStateById = window.parent.resetWebViewStateById; - window.getWebViewState = (stateKey) => { return getWebViewStateById('${webView.id}', stateKey) }; + window.getWebViewState = (stateKey, defaultValue) => { return getWebViewStateById('${webView.id}', stateKey, defaultValue) }; window.setWebViewState = (stateKey, stateValue) => { setWebViewStateById('${webView.id}', stateKey, stateValue) }; window.resetWebViewState = (stateKey) => { resetWebViewStateById('${webView.id}', stateKey) }; window.useWebViewState = window.parent.useWebViewState.bind(window); diff --git a/src/shared/global-this.model.ts b/src/shared/global-this.model.ts index e9dc784b0b..f739591a5b 100644 --- a/src/shared/global-this.model.ts +++ b/src/shared/global-this.model.ts @@ -34,8 +34,11 @@ declare global { var webViewComponent: FunctionComponent; /** JSDOC DESTINATION UseWebViewStateHook */ var useWebViewState: UseWebViewStateHook; - /** Retrieve the value from web view state with the given 'stateKey', if it exists. */ - var getWebViewState: (stateKey: string) => T | undefined; + /** + * Retrieve the value from web view state with the given 'stateKey', if it exists. Otherwise + * return default value + */ + var getWebViewState: (stateKey: string, defaultValue: T) => T; /** Set the value for a given key in the web view state. */ var setWebViewState: (stateKey: string, stateValue: T) => void; /** Remove the value for a given key in the web view state */ diff --git a/src/shared/models/web-view.model.ts b/src/shared/models/web-view.model.ts index 140d7f76ac..d1bac84769 100644 --- a/src/shared/models/web-view.model.ts +++ b/src/shared/models/web-view.model.ts @@ -1,5 +1,3 @@ -import { Dispatch, SetStateAction } from 'react'; - /** The type of code that defines a webview's content */ export enum WebViewContentType { /** @@ -221,7 +219,7 @@ export type WebViewDefinitionUpdateInfo = Partial( stateKey: string, defaultStateValue: T, -) => [webViewState: T, setWebViewState: Dispatch>, resetWebViewState: () => void]; +) => [webViewState: T, setWebViewState: (stateValue: T) => void, resetWebViewState: () => void]; // Note: the following comment uses @, not the actual @ character, to hackily provide @param and // such on this type. It seem that, for some reason, JSDoc does not carry these annotations on diff --git a/src/shared/services/settings.service.ts b/src/shared/services/settings.service.ts index 3d4e5a13b5..586c6c85eb 100644 --- a/src/shared/services/settings.service.ts +++ b/src/shared/services/settings.service.ts @@ -28,9 +28,8 @@ const onDidUpdateSettingEmitters = new Map< * * @param key The string id of the setting for which the value is being retrieved * @param defaultSetting The default value used for the setting if no value is available for the key - * @returns The value of the specified setting, parsed to an object. Returns `undefined` if setting - * is not present or no value is available - * @throws When defaultSetting is required but not provided + * @returns The value of the specified setting, parsed to an object. Returns default setting if + * setting does not exist */ const getSetting = ( key: SettingName, @@ -42,10 +41,7 @@ const getSetting = ( if (settingString !== null) { return deserialize(settingString); } - if (defaultSetting) { - return defaultSetting; - } - throw new Error(`No default value provided for setting '${key}'`); + return defaultSetting; }; /** From 21c777c6e7df966605cc4edde1ca188a3634ff24 Mon Sep 17 00:00:00 2001 From: Rolf Heij Date: Thu, 18 Jan 2024 12:41:04 +0100 Subject: [PATCH 6/6] Update papi.d.ts --- lib/papi-dts/papi.d.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/papi-dts/papi.d.ts b/lib/papi-dts/papi.d.ts index 95928f99f0..cad6d43a21 100644 --- a/lib/papi-dts/papi.d.ts +++ b/lib/papi-dts/papi.d.ts @@ -2,7 +2,6 @@ /// /// declare module 'shared/models/web-view.model' { - import { Dispatch, SetStateAction } from 'react'; /** The type of code that defines a webview's content */ export enum WebViewContentType { /** @@ -201,11 +200,7 @@ declare module 'shared/models/web-view.model' { export type UseWebViewStateHook = ( stateKey: string, defaultStateValue: T, - ) => [ - webViewState: T, - setWebViewState: Dispatch>, - resetWebViewState: () => void, - ]; + ) => [webViewState: T, setWebViewState: (stateValue: T) => void, resetWebViewState: () => void]; /** * * Gets the updatable properties on this WebView's WebView definition