()(
starts: [DEFAULT_NODE.applicationSubmittedNode.key],
entries: {},
+ loadGraphFromLocalStorage: () => {
+ const graphJson = localStorage.getItem("graph")
+ if (!graphJson) {
+ // if there is no saved data, then we simply return
+ // this is not considered to be an error
+ return true
+ }
+
+ const graph = JSON.parse(graphJson)
+ if (!is(graph, $Graph)) {
+ return false
+ }
+
+ set({
+ nodes: graph.nodes,
+ starts: graph.starts,
+ entries: graph.entries,
+ })
+
+ return true
+ },
+
+ resetGraph: () =>
+ set({
+ nodes: {
+ [DEFAULT_NODE.applicationSubmittedNode.key]:
+ DEFAULT_NODE.applicationSubmittedNode,
+ },
+ starts: [DEFAULT_NODE.applicationSubmittedNode.key],
+ entries: {},
+ }),
+
addEntry: (name) =>
set((state) => {
const currentEntries = state.entries
diff --git a/app/routes/home.tsx b/app/routes/home.tsx
index fe31386..9a7bba1 100644
--- a/app/routes/home.tsx
+++ b/app/routes/home.tsx
@@ -16,6 +16,25 @@ export function meta() {
}
export default function Home() {
+ const loadGraphFromLocalStorage = useRootStore(
+ (state) => state.loadGraphFromLocalStorage,
+ )
+
+ useEffect(function saveGraphToLocalStorage() {
+ const unsub = useRootStore.subscribe(({ nodes, starts, entries }) => {
+ localStorage.setItem("graph", JSON.stringify({ nodes, starts, entries }))
+ })
+ return () => {
+ unsub()
+ }
+ }, [])
+
+ useEffect(() => {
+ if (!loadGraphFromLocalStorage()) {
+ alert("Unable to load locally saved data due to inconsistency.")
+ }
+ }, [loadGraphFromLocalStorage])
+
return (
@@ -37,26 +56,34 @@ export default function Home() {
function FlufferChart() {
const nodes = useRootStore((state) => state.nodes)
const starts = useRootStore((state) => state.starts)
+ const resetGraph = useRootStore((state) => state.resetGraph)
const uiMode = useUiMode()
const data = useMemo(() => {
- const rows: [string, string, number][] = []
- const queue = new Queue()
- for (const nodeKey of starts) {
- queue.enqueue(nodes[nodeKey])
- }
- while (!queue.isEmpty) {
- // biome-ignore lint/style/noNonNullAssertion: if queue is non empty, then dequeue will always be non null
- const currentNode = queue.dequeue()!
- for (const nodeKey in currentNode.outs) {
- // biome-ignore lint/style/noNonNullAssertion:
- const connection = currentNode.outs[nodeKey]!
- rows.push([currentNode.key, connection.nodeKey, connection.weight])
- queue.enqueue(nodes[connection.nodeKey])
+ try {
+ const rows: [string, string, number][] = []
+ const queue = new Queue()
+ for (const nodeKey of starts) {
+ queue.enqueue(nodes[nodeKey])
}
+ while (!queue.isEmpty) {
+ // biome-ignore lint/style/noNonNullAssertion: if queue is non empty, then dequeue will always be non null
+ const currentNode = queue.dequeue()!
+ for (const nodeKey in currentNode.outs) {
+ // biome-ignore lint/style/noNonNullAssertion:
+ const connection = currentNode.outs[nodeKey]!
+ rows.push([currentNode.key, connection.nodeKey, connection.weight])
+ queue.enqueue(nodes[connection.nodeKey])
+ }
+ }
+ return rows
+ } catch {
+ if (confirm("Invalid data detected. Erase data and reset?")) {
+ resetGraph()
+ }
+ return []
}
- return rows
- }, [starts, nodes])
+ }, [starts, nodes, resetGraph])
const hasData = data.length > 0
diff --git a/bun.lockb b/bun.lockb
index fec5af0..3b03ec8 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 35b9281..8d42648 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"react-dom": "^19.0.0",
"react-google-charts": "^5.2.1",
"react-router": "^7.1.3",
+ "superstruct": "^2.0.2",
"zustand": "^5.0.3"
},
"devDependencies": {