diff --git a/dev_data/state/.gitignore b/dev_data/state/.gitignore index cd3d225..f1a26a4 100644 --- a/dev_data/state/.gitignore +++ b/dev_data/state/.gitignore @@ -1 +1,2 @@ -logs \ No newline at end of file +logs +local_storage \ No newline at end of file diff --git a/dev_plugin/src/command-generator.ts b/dev_plugin/src/command-generator.ts index b063d79..39f91af 100644 --- a/dev_plugin/src/command-generator.ts +++ b/dev_plugin/src/command-generator.ts @@ -18,6 +18,12 @@ export default function CommandGenerator(): GeneratedCommand[] { name: 'Generated Item 2', fn: () => { console.log('generated-test-2') + + sessionStorage.setItem("test", "test") + console.dir(sessionStorage.getItem("test")) + + localStorage.setItem("test", "test") + console.dir(localStorage.getItem("test")) } }, { diff --git a/dev_plugin/src/grid-view.tsx b/dev_plugin/src/grid-view.tsx index c7af561..1180676 100644 --- a/dev_plugin/src/grid-view.tsx +++ b/dev_plugin/src/grid-view.tsx @@ -1,11 +1,17 @@ import { Grid } from "@project-gauntlet/api/components"; import { ReactElement } from "react"; +import { useStorage } from "@project-gauntlet/api/hooks"; export default function GridView(): ReactElement { const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; + const [val1, setValue1] = useStorage("test", undefined); + const [val2, setValue2] = useStorage("test", { " test": "test" }); + const [val3, setValue3] = useStorage("test", ""); + const [val4, setValue4] = useStorage("test", ""); + return ( - + {}}> { numbers.map(value => ( diff --git a/js/api/src/hooks.ts b/js/api/src/hooks.ts index b644a0c..94dde6f 100644 --- a/js/api/src/hooks.ts +++ b/js/api/src/hooks.ts @@ -1,4 +1,4 @@ -import { ReactNode, useRef, useState, useCallback, useEffect, MutableRefObject } from 'react'; +import { ReactNode, useRef, useState, useCallback, useEffect, MutableRefObject, Dispatch, SetStateAction } from 'react'; // @ts-ignore TODO how to add declaration for this? import { useGauntletContext } from "gauntlet:renderer"; @@ -203,3 +203,45 @@ export function usePromise Promise, R>( ...state }; } + +// persistent, uses localStorage under the hood +export function useStorage(key: string, initialState: T | (() => T)): [T, Dispatch>] { + return useWebStorage(key, initialState, localStorage) +} + +// ephemeral, uses sessionStorage under the hood +export function useCache(key: string, initialState: T | (() => T)): [T, Dispatch>] { + return useWebStorage(key, initialState, sessionStorage) +} + +// keys are shared per plugin, across all entrypoints +// uses JSON.serialize +function useWebStorage( + key: string, + initialState: T | (() => T), + storageObject: Storage +): [T, Dispatch>] { + + const [value, setValue] = useState(() => { + const jsonValue = storageObject.getItem(key) + + if (jsonValue != null) { + return JSON.parse(jsonValue) as T + } + + if (initialState instanceof Function) { + return initialState() + } else { + return initialState + } + }) + + useEffect(() => { + if (value === undefined) { + return storageObject.removeItem(key) + } + storageObject.setItem(key, JSON.stringify(value)) + }, [key, value, storageObject]) + + return [value, setValue] +} diff --git a/rust/common/src/dirs.rs b/rust/common/src/dirs.rs index 96f3485..3da1480 100644 --- a/rust/common/src/dirs.rs +++ b/rust/common/src/dirs.rs @@ -94,6 +94,10 @@ impl Dirs { (out_log_file, err_log_file) } + pub fn plugin_local_storage(&self, plugin_uuid: &str) -> PathBuf { + self.state_dir().join("local_storage").join(&plugin_uuid) + } + pub fn state_dir(&self) -> PathBuf { let state_dir = if cfg!(feature = "release") || cfg!(feature = "scenario_runner") { let dir = match self.inner.state_dir() { diff --git a/rust/server/src/plugins/js/mod.rs b/rust/server/src/plugins/js/mod.rs index a6280a5..f385962 100644 --- a/rust/server/src/plugins/js/mod.rs +++ b/rust/server/src/plugins/js/mod.rs @@ -322,6 +322,8 @@ async fn start_js_runtime( (StdioPipe::Inherit, StdioPipe::Inherit) }; + let local_storage_dir = dirs.plugin_local_storage(&plugin_uuid); + // let _inspector_server = Arc::new( // InspectorServer::new( // "127.0.0.1:9229".parse::().unwrap(), @@ -352,6 +354,7 @@ async fn start_js_runtime( maybe_inspector_server: None, should_wait_for_inspector_session: false, should_break_on_first_statement: false, + origin_storage_dir: Some(local_storage_dir), stdio: Stdio { stdin: StdioPipe::Inherit, stdout,