Skip to content
This repository was archived by the owner on Nov 1, 2024. It is now read-only.

Add page for pending access request and switch to new access request endpoint #308

Merged
merged 9 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 82 additions & 46 deletions components/dataproducts/access/datasetAccess.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { useState } from 'react'
import { isAfter, parseISO, format } from 'date-fns'
import {
useRevokeAccessMutation,
useApproveAccessRequestMutation,
useDenyAccessRequestMutation,
} from '../../../lib/schema/graphql'
import {
Alert,
Expand All @@ -19,7 +17,7 @@ import { ExternalLink } from '@navikt/ds-icons'
import { nb } from 'date-fns/locale'
import ErrorMessage from '../../lib/error'
import { useGetDataset } from '../../../lib/rest/dataproducts'
import { useFetchAccessRequestsForDataset } from '../../../lib/rest/access'
import { apporveAccessRequest, denyAccessRequest, useFetchAccessRequestsForDataset } from '../../../lib/rest/access'

interface AccessEntry {
subject: string
Expand Down Expand Up @@ -126,23 +124,89 @@ interface AccessModalProps {

interface AccessRequestModalProps {
requestID: string
actionDeny: (requestID: string, setOpen: Function) => void
actionApprove: (requestID: string) => void
user?: string
}

const AccessRequestModal = ({
export const AccessRequestModal = ({
requestID,
actionDeny,
actionApprove,
user,
}: AccessRequestModalProps) => {
const [open, setOpen] = useState(false)
const [openDeny, setOpenDeny] = useState(false)
const [openApprove, setOpenApprove] = useState(false)
const [errorApprove, setErrorApprove] = useState<string|undefined>(undefined)
const [errorDeny, setErrorDeny] = useState<string|undefined>(undefined)
const approve = async (requestID: string) =>
apporveAccessRequest(requestID).then(res=>
{
setOpenApprove(false)
setErrorApprove(undefined)
window.location.reload();
}
).catch((e:any)=>{
setErrorApprove(e.message)
})
const deny = async (requestID: string, reason?: string)=>denyAccessRequest(requestID, reason ||'')
.then(()=>{
setOpenDeny(false)
setErrorDeny(undefined)
window.location.reload();
}).catch((e:any)=>{
setErrorDeny(e.message)
})


const cancelApprove = () => {
setOpenApprove(false)
setErrorApprove(undefined)
}

const cancelDeny = () => {
setOpenDeny(false)
setErrorDeny(undefined)
}

return (
<>
<Modal
open={open}
open={openApprove}
aria-label="Godkjenn søknad"
onClose={() => setOpenApprove(false)}
className='w-full md:w-[60rem] px-8 h-[13rem]'
>
<Modal.Body className='h-full'>
<div className='flex flex-col justify-center items-center'>
<Heading level="1" size="medium">
Godkjenn søknad
</Heading>
<p className='mt-4 mb-4'>Gi tilgang til datasett{user ? ` til ${user}` : ''}? </p>
<div className="flex flex-row gap-4">
<Button
onClick={cancelApprove}
variant="secondary"
size="small"
>
Avbryt
</Button>
<Button
onClick={() => {
approve(requestID)
}}
variant="primary"
size="small"
>
Godkjenn
</Button>
</div>
{errorApprove && <div className='text-red-600'>{errorApprove}</div>}
</div>
</Modal.Body>
</Modal>

<Modal
open={openDeny}
aria-label="Avslå søknad"
onClose={() => setOpen(false)}
className="max-w-full md:max-w-3xl px-8 h-[20rem]"
onClose={() => setOpenDeny(false)}
className="max-w-full md:max-w-3xl px-8 h-[24rem]"
>
<Modal.Body className="h-full">
<div className="flex flex-col gap-8">
Expand All @@ -152,32 +216,33 @@ const AccessRequestModal = ({
<Textarea label="Begrunnelse" />
<div className="flex flex-row gap-4">
<Button
onClick={() => setOpen(false)}
onClick={cancelDeny}
variant="secondary"
size="small"
>
Avbryt
</Button>
<Button
onClick={() => actionDeny(requestID, setOpen)}
onClick={() => deny(requestID)}
variant="primary"
size="small"
>
Avslå
</Button>
</div>
{errorDeny && <div className='text-red-600'>{errorDeny}</div>}
</div>
</Modal.Body>
</Modal>
<div className="flex flex-row flex-nowrap gap-4 justify-end">
<Button
onClick={() => actionApprove(requestID)}
onClick={() => setOpenApprove(true)}
variant="secondary"
size="small"
>
Godkjenn
</Button>
<Button onClick={() => setOpen(true)} variant="secondary" size="small">
<Button onClick={() => setOpenDeny(true)} variant="secondary" size="small">
Avslå
</Button>
</div>
Expand Down Expand Up @@ -235,8 +300,6 @@ const AccessModal = ({ accessEntry, action }: AccessModalProps) => {
const DatasetAccess = ({ id }: AccessListProps) => {
const [formError, setFormError] = useState('')
const [revokeAccess] = useRevokeAccessMutation()
const [approveAccessRequest] = useApproveAccessRequestMutation()
const [denyAccessRequest] = useDenyAccessRequestMutation()
const fetchAccessRequestsForDataset = useFetchAccessRequestsForDataset(id)

const getDataset = useGetDataset(id)
Expand All @@ -256,32 +319,6 @@ const DatasetAccess = ({ id }: AccessListProps) => {
!getDataset?.dataset?.access ? [] :
getDataset.dataset.access

const approveRequest = async (requestID: string) => {
try {
await approveAccessRequest({
variables: { id: requestID },
refetchQueries: [
],
})
} catch (e: any) {
setFormError(e.message)
}
}

const denyRequest = async (requestID: string, setOpen: Function) => {
try {
await denyAccessRequest({
variables: { id: requestID },
refetchQueries: [
],
})
} catch (e: any) {
setFormError(e.message)
} finally {
setOpen(false)
}
}

const removeAccess = async (a: access, setOpen: Function) => {
try {
await revokeAccess({
Expand Down Expand Up @@ -345,8 +382,7 @@ const DatasetAccess = ({ id }: AccessListProps) => {
<Table.DataCell className="w-[150px]" align="right">
<AccessRequestModal
requestID={r.id}
actionApprove={approveRequest}
actionDeny={denyRequest}
user={r.subject}
/>
</Table.DataCell>
</Table.Row>
Expand Down

This file was deleted.

9 changes: 9 additions & 0 deletions components/header/user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ export default function User() {
Mine innsiktsprodukter
</Dropdown.Menu.GroupedList.Item>

<Dropdown.Menu.GroupedList.Item
className={'text-base'}
onClick={() => {
router.push({ pathname: '/user/requestsForGroup' })
}}
>
Tilgangssøknader til meg
</Dropdown.Menu.GroupedList.Item>

<Dropdown.Menu.GroupedList.Item
className={'text-base'}
onClick={() => {
Expand Down
11 changes: 11 additions & 0 deletions components/user/accessRequestAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Alert, Link } from "@navikt/ds-react"
import { useContext, useState } from "react"
import { UserState } from "../../lib/context"

export const AccessRequestAlert = () => {
const userData = useContext(UserState)
return userData?.accessRequests?.length ?(
<Alert variant='info'>
Du har tilgangssøknad som venter på <Link href="/user/requestsForGroup">behandling</Link>.
</Alert>): <></>
}
22 changes: 22 additions & 0 deletions components/user/accessRequestsForGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Heading, Link, Table, Tabs } from "@navikt/ds-react"
import { PendingAccessRequestBar } from "./pendingAccessRequestBar"

interface pendingAccessRequestsForGroupProps {
accessRequests: any[]
}

export const AccessRequestsForGroup = ({ accessRequests }: pendingAccessRequestsForGroupProps) => {
//TODO: support approved and denied requests
const pendingRequest = accessRequests.filter((r) => r.status === 'pending')
return <><div>
{pendingRequest?.length > 0 ? (<div>
{pendingRequest.map((r: any, i: number) => (
<PendingAccessRequestBar accessRequest={r} key={i}></PendingAccessRequestBar>
))
}</div>
) : (
<div>Ingen tilgangssøknader</div>
)}
</div>
</>
}
44 changes: 44 additions & 0 deletions components/user/pendingAccessRequestBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Link } from "@navikt/ds-react"
import { useContext, useState } from "react"
import { AccessRequestModal } from "../dataproducts/access/datasetAccess"
import { apporveAccessRequest, denyAccessRequest } from "../../lib/rest/access"
import { ExternalLink } from "@navikt/ds-icons"
import { UserState } from "../../lib/context"

interface PendingAccessRequestBarProps {
accessRequest: any
}

export const PendingAccessRequestBar = ({ accessRequest }: PendingAccessRequestBarProps) => {
return (
<div key={accessRequest.id} className="w-[60rem] mb-5 mt-5 border pt-2 pb-2 pl-4 pr-4 flex flex-row justify-between rounded border-gray-200">
<div>
<h3> <Link rel="norefferer" href={`/dataproduct/${accessRequest.dataproductID}/${accessRequest.dataproductSlug}/${accessRequest.datasetID}`}>
{`${accessRequest?.datasetName} - ${accessRequest?.dataproductName}`}
</Link>
</h3>
{accessRequest.owner}
<br></br>
<div className="flex flex-row">
<div>
{!accessRequest.expires ? "Alltid tilgang fra ": "Tilgangsperiode: "}
{new Date(accessRequest.created).toLocaleDateString('no-NO')}
{accessRequest.expires && ` - ${new Date(accessRequest.expires).toLocaleDateString('no-NO')}`}
</div>
<div className="ml-[2rem]">
{accessRequest.polly?.url ? (
<Link target="_blank" rel="norefferer" href={accessRequest.polly.url}>
Åpne behandling
<ExternalLink />
</Link>
) : (
'Ingen behandling'
)}
</div>
</div>
</div>
<div>
<AccessRequestModal requestID={accessRequest.id}></AccessRequestModal>
</div>
</div>)
}
7 changes: 0 additions & 7 deletions lib/queries/accessRequest/approveAccessRequest.ts

This file was deleted.

7 changes: 0 additions & 7 deletions lib/queries/accessRequest/denyAccessRequest.ts

This file was deleted.

Loading