1
Fork 0
mirror of https://github.com/Steffo99/sophon.git synced 2024-12-22 14:54:22 +00:00

🔧 Move users list to its own context

This commit is contained in:
Steffo 2021-10-12 04:12:17 +02:00
parent eb7d0ed84e
commit cd8dfb14d0
7 changed files with 72 additions and 79 deletions

View file

@ -21,6 +21,7 @@ import {ProjectRouter} from "./components/project/ProjectRouter"
import {ThemedBluelib} from "./components/theme/ThemedBluelib" import {ThemedBluelib} from "./components/theme/ThemedBluelib"
import {ThemedTitle} from "./components/theme/ThemedTitle" import {ThemedTitle} from "./components/theme/ThemedTitle"
import {AuthorizationProvider} from "./contexts/authorization" import {AuthorizationProvider} from "./contexts/authorization"
import {CacheProvider} from "./contexts/cache"
import {InstanceProvider} from "./contexts/instance" import {InstanceProvider} from "./contexts/instance"
import {ThemeProvider} from "./contexts/theme" import {ThemeProvider} from "./contexts/theme"
@ -40,26 +41,28 @@ function App({..._}: RouteComponentProps) {
<AuthorizationStepPage/> <AuthorizationStepPage/>
</>} </>}
selectedRoute={() => <> selectedRoute={() => <>
<GroupRouter <CacheProvider>
unselectedRoute={({viewSet}) => <> <GroupRouter
<GroupListBox viewSet={viewSet}/> unselectedRoute={({viewSet}) => <>
<GroupCreateBox viewSet={viewSet}/> <GroupListBox viewSet={viewSet}/>
</>} <GroupCreateBox viewSet={viewSet}/>
selectedRoute={({selection}) => <> </>}
<GroupDescriptionBox resource={selection}/> selectedRoute={({selection}) => <>
<ProjectRouter <GroupDescriptionBox resource={selection}/>
groupPk={selection.value.slug} <ProjectRouter
unselectedRoute={({viewSet}) => <ProjectListBox viewSet={viewSet}/>} groupPk={selection.value.slug}
selectedRoute={({selection}) => <> unselectedRoute={({viewSet}) => <ProjectListBox viewSet={viewSet}/>}
<NotebookRouter selectedRoute={({selection}) => <>
projectPk={selection.value.slug} <NotebookRouter
unselectedRoute={({viewSet}) => <NotebookListBox viewSet={viewSet}/>} projectPk={selection.value.slug}
selectedRoute={DebugBox} unselectedRoute={({viewSet}) => <NotebookListBox viewSet={viewSet}/>}
/> selectedRoute={DebugBox}
</>} />
/> </>}
</>} />
/> </>}
/>
</CacheProvider>
</>} </>}
/> />
</AuthorizationProvider> </AuthorizationProvider>

View file

@ -1,15 +1,18 @@
import {Box, BringAttention as B, Heading, ListUnordered as UL} from "@steffo/bluelib-react" import {Box, BringAttention as B, Heading, ListUnordered as UL} from "@steffo/bluelib-react"
import * as React from "react" import * as React from "react"
import {useInstanceContext} from "../../contexts/instance" import {useCacheContext} from "../../contexts/cache"
export function InstanceStatsBox(): JSX.Element | null { export function CacheStatsBox(): JSX.Element | null {
const instance = useInstanceContext() const cache = useCacheContext()
if(!instance) { if(!cache) {
return null return null
} }
if(!instance.state.users) { if(!cache.users) {
return null
}
if(!cache.users.resources) {
return null return null
} }
@ -19,7 +22,7 @@ export function InstanceStatsBox(): JSX.Element | null {
Instance stats Instance stats
</Heading> </Heading>
<UL> <UL>
<UL.Item>This instance has <B>{instance.state.users.length}</B> registered users.</UL.Item> <UL.Item>This instance has <B>{cache.users.resources.length}</B> registered users.</UL.Item>
</UL> </UL>
</Box> </Box>
) )

View file

@ -1,6 +1,7 @@
import {Box, Details, Form, useFormState} from "@steffo/bluelib-react" import {Box, Details, Form, useFormState} from "@steffo/bluelib-react"
import * as React from "react" import * as React from "react"
import {useAuthorizationContext} from "../../contexts/authorization" import {useAuthorizationContext} from "../../contexts/authorization"
import {useCacheContext} from "../../contexts/cache"
import {useInstanceContext} from "../../contexts/instance" import {useInstanceContext} from "../../contexts/instance"
import {ManagedViewSet} from "../../hooks/useManagedViewSet" import {ManagedViewSet} from "../../hooks/useManagedViewSet"
import {SophonResearchGroup} from "../../types/SophonTypes" import {SophonResearchGroup} from "../../types/SophonTypes"
@ -15,6 +16,7 @@ export interface GroupCreateBoxProps {
export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | null { export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | null {
const instance = useInstanceContext() const instance = useInstanceContext()
const authorization = useAuthorizationContext() const authorization = useAuthorizationContext()
const cache = useCacheContext()
const name = const name =
useFormState<string>("", val => val.length > 0 ? true : undefined) useFormState<string>("", val => val.length > 0 ? true : undefined)
@ -24,9 +26,9 @@ export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | nu
const membersOptions: { [key: string]: number } | undefined = const membersOptions: { [key: string]: number } | undefined =
React.useMemo( React.useMemo(
() => instance?.state?.users?.filter(m => m.id !== authorization?.state.user?.id).map(m => { () => cache.users?.resources?.filter(m => m.value.id !== authorization?.state.user?.id).map(m => {
const obj: { [key: string]: number } = {} const obj: { [key: string]: number } = {}
obj[m.username] = m.id obj[m.value.username] = m.value.id
return obj return obj
}).reduce((a, b) => { }).reduce((a, b) => {
return {...a, ...b} return {...a, ...b}

View file

@ -1,12 +1,11 @@
import {navigate} from "@reach/router" import {navigate} from "@reach/router"
import {Box, Form, Heading, useFormState} from "@steffo/bluelib-react" import {Box, Form, Heading, useFormState} from "@steffo/bluelib-react"
import {Validator} from "@steffo/bluelib-react/dist/types" import {Validator} from "@steffo/bluelib-react/dist/types"
import Axios, {AxiosResponse} from "axios-lab" import Axios from "axios-lab"
import * as React from "react" import * as React from "react"
import {CHECK_TIMEOUT_MS} from "../../constants" import {CHECK_TIMEOUT_MS} from "../../constants"
import {useInstanceContext} from "../../contexts/instance" import {useInstanceContext} from "../../contexts/instance"
import {DjangoPage} from "../../types/DjangoTypes" import {SophonInstanceDetails} from "../../types/SophonTypes"
import {SophonInstanceDetails, SophonUser} from "../../types/SophonTypes"
import {InstanceEncoder} from "../../utils/InstanceEncoder" import {InstanceEncoder} from "../../utils/InstanceEncoder"
@ -70,31 +69,11 @@ export function InstanceFormBox(): JSX.Element {
return null return null
} }
// Try to get the user data from the backend
// FIXME: This won't work if Django returns multiple pages, but it is insignificant right now, as we won't ever have >500 users
let users: AxiosResponse<DjangoPage<SophonUser>>
try {
users = await Axios.get<DjangoPage<SophonUser>>("/api/core/users/", {baseURL: url.toString(), signal})
}
catch(e) {
if(signal.aborted) {
return
}
else {
throw e
}
}
if(signal.aborted) {
return
}
// If the response is successful, update the info about the current instance // If the response is successful, update the info about the current instance
instance.dispatch({ instance.dispatch({
type: "select", type: "select",
url: url, url: url,
details: response.data, details: response.data,
users: users.data.results,
}) })
// Success! // Success!

View file

@ -3,8 +3,7 @@ import * as React from "react"
import {useInstanceContext} from "../../contexts/instance" import {useInstanceContext} from "../../contexts/instance"
import {useAbortEffect} from "../../hooks/useAbortEffect" import {useAbortEffect} from "../../hooks/useAbortEffect"
import {useSophonPath} from "../../hooks/useSophonPath" import {useSophonPath} from "../../hooks/useSophonPath"
import {DjangoPage} from "../../types/DjangoTypes" import {SophonInstanceDetails} from "../../types/SophonTypes"
import {SophonInstanceDetails, SophonUser} from "../../types/SophonTypes"
import {InstanceEncoder} from "../../utils/InstanceEncoder" import {InstanceEncoder} from "../../utils/InstanceEncoder"
@ -54,31 +53,11 @@ export function useInstanceLoader() {
return return
} }
// Try to get the user data from the backend
// FIXME: This won't work if Django returns multiple pages, but it is insignificant right now, as we won't ever have >500 users
let users: AxiosResponse<DjangoPage<SophonUser>>
try {
users = await Axios.get<DjangoPage<SophonUser>>("/api/core/users/", {baseURL: url.toString(), signal})
}
catch(e) {
if(signal.aborted) {
return
}
else {
throw e
}
}
if(signal.aborted) {
return
}
// If the response is successful, update the info about the current instance // If the response is successful, update the info about the current instance
instance.dispatch({ instance.dispatch({
type: "select", type: "select",
url: url, url: url,
details: response.data, details: response.data,
users: users.data.results,
}) })
}, },
[instance, path], [instance, path],

View file

@ -0,0 +1,32 @@
import * as React from "react"
import {ManagedViewSet, useManagedViewSet} from "../hooks/useManagedViewSet"
import {WithChildren} from "../types/ExtraTypes"
import {SophonUser} from "../types/SophonTypes"
// States
type Cache = {
users?: ManagedViewSet<SophonUser>,
}
// Actions
const cacheContext = React.createContext<Cache>({})
const CacheContext = cacheContext
// Hooks
export function useCacheContext(): Cache {
return React.useContext(cacheContext)
}
// Components
export function CacheProvider({children}: WithChildren): JSX.Element {
const users = useManagedViewSet<SophonUser>("/api/core/users/", "id")
return <CacheContext.Provider value={{users}} children={children}/>
}

View file

@ -1,20 +1,18 @@
import * as React from "react" import * as React from "react"
import {ContextData} from "../types/ContextTypes" import {ContextData} from "../types/ContextTypes"
import {WithChildren} from "../types/ExtraTypes" import {WithChildren} from "../types/ExtraTypes"
import {SophonInstanceDetails, SophonUser} from "../types/SophonTypes" import {SophonInstanceDetails} from "../types/SophonTypes"
// States // States
type InstanceNotSelected = { type InstanceNotSelected = {
url: undefined, url: undefined,
details: undefined, details: undefined,
users: undefined,
} }
type InstanceSelected = { type InstanceSelected = {
url: URL, url: URL,
details: SophonInstanceDetails, details: SophonInstanceDetails,
users: SophonUser[],
} }
@ -24,7 +22,6 @@ type InstanceSelect = {
type: "select", type: "select",
url: URL, url: URL,
details: SophonInstanceDetails, details: SophonInstanceDetails,
users: SophonUser[],
} }
type InstanceDeselect = { type InstanceDeselect = {
@ -44,7 +41,6 @@ export type InstanceContextData = ContextData<InstanceState, InstanceAction> | u
const instanceDefaultState: InstanceState = { const instanceDefaultState: InstanceState = {
url: undefined, url: undefined,
details: undefined, details: undefined,
users: undefined,
} }
const instanceReducer: React.Reducer<InstanceState, InstanceAction> = (prevState, action) => { const instanceReducer: React.Reducer<InstanceState, InstanceAction> = (prevState, action) => {
@ -58,7 +54,6 @@ const instanceReducer: React.Reducer<InstanceState, InstanceAction> = (prevState
return { return {
url: action.url, url: action.url,
details: action.details, details: action.details,
users: action.users,
} }
case "deselect": case "deselect":
// Bail out if no instance is currently selected // Bail out if no instance is currently selected