Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions gui/src/app/SPAnalysis/SPAnalysisContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { initialDataModel, SPAnalysisDataModel } from "./SPAnalysisDataModel"
import { createContext, FunctionComponent, PropsWithChildren, useEffect, useReducer } from "react"
import { SPAnalysisReducer, SPAnalysisReducerAction, SPAnalysisReducerType } from "./SPAnalysisReducer"
import { deserializeAnalysisFromLocalStorage, serializeAnalysisToLocalStorage } from "./SPAnalysisSerialization"
import { fetchRemoteAnalysis, queryStringHasParameters, useQueryParams } from "./SPAnalysisQueryLoading"
import { fetchRemoteAnalysis, queryStringHasParameters, fromQueryParams } from "./SPAnalysisQueryLoading"
import { useSearchParams } from "react-router-dom"

type SPAnalysisContextType = {
data: SPAnalysisDataModel
Expand All @@ -19,10 +20,9 @@ export const SPAnalysisContext = createContext<SPAnalysisContextType>({


const SPAnalysisContextProvider: FunctionComponent<PropsWithChildren<SPAnalysisContextProviderProps>> = ({ children }) => {
const [data, update] = useReducer<SPAnalysisReducerType>(SPAnalysisReducer, initialDataModel)

const { queries, clearSearchParams } = useQueryParams();

const [data, update] = useReducer<SPAnalysisReducerType>(SPAnalysisReducer(clearSearchParams), initialDataModel)
const [searchParams, setSearchParams] = useSearchParams();

useEffect(() => {
// as user reloads the page or closes the tab, save state to local storage
Expand All @@ -38,11 +38,15 @@ const SPAnalysisContextProvider: FunctionComponent<PropsWithChildren<SPAnalysisC
}, [data])

useEffect(() => {
if (data != initialDataModel) return;

const queries = fromQueryParams(searchParams)
if (queryStringHasParameters(queries)) {
fetchRemoteAnalysis(queries).then((data) => {
update({ type: 'loadInitialData', state: data })
update({ type: 'loadInitialData', state: data });

// set title so that history is better preserved in the browser
document.title = "Stan Playground - " + data.meta.title;
// clear search parameters now that load is complete
setSearchParams(new URLSearchParams());
})
} else {
// load the saved state on first load
Expand All @@ -51,8 +55,10 @@ const SPAnalysisContextProvider: FunctionComponent<PropsWithChildren<SPAnalysisC
const parsedData = deserializeAnalysisFromLocalStorage(savedState)
update({ type: 'loadInitialData', state: parsedData })
}

}, [data, queries])
// once we have loaded some data, we don't need the localStorage again
// and it will be overwritten by the above event listener on close
localStorage.removeItem('stan-playground-saved-state')
}, [searchParams, setSearchParams])

return (
<SPAnalysisContext.Provider value={{ data, update }}>
Expand Down
15 changes: 2 additions & 13 deletions gui/src/app/SPAnalysis/SPAnalysisQueryLoading.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useSearchParams } from "react-router-dom";
import { SPAnalysisDataModel, initialDataModel, persistStateToEphemera } from "./SPAnalysisDataModel";
import { useCallback } from "react";


enum QueryParamKeys {
Expand All @@ -19,16 +17,7 @@ type QueryParams = {
[key in QueryParamKeys]: string | null
}

export const useQueryParams = () => {
const [searchParams, setSearchParams] = useSearchParams();

const clearSearchParams = useCallback(() => {
// whenever the data state is 'dirty', we want to
// clear the URL bar as to indiciate that the viewed content is
// no longer what the link would point to
if (searchParams.size !== 0)
setSearchParams(new URLSearchParams())
}, [searchParams, setSearchParams]);
export const fromQueryParams = (searchParams: URLSearchParams) => {

for (const key of searchParams.keys()) {
// warn on unknown keys
Expand All @@ -49,7 +38,7 @@ export const useQueryParams = () => {
seed: searchParams.get(QueryParamKeys.SOSeed),
}

return { queries, clearSearchParams }
return queries;
}

export const queryStringHasParameters = (query: QueryParams) => {
Expand Down
11 changes: 2 additions & 9 deletions gui/src/app/SPAnalysis/SPAnalysisReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,7 @@ export type SPAnalysisReducerAction = {
type: 'clear'
}

export const SPAnalysisReducer = (onDirty: () => void) => (s: SPAnalysisDataModel, a: SPAnalysisReducerAction) => {
if (a.type !== "loadInitialData") {
// TextEditor seems to trigger occasional spurious edits where nothing changes
if (a.type !== "editFile" || s[a.filename] != a.content) {
onDirty();
}
}

export const SPAnalysisReducer = (s: SPAnalysisDataModel, a: SPAnalysisReducerAction) => {
switch (a.type) {
case "loadStanie": {
const dataFileContent = JSON.stringify(a.stanie.data, null, 2);
Expand Down Expand Up @@ -123,4 +116,4 @@ const loadFromProjectFiles = (data: SPAnalysisDataModel, files: Partial<FieldsCo
newData = fileKeys.reduce((currData, currField) => loadFileFromString(currData, currField, files[currField] ?? ''), newData)
newData = persistStateToEphemera(newData)
return newData
}
}