diff --git a/.gitignore b/.gitignore
index d644fa07..13b3d6cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,5 +41,9 @@ yarn-error.log*
spec-v1.0.yaml
data.sql
+# local graphql
+.graphqlconfig
+schema.graphql
+
# asdf
.tool-versions
\ No newline at end of file
diff --git a/components/dataproducts/access/owner.tsx b/components/dataproducts/access/owner.tsx
index 9bd43c48..696e565e 100644
--- a/components/dataproducts/access/owner.tsx
+++ b/components/dataproducts/access/owner.tsx
@@ -5,7 +5,7 @@ import LoaderSpinner from '../../lib/spinner'
import * as React from 'react'
import { useState } from 'react'
import { Button } from '@navikt/ds-react'
-import AccessList from './accessList'
+import OwnerAccessList from './ownerAccessList'
import ExpiredAccessList from './expiredAccessList'
import { AddCircle } from '@navikt/ds-icons'
import NewAccessForm from "./newAccessForm";
@@ -33,7 +33,7 @@ const Owner = ({ accessQuery }: OwnerProps) => {
Aktive tilganger
-
+
setShowExpired(!showExpired)}>Utløpte tilganger {showExpired ? : }
{showExpired && }
diff --git a/components/dataproducts/access/accessList.tsx b/components/dataproducts/access/ownerAccessList.tsx
similarity index 95%
rename from components/dataproducts/access/accessList.tsx
rename to components/dataproducts/access/ownerAccessList.tsx
index 386260fd..448edc32 100644
--- a/components/dataproducts/access/accessList.tsx
+++ b/components/dataproducts/access/ownerAccessList.tsx
@@ -52,7 +52,7 @@ interface AccessListProps {
requesters: string[],
}
-const AccessList = ({ id, access, requesters }: AccessListProps) => {
+const OwnerAccessList = ({ id, access, requesters }: AccessListProps) => {
const [revokeAccess] = useRevokeAccessMutation()
const [removeRequester] = useRemoveRequesterMutation()
const removeAccess = async (id: string, a: AccessEntry) => {
@@ -95,7 +95,7 @@ const AccessList = ({ id, access, requesters }: AccessListProps) => {
Bruker / gruppe
- Kan be om tilgang
+ Kan gi seg selv tilgang
Har tilgang
Fjern tilgang
@@ -118,4 +118,4 @@ const AccessList = ({ id, access, requesters }: AccessListProps) => {
)
}
-export default AccessList
+export default OwnerAccessList
diff --git a/components/dataproducts/access/user.tsx b/components/dataproducts/access/user.tsx
index 7b0971e8..1baa7d98 100644
--- a/components/dataproducts/access/user.tsx
+++ b/components/dataproducts/access/user.tsx
@@ -1,5 +1,5 @@
import { QueryResult } from '@apollo/client'
-import { DataproductAccessQuery, Exact, useRevokeAccessMutation } from '../../../lib/schema/graphql'
+import { DataproductAccessQuery, Exact, useRevokeAccessMutation, } from '../../../lib/schema/graphql'
import ErrorMessage from '../../lib/error'
import LoaderSpinner from '../../lib/spinner'
import * as React from 'react'
@@ -7,8 +7,10 @@ import { useState } from 'react'
import { isAfter, parseISO } from 'date-fns'
import humanizeDate from '../../../lib/humanizeDate'
import { Alert, Button } from '@navikt/ds-react'
-import { Delete } from '@navikt/ds-icons'
+import {AddCircle, Delete} from '@navikt/ds-icons'
import AddAccess from './addAccess'
+import SubHeader from "../../lib/subHeader";
+import UserAccessList from "./userAccessList";
interface UserProps {
accessQuery: QueryResult>
@@ -42,48 +44,23 @@ const User = ({ accessQuery, currentUser, groups }: UserProps) => {
}
// Has access
- if (activeAccess) return (<>
- {formError && {formError}}
- Du har tilgang til dette produktet{' '}
- {activeAccess.expires && <>til {humanizeDate(activeAccess.expires)}>}
- {' '}{group && `via gruppen ${group}`}
-
- {personalAccess &&
- }
- >)
- // Can request access
- if (dataproduct.requesters.length > 0) {
- if (dataproduct.requesters.includes(currentUser) || groups.some(g => dataproduct.requesters.includes(g))){
- return (
- <>
- Du kan gi deg selv tidsbegrenset tilgang.
-
-
-
- >)}}
-
return (
- <>
- Du har visst ikke tilgang til disse dataene.
-
- Ta kontakt med eieren av produktet (team {dataproduct.owner.group.split('@')[0]}), så finner dere en løsning.
-
- {dataproduct.owner?.teamkatalogenURL && (
-
- Team {dataproduct.owner.group.split('@')[0]} i Teamkatalogen
-
- )}
- >)
+ <>
+
+
+ {false && <>
+ Søknader
+
+ >
+ }
+ {dataproduct.access.length != 0 && <>
+ Aktive tilganger
+
+ >
+}
+ >
+ )
}
export default User
\ No newline at end of file
diff --git a/components/dataproducts/access/userAccessList.tsx b/components/dataproducts/access/userAccessList.tsx
new file mode 100644
index 00000000..0c3273b1
--- /dev/null
+++ b/components/dataproducts/access/userAccessList.tsx
@@ -0,0 +1,95 @@
+import {Table, TableBody, TableCell, TableHead, TableRow} from '@mui/material'
+import * as React from 'react'
+import {useState} from 'react'
+import {Delete, Error, Success} from '@navikt/ds-icons'
+import {navGronn, navRod} from '../../../styles/constants'
+import humanizeDate from '../../../lib/humanizeDate'
+import {isAfter, parseISO} from 'date-fns'
+import {useRemoveRequesterMutation, useRevokeAccessMutation} from '../../../lib/schema/graphql'
+import {Alert} from '@navikt/ds-react'
+import {Accessibility} from "@mui/icons-material";
+
+interface AccessEntry {
+ subject: string,
+ access?: access,
+}
+
+const productAccess = (access: access[]): AccessEntry[] => {
+ // Valid access entries are unrevoked and either eternal or expires in the future
+ const valid = (a: access) => !a.revoked && (!a.expires || isAfter(parseISO(a.expires), Date.now()))
+ return access.filter(valid).map(a => {
+ return {
+ access: a,
+ subject: a.subject.split(":")[1],
+ };
+ })
+}
+
+interface access {
+ id: string;
+ subject: string;
+ granter: string;
+ expires?: any;
+ created: any;
+ revoked?: any;
+}
+
+interface request {
+
+}
+
+interface AccessListProps {
+ id: string,
+ access: access[],
+ requests: request[]
+}
+
+const UserAccessList = ({ id, access, requests}: AccessListProps) => {
+ const [revokeAccess] = useRevokeAccessMutation()
+ const removeAccess = async (id: string, a: AccessEntry) => {
+ if (a.access) {
+ try {
+ await revokeAccess({
+ variables: { id: a.access.id },
+ refetchQueries: ['DataproductAccess'],
+ },
+ )
+ } catch (e: any) {
+ setFormError(e.message)
+ }
+ }
+
+ }
+
+ const [formError, setFormError] = useState('')
+ const accesses = productAccess(access)
+
+ return (
+
+ {formError &&
{formError}}
+
+
+
+ Bruker / gruppe
+ {accesses.length != 0 && Har tilgang til}
+ Din søknad
+ Fjern tilgang
+
+
+
+ {accesses.map((a, i) =>
+ {a.subject}
+ {accesses.length != 0 && {a.access ? <>{a.access.expires ? humanizeDate(a.access.expires) : 'evig'}> :
+ }
+ }
+ show
+ removeAccess(id, a)}/>
+ )}
+
+
+
+
+ )
+}
+export default UserAccessList
diff --git a/lib/queries/accessRequest/accessRequestsForOwner.ts b/lib/queries/accessRequest/accessRequestsForOwner.ts
new file mode 100644
index 00000000..fa918295
--- /dev/null
+++ b/lib/queries/accessRequest/accessRequestsForOwner.ts
@@ -0,0 +1,18 @@
+import { gql } from 'graphql-tag'
+
+export const ACCESS_REQUESTS_FOR_OWNER = gql`
+ query AccessRequestsForOwner {
+ accessRequestsForOwner {
+ id
+ dataproductID
+ subject
+ subjectType
+ polly {
+ id
+ externalID
+ name
+ url
+ }
+ }
+ }
+`
diff --git a/lib/schema/graphql.ts b/lib/schema/graphql.ts
index 7f3a0784..b72111c4 100644
--- a/lib/schema/graphql.ts
+++ b/lib/schema/graphql.ts
@@ -35,14 +35,29 @@ export type Access = {
granter: Scalars['String']
/** id for the access entry */
id: Scalars['ID']
- /** polly is the documentation for the access grant */
- polly?: Maybe
/** revoked is timestamp for when access was revoked */
revoked?: Maybe
/** subject to grant access */
subject: Scalars['String']
}
+/** AccessRequest contains metadata on a request to access a dataproduct */
+export type AccessRequest = {
+ __typename?: 'AccessRequest'
+ /** id of dataproduct. */
+ dataproductID: Scalars['ID']
+ /** id of access request. */
+ id: Scalars['ID']
+ /** owner of the access request */
+ owner?: Maybe
+ /** polly is the process policy attached to this grant */
+ polly?: Maybe
+ /** subject to be granted access. */
+ subject?: Maybe
+ /** subjectType is the type of entity which should be granted access (user, group or service account). */
+ subjectType?: Maybe
+}
+
/** BigQuery contains metadata on a BigQuery table. */
export type BigQuery = {
__typename?: 'BigQuery'
@@ -180,12 +195,24 @@ export type Mutation = {
* Requires authentication.
*/
addRequesterToDataproduct: Scalars['Boolean']
+ /**
+ * createAccessRequest creates a new access request for a dataproduct
+ *
+ * Requires authentication
+ */
+ createAccessRequest: AccessRequest
/**
* createDataproduct creates a new dataproduct
*
* Requires authentication.
*/
createDataproduct: Dataproduct
+ /**
+ * deleteAccessRequest deletes a dataproduct access request.
+ *
+ * Requires authentication
+ */
+ deleteAccessRequest: Scalars['Boolean']
/**
* deleteDataproduct deletes a dataproduct.
*
@@ -230,6 +257,12 @@ export type Mutation = {
* Requires authentication.
*/
revokeAccessToDataproduct: Scalars['Boolean']
+ /**
+ * createAccessRequest creates a new access request for a dataproduct
+ *
+ * Requires authentication
+ */
+ updateAccessRequest: AccessRequest
/**
* updateDataproduct updates an existing dataproduct
*
@@ -249,10 +282,18 @@ export type MutationAddRequesterToDataproductArgs = {
subject: Scalars['String']
}
+export type MutationCreateAccessRequestArgs = {
+ input: NewAccessRequest
+}
+
export type MutationCreateDataproductArgs = {
input: NewDataproduct
}
+export type MutationDeleteAccessRequestArgs = {
+ id: Scalars['ID']
+}
+
export type MutationDeleteDataproductArgs = {
id: Scalars['ID']
}
@@ -287,6 +328,10 @@ export type MutationRevokeAccessToDataproductArgs = {
id: Scalars['ID']
}
+export type MutationUpdateAccessRequestArgs = {
+ input: UpdateAccessRequest
+}
+
export type MutationUpdateDataproductArgs = {
id: Scalars['ID']
input: UpdateDataproduct
@@ -299,6 +344,20 @@ export type MutationUpdateStoryMetadataArgs = {
teamkatalogenURL?: Maybe
}
+/** NewAccessRequest contains metadata on a request to access a dataproduct */
+export type NewAccessRequest = {
+ /** id of dataproduct. */
+ dataproductID: Scalars['ID']
+ /** owner is the owner of the access request */
+ owner?: Maybe
+ /** polly is the process policy attached to this grant */
+ polly?: Maybe
+ /** subject to be granted access. */
+ subject?: Maybe
+ /** subjectType is the type of entity which should be granted access (user, group or service account). */
+ subjectType?: Maybe
+}
+
/** NewBigQuery contains metadata for creating a new bigquery data source */
export type NewBigQuery = {
/** dataset is the name of the dataset. */
@@ -331,20 +390,27 @@ export type NewDataproduct = {
teamkatalogenURL?: Maybe
}
-/** NewGrant contains metadata on a dataproduct grant */
+/** NewGrant contains metadata on a request to access a dataproduct */
export type NewGrant = {
/** id of dataproduct. */
dataproductID: Scalars['ID']
/** expires is a timestamp for when the access expires. */
expires?: Maybe
- /** polly is the process policy attached to this grant */
- polly?: Maybe
/** subject to be granted access. */
subject?: Maybe
/** subjectType is the type of entity which should be granted access (user, group or service account). */
subjectType?: Maybe
}
+export type NewPolly = {
+ /** id from polly */
+ externalID: Scalars['String']
+ /** name from polly */
+ name: Scalars['String']
+ /** url from polly */
+ url: Scalars['String']
+}
+
export type NewStory = {
/** group is the owner group for the story. */
group: Scalars['String']
@@ -367,19 +433,12 @@ export type Owner = {
teamkatalogenURL?: Maybe
}
-export type PollyInput = {
+export type Polly = {
+ __typename?: 'Polly'
/** id from polly */
- id: Scalars['String']
- /** name from polly */
- name: Scalars['String']
- /** url from polly */
- url: Scalars['String']
-}
-
-export type PollyResult = {
- __typename?: 'PollyResult'
- /** id from polly */
- id: Scalars['String']
+ externalID: Scalars['String']
+ /** database id */
+ id: Scalars['ID']
/** name from polly */
name: Scalars['String']
/** url from polly */
@@ -388,6 +447,12 @@ export type PollyResult = {
export type Query = {
__typename?: 'Query'
+ /** accessRequest returns one specific access request */
+ accessRequest: AccessRequest
+ /** accessRequests returns all access requests for a dataproduct */
+ accessRequestsForDataproduct: Array
+ /** accessRequests returns all access requests for an owner */
+ accessRequestsForOwner: Array
/** dataproduct returns the given dataproduct. */
dataproduct: Dataproduct
/** dataproducts returns a list of dataproducts. Pagination done using the arguments. */
@@ -409,7 +474,8 @@ export type Query = {
/** Keywords returns all keywords, with an optional filter */
keywords: Array
/** searches polly for process purposes matching query input */
- polly: Array
+
+ polly: Array
/** search through existing dataproducts. */
search: Array
/** stories returns all either draft or published stories depending on the draft boolean. */
@@ -432,6 +498,14 @@ export type Query = {
version: Scalars['String']
}
+export type QueryAccessRequestArgs = {
+ id: Scalars['ID']
+}
+
+export type QueryAccessRequestsForDataproductArgs = {
+ dataproductID: Scalars['ID']
+}
+
export type QueryDataproductArgs = {
id: Scalars['ID']
}
@@ -491,6 +565,16 @@ export type QueryTeamkatalogenArgs = {
q: Scalars['String']
}
+export type QueryPolly = {
+ __typename?: 'QueryPolly'
+ /** id from polly */
+ externalID: Scalars['String']
+ /** name from polly */
+ name: Scalars['String']
+ /** url from polly */
+ url: Scalars['String']
+}
+
export type SearchOptions = {
/** groups filters results on the group. */
groups?: Maybe>
@@ -655,6 +739,18 @@ export type TeamkatalogenResult = {
url: Scalars['String']
}
+/** UpdateAccessRequest contains metadata on a request to access a dataproduct */
+export type UpdateAccessRequest = {
+ /** id of access request. */
+ id: Scalars['ID']
+ /** newPolly is the new polly documentation for this access request. */
+ newPolly?: Maybe
+ /** owner is the owner of the access request. */
+ owner: Scalars['String']
+ /** pollyID is the id of the existing polly documentation. */
+ pollyID?: Maybe
+}
+
/** UpdateDataproduct contains metadata for updating a dataproduct */
export type UpdateDataproduct = {
/** description of the dataproduct */
diff --git a/pages/dataproduct/[id]/[[...page]].tsx b/pages/dataproduct/[id]/[[...page]].tsx
index 5959a303..a658396a 100644
--- a/pages/dataproduct/[id]/[[...page]].tsx
+++ b/pages/dataproduct/[id]/[[...page]].tsx
@@ -125,19 +125,36 @@ const Dataproduct = (props: DataproductProps) => {
component: (
),
- },
- {
+ }
+ ];
+
+ if (userInfo && accessType.type == "owner") {
+ menuItems.push({
title: 'tilganger',
slug: 'access',
- component: !userInfo ? <>Du må logge inn for å gjøre noe her> : userInfo && isOwner ?
- : g.email)}/>,
- },
- {
+ component: ,
+ })
+ }
+
+ if (userInfo && accessType.type == "user") {
+ menuItems.push({
+ title: 'dine tilganger',
+ slug: 'your-accesses',
+ component: g.email)}/>,
+ })
+ }
+
+ if (userInfo && ["user", "owner"].includes(accessType.type)) {
+ menuItems.push({
title: 'utforsk',
slug: 'explore',
component: ,
- },
- ]
+ })
+ }
+
+ if (userInfo && accessType.type != "none") {
+
+ }
const currentPage = menuItems
.map((e) => e.slug)
@@ -195,7 +212,7 @@ const Dataproduct = (props: DataproductProps) => {
error={deleteError}
/>
-
+
>
)