1
Fork 0
mirror of https://github.com/pds-nest/nest.git synced 2024-11-25 14:34:19 +00:00

Merge remote-tracking branch 'origin/main' into main

This commit is contained in:
Lorenzo Balugani 2021-05-10 16:25:43 +02:00
commit b5af4283ce
9 changed files with 172 additions and 32 deletions

View file

@ -7,6 +7,7 @@ import PageSettings from "./routes/PageSettings"
import PageSandbox from "./routes/PageSandbox"
import PageDashboard from "./routes/PageDashboard"
import PageRoot from "./routes/PageRoot"
import PageEdit from "./routes/PageEdit"
export default function PageSwitcher({ ...props }) {
@ -15,6 +16,9 @@ export default function PageSwitcher({ ...props }) {
<Route path={"/login"} exact={true}>
<PageLogin/>
</Route>
<Route path={"/repositories/:id/edit"} exact={true}>
<PageEdit/>
</Route>
<Route path={"/repositories"} exact={true}>
<PageRepositories/>
</Route>

View file

@ -18,18 +18,15 @@ import useDataImmediately from "../../hooks/useDataImmediately"
*/
export default function BoxRepositoriesActive({ ...props }) {
const {user, fetchDataAuth} = useContext(ContextUser)
const {data, started, loading, error} = useDataImmediately(fetchDataAuth, "GET", "/api/v1/repositories/", {
const {data, error} = useDataImmediately(fetchDataAuth, "GET", "/api/v1/repositories/", {
"onlyActive": true,
})
let contents;
if(!started || loading) {
contents = <Loading/>
}
else if(error) {
if(error) {
contents = <BoxAlert color={"Red"}>{error.toString()}</BoxAlert>
}
else {
else if(data) {
let repositories = [...data["owner"], ...data["spectator"]]
if(repositories.length > 0) {
contents = repositories.map(repo => (
@ -46,6 +43,9 @@ export default function BoxRepositoriesActive({ ...props }) {
contents = <i>There's nothing here.</i>
}
}
else {
contents = <Loading/>
}
return (
<BoxFull header={"Your active repositories"} {...props}>

View file

@ -17,18 +17,15 @@ import useDataImmediately from "../../hooks/useDataImmediately"
*/
export default function BoxRepositoriesArchived({ ...props }) {
const {user, fetchDataAuth} = useContext(ContextUser)
const {data, started, loading, error} = useDataImmediately(fetchDataAuth, "GET", "/api/v1/repositories/", {
const {data, error} = useDataImmediately(fetchDataAuth, "GET", "/api/v1/repositories/", {
"onlyDead": true,
})
let contents;
if(!started || loading) {
contents = <Loading/>
}
else if(error) {
if(error) {
contents = <BoxAlert color={"Red"}>{error.toString()}</BoxAlert>
}
else {
else if(data) {
let repositories = [...data["owner"], ...data["spectator"]]
if(repositories.length > 0) {
contents = repositories.map(repo => (
@ -45,6 +42,9 @@ export default function BoxRepositoriesArchived({ ...props }) {
contents = <i>There's nothing here.</i>
}
}
else {
contents = <Loading/>
}
return (
<BoxFull header={"Your archived repositories"} {...props}>

View file

@ -3,15 +3,23 @@ import BoxFull from "../base/BoxFull"
import FormLabelled from "../base/FormLabelled"
import FormLabel from "../base/formparts/FormLabel"
import InputWithIcon from "../base/InputWithIcon"
import { faFolder, faPlus } from "@fortawesome/free-solid-svg-icons"
import { faFolder, faPencilAlt, faPlus } from "@fortawesome/free-solid-svg-icons"
import Radio from "../base/Radio"
import Button from "../base/Button"
import useRepositoryEditor from "../../hooks/useRepositoryEditor"
import FormAlert from "../base/formparts/FormAlert"
/**
* A {@link BoxFull} allowing the user to save the changes made in the current {@link RepositoryEditor}.
*
* @param props
* @returns {JSX.Element}
* @constructor
*/
export default function BoxRepositoryCreate({ ...props }) {
const {
id,
evaluationMode,
setEvaluationMode,
name,
@ -35,7 +43,7 @@ export default function BoxRepositoryCreate({ ...props }) {
<label>
<Radio
name={"filter-mode"}
onClick={() => setEvaluationMode(0)}
onChange={() => setEvaluationMode(0)}
checked={evaluationMode === 0}
/>
At least one filter
@ -44,7 +52,7 @@ export default function BoxRepositoryCreate({ ...props }) {
<label>
<Radio
name={"filter-mode"}
onClick={() => setEvaluationMode(1)}
onChange={() => setEvaluationMode(1)}
checked={evaluationMode === 1}
/>
Every filter
@ -55,9 +63,28 @@ export default function BoxRepositoryCreate({ ...props }) {
{error.toString()}
</FormAlert>
: null}
<Button style={{"gridColumn": "1 / 3"}} icon={faPlus} color={"Green"} onClick={e => save()}>
{id ?
<Button
style={{"gridColumn": "1 / 3"}}
icon={faPencilAlt}
color={"Green"}
goTo={"/repositories"}
onClick={e => save()}
>
Edit repository
</Button>
:
<Button
style={{"gridColumn": "1 / 3"}}
icon={faPlus}
color={"Green"}
goTo={"/repositories"}
onClick={e => save()}
>
Create repository
</Button>
}
</FormLabelled>
</BoxFull>
)

View file

@ -1,18 +1,21 @@
import React from "react"
import React, { useContext } from "react"
import Style from "./RepositorySummaryBase.module.css"
import classNames from "classnames"
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
import Button from "../base/Button"
import { faArchive, faPencilAlt, faTrash } from "@fortawesome/free-solid-svg-icons"
import { useHistory } from "react-router"
import useData from "../../hooks/useData"
import ContextUser from "../../contexts/ContextUser"
/**
* A long line representing a repository in a list.
*
* @param id - The id of the repository.
* @param owner - The owner of the repository.
* @param icon - The FontAwesome IconDefinition that represents the repository.
* @param name - The title of the repository.
* @todo What goes in the details field?
* @param details - Whatever should be rendered in the details field.
* @param start - The start date of the repository.
* @param end - The end date of the repository.
* @param isActive - Whether the repository is active or not.
@ -25,8 +28,14 @@ import { faArchive, faPencilAlt, faTrash } from "@fortawesome/free-solid-svg-ico
* @constructor
*/
export default function RepositorySummaryBase(
{ icon, name, details, start, end, isActive, canDelete, canEdit, canArchive, className, ...props }
{ id, owner, icon, name, start, end, isActive, canDelete, canEdit, canArchive, className, ...props }
) {
const {fetchDataAuth} = useContext(ContextUser)
const {history} = useHistory()
const {fetchNow: archiveThis} = useData(fetchDataAuth, "PATCH", `/api/v1/repositories/${id}`, {"close": true})
const {fetchNow: unarchiveThis} = useData(fetchDataAuth, "PATCH", `/api/v1/repositories/${id}`, {"open": true})
const {fetchNow: deletThis} = useData(fetchDataAuth, "DELETE", `/api/v1/repositories/${id}`)
return (
<div className={classNames(Style.RepositorySummary, className)} {...props}>
<div className={Style.Left}>
@ -36,22 +45,45 @@ export default function RepositorySummaryBase(
<div className={Style.Title}>
{name}
</div>
<div className={Style.StartDate}>
{start}
<div className={Style.Author}>
{owner["username"]}
</div>
</div>
<div className={Style.Middle}>
{details}
<div className={Style.StartDate}>
Start: {start}
</div>
<div className={Style.EndDate}>
End: {end}
</div>
</div>
<div className={Style.Right}>
{canDelete ?
<Button color={"Red"} icon={faTrash}>Delete</Button>
<Button
color={"Red"}
icon={faTrash}
onClick={deletThis}
>
Delete
</Button>
: null}
{canEdit ?
<Button color={"Yellow"} icon={faPencilAlt}>Edit</Button>
<Button
color={"Yellow"}
icon={faPencilAlt}
onClick={() => history.push(`/repositories/${id}/edit`)}
>
Edit
</Button>
: null}
{canArchive ?
<Button color={"Grey"} icon={faArchive}>{isActive ? "Archive" : "Unarchive"}</Button>
<Button
color={"Grey"}
icon={faArchive}
onClick={isActive ? archiveThis : unarchiveThis}
>
{isActive ? "Archive" : "Unarchive"}
</Button>
: null}
</div>
</div>

View file

@ -50,7 +50,7 @@
align-self: flex-end;
}
.StartDate {
.Author {
grid-area: d;
font-size: small;
@ -59,10 +59,23 @@
.Middle {
flex-grow: 1;
height: 60px;
background-color: var(--bg-light);
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
}
.StartDate {
}
.EndDate {
}
.Right {

View file

@ -20,16 +20,19 @@ export default function useData(fetchData, method, path, body, init) {
*/
const load = useCallback(
async () => {
console.debug(`Trying to ${method} ${path}...`)
console.debug(`Loading ${method} ${path}...`)
setLoading(true)
console.debug(`Fetching ${method} ${path}...`)
try {
const _data = await fetchData(method, path, body, init)
console.debug(`Displaying data of ${method} ${path}: `, _data)
setData(_data)
} catch(e) {
console.debug(`Displaying error of ${method} ${path}: `, e)
setError(e)
} finally {
console.debug(`Stopping loading of ${method} ${path}...`)
setLoading(false)
}
},

View file

@ -0,0 +1,38 @@
import React, { useContext } from "react"
import Style from "./PageDashboard.module.css"
import classNames from "classnames"
import BoxHeader from "../components/base/BoxHeader"
import RepositoryEditor from "../components/providers/RepositoryEditor"
import useDataImmediately from "../hooks/useDataImmediately"
import ContextUser from "../contexts/ContextUser"
import BoxAlert from "../components/base/BoxAlert"
import RepositorySummaryBase from "../components/interactive/RepositorySummaryBase"
import { faSearch } from "@fortawesome/free-solid-svg-icons"
import Loading from "../components/base/Loading"
import BoxFull from "../components/base/BoxFull"
export default function PageEdit({ id, className, ...props }) {
const {fetchDataAuth} = useContext(ContextUser)
const {data, error} = useDataImmediately(fetchDataAuth, "GET", `/api/v1/repositories/${id}`)
let contents;
if(error) {
contents = <BoxAlert color={"Red"}>{error.toString()}</BoxAlert>
}
else if(data) {
contents = <RepositoryEditor className={Style.RepositoryEditor} {...data}/>
}
else {
contents = <Loading/>
}
return (
<div className={classNames(Style.PageHome, className)} {...props}>
<BoxHeader className={Style.Header}>
Edit repository
</BoxHeader>
{contents}
</div>
)
}

View file

@ -0,0 +1,23 @@
/**
* Decorator which adds a redirect on success to an event handler.
*
* @param func - The function to decorate.
* @param history - The history to push the destination to.
* @param destination - The path of the destination.
* @returns {(function(): void)|*}
*/
export default function goToOnSuccess(func, history, destination) {
return ([...args]) => {
let success = false
try {
func(...args)
success = true
}
catch(e) {
success = false
}
if(success) {
history.push(destination)
}
}
}