diff --git a/nest_frontend/components/interactive/BoxUserList.js b/nest_frontend/components/interactive/BoxUserList.js
index 4f18b1b..093f86b 100644
--- a/nest_frontend/components/interactive/BoxUserList.js
+++ b/nest_frontend/components/interactive/BoxUserList.js
@@ -9,13 +9,15 @@ import ContextLanguage from "../../contexts/ContextLanguage"
* A {@link BoxFullScrollable} rendering an array of users as {@link SummaryUser}s.
*
* @param users - Array of users to render.
+ * @param shareWithUser - Async function to share a repository with an user, to be passed to {@link SummaryUser}.
+ * @param unshareWithUser - Async function to unshare a repository with an user, to be passed to {@link SummaryUser}.
* @param destroyUser - Async function to destroy an user, to be passed to {@link SummaryUser}.
* @param running - Whether another request is currently running.
* @param props - Additional props to pass to the box.
* @returns {JSX.Element}
* @constructor
*/
-export default function BoxUserList({ users, destroyUser, running, ...props }) {
+export default function BoxUserList({ users, shareWithUser, unshareWithUser, destroyUser, running, ...props }) {
const { strings } = useContext(ContextLanguage)
let contents
@@ -23,8 +25,17 @@ export default function BoxUserList({ users, destroyUser, running, ...props }) {
contents =
}
else {
- contents = users.map(user =>
-
)
+ contents = users.map(user => (
+
+ )
+ )
}
return (
diff --git a/nest_frontend/components/interactive/SummaryRepository.js b/nest_frontend/components/interactive/SummaryRepository.js
index 2add0a4..75ba44e 100644
--- a/nest_frontend/components/interactive/SummaryRepository.js
+++ b/nest_frontend/components/interactive/SummaryRepository.js
@@ -35,6 +35,7 @@ export default function SummaryRepository(
title={repo.name}
subtitle={repo.owner ? repo.owner.username : null}
onClick={view}
+ disabled={running}
/>
to destroy an user from the frontend.
* @param running - Whether another request is already running.
* @param props - Additional props to pass to the summary.
* @returns {JSX.Element}
* @constructor
*/
-export default function SummaryUser({ user, destroyUser, running, ...props }) {
+export default function SummaryUser({ user, shareWithUser, unshareWithUser, destroyUser, running, ...props }) {
const { strings } = useContext(ContextLanguage)
return (
@@ -27,23 +30,52 @@ export default function SummaryUser({ user, destroyUser, running, ...props }) {
icon={user.isAdmin ? faStar : faUser}
title={user.username}
subtitle={user.email}
+ disabled={running}
/>
- {
- event.stopPropagation()
- // TODO: Errors are not caught here. Where should they be displayed?
- await destroyUser(user["email"])
- }}
- disabled={running}
- >
- {strings.delete}
-
+ {shareWithUser ?
+ {
+ event.stopPropagation()
+ await shareWithUser(user)
+ }}
+ disabled={running}
+ >
+ {strings.share}
+
+ : null}
+ {unshareWithUser ?
+ }
+ onClick={async event => {
+ event.stopPropagation()
+ await unshareWithUser(user)
+ }}
+ disabled={running}
+ >
+ {strings.unshare}
+
+ : null}
+ {destroyUser ?
+ {
+ event.stopPropagation()
+ // TODO: Errors are not caught here. Where should they be displayed?
+ await destroyUser(user["email"])
+ }}
+ disabled={running}
+ >
+ {strings.delete}
+
+ : null}
)
diff --git a/nest_frontend/index.css b/nest_frontend/index.css
index 840c96b..861df53 100644
--- a/nest_frontend/index.css
+++ b/nest_frontend/index.css
@@ -24,8 +24,9 @@ h1, h2, h3, h4, h5, h6 {
font-family: var(--font-title);
}
-*[disabled] {
- cursor: not-allowed;
+*[disabled], .Disabled {
+ opacity: 0.5;
+ cursor: not-allowed !important;
}
a {
diff --git a/nest_frontend/routes/PageShare.js b/nest_frontend/routes/PageShare.js
index acbab77..404f33f 100644
--- a/nest_frontend/routes/PageShare.js
+++ b/nest_frontend/routes/PageShare.js
@@ -1,18 +1,76 @@
-import React, { useContext } from "react"
+import React, { useCallback, useContext } from "react"
import classNames from "classnames"
import BoxHeader from "../components/base/BoxHeader"
import ContextLanguage from "../contexts/ContextLanguage"
import Style from "./PageShare.module.css"
+import BoxUserList from "../components/interactive/BoxUserList"
+import useBackendViewset from "../hooks/useBackendViewset"
+import { useParams } from "react-router"
export default function PageShare({ className, ...props }) {
const { strings } = useContext(ContextLanguage)
+ const { id } = useParams()
+ const {resources: users} = useBackendViewset(
+ "/api/v1/users/",
+ "email",
+ {
+ list: true,
+ create: false,
+ retrieve: false,
+ edit: false,
+ destroy: false,
+ command: false,
+ action: false,
+ }
+ )
+ const {resources: authorizations, createResource: createAuthorization, destroyResource: destroyAuthorization} = useBackendViewset(
+ `/api/v1/repositories/${id}/authorizations/`,
+ "email",
+ {
+ list: true,
+ create: true,
+ retrieve: false,
+ edit: false,
+ destroy: true,
+ command: false,
+ action: false,
+ }
+ )
+
+ const shareWith = useCallback(
+ user => {
+ console.info("Authorizing ", user, " ...")
+ createAuthorization({rid: id, email: user.email})
+ },
+ [createAuthorization, id]
+ )
+
+ const unshareWith = useCallback(
+ user => {
+ console.info("Deauthorizing ", user, " ...")
+ destroyAuthorization(user.email)
+ },
+ [destroyAuthorization, id]
+ )
return (
{strings.repoShare}
+ !authorizations.map(a => a.email).includes(user.email))}
+ shareWithUser={shareWith}
+ header={strings.availableUsers}
+ />
+ authorizations.map(a => a.email).includes(user.email))}
+ unshareWithUser={unshareWith}
+ header={strings.sharingWith}
+ />
)
}
diff --git a/nest_frontend/routes/PageShare.module.css b/nest_frontend/routes/PageShare.module.css
index e385935..f2b083e 100644
--- a/nest_frontend/routes/PageShare.module.css
+++ b/nest_frontend/routes/PageShare.module.css
@@ -1,3 +1,27 @@
.PageShare {
+ display: grid;
+ grid-template-areas:
+ "a"
+ "b"
+ "c";
+ grid-template-rows: auto 1fr 1fr;
+ grid-template-columns: 1fr;
+ grid-gap: 10px;
+
+ width: 100%;
+ height: 100%;
+}
+
+
+.Header {
+ grid-area: a;
+}
+
+.UserList {
+ grid-area: b;
+}
+
+.SharingWith {
+ grid-area: c;
}