set up rtk query
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ function App() {
|
||||
setCurLevel(1)
|
||||
}
|
||||
|
||||
const title = useAppSelector(state => state.game.title)
|
||||
const title = ""//useAppSelector(state => state.gameApi.data.title)
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
|
||||
@@ -110,7 +110,7 @@ function Level() {
|
||||
|
||||
// The next function will be called when the level changes
|
||||
useEffect(() => {
|
||||
connection.whenLeanClientStarted((leanClient) => {
|
||||
connection.startLeanClient().then((leanClient) => {
|
||||
if (editor) {
|
||||
|
||||
const model = monaco.editor.createModel('', 'lean4', monaco.Uri.parse(uri))
|
||||
|
||||
@@ -6,24 +6,18 @@ import '@fontsource/roboto/300.css';
|
||||
import '@fontsource/roboto/400.css';
|
||||
import '@fontsource/roboto/500.css';
|
||||
import '@fontsource/roboto/700.css';
|
||||
import * as rpc from 'vscode-ws-jsonrpc';
|
||||
import cytoscape from 'cytoscape'
|
||||
import klay from 'cytoscape-klay';
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { fetchGame } from '../game/gameSlice'
|
||||
import { Link as RouterLink, useNavigate } from 'react-router-dom';
|
||||
|
||||
|
||||
cytoscape.use( klay );
|
||||
|
||||
import { Box, Typography, Button, CircularProgress, Grid } from '@mui/material';
|
||||
import { LeanClient } from 'lean4web/client/src/editor/leanclient';
|
||||
import { ConnectionContext } from '../connection';
|
||||
import { useAppDispatch, useAppSelector } from '../hooks';
|
||||
import { useGetGameInfoQuery } from '../game/api';
|
||||
|
||||
|
||||
function Welcome() {
|
||||
const dispatch = useAppDispatch()
|
||||
const navigate = useNavigate();
|
||||
|
||||
const worldsRef = useRef<HTMLDivElement>(null)
|
||||
@@ -75,23 +69,25 @@ function Welcome() {
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => { dispatch(fetchGame); }, [])
|
||||
const gameInfo = useGetGameInfoQuery()
|
||||
|
||||
const worlds = useAppSelector(state => state.game.worlds)
|
||||
useEffect(() => { if (worlds) { drawWorlds(worlds); } }, [worlds])
|
||||
useEffect(() => {
|
||||
if (gameInfo.data?.worlds) { drawWorlds(gameInfo.data.worlds); }
|
||||
}, [gameInfo.data?.worlds])
|
||||
|
||||
const title = useAppSelector(state => state.game.title)
|
||||
useEffect(() => { window.document.title = title }, [title])
|
||||
|
||||
const introduction = useAppSelector(state => state.game.introduction)
|
||||
useEffect(() => {
|
||||
if (gameInfo.data?.title) window.document.title = gameInfo.data.title
|
||||
}, [gameInfo.data?.title])
|
||||
|
||||
return <div>
|
||||
{ introduction?// TODO: find a better way to mark loading state?
|
||||
{ gameInfo.isLoading?
|
||||
<Box display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
|
||||
:
|
||||
<div>
|
||||
<Box sx={{ m: 3 }}>
|
||||
<Typography variant="body1" component="div">
|
||||
<MathJax>
|
||||
<ReactMarkdown>{introduction}</ReactMarkdown>
|
||||
<ReactMarkdown>{gameInfo.data.introduction}</ReactMarkdown>
|
||||
</MathJax>
|
||||
</Typography>
|
||||
</Box>
|
||||
@@ -100,7 +96,6 @@ function Welcome() {
|
||||
</Box>
|
||||
<div ref={worldsRef} style={{"width": "100%","height": "50em"}} />
|
||||
</div>
|
||||
: <Box display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
+14
-10
@@ -18,17 +18,21 @@ export class Connection {
|
||||
return this.leanClient
|
||||
}
|
||||
|
||||
/** Call `callback` when the leanClient has started. If not already started, start it. */
|
||||
whenLeanClientStarted = (callback) => {
|
||||
const leanClient = this.getLeanClient()
|
||||
if (leanClient.isRunning()) {
|
||||
callback(leanClient)
|
||||
} else {
|
||||
if (!leanClient.isStarted()) {
|
||||
leanClient.start()
|
||||
/** If not already started, starts the Lean client. resolves the returned promise as soon as a
|
||||
* Lean client is running.
|
||||
*/
|
||||
startLeanClient = () => {
|
||||
return new Promise<LeanClient>((resolve) => {
|
||||
const leanClient = this.getLeanClient()
|
||||
if (leanClient.isRunning()) {
|
||||
resolve(leanClient)
|
||||
} else {
|
||||
if (!leanClient.isStarted()) {
|
||||
leanClient.start()
|
||||
}
|
||||
leanClient.restarted(() => { resolve(leanClient) })
|
||||
}
|
||||
leanClient.restarted(() => { callback(leanClient) })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
|
||||
import { Connection } from '../connection'
|
||||
|
||||
interface GameState {
|
||||
title: null|string,
|
||||
introduction: null|string,
|
||||
worlds: null|{nodes: string[], edges: string[][2]},
|
||||
authors: null|string[],
|
||||
conclusion: null|string,
|
||||
}
|
||||
|
||||
const customBaseQuery = async (
|
||||
args : {method: string, params?: any},
|
||||
{ signal, dispatch, getState, extra },
|
||||
extraOptions
|
||||
) => {
|
||||
const connection : Connection = extra.connection
|
||||
let leanClient = await connection.startLeanClient()
|
||||
console.log(`Sending request ${args.method}`)
|
||||
let res = await leanClient.sendRequest(args.method, args.params)
|
||||
console.log('Received response', res)
|
||||
return {'data': res}
|
||||
}
|
||||
|
||||
// Define a service using a base URL and expected endpoints
|
||||
export const gameApi = createApi({
|
||||
reducerPath: 'gameApi',
|
||||
baseQuery: customBaseQuery,
|
||||
endpoints: (builder) => ({
|
||||
getGameInfo: builder.query<GameState, void>({
|
||||
query: () => {return {method: 'info', params: {}}},
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
// Export hooks for usage in functional components, which are
|
||||
// auto-generated based on the defined endpoints
|
||||
export const { useGetGameInfoQuery } = gameApi
|
||||
@@ -1,48 +0,0 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import { LeanClient } from 'lean4web/client/src/editor/leanclient'
|
||||
import { Connection } from '../connection'
|
||||
import type { RootState } from '../store'
|
||||
|
||||
interface GameState {
|
||||
title: null|string,
|
||||
introduction: null|string,
|
||||
worlds: null|{nodes: string[], edges: string[][2]},
|
||||
authors: null|string[],
|
||||
conclusion: null|string,
|
||||
}
|
||||
|
||||
const initialState : GameState = {
|
||||
title: null,
|
||||
introduction: null,
|
||||
worlds: null,
|
||||
authors: null,
|
||||
conclusion: null,
|
||||
}
|
||||
|
||||
export const gameSlice = createSlice({
|
||||
name: 'game',
|
||||
initialState,
|
||||
reducers: {
|
||||
loadedGame: (state, action: PayloadAction<any>) => {
|
||||
state.title = action.payload.title
|
||||
state.introduction = action.payload.introduction
|
||||
state.worlds = action.payload.worlds
|
||||
state.authors = action.payload.authors
|
||||
state.conclusion = action.payload.conclusion
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const { loadedGame } = gameSlice.actions
|
||||
|
||||
|
||||
export const fetchGame = (dispatch, getState, extraArgument) => {
|
||||
const connection : Connection = extraArgument.connection
|
||||
connection.whenLeanClientStarted(() => {
|
||||
connection.getLeanClient().sendRequest("info", {}).then((res) =>{
|
||||
dispatch(loadedGame(res))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default gameSlice.reducer
|
||||
+3
-5
@@ -1,21 +1,19 @@
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import gameReducer from './game/gameSlice';
|
||||
import { connection } from './connection'
|
||||
import thunkMiddleware from 'redux-thunk'
|
||||
import { gameApi } from './game/api'
|
||||
|
||||
|
||||
const thunkMiddlewareWithArg = thunkMiddleware.withExtraArgument({ connection })
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
game: gameReducer,
|
||||
[gameApi.reducerPath]: gameApi.reducer,
|
||||
},
|
||||
middleware: getDefaultMiddleware =>
|
||||
getDefaultMiddleware({
|
||||
thunk: {
|
||||
extraArgument: { connection }
|
||||
}
|
||||
})
|
||||
}).concat(gameApi.middleware),
|
||||
});
|
||||
|
||||
// Infer the `RootState` and `AppDispatch` types from the store itself
|
||||
|
||||
Reference in New Issue
Block a user