-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #77 from flatironinstitute/general-data-model-js
- Loading branch information
Showing
11 changed files
with
382 additions
and
260 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,5 +50,6 @@ | |
"typescript": "^5.0.2", | ||
"vite": "^5.2.12", | ||
"vitest": "^1.6.0" | ||
} | ||
}, | ||
"packageManager": "[email protected]+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610" | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { createContext, FunctionComponent, PropsWithChildren, useEffect, useReducer } from "react" | ||
import { deserializeAnalysis, initialDataModel, serializeAnalysis, SPAnalysisDataModel } from "./SPAnalysisDataModel" | ||
import { SPAnalysisReducer, SPAnalysisReducerAction, SPAnalysisReducerType } from "./SPAnalysisReducer" | ||
|
||
type SPAnalysisContextType = { | ||
data: SPAnalysisDataModel | ||
update: React.Dispatch<SPAnalysisReducerAction> | ||
} | ||
|
||
type SPAnalysisContextProviderProps = { | ||
// may be used in the future when we allow parameters to be passed through the string | ||
sourceDataUri: string | ||
} | ||
|
||
export const SPAnalysisContext = createContext<SPAnalysisContextType>({ | ||
data: initialDataModel, | ||
update: () => {} | ||
}) | ||
|
||
const SPAnalysisContextProvider: FunctionComponent<PropsWithChildren<SPAnalysisContextProviderProps>> = ({children}) => { | ||
const [data, update] = useReducer<SPAnalysisReducerType>(SPAnalysisReducer, initialDataModel) | ||
|
||
//////////////////////////////////////////////////////////////////////////////////////// | ||
// For convenience, we save the state to local storage so it is available on | ||
// reload of the page But this will be revised in the future to use a more | ||
// sophisticated storage mechanism. | ||
useEffect(() => { | ||
// as user reloads the page or closes the tab, save state to local storage | ||
const handleBeforeUnload = () => { | ||
const state = serializeAnalysis(data) | ||
localStorage.setItem('stan-playground-saved-state', state) | ||
}; | ||
window.addEventListener('beforeunload', handleBeforeUnload); | ||
|
||
return () => { | ||
window.removeEventListener('beforeunload', handleBeforeUnload); | ||
}; | ||
}, [data]) | ||
|
||
useEffect(() => { | ||
// load the saved state on first load | ||
const savedState = localStorage.getItem('stan-playground-saved-state') | ||
if (!savedState) return | ||
const parsedData = deserializeAnalysis(savedState) | ||
update({ type: 'loadLocalStorage', state: parsedData }) | ||
}, []) | ||
//////////////////////////////////////////////////////////////////////////////////////// | ||
|
||
return ( | ||
<SPAnalysisContext.Provider value={{data, update}}> | ||
{children} | ||
</SPAnalysisContext.Provider> | ||
) | ||
} | ||
|
||
export default SPAnalysisContextProvider | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { SamplingOpts, defaultSamplingOpts } from "../StanSampler/StanSampler" | ||
|
||
export enum SPAnalysisKnownFiles { | ||
STANFILE = 'stanFileContent', | ||
DATAFILE = 'dataFileContent', | ||
} | ||
|
||
type SPAnalysisFiles = { | ||
[filetype in SPAnalysisKnownFiles]: string | ||
} | ||
|
||
type SPAnalysisBase = SPAnalysisFiles & | ||
{ | ||
samplingOpts: SamplingOpts | ||
} | ||
|
||
type SPAnalysisMetadata = { | ||
title: string | ||
} | ||
|
||
type SPAnalysisEphemeralData = SPAnalysisFiles & { | ||
// possible future things to track include the compilation status | ||
// of the current stan src file(s) | ||
// not implemented in this PR, but we need some content for the type | ||
server?: string | ||
} | ||
|
||
export type SPAnalysisDataModel = SPAnalysisBase & | ||
{ | ||
meta: SPAnalysisMetadata, | ||
ephemera: SPAnalysisEphemeralData | ||
} | ||
|
||
export const initialDataModel: SPAnalysisDataModel = { | ||
meta: { title: "Undefined" }, | ||
ephemera: { | ||
stanFileContent: "", | ||
dataFileContent: "", | ||
}, | ||
stanFileContent: "", | ||
dataFileContent: "", | ||
samplingOpts: defaultSamplingOpts | ||
} | ||
|
||
export const serializeAnalysis = (data: SPAnalysisDataModel): string => { | ||
const intermediary = { | ||
...data, ephemera: undefined } | ||
return JSON.stringify(intermediary) | ||
} | ||
|
||
export const deserializeAnalysis = (serialized: string): SPAnalysisDataModel => { | ||
const intermediary = JSON.parse(serialized) | ||
// Not sure if this is strictly necessary | ||
intermediary.ephemera = {} | ||
const stringFileKeys = Object.values(SPAnalysisKnownFiles).filter((v) => isNaN(Number(v))); | ||
stringFileKeys.forEach((k) => intermediary.ephemera[k] = intermediary[k]); | ||
return intermediary as SPAnalysisDataModel | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { Reducer } from "react" | ||
import { Stanie } from "../exampleStanies/exampleStanies" | ||
import { defaultSamplingOpts, SamplingOpts } from '../StanSampler/StanSampler' | ||
import { initialDataModel, SPAnalysisDataModel, SPAnalysisKnownFiles } from "./SPAnalysisDataModel" | ||
|
||
|
||
export type SPAnalysisReducerType = Reducer<SPAnalysisDataModel, SPAnalysisReducerAction> | ||
|
||
export type SPAnalysisReducerAction = { | ||
type: 'loadStanie', | ||
stanie: Stanie | ||
} | { | ||
type: 'retitle', | ||
title: string | ||
} | { | ||
type: 'editFile', | ||
content: string, | ||
filename: SPAnalysisKnownFiles | ||
} | { | ||
type: 'commitFile', | ||
filename: SPAnalysisKnownFiles | ||
} | { | ||
type: 'setSamplingOpts', | ||
opts: Partial<SamplingOpts> | ||
} | { | ||
type: 'loadLocalStorage', | ||
state: SPAnalysisDataModel | ||
} | { | ||
type: 'clear' | ||
} | ||
|
||
export const SPAnalysisReducer: SPAnalysisReducerType = (s: SPAnalysisDataModel, a: SPAnalysisReducerAction) => { | ||
switch (a.type) { | ||
case "loadStanie": { | ||
return { | ||
...s, | ||
stanFileContent: a.stanie.stan, | ||
dataFileContent: JSON.stringify(a.stanie.data), | ||
samplingOpts: defaultSamplingOpts, | ||
meta: { ...s.meta, title: a.stanie.meta.title ?? 'Untitled' }, | ||
ephemera: { | ||
...s.ephemera, | ||
stanFileContent: a.stanie.stan, | ||
dataFileContent: JSON.stringify(a.stanie.data) | ||
} | ||
} | ||
} | ||
case "retitle": { | ||
return { | ||
...s, | ||
meta: { ...s.meta, title: a.title } | ||
} | ||
} | ||
case "editFile": { | ||
const newEphemera = { ...s.ephemera } | ||
newEphemera[a.filename] = a.content | ||
return { ...s, ephemera: newEphemera } | ||
} | ||
case "commitFile": { | ||
const newState = { ...s } | ||
newState[a.filename] = s.ephemera[a.filename] | ||
return newState | ||
} | ||
case "setSamplingOpts": { | ||
return { ...s, samplingOpts: { ...s.samplingOpts, ...a.opts }} | ||
} | ||
case "loadLocalStorage": { | ||
return a.state; | ||
} | ||
case "clear": { | ||
return initialDataModel | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.