From c17a1e8be20449cf38e98665009b3bc93a42073c Mon Sep 17 00:00:00 2001 From: "meng.zhu@nav.no" Date: Wed, 17 Apr 2024 10:07:37 +0200 Subject: [PATCH 1/6] access page --- components/user/accessRequestsForGroup.tsx | 81 +++++++++++++++++++++ components/user/pendingAccessRequestBar.tsx | 27 +++++++ pages/user/[[...page]].tsx | 13 ++++ 3 files changed, 121 insertions(+) create mode 100644 components/user/accessRequestsForGroup.tsx create mode 100644 components/user/pendingAccessRequestBar.tsx diff --git a/components/user/accessRequestsForGroup.tsx b/components/user/accessRequestsForGroup.tsx new file mode 100644 index 00000000..c93f48e9 --- /dev/null +++ b/components/user/accessRequestsForGroup.tsx @@ -0,0 +1,81 @@ +import { Heading, Link, Table, Tabs } from "@navikt/ds-react" +import { PendingAccessRequestBar } from "./pendingAccessRequestBar" + +interface pendingAccessRequestsForGroupProps { + accessRequests: any[] +} + +export const AccessRequestsForGroup = ({ accessRequests }: pendingAccessRequestsForGroupProps) => { + const pendingRequest = accessRequests.filter((r) => r.status === 'pending') + const processedRequest = accessRequests.filter((r) => r.status === 'approved' || r.status === 'denied') + return <>
+ + + + + + +
+ {pendingRequest?.length > 0 ? (
+ {pendingRequest.map((r: any) => ( + + )) + }
+ ) : ( +
'Ingen tilgangssøknader'
+ )} +
+ +
+ +
+ {processedRequest?.length > 0 ? ( + + + + Dataprodukt + Datasett + Bruker/gruppe + + + + {processedRequest.map((r, i) => ( + <> + + {r.dataproductName} + + {r.datasetName} + + + {r.subject} + + + + Til datasett + + + + + )) + } +
+ ) : ( + 'Ingen tilgangssøknader' + )} +
+ +
+
+
+ +
+} \ No newline at end of file diff --git a/components/user/pendingAccessRequestBar.tsx b/components/user/pendingAccessRequestBar.tsx new file mode 100644 index 00000000..4d25cb8a --- /dev/null +++ b/components/user/pendingAccessRequestBar.tsx @@ -0,0 +1,27 @@ +import { ExpansionCard } from "@navikt/ds-react" +import { useState } from "react" + +interface PendingAccessRequestBarProps { + accessRequest: any +} + +export const PendingAccessRequestBar = ({ accessRequest }: PendingAccessRequestBarProps) => { + const [expanded, setExpanded] = useState(false) + return ( +
+ setExpanded(open)}> + + {`${accessRequest?.datasetName} - ${accessRequest?.dataproductName}`} + +

fra {accessRequest.owner} - {new Date(accessRequest.created).toLocaleDateString('no-NO')}

+

+
+
+ +
+ behandle +
+
+
+
) +} \ No newline at end of file diff --git a/pages/user/[[...page]].tsx b/pages/user/[[...page]].tsx index 82ed6bdf..511c2ebd 100644 --- a/pages/user/[[...page]].tsx +++ b/pages/user/[[...page]].tsx @@ -11,6 +11,7 @@ import { JoinableViewsList } from '../../components/dataProc/joinableViewsList' import { DataproductsList } from '../../components/dataproducts/dataproductList' import { Tabs } from '@navikt/ds-react' import { useFetchUserData } from '../../lib/rest/userData' +import { AccessRequestsForGroup } from '../../components/user/accessRequestsForGroup' export const UserPages = () => { const router = useRouter() @@ -62,6 +63,18 @@ export const UserPages = () => { ), }, + { + title: 'Tilgangssøknader til min gruppe', + slug: 'requestsForGroup', + component: ( +
+

Tilgangssøknader til min gruppe

+ +
+ ), + }, { title: 'Mine tilgangssøknader', slug: 'requests', From 9fe82c819ff68486216694f77c331088fbba36db Mon Sep 17 00:00:00 2001 From: "meng.zhu@nav.no" Date: Wed, 17 Apr 2024 12:47:27 +0200 Subject: [PATCH 2/6] fix access request page --- .../dataproducts/access/datasetAccess.tsx | 2 +- components/user/accessRequestAlert.tsx | 11 +++ components/user/accessRequestsForGroup.tsx | 81 +++---------------- components/user/pendingAccessRequestBar.tsx | 36 +++++---- pages/index.tsx | 2 + pages/user/[[...page]].tsx | 4 +- 6 files changed, 46 insertions(+), 90 deletions(-) create mode 100644 components/user/accessRequestAlert.tsx diff --git a/components/dataproducts/access/datasetAccess.tsx b/components/dataproducts/access/datasetAccess.tsx index 6040b85e..0e110660 100644 --- a/components/dataproducts/access/datasetAccess.tsx +++ b/components/dataproducts/access/datasetAccess.tsx @@ -130,7 +130,7 @@ interface AccessRequestModalProps { actionApprove: (requestID: string) => void } -const AccessRequestModal = ({ +export const AccessRequestModal = ({ requestID, actionDeny, actionApprove, diff --git a/components/user/accessRequestAlert.tsx b/components/user/accessRequestAlert.tsx new file mode 100644 index 00000000..b2da79e4 --- /dev/null +++ b/components/user/accessRequestAlert.tsx @@ -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 ?( + + Du har tilgangssøknad som venter på behandling. + ): <> +} \ No newline at end of file diff --git a/components/user/accessRequestsForGroup.tsx b/components/user/accessRequestsForGroup.tsx index c93f48e9..a32f4a97 100644 --- a/components/user/accessRequestsForGroup.tsx +++ b/components/user/accessRequestsForGroup.tsx @@ -6,76 +6,17 @@ interface pendingAccessRequestsForGroupProps { } export const AccessRequestsForGroup = ({ accessRequests }: pendingAccessRequestsForGroupProps) => { + //TODO: support approved and denied requests const pendingRequest = accessRequests.filter((r) => r.status === 'pending') - const processedRequest = accessRequests.filter((r) => r.status === 'approved' || r.status === 'denied') return <>
- - - - - - -
- {pendingRequest?.length > 0 ? (
- {pendingRequest.map((r: any) => ( - - )) - }
- ) : ( -
'Ingen tilgangssøknader'
- )} -
- -
- -
- {processedRequest?.length > 0 ? ( - - - - Dataprodukt - Datasett - Bruker/gruppe - - - - {processedRequest.map((r, i) => ( - <> - - {r.dataproductName} - - {r.datasetName} - - - {r.subject} - - - - Til datasett - - - - - )) - } -
- ) : ( - 'Ingen tilgangssøknader' - )} -
- -
-
-
- -
+ {pendingRequest?.length > 0 ? (
+ {pendingRequest.map((r: any) => ( + + )) + }
+ ) : ( +
'Ingen tilgangssøknader'
+ )} + + } \ No newline at end of file diff --git a/components/user/pendingAccessRequestBar.tsx b/components/user/pendingAccessRequestBar.tsx index 4d25cb8a..2d0c8525 100644 --- a/components/user/pendingAccessRequestBar.tsx +++ b/components/user/pendingAccessRequestBar.tsx @@ -1,5 +1,7 @@ -import { ExpansionCard } from "@navikt/ds-react" +import { ExpansionCard, Link } from "@navikt/ds-react" import { useState } from "react" +import { AccessRequestModal } from "../dataproducts/access/datasetAccess" +import { Header } from "@navikt/ds-react-internal" interface PendingAccessRequestBarProps { accessRequest: any @@ -8,20 +10,20 @@ interface PendingAccessRequestBarProps { export const PendingAccessRequestBar = ({ accessRequest }: PendingAccessRequestBarProps) => { const [expanded, setExpanded] = useState(false) return ( -
- setExpanded(open)}> - - {`${accessRequest?.datasetName} - ${accessRequest?.dataproductName}`} - -

fra {accessRequest.owner} - {new Date(accessRequest.created).toLocaleDateString('no-NO')}

-

-
-
- -
- behandle -
-
-
-
) +
+
+

+ {`${accessRequest?.datasetName} - ${accessRequest?.dataproductName}`} + +

+ fra {accessRequest.owner} - {new Date(accessRequest.created).toLocaleDateString('no-NO')} +
+
+ +
+
) } \ No newline at end of file diff --git a/pages/index.tsx b/pages/index.tsx index 50e16c88..01eb8bac 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -14,6 +14,7 @@ import LegalGuidanceIcon from "../components/lib/icons/legalGuidanceIcon"; import GetStartedIcon from "../components/lib/icons/getStartedIcon"; import { Next } from '@navikt/ds-icons' import DatadrivenIcon from "../components/lib/icons/datadrivenIcon"; +import { AccessRequestAlert } from '../components/user/accessRequestAlert' const SEARCH_LIMIT = 6 @@ -34,6 +35,7 @@ const LandingPage = () => { datamarkedsplassen +
diff --git a/pages/user/[[...page]].tsx b/pages/user/[[...page]].tsx index 511c2ebd..fb9dac8f 100644 --- a/pages/user/[[...page]].tsx +++ b/pages/user/[[...page]].tsx @@ -146,8 +146,8 @@ export const UserPages = () => { Brukerside -
-
+
+
{menuItems.map(({ title, slug }, idx) => currentPage == idx ? (

Date: Wed, 17 Apr 2024 13:18:02 +0200 Subject: [PATCH 3/6] fix syntax --- components/user/accessRequestsForGroup.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/user/accessRequestsForGroup.tsx b/components/user/accessRequestsForGroup.tsx index a32f4a97..d5812bf3 100644 --- a/components/user/accessRequestsForGroup.tsx +++ b/components/user/accessRequestsForGroup.tsx @@ -10,12 +10,12 @@ export const AccessRequestsForGroup = ({ accessRequests }: pendingAccessRequests const pendingRequest = accessRequests.filter((r) => r.status === 'pending') return <>

{pendingRequest?.length > 0 ? (
- {pendingRequest.map((r: any) => ( - + {pendingRequest.map((r: any, i: number) => ( + )) }
) : ( -
'Ingen tilgangssøknader'
+
Ingen tilgangssøknader
)}
From c3ccbf9415a6ef433213dcac8219a4f3dc69f173 Mon Sep 17 00:00:00 2001 From: "meng.zhu@nav.no" Date: Thu, 18 Apr 2024 10:25:56 +0200 Subject: [PATCH 4/6] process access --- components/user/pendingAccessRequestBar.tsx | 42 ++++++++++++++++----- lib/rest/access.ts | 12 +++++- lib/rest/restApi.ts | 12 ++++++ 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/components/user/pendingAccessRequestBar.tsx b/components/user/pendingAccessRequestBar.tsx index 2d0c8525..5318fd52 100644 --- a/components/user/pendingAccessRequestBar.tsx +++ b/components/user/pendingAccessRequestBar.tsx @@ -1,7 +1,9 @@ -import { ExpansionCard, Link } from "@navikt/ds-react" -import { useState } from "react" +import { Link } from "@navikt/ds-react" +import { useContext, useState } from "react" import { AccessRequestModal } from "../dataproducts/access/datasetAccess" -import { Header } from "@navikt/ds-react-internal" +import { apporveAccessRequest, denyAccessRequest } from "../../lib/rest/access" +import { ExternalLink } from "@navikt/ds-icons" +import { UserState } from "../../lib/context" interface PendingAccessRequestBarProps { accessRequest: any @@ -9,6 +11,14 @@ interface PendingAccessRequestBarProps { export const PendingAccessRequestBar = ({ accessRequest }: PendingAccessRequestBarProps) => { const [expanded, setExpanded] = useState(false) + const userData = useContext(UserState) + const approve = (requestID: string) => { + apporveAccessRequest(requestID) + } + const deny = (requestID: string) => { + denyAccessRequest(requestID, "") + } + return (
@@ -16,14 +26,28 @@ export const PendingAccessRequestBar = ({ accessRequest }: PendingAccessRequestB {`${accessRequest?.datasetName} - ${accessRequest?.dataproductName}`} - fra {accessRequest.owner} - {new Date(accessRequest.created).toLocaleDateString('no-NO')} + {accessRequest.owner} +

+
+
+ {!accessRequest.expires ? "Alltid tilgang fra ": "Tilgangsperiode: "} + {new Date(accessRequest.created).toLocaleDateString('no-NO')} + {accessRequest.expires && ` - ${new Date(accessRequest.expires).toLocaleDateString('no-NO')}`} +
+
+ {accessRequest.polly?.url ? ( + + Åpne behandling + + + ) : ( + 'Ingen behandling' + )} +
+
- +
) } \ No newline at end of file diff --git a/lib/rest/access.ts b/lib/rest/access.ts index 52a05cce..dee3950f 100644 --- a/lib/rest/access.ts +++ b/lib/rest/access.ts @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { fetchAccessRequestUrl, fetchTemplate } from "./restApi"; +import { approveAccessRequestUrl, denyAccessRequestUrl, fetchAccessRequestUrl, fetchTemplate, postTemplate } from "./restApi"; export const fetchAccessRequests = async (datasetId: string) => { const url = fetchAccessRequestUrl(datasetId); @@ -29,4 +29,14 @@ export const useFetchAccessRequestsForDataset = (datasetId: string)=>{ }, [datasetId]) return {data, loading, error} +} + +export const apporveAccessRequest = async (accessRequestId: string) => { + const url = approveAccessRequestUrl(accessRequestId); + return postTemplate(url); +} + +export const denyAccessRequest = async (accessRequestId: string, reason: string) => { + const url = denyAccessRequestUrl(accessRequestId, reason); + return postTemplate(url); } \ No newline at end of file diff --git a/lib/rest/restApi.ts b/lib/rest/restApi.ts index 0eb4a72e..5b6d5fc2 100644 --- a/lib/rest/restApi.ts +++ b/lib/rest/restApi.ts @@ -24,6 +24,8 @@ export const searchTeamKatalogenUrl = (gcpGroups?: string[]) => { const query = parameters ? `?${parameters}` : '' return `${apiUrl()}/teamkatalogen${query}` } +export const approveAccessRequestUrl = (accessRequestId: string) => `${apiUrl()}/accessRequests/${accessRequestId}?action=approve` +export const denyAccessRequestUrl = (accessRequestId: string, reason: string) => `${apiUrl()}/accessRequests/${accessRequestId}?action=deny&reason=${reason}` export const fetchTemplate = (url: string) => fetch(url, { method: 'GET', @@ -33,6 +35,16 @@ export const fetchTemplate = (url: string) => fetch(url, { }, }) +export const postTemplate = (url: string, body?: any) => fetch(url, { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), +}) + + export const searchUrl = (options: SearchOptions) => { let queryParams: string[] = []; From 52adeae4fe02ffcd5fc4c738d07b29515ecec5f7 Mon Sep 17 00:00:00 2001 From: "meng.zhu@nav.no" Date: Fri, 19 Apr 2024 12:59:38 +0200 Subject: [PATCH 5/6] access request ui --- .../dataproducts/access/datasetAccess.tsx | 124 ++++++++++++------ components/header/user.tsx | 9 ++ components/user/pendingAccessRequestBar.tsx | 11 +- lib/rest/restApi.ts | 10 ++ pages/user/[[...page]].tsx | 4 +- 5 files changed, 103 insertions(+), 55 deletions(-) diff --git a/components/dataproducts/access/datasetAccess.tsx b/components/dataproducts/access/datasetAccess.tsx index 537721cc..1459d596 100644 --- a/components/dataproducts/access/datasetAccess.tsx +++ b/components/dataproducts/access/datasetAccess.tsx @@ -19,7 +19,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 @@ -126,23 +126,89 @@ interface AccessModalProps { interface AccessRequestModalProps { requestID: string - actionDeny: (requestID: string, setOpen: Function) => void - actionApprove: (requestID: string) => void + user?: string } 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(undefined) + const [errorDeny, setErrorDeny] = useState(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 ( <> setOpenApprove(false)} + className='w-full md:w-[60rem] px-8 h-[13rem]' + > + +
+ + Godkjenn søknad + +

Gi tilgang til datasett{user ? ` til ${user}` : ''}?

+
+ + +
+ {errorApprove &&
{errorApprove}
} +
+
+
+ + 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]" >
@@ -152,32 +218,33 @@ export const AccessRequestModal = ({