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

🚧 More WIP API stuff

This commit is contained in:
Steffo 2021-09-19 23:49:16 +02:00
parent bcf1b3f238
commit 6ad2fd7070
Signed by: steffo
GPG key ID: 6965406171929D01
5 changed files with 172 additions and 18 deletions

View file

@ -102,7 +102,7 @@ export function useLoginAxios(config: AxiosRequestConfig = {}) {
baseURL: instance.value,
headers: {
...config?.headers,
authHeader,
...authHeader,
}
})
},

View file

@ -3,7 +3,11 @@ import * as ReactDOM from "react-dom"
import {useLoginAxios} from "./LoginContext";
import {useMemo} from "react";
import {Box, Heading} from "@steffo/bluelib-react";
import {ResearchGroupPanel, ResearchGroupPanelProps} from "./ResearchGroupPanel";
import {ResearchGroupPanel} from "./ResearchGroupPanel";
import {DRFList, ResearchGroup} from "../types";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faSpinner} from "@fortawesome/free-solid-svg-icons";
import {useDRFManagedViewSet} from "../hooks/useDRF";
interface ResearchGroupListBoxProps {
@ -12,10 +16,19 @@ interface ResearchGroupListBoxProps {
export function ResearchGroupListBox({}: ResearchGroupListBoxProps): JSX.Element {
const api = useLoginAxios()
const loading = React.useState<boolean>()
const {resources, refreshing} = useDRFManagedViewSet<ResearchGroup>("/api/core/groups/", "slug")
const data = React.useState<ResearchGroupPanelProps[]>([])
const groups = React.useMemo(
() => {
if(refreshing) {
return <span><FontAwesomeIcon icon={faSpinner} pulse={true}/> Loading...</span>
}
return resources.map(
res => <ResearchGroupPanel {...res}/>
)
},
[resources, refreshing]
)
return (
<Box>
@ -23,7 +36,7 @@ export function ResearchGroupListBox({}: ResearchGroupListBoxProps): JSX.Element
Research groups
</Heading>
<div>
{data.map(group => <ResearchGroupPanel {...group}/>)}
{groups}
</div>
</Box>
)

View file

@ -6,19 +6,10 @@ import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faEnvelope, faEye, faGlobe, faQuestion} from "@fortawesome/free-solid-svg-icons";
import {navigate} from "@reach/router";
import {IconDefinition} from "@fortawesome/fontawesome-svg-core";
import {ResearchGroup} from "../types";
export interface ResearchGroupPanelProps {
owner: number,
members: number[],
name: string,
description: string,
access: "OPEN" | "MANUAL",
slug: string,
}
export function ResearchGroupPanel({owner, name, access, slug}: ResearchGroupPanelProps): JSX.Element {
export function ResearchGroupPanel({owner, name, access, slug}: ResearchGroup): JSX.Element {
let accessIcon: IconDefinition
if(access === "OPEN") {
accessIcon = faGlobe

View file

@ -0,0 +1,145 @@
import {useLoginAxios} from "../components/LoginContext";
import * as React from "react";
import {DRFDetail, DRFList} from "../types";
import {AxiosRequestConfig, AxiosResponse} from "axios-lab";
export interface AxiosRequestConfigWithURL extends AxiosRequestConfig {
url: string,
}
export function useDRFViewSet<Resource extends DRFDetail>(baseRoute: string) {
const api = useLoginAxios()
const command =
React.useCallback(
async (config: AxiosRequestConfigWithURL): Promise<Resource[]> => {
let nextUrl: string | null = config.url
let resources: Resource[] = []
while(nextUrl !== null) {
const response: AxiosResponse<DRFList<Resource>> = await api.request<DRFList<Resource>>({...config, url: nextUrl})
nextUrl = response.data.next
resources = [...resources, ...response.data.results]
}
return resources
},
[api]
)
const action =
React.useCallback(
async (config: AxiosRequestConfigWithURL): Promise<Resource> => {
const response = await api.request<Resource>(config)
return response.data
},
[api]
)
const list =
React.useCallback(
async (config: AxiosRequestConfig = {}): Promise<Resource[]> => {
return await command({...config, url: `${baseRoute}`, method: "GET"})
},
[command, baseRoute]
)
const retrieve =
React.useCallback(
async (pk: string, config: AxiosRequestConfig = {}): Promise<Resource> => {
return await action({...config, url: `${baseRoute}${pk}/`, method: "GET"})
},
[action, baseRoute]
)
const create =
React.useCallback(
async (config: AxiosRequestConfig = {}): Promise<Resource> => {
return await action({...config, url: `${baseRoute}`, method: "POST"})
},
[action, baseRoute]
)
const update =
React.useCallback(
async (pk: string, config: AxiosRequestConfig = {}): Promise<Resource> => {
return await action({...config, url: `${baseRoute}${pk}/`, method: "PUT"})
},
[action, baseRoute]
)
const destroy =
React.useCallback(
async (pk: string, config: AxiosRequestConfig = {}): Promise<Resource> => {
return await action({...config, url: `${baseRoute}${pk}/`, method: "DELETE"})
},
[action, baseRoute]
)
return {command, action, list, retrieve, create, update, destroy}
}
export function useDRFManagedViewSet<Resource extends DRFDetail>(baseRoute: string, pkKey: string) {
const {list} = useDRFViewSet<Resource>(baseRoute)
const [resources, setResources] = React.useState<Resource[]>([])
const [refreshing, setRefreshing] = React.useState<boolean>(false)
const [running, setRunning] = React.useState<{[key: string]: boolean}>({})
const [error, setError] = React.useState<Error | null>(null)
const initRunning = React.useCallback(
(data: Resource[]): void => {
const runningMap = data.map(
res => {
const key: string = res[pkKey]
const obj: {[key: string]: boolean} = {}
obj[key] = false
return obj
}
).reduce(
(a, b) => {
return {...a, ...b}
}
)
setRunning(runningMap)
},
[pkKey, setRunning]
)
const refresh = React.useCallback(
async (signal: AbortSignal): Promise<void> => {
setRefreshing(true)
let data: Resource[]
try {
data = await list({signal})
}
catch(e) {
if(!signal.aborted) {
setError(e as Error)
}
return
}
finally {
setRefreshing(false)
}
setResources(data)
initRunning(data)
},
[list, setError, setRefreshing, setResources, initRunning]
)
React.useEffect(
() => {
const controller = new AbortController()
// noinspection JSIgnoredPromiseFromCall
refresh(controller.signal)
return () => {
controller.abort()
}
},
[]
)
return {resources, refreshing, running, error, refresh}
}

View file

@ -1,4 +1,9 @@
export interface DRFList<T> {
export interface DRFDetail {
[key: string]: any,
}
export interface DRFList<T extends DRFDetail> {
count: number,
next: string | null,
previous: string | null,