2021-05-19 17:56:41 +00:00
|
|
|
import { useCallback, useEffect, useState } from "react"
|
|
|
|
import useBackendRequest from "./useBackendRequest"
|
2021-05-12 02:10:36 +00:00
|
|
|
|
|
|
|
|
2021-05-19 14:47:29 +00:00
|
|
|
/**
|
|
|
|
* An hook which allows access to a full REST viewset (list, create, retrieve, edit, delete).
|
|
|
|
*
|
|
|
|
* @param resourcesPath - The path of the resource directory.
|
|
|
|
* @param pkName - The name of the primary key attribute of the elements.
|
2021-05-19 17:56:41 +00:00
|
|
|
* @param allowViews - An object with maps views to a boolean detailing if they're allowed in the viewset or not.
|
2021-05-19 14:47:29 +00:00
|
|
|
*/
|
2021-05-19 17:56:41 +00:00
|
|
|
export default function useBackendViewset(resourcesPath, pkName,
|
|
|
|
{
|
|
|
|
list: allowList = true,
|
|
|
|
create: allowCreate = true,
|
|
|
|
retrieve: allowRetrieve = true,
|
|
|
|
edit: allowEdit = true,
|
|
|
|
destroy: allowDestroy = true,
|
|
|
|
command: allowCommand = false,
|
|
|
|
action: allowAction = false,
|
|
|
|
} = {}) {
|
|
|
|
const {abort, running, apiRequest} = useBackendRequest()
|
|
|
|
|
|
|
|
const [firstLoad, setFirstLoad] = useState(false)
|
|
|
|
const [resources, setResources] = useState([])
|
|
|
|
const [error, setError] = useState(null)
|
2021-05-12 02:10:36 +00:00
|
|
|
|
|
|
|
const apiList = useCallback(
|
2021-05-19 17:56:41 +00:00
|
|
|
async (init) => {
|
|
|
|
if(!allowList) throw new ViewNotAllowedError("list")
|
|
|
|
return await apiRequest("GET", `${resourcesPath}`, undefined, init)
|
|
|
|
},
|
|
|
|
[apiRequest, allowList, resourcesPath],
|
2021-05-12 02:10:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const apiRetrieve = useCallback(
|
2021-05-19 17:56:41 +00:00
|
|
|
async (id, init) => {
|
|
|
|
if(!allowRetrieve) throw new ViewNotAllowedError("retrieve")
|
|
|
|
return await apiRequest("GET", `${resourcesPath}${id}`, undefined, init)
|
|
|
|
},
|
|
|
|
[apiRequest, allowRetrieve, resourcesPath],
|
2021-05-12 02:10:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const apiCreate = useCallback(
|
2021-05-19 17:56:41 +00:00
|
|
|
async (data, init) => {
|
|
|
|
if(!allowCreate) throw new ViewNotAllowedError("create")
|
|
|
|
return await apiRequest("POST", `${resourcesPath}`, data, init)
|
|
|
|
},
|
|
|
|
[apiRequest, allowCreate, resourcesPath],
|
2021-05-12 02:10:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const apiEdit = useCallback(
|
2021-05-19 17:56:41 +00:00
|
|
|
async (id, data, init) => {
|
|
|
|
if(!allowEdit) throw new ViewNotAllowedError("edit")
|
|
|
|
return await apiRequest("PUT", `${resourcesPath}${id}`, data, init)
|
|
|
|
},
|
|
|
|
[apiRequest, allowEdit, resourcesPath],
|
2021-05-12 02:10:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const apiDestroy = useCallback(
|
2021-05-19 17:56:41 +00:00
|
|
|
async (id, init) => {
|
|
|
|
if(!allowDestroy) throw new ViewNotAllowedError("destroy")
|
|
|
|
return await apiRequest("DELETE", `${resourcesPath}${id}`, undefined, init)
|
|
|
|
},
|
|
|
|
[apiRequest, allowDestroy, resourcesPath],
|
2021-05-12 02:10:36 +00:00
|
|
|
)
|
|
|
|
|
2021-05-19 17:56:41 +00:00
|
|
|
const apiCommand = useCallback(
|
|
|
|
async (method, command, data, init) => {
|
|
|
|
if(!allowCommand) throw new ViewNotAllowedError("command")
|
|
|
|
return await apiRequest(method, `${resourcesPath}${command}`, data, init)
|
|
|
|
},
|
|
|
|
[apiRequest, allowCommand, resourcesPath]
|
|
|
|
)
|
|
|
|
|
|
|
|
const apiAction = useCallback(
|
|
|
|
async (method, id, command, data, init) => {
|
|
|
|
if(!allowAction) throw new ViewNotAllowedError("action")
|
|
|
|
return await apiRequest(method, `${resourcesPath}${id}/${command}`, data, init)
|
|
|
|
},
|
|
|
|
[apiRequest, allowAction, resourcesPath]
|
|
|
|
)
|
|
|
|
|
|
|
|
const listResources = useCallback(
|
2021-05-12 02:10:36 +00:00
|
|
|
async () => {
|
|
|
|
try {
|
|
|
|
setResources(await apiList())
|
|
|
|
}
|
|
|
|
catch(e) {
|
2021-05-19 17:56:41 +00:00
|
|
|
setError(e)
|
|
|
|
throw e
|
2021-05-12 02:10:36 +00:00
|
|
|
}
|
2021-05-19 17:56:41 +00:00
|
|
|
setError(null)
|
2021-05-12 02:10:36 +00:00
|
|
|
return {}
|
|
|
|
},
|
|
|
|
[apiList],
|
|
|
|
)
|
|
|
|
|
2021-05-19 17:56:41 +00:00
|
|
|
const retrieveResource = useCallback(
|
2021-05-12 23:07:17 +00:00
|
|
|
async (pk) => {
|
2021-05-19 17:56:41 +00:00
|
|
|
const refreshedResource = await apiRetrieve(pk)
|
|
|
|
setResources(resources => resources.map(resource => {
|
|
|
|
if(resource[pkName] === pk) {
|
|
|
|
return refreshedResource
|
|
|
|
}
|
|
|
|
return resource
|
|
|
|
}))
|
|
|
|
return refreshedResource
|
2021-05-12 23:07:17 +00:00
|
|
|
},
|
2021-05-13 15:05:33 +00:00
|
|
|
[apiRetrieve, pkName],
|
2021-05-12 23:07:17 +00:00
|
|
|
)
|
|
|
|
|
2021-05-12 02:10:36 +00:00
|
|
|
const createResource = useCallback(
|
|
|
|
async (data) => {
|
2021-05-19 17:56:41 +00:00
|
|
|
const newResource = await apiCreate(data)
|
|
|
|
setResources(resources => [...resources, newResource])
|
|
|
|
return newResource
|
2021-05-12 02:10:36 +00:00
|
|
|
},
|
|
|
|
[apiCreate],
|
|
|
|
)
|
|
|
|
|
|
|
|
const editResource = useCallback(
|
|
|
|
async (pk, data) => {
|
2021-05-19 17:56:41 +00:00
|
|
|
const editedResource = await apiEdit(pk, data)
|
|
|
|
setResources(resources => resources.map(resource => {
|
|
|
|
if(resource[pkName] === pk) {
|
|
|
|
return editedResource
|
|
|
|
}
|
|
|
|
return resource
|
|
|
|
}))
|
|
|
|
return editedResource
|
2021-05-12 02:10:36 +00:00
|
|
|
},
|
|
|
|
[apiEdit, pkName],
|
|
|
|
)
|
|
|
|
|
|
|
|
const destroyResource = useCallback(
|
|
|
|
async (pk) => {
|
2021-05-19 17:56:41 +00:00
|
|
|
await apiDestroy(pk)
|
|
|
|
setResources(resources => resources.filter(resource => resource[pkName] !== pk))
|
|
|
|
return null
|
2021-05-12 02:10:36 +00:00
|
|
|
},
|
|
|
|
[apiDestroy, pkName],
|
|
|
|
)
|
|
|
|
|
|
|
|
useEffect(
|
2021-05-19 17:56:41 +00:00
|
|
|
async () => {
|
|
|
|
if(allowList && !firstLoad && !running) {
|
|
|
|
await listResources()
|
|
|
|
setFirstLoad(true)
|
2021-05-12 02:10:36 +00:00
|
|
|
}
|
|
|
|
},
|
2021-05-19 17:56:41 +00:00
|
|
|
[listResources, firstLoad, running, allowList],
|
2021-05-12 02:10:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
return {
|
|
|
|
abort,
|
|
|
|
resources,
|
2021-05-19 17:56:41 +00:00
|
|
|
firstLoad,
|
2021-05-12 02:10:36 +00:00
|
|
|
running,
|
2021-05-19 17:56:41 +00:00
|
|
|
error,
|
2021-05-12 23:07:17 +00:00
|
|
|
apiRequest,
|
2021-05-19 17:56:41 +00:00
|
|
|
allowList,
|
2021-05-12 02:10:36 +00:00
|
|
|
apiList,
|
2021-05-19 17:56:41 +00:00
|
|
|
listResources,
|
|
|
|
allowRetrieve,
|
2021-05-12 02:10:36 +00:00
|
|
|
apiRetrieve,
|
2021-05-19 17:56:41 +00:00
|
|
|
retrieveResource,
|
|
|
|
allowCreate,
|
2021-05-12 02:10:36 +00:00
|
|
|
apiCreate,
|
|
|
|
createResource,
|
2021-05-19 17:56:41 +00:00
|
|
|
allowEdit,
|
|
|
|
apiEdit,
|
2021-05-12 02:10:36 +00:00
|
|
|
editResource,
|
2021-05-19 17:56:41 +00:00
|
|
|
allowDestroy,
|
|
|
|
apiDestroy,
|
2021-05-12 02:10:36 +00:00
|
|
|
destroyResource,
|
2021-05-19 17:56:41 +00:00
|
|
|
apiCommand,
|
|
|
|
apiAction,
|
2021-05-12 02:10:36 +00:00
|
|
|
}
|
|
|
|
}
|