Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(UI): AccessManagement UI to access the role metadata for a dataset #8541

Merged
merged 14 commits into from
Sep 8, 2023

Conversation

Ramendra761
Copy link
Contributor

The aim of this feature is to add a new tab for Access Management to enable users to view the required roles (Roles/Policies defined in Access Management System of an organisation) for accessing a dataset in that organisation for a dataset. Also allow user to raise the request for a required role if user dont have access.

People can navigate to a dataset and view list of roles necessary to access that dataset. We can click on a dataset role and request access from that page.

Attaching the RFC for further details
rfc-DatahubUI.pdf
Uploading RFC.-.Addition.of.External.Access.Managemt.pdf…

reference PR - 8499

Checklist

  • The PR conforms to DataHub's Contributing Guideline (particularly Commit Message Format)
  • Links to related issues (if applicable)
  • Tests for the changes have been added/updated (if applicable)
  • Docs related to the changes have been added/updated (if applicable). If a new feature has been added a Usage Guide has been added for the same.
  • For any breaking change/potential downtime/deprecation/big changes an entry has been made in Updating DataHub

@Ramendra761
Copy link
Contributor Author

@jjoyce0510
could you please take a look.
thanks ,
Ramendra

};

export default function AccessManagerDescription({ description }: Props) {
const DescriptionContainer = styled.div`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please place these styled components at the top of the file (similar to other components)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

@@ -0,0 +1,27 @@
export default function handleExternalRoles(externalRoles, loggedInUser) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's name this file utils.ts since it's just a utility function

we can also remove the "Default" in front of function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to utils.ts

externalRoles?.dataset?.access.roles.length > 0
) {
externalRoles?.dataset?.access?.roles?.forEach((userRoles) => {
const arr = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does "arr" mean here?

can we name this "role"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

const arr = {
name: userRoles?.role?.properties?.name || ' ',
description: userRoles?.role?.properties?.description || ' ',
accesstype: userRoles?.role?.properties?.type || ' ',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

camelCase please!

accessType

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

name: userRoles?.role?.properties?.name || ' ',
description: userRoles?.role?.properties?.description || ' ',
accesstype: userRoles?.role?.properties?.type || ' ',
access:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's name this:

hasAccess

to imply that it is boolean

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

setIsExpanded(!expanded);
};

if (description.length > 150) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we combine these 2 blocks into 1?


const shouldTruncateDescription = description.length > 150;
const [expanded, setIsExpanded] = useState(!shouldTruncateDescription);
const finalDescription = expanded ? description : description.slice(0, 150);

return (
    <DescriptionContainer>
        {finalDescription}
        <Typography.Link
            onClick={() => {
                toggleExpanded();
            }}
        >
            {shouldTruncate && (expanded ? ' Read Less' : '...Read More') || undefined}
        </Typography.Link>
    </DescriptionContainer>
);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

];

return (
<div>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we remove this additional div?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

render: (text, record) => {
if (text) {
return (
<div
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pleae use styled component

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

<button
type="button"
style={{
backgroundColor: '#1890ff',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use styled component

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update


const columns = [
{
title: 'RoleName',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Role Name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

import AccessManagerDescription from './AccessManagerDescription';

export default function AccessManagement() {
const StyledTable = styled(Table)`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please place this at the top of the file, similar to toher components

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

@@ -68,6 +70,8 @@ export class DatasetEntity implements Entity<Dataset> {

isSearchEnabled = () => true;

isAccessManagementEnabled = useIsShowAccessManagementEnabled;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's get rid of this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recieving below error
"React Hook "useIsShowAccessManagementEnabled" is called in function "visible" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter react-hooks/rules-of-hooks"

to resolve that we used isAccessManagementEnabled

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(please remove this line)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking w my colleague @chriscollins3456

name: 'Access Management',
component: AccessManagement,
display: {
visible: (_, _1) => this.isAccessManagementEnabled(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just use the hook here:

                        visible: (_, _1) => useIsShowAccessManagementEnabled(),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recieving below error
"React Hook "useIsShowAccessManagementEnabled" is called in function "visible" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter react-hooks/rules-of-hooks"

to resolve that we used isAccessManagementEnabled

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. here's what we want to do then... pass a new optional parameter into the function called "appConfig" in line 249 on EntityProfile.tsx

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use a context object actually, then the method can just use that instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @jjoyce0510 we used a context object still had hooks issue. as a solution we called "appConfig" in datasetEntity.tsx

fontSize?: number;
}

export default function AccessTermstyle({ data, fontSize, highlightText }: Props) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename the file name and let's revisit the name of this component

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we name it AccessRoleLabel.tsx?

Copy link
Contributor Author

@Ramendra761 Ramendra761 Sep 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the changes as we cannot make changes in the default preview card

if (maxShow && renderedTags > maxShow) return null;
return (
<div>
{console.log(role?.role)}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the changes as we cannot make changes in the default preview card

entityType={EntityType.Role}
useEntityQuery={useGetExternalRoleQuery}
getOverrideProperties={this.getOverridePropertiesFromEntity}
tabs={[]}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want Documentation tab?

Since you have the About section, which displays the same information

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added RoleEntityProfile in renderpreview similar to tagProfile.tsx

@@ -252,6 +264,7 @@ export class DatasetEntity implements Entity<Dataset> {
platformLogo={data.platform.properties?.logoUrl}
platformInstanceId={data.dataPlatformInstance?.instanceId}
owners={data.ownership?.owners}
access={this.isAccessManagementEnabled() ? data?.access : null}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not change this preview DatasetEntity.tsx - what are you hoping to achieve with this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

@@ -290,6 +303,7 @@ export class DatasetEntity implements Entity<Dataset> {
glossaryTerms={data.glossaryTerms}
subtype={data.subTypes?.typeNames?.[0]}
container={data.container}
access={this.isAccessManagementEnabled() ? data?.access : null}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not change this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

@@ -101,6 +104,7 @@ export const Preview = ({
tags={globalTags || undefined}
owners={owners}
domain={domain}
access={access}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not change this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

key: 'hasAccess',
render: (text, record) => {
if (text) {
return <Accessprovision>Provisioned</Accessprovision>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we using a Divider component to wrap this text? Let's use a or something similar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated with StyledSection

@@ -355,6 +359,8 @@ export default function DefaultPreviewCard({
{hasGlossaryTerms && <TagTermGroup uneditableGlossaryTerms={glossaryTerms} maxShow={3} />}
{((hasGlossaryTerms && hasTags) || ((dataProduct || domain) && hasTags)) && <TagSeparator />}
{hasTags && <TagTermGroup uneditableTags={tags} maxShow={3} />}
{hasAccess && <TagSeparator />}
{hasAccess && <TagTermGroup uneditableAccess={access} maxShow={3} />}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this please. We do not want to accept changes to one of the most important components we have - the default preview card.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done update

@@ -12,3 +12,8 @@ export function useIsShowAcrylInfoEnabled() {
const appConfig = useAppConfig();
return appConfig.config.featureFlags.showAcrylInfo;
}

export function useIsShowAccessManagementEnabled(): boolean {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we pass the appConfig into the visible function, we should no longer need this method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed useIsShowAccessManagementEnabled()

@@ -1451,7 +1455,7 @@ type Role implements Entity {
"""
Role properties to include Request Access Url
"""
properties: RoleProperties!
properties: RoleProperties
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this no longer an optional field? What happens if someone wishes to create a role without properties?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @anshbansal we are facing issues in search and autocomplete in web-react search.graphql if we are making it as optional field. i.e why we update the same.

Copy link
Collaborator

@chriscollins3456 chriscollins3456 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice stuff here gang! this PR is very very close. I only have one real request and that's around an error I saw in the UI when no actors were associated with a role and so we weren't setting it on the role graphql object but we defined it as required on the graphql side (simple fix is simply make actors not required to return on graphql)

Otherwise I have a few small suggestions and wanted to call out how the profile page is pretty bare bones right now but maybe that's alright.

Comment on lines +70 to +72
<Paragraph style={{ fontSize: '12px', lineHeight: '15px', padding: '5px 0px' }}>
{data?.role?.properties?.description}
</Paragraph>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so you don't want to allow users to edit role entity descriptions through the UI? you could get the same functionality as other entities if you used EntityProfile and passed in a list of tabs and sidebar sections instead of defining your own entity profile page for this one entity

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm just thinking this is pretty bare bones but maybe that is alright for now.

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @chriscollins3456 for Roles the description is not editable. We have description for the accessRole coming from an external source we are updating in datahub if we provide option to edit the dscription we would not be able to update the same at source.

@@ -1451,7 +1455,7 @@ type Role implements Entity {
"""
Role properties to include Request Access Url
"""
properties: RoleProperties!
properties: RoleProperties

"""
A standard Entity Type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm getting an error when trying locally if I don't set any role actors on a role saying that this is a required field that was not set.

I'd make this field not required for graphql since we aren't always setting actors on the result as you can see in RoleMapper.java

        final EnvelopedAspect envelopedUsers = aspects.get(Constants.ROLE_ACTORS_ASPECT_NAME);
        if (envelopedUsers != null) {
            result.setActors(mapActor(new Actors(envelopedUsers.getValue().data())));
        }

Or alternatively we could always set an empty list of actors and always return it saying we don't have any actors. either way we need to prevent this error from popping up:
image

Copy link
Contributor Author

@Ramendra761 Ramendra761 Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the actor as optional.

Comment on lines 90 to 91
render: (text, record) => {
if (text) {
Copy link
Collaborator

@chriscollins3456 chriscollins3456 Sep 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

text is a bit confusing here. can it be called hasAccess instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

(user) => user.user.urn === loggedInUser?.me?.corpUser.urn,
)) ||
false,
url: userRoles?.role?.properties?.requestUrl || window.location.href,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: so if there's no requestUrl on the role we just send them to this page? I feel like the button should either not exist to request access or it should be disabled with a tooltip saying this role has no request access URL associated with it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @chriscollins3456 updated we have removed request button if there is no request url

Copy link
Collaborator

@chriscollins3456 chriscollins3456 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice thanks for addressing those comments! this is looking good to me thanks for all of your work here 👍

@anshbansal anshbansal merged commit 75252a3 into datahub-project:master Sep 8, 2023
41 checks passed
@YuriyGavrilov
Copy link
Contributor

@Ramendra761 Could you please describe shortly how to use this feature? just deployed 0.12 but didn't see any Access management tab in the UI.

@stevenayers
Copy link
Contributor

@Ramendra761 nice work!

I enabled access management via the SHOW_ACCESS_MANAGEMENT env var in the gms container and I can see the tab in the UI, but I'm unsure how to add roles that can be granted. Are there any docs on this yet?

Screenshot 2024-04-08 at 14 16 00

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
devops PR or Issue related to DataHub backend & deployment product PR or Issue related to the DataHub UI/UX
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants