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

Add group edit box

This commit is contained in:
Steffo 2021-10-12 05:27:39 +02:00
parent b100f148ea
commit 7ebc8a82d8
4 changed files with 81 additions and 39 deletions

View file

@ -8,7 +8,7 @@
"@fortawesome/free-solid-svg-icons": "^5.15.4", "@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15", "@fortawesome/react-fontawesome": "^0.1.15",
"@reach/router": "^1.3.4", "@reach/router": "^1.3.4",
"@steffo/bluelib-react": "^4.0.4", "@steffo/bluelib-react": "^4.0.5",
"@testing-library/jest-dom": "^5.11.4", "@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0", "@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10", "@testing-library/user-event": "^12.1.10",

View file

@ -57,6 +57,7 @@ function App({..._}: RouteComponentProps) {
groupPk={selection.value.slug} groupPk={selection.value.slug}
unselectedRoute={({viewSet}) => <> unselectedRoute={({viewSet}) => <>
<ProjectListBox viewSet={viewSet}/> <ProjectListBox viewSet={viewSet}/>
<GroupCreateBox resource={selection}/>
</>} </>}
selectedRoute={({selection}) => <> selectedRoute={({selection}) => <>
<NotebookRouter <NotebookRouter

View file

@ -1,28 +1,28 @@
import {Box, Details, Form, useFormState} from "@steffo/bluelib-react" import {Box, Details, Form, Idiomatic as I, 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 {useCacheContext} from "../../contexts/cache"
import {useInstanceContext} from "../../contexts/instance" import {useInstanceContext} from "../../contexts/instance"
import {ManagedViewSet} from "../../hooks/useManagedViewSet" import {ManagedResource, ManagedViewSet} from "../../hooks/useManagedViewSet"
import {SophonResearchGroup} from "../../types/SophonTypes" import {SophonResearchGroup} from "../../types/SophonTypes"
import {ErrorBox} from "../errors/ErrorBox"
export interface GroupCreateBoxProps { export interface GroupCreateBoxProps {
viewSet: ManagedViewSet<SophonResearchGroup> viewSet?: ManagedViewSet<SophonResearchGroup>,
resource?: ManagedResource<SophonResearchGroup>,
} }
export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | null { export function GroupCreateBox({viewSet, resource}: GroupCreateBoxProps): JSX.Element | null {
const instance = useInstanceContext() const instance = useInstanceContext()
const authorization = useAuthorizationContext() const authorization = useAuthorizationContext()
const cache = useCacheContext() const cache = useCacheContext()
const name = const name =
useFormState<string>("", val => val.length > 0 ? true : undefined) useFormState<string>(resource?.value.name ?? "", val => val.length > 0 ? true : undefined)
const description = const description =
useFormState<string>("", val => val.length > 0 ? true : undefined) useFormState<string>(resource?.value.description ?? "", val => val.length > 0 ? true : undefined)
const membersOptions: { [key: string]: number } | undefined = const membersOptions: { [key: string]: number } | undefined =
React.useMemo( React.useMemo(
@ -37,18 +37,28 @@ export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | nu
) )
const members = const members =
useFormState<number[]>([], arr => arr.length > 0 ? true : undefined) useFormState<number[]>(resource?.value.members ?? [], arr => arr.length > 0 ? true : undefined)
const access = const access =
useFormState<"OPEN" | "MANUAL" | undefined>(undefined, val => ( useFormState<"OPEN" | "MANUAL" | undefined>(resource?.value.access ?? undefined, val => (
val?.length val?.length
) ? true : undefined) ) ? true : undefined)
const slug = name.value.replaceAll(/[^A-Za-z0-9-]/g, "-").toLowerCase() const slug = name.value.replaceAll(/[^A-Za-z0-9-]/g, "-").toLowerCase()
const doCreate = const onSubmit =
React.useCallback( React.useCallback(
async () => { async () => {
if(resource) {
await resource.update({
name: name.value,
slug: slug,
description: description.value,
members: members.value,
access: access.value,
})
}
else if(viewSet) {
await viewSet.create({ await viewSet.create({
name: name.value, name: name.value,
slug: slug, slug: slug,
@ -56,11 +66,36 @@ export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | nu
members: members.value, members: members.value,
access: access.value, access: access.value,
}) })
}
}, },
[viewSet, name, slug, description, members, access], [viewSet, resource, name, slug, description, members, access],
) )
const canCreate = const trueMembers =
React.useMemo(
() => resource ? [...new Set([resource.value.owner, ...resource.value.members])] : undefined,
[resource],
)
const canEdit =
React.useMemo(
() => !resource ||
(
authorization && authorization.state.user && trueMembers?.includes(authorization.state.user.id)
),
[authorization, resource],
)
const canAdministrate =
React.useMemo(
() => !resource ||
(
authorization && authorization.state.user && authorization.state.user.id === resource.value.owner
),
[authorization, resource],
)
const canSubmit =
React.useMemo( React.useMemo(
() => name.validity === true && access.validity === true && Boolean(authorization?.state.user?.username), () => name.validity === true && access.validity === true && Boolean(authorization?.state.user?.username),
[name, access, authorization], [name, access, authorization],
@ -69,22 +104,31 @@ export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | nu
if(!authorization?.state.token) { if(!authorization?.state.token) {
return null return null
} }
if(!(
viewSet || resource
)) {
return null
}
if(!canEdit) {
return null
}
return ( return (
<Box> <Box>
<Details> <Details>
<Details.Summary> <Details.Summary>
Create a new group {resource ? <>Edit <I>{resource.value.name}</I></> : "Create a new group"}
</Details.Summary> </Details.Summary>
<Details.Content> <Details.Content>
<Form> <Form>
<Form.Field label={"Name"} required {...name}/> <Form.Field label={"Name"} required disabled={!canEdit} {...name}/>
<Form.Field label={"Slug"} required disabled={true} value={slug} validity={slug.length > 0 ? true : undefined}/> <Form.Field label={"Slug"} required disabled={true} value={slug} validity={slug.length > 0 ? true : undefined}/>
<Form.Area label={"Description"} {...description}/> <Form.Area label={"Description"} disabled={!canEdit} {...description}/>
<Form.Multiselect label={"Members"} options={membersOptions ?? {}} {...members}/> <Form.Multiselect label={"Members"} disabled={!canAdministrate} options={membersOptions ?? {}} {...members}/>
<Form.Field label={"Owner"} required disabled={true} value={authorization?.state.user?.username} validity={Boolean(authorization?.state.user?.username)}/> <Form.Field label={"Owner"} required disabled={true} value={authorization?.state.user?.username} validity={Boolean(authorization?.state.user?.username)}/>
<Form.Select <Form.Select
label={"Access"} label={"Access"}
disabled={!canAdministrate}
options={{ options={{
"": undefined, "": undefined,
"⛔️ Collaborators must be added manually": "MANUAL", "⛔️ Collaborators must be added manually": "MANUAL",
@ -92,16 +136,13 @@ export function GroupCreateBox({viewSet}: GroupCreateBoxProps): JSX.Element | nu
}} }}
{...access} {...access}
/> />
{
viewSet.operationError ?
<Form.Row> <Form.Row>
<ErrorBox error={viewSet.operationError ?? undefined}/> <Form.Button
</Form.Row> type={"button"} onClick={onSubmit} disabled={!canSubmit} builtinColor={(
: null viewSet?.operationError || resource?.error
} ) ? "red" : undefined}
<Form.Row> >
<Form.Button type={"button"} onClick={doCreate} disabled={!canCreate}> {resource ? "Edit" : "Create"}
Create
</Form.Button> </Form.Button>
</Form.Row> </Form.Row>
</Form> </Form>

View file

@ -1617,10 +1617,10 @@
dependencies: dependencies:
"@sinonjs/commons" "^1.7.0" "@sinonjs/commons" "^1.7.0"
"@steffo/bluelib-react@^4.0.4": "@steffo/bluelib-react@^4.0.5":
version "4.0.4" version "4.0.5"
resolved "https://registry.yarnpkg.com/@steffo/bluelib-react/-/bluelib-react-4.0.4.tgz#1a4f4ccd3ee185603a95b7a0a183a919f29e9d32" resolved "https://registry.yarnpkg.com/@steffo/bluelib-react/-/bluelib-react-4.0.5.tgz#6128454b03fc1888c4e7f4dbb1675f71fba2153c"
integrity sha512-ZwnAqbZ4LaYbQu56fMX0OIKBJA1X4LUfTIJsxnkJbPrr2qX0D+zQUl2vI2Jm/wlZdltvwm5ftCTLDwpqg/1h/g== integrity sha512-W2TguaP5vixV0C1/chQ+SO69YydBMLWG+ml7TVgRIHoRtr3cKHpp8VVij8qxovdZ1dnkBMD9/z3skcdoRpToag==
dependencies: dependencies:
"@babel/runtime" "^7.15.3" "@babel/runtime" "^7.15.3"
classnames "^2.3.1" classnames "^2.3.1"