1
Fork 0
mirror of https://github.com/pds-nest/nest.git synced 2024-11-26 06:54:18 +00:00

🔧 "Complete" RepositoryEditor

This commit is contained in:
Stefano Pigozzi 2021-05-08 01:40:49 +02:00
parent 22303cb85a
commit 0ce4ec6993
Signed by untrusted user who does not match committer: steffo
GPG key ID: 6965406171929D01
6 changed files with 68 additions and 32 deletions

View file

@ -6,6 +6,7 @@ import RepositorySummaryBase from "./RepositorySummaryBase"
import Loading from "../base/Loading" import Loading from "../base/Loading"
import BoxAlert from "../base/BoxAlert" import BoxAlert from "../base/BoxAlert"
import { faSearch } from "@fortawesome/free-solid-svg-icons" import { faSearch } from "@fortawesome/free-solid-svg-icons"
import useDataImmediately from "../../hooks/useDataImmediately"
/** /**
@ -17,7 +18,7 @@ import { faSearch } from "@fortawesome/free-solid-svg-icons"
*/ */
export default function BoxRepositoriesActive({ ...props }) { export default function BoxRepositoriesActive({ ...props }) {
const {user, fetchDataAuth} = useContext(ContextUser) const {user, fetchDataAuth} = useContext(ContextUser)
const {data, started, loading, error} = useData(fetchDataAuth, "GET", "/api/v1/repositories/", { const {data, started, loading, error} = useDataImmediately(fetchDataAuth, "GET", "/api/v1/repositories/", {
"onlyActive": true, "onlyActive": true,
}) })

View file

@ -1,11 +1,11 @@
import React, { useContext } from "react" import React, { useContext } from "react"
import BoxFull from "../base/BoxFull" import BoxFull from "../base/BoxFull"
import ContextUser from "../../contexts/ContextUser" import ContextUser from "../../contexts/ContextUser"
import useData from "../../hooks/useData"
import RepositorySummaryBase from "./RepositorySummaryBase" import RepositorySummaryBase from "./RepositorySummaryBase"
import Loading from "../base/Loading" import Loading from "../base/Loading"
import BoxAlert from "../base/BoxAlert" import BoxAlert from "../base/BoxAlert"
import { faSearch } from "@fortawesome/free-solid-svg-icons" import { faSearch } from "@fortawesome/free-solid-svg-icons"
import useDataImmediately from "../../hooks/useDataImmediately"
/** /**
@ -17,7 +17,7 @@ import { faSearch } from "@fortawesome/free-solid-svg-icons"
*/ */
export default function BoxRepositoriesArchived({ ...props }) { export default function BoxRepositoriesArchived({ ...props }) {
const {user, fetchDataAuth} = useContext(ContextUser) const {user, fetchDataAuth} = useContext(ContextUser)
const {data, started, loading, error} = useData(fetchDataAuth, "GET", "/api/v1/repositories/", { const {data, started, loading, error} = useDataImmediately(fetchDataAuth, "GET", "/api/v1/repositories/", {
"onlyDead": true, "onlyDead": true,
}) })

View file

@ -7,6 +7,7 @@ import { faFolder, faPlus } from "@fortawesome/free-solid-svg-icons"
import Radio from "../base/Radio" import Radio from "../base/Radio"
import Button from "../base/Button" import Button from "../base/Button"
import useRepositoryEditor from "../../hooks/useRepositoryEditor" import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import FormAlert from "../base/formparts/FormAlert"
export default function BoxRepositoryCreate({ ...props }) { export default function BoxRepositoryCreate({ ...props }) {
@ -16,11 +17,12 @@ export default function BoxRepositoryCreate({ ...props }) {
name, name,
setName, setName,
save, save,
error,
} = useRepositoryEditor() } = useRepositoryEditor()
return ( return (
<BoxFull header={"Create repository"} {...props}> <BoxFull header={"Create repository"} {...props}>
<FormLabelled> <FormLabelled onSubmit={e => {e.preventDefault(); save()}}>
<FormLabel htmlFor={"repo-name"} text={"Repository name"}> <FormLabel htmlFor={"repo-name"} text={"Repository name"}>
<InputWithIcon <InputWithIcon
id={"repo-name"} id={"repo-name"}
@ -48,6 +50,11 @@ export default function BoxRepositoryCreate({ ...props }) {
Every filter Every filter
</label> </label>
</FormLabel> </FormLabel>
{error ?
<FormAlert color={"Red"}>
{error.toString()}
</FormAlert>
: null}
<Button style={{"gridColumn": "1 / 3"}} icon={faPlus} color={"Green"} onClick={e => save()}> <Button style={{"gridColumn": "1 / 3"}} icon={faPlus} color={"Green"} onClick={e => save()}>
Create repository Create repository
</Button> </Button>

View file

@ -1,4 +1,4 @@
import React, { useCallback, useState } from "react" import React, { useCallback, useContext, useState } from "react"
import ContextRepositoryEditor from "../../contexts/ContextRepositoryEditor" import ContextRepositoryEditor from "../../contexts/ContextRepositoryEditor"
import useArrayState from "../../hooks/useArrayState" import useArrayState from "../../hooks/useArrayState"
import Style from "./RepositoryEditor.module.css" import Style from "./RepositoryEditor.module.css"
@ -9,10 +9,11 @@ import BoxConditionDatetime from "../interactive/BoxConditionDatetime"
import BoxConditions from "../interactive/BoxConditions" import BoxConditions from "../interactive/BoxConditions"
import BoxRepositoryCreate from "../interactive/BoxRepositoryCreate" import BoxRepositoryCreate from "../interactive/BoxRepositoryCreate"
import classNames from "classnames" import classNames from "classnames"
import ContextUser from "../../contexts/ContextUser"
import useData from "../../hooks/useData"
export default function RepositoryEditor({ export default function RepositoryEditor({
refresh,
id = null, id = null,
name, name,
is_active: isActive, is_active: isActive,
@ -44,27 +45,38 @@ export default function RepositoryEditor({
} = useArrayState(conditions) } = useArrayState(conditions)
/** The operator the conditions should be evaluated with. */ /** The operator the conditions should be evaluated with. */
const [_evaluationMode, setEvaluationMode] = useState(evaluationMode) const [_evaluationMode, setEvaluationMode] = useState(evaluationMode ?? 0)
const {user, fetchDataAuth} = useContext(ContextUser)
const method = id ? "PUT" : "POST"
const path = id ? `/api/v1/repositories/${id}` : `/api/v1/repositories/`
const body = {
"conditions": _conditions,
"end": _end,
"evaluation_mode": _evaluationMode,
"id": id,
"is_active": true,
"name": _name,
"owner": user,
"start": _start,
}
const {error, loading, fetchNow} = useData(fetchDataAuth, method, path, body)
/**
* Invia al backend le modifiche effettuate.
*/
const save = useCallback( const save = useCallback(
() => { () => {
if(id === null) { if(id) {
// POST console.info("Creating new repository with body: ", body)
throw new Error("Not yet implemented")
} }
else { else {
// PUT console.info("Editing repository ", id, " with body: ", body)
throw new Error("Not yet implemented")
} }
fetchNow()
refresh()
}, },
[id] [id, body, fetchNow]
) )
/** /**
* Cancel the changes made so far to the repository. * Cancel the changes made so far to the repository.
*/ */
@ -119,6 +131,7 @@ export default function RepositoryEditor({
end: _end, setEnd, end: _end, setEnd,
conditions: _conditions, addCondition, appendRawCondition, removeRawCondition, spliceRawCondition, conditions: _conditions, addCondition, appendRawCondition, removeRawCondition, spliceRawCondition,
evaluationMode: _evaluationMode, setEvaluationMode, evaluationMode: _evaluationMode, setEvaluationMode,
error, loading,
revert, save, revert, save,
}}> }}>
<div className={classNames(Style.RepositoryEditor, className)}> <div className={classNames(Style.RepositoryEditor, className)}>

View file

@ -9,13 +9,11 @@ import { useCallback, useEffect, useState } from "react"
* @param path - The HTTP path to fetch the data at. * @param path - The HTTP path to fetch the data at.
* @param body - The body of the HTTP request (it will be JSONified before being sent). * @param body - The body of the HTTP request (it will be JSONified before being sent).
* @param init - Additional `init` parameters to pass to `fetch`. * @param init - Additional `init` parameters to pass to `fetch`.
* @returns {{data: *, refresh: function, error: Error}}
*/ */
export default function useData(fetchData, method, path, body, init) { export default function useData(fetchData, method, path, body, init) {
const [error, setError] = useState(null) const [error, setError] = useState(null)
const [data, setData] = useState(null) const [data, setData] = useState(null)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const started = (loading || data || error)
/** /**
* Load data from the API. * Load data from the API.
@ -41,7 +39,7 @@ export default function useData(fetchData, method, path, body, init) {
/** /**
* Invalidate the data loaded from the API and try to load it again. * Invalidate the data loaded from the API and try to load it again.
*/ */
const refresh = useCallback( const fetchNow = useCallback(
async () => { async () => {
console.debug("Clearing data...") console.debug("Clearing data...")
setData(null) setData(null)
@ -54,15 +52,5 @@ export default function useData(fetchData, method, path, body, init) {
[load] [load]
) )
useEffect( return {data, error, loading, fetchNow}
() => {
if(!started) {
// noinspection JSIgnoredPromiseFromCall
load()
}
},
[load, started]
)
return {data, error, loading, started, refresh}
} }

View file

@ -0,0 +1,27 @@
import useData from "./useData"
import { useEffect } from "react"
/**
* Like {@link useData}, but runs as soon as the component is rendered.
*
* @param fetchData - The function to use when fetching data.
* @param method - The HTTP method to use.
* @param path - The HTTP path to fetch the data at.
* @param body - The body of the HTTP request (it will be JSONified before being sent).
* @param init - Additional `init` parameters to pass to `fetch`.
*/
export default function useDataImmediately(fetchData, method, path, body, init) {
const {data, error, loading, fetchNow} = useData(fetchData, method, path, body, init)
useEffect(
() => {
if(!(loading || data || error)) {
fetchNow()
}
},
[data, error, loading, fetchNow]
)
return {data, error, loading, fetchNow}
}