From 1928435f6f0165ee5055609dff9cd56eaeb63d66 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sun, 23 May 2021 17:35:38 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20initial=20support=20for=20sha?= =?UTF-8?q?ring=20a=20repository?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/base/Button.module.css | 6 -- .../components/base/summary/SummaryLeft.js | 13 +++- .../components/interactive/BoxUserList.js | 17 +++++- .../interactive/SummaryRepository.js | 1 + .../components/interactive/SummaryUser.js | 60 ++++++++++++++----- nest_frontend/index.css | 5 +- nest_frontend/routes/PageShare.js | 60 ++++++++++++++++++- nest_frontend/routes/PageShare.module.css | 24 ++++++++ 8 files changed, 157 insertions(+), 29 deletions(-) diff --git a/nest_frontend/components/base/Button.module.css b/nest_frontend/components/base/Button.module.css index e8e3f9a..9afa1d0 100644 --- a/nest_frontend/components/base/Button.module.css +++ b/nest_frontend/components/base/Button.module.css @@ -11,12 +11,6 @@ cursor: pointer; } -.Button[disabled] { - opacity: 0.5; - - cursor: not-allowed; -} - .Button:focus-visible { outline: 4px solid var(--outline); } diff --git a/nest_frontend/components/base/summary/SummaryLeft.js b/nest_frontend/components/base/summary/SummaryLeft.js index 6ece72c..c9070b9 100644 --- a/nest_frontend/components/base/summary/SummaryLeft.js +++ b/nest_frontend/components/base/summary/SummaryLeft.js @@ -4,11 +4,18 @@ import classNames from "classnames" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" -export default function SummaryLeft({ icon, title, subtitle, className, onClick, ...props }) { +export default function SummaryLeft({ icon, title, subtitle, className, onClick, disabled, ...props }) { + const _onClick = disabled ? null : onClick + return (
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; }