feat(ui): Changes to allow editable dataset name (#10608)

Co-authored-by: Jay Kadambi <jayasimhan_venkatadri@optum.com>
This commit is contained in:
jayasimhankv 2024-08-09 11:02:17 -05:00 committed by GitHub
parent aa07e2a937
commit 3a38415d6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 113 additions and 7 deletions

View File

@ -21,5 +21,6 @@ public class FeatureFlags {
private boolean schemaFieldEntityFetchEnabled = false; private boolean schemaFieldEntityFetchEnabled = false;
private boolean businessAttributeEntityEnabled = false; private boolean businessAttributeEntityEnabled = false;
private boolean dataContractsEnabled = false; private boolean dataContractsEnabled = false;
private boolean editableDatasetNameEnabled = false;
private boolean showSeparateSiblings = false; private boolean showSeparateSiblings = false;
} }

View File

@ -186,6 +186,7 @@ public class AppConfigResolver implements DataFetcher<CompletableFuture<AppConfi
.setNestedDomainsEnabled(_featureFlags.isNestedDomainsEnabled()) .setNestedDomainsEnabled(_featureFlags.isNestedDomainsEnabled())
.setPlatformBrowseV2(_featureFlags.isPlatformBrowseV2()) .setPlatformBrowseV2(_featureFlags.isPlatformBrowseV2())
.setDataContractsEnabled(_featureFlags.isDataContractsEnabled()) .setDataContractsEnabled(_featureFlags.isDataContractsEnabled())
.setEditableDatasetNameEnabled(_featureFlags.isEditableDatasetNameEnabled())
.setShowSeparateSiblings(_featureFlags.isShowSeparateSiblings()) .setShowSeparateSiblings(_featureFlags.isShowSeparateSiblings())
.build(); .build();

View File

@ -4,9 +4,11 @@ import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.persistAspect; import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.persistAspect;
import com.linkedin.businessattribute.BusinessAttributeInfo; import com.linkedin.businessattribute.BusinessAttributeInfo;
import com.linkedin.common.AuditStamp;
import com.linkedin.common.urn.CorpuserUrn; import com.linkedin.common.urn.CorpuserUrn;
import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.Urn;
import com.linkedin.common.urn.UrnUtils; import com.linkedin.common.urn.UrnUtils;
import com.linkedin.data.template.SetMode;
import com.linkedin.datahub.graphql.QueryContext; import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils; import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.concurrency.GraphQLConcurrencyUtils; import com.linkedin.datahub.graphql.concurrency.GraphQLConcurrencyUtils;
@ -20,6 +22,7 @@ import com.linkedin.datahub.graphql.resolvers.mutate.util.BusinessAttributeUtils
import com.linkedin.datahub.graphql.resolvers.mutate.util.DomainUtils; import com.linkedin.datahub.graphql.resolvers.mutate.util.DomainUtils;
import com.linkedin.datahub.graphql.resolvers.mutate.util.GlossaryUtils; import com.linkedin.datahub.graphql.resolvers.mutate.util.GlossaryUtils;
import com.linkedin.dataproduct.DataProductProperties; import com.linkedin.dataproduct.DataProductProperties;
import com.linkedin.dataset.EditableDatasetProperties;
import com.linkedin.domain.DomainProperties; import com.linkedin.domain.DomainProperties;
import com.linkedin.domain.Domains; import com.linkedin.domain.Domains;
import com.linkedin.entity.client.EntityClient; import com.linkedin.entity.client.EntityClient;
@ -70,6 +73,8 @@ public class UpdateNameResolver implements DataFetcher<CompletableFuture<Boolean
return updateDataProductName(targetUrn, input, context); return updateDataProductName(targetUrn, input, context);
case Constants.BUSINESS_ATTRIBUTE_ENTITY_NAME: case Constants.BUSINESS_ATTRIBUTE_ENTITY_NAME:
return updateBusinessAttributeName(targetUrn, input, environment.getContext()); return updateBusinessAttributeName(targetUrn, input, environment.getContext());
case Constants.DATASET_ENTITY_NAME:
return updateDatasetName(targetUrn, input, environment.getContext());
default: default:
throw new RuntimeException( throw new RuntimeException(
String.format( String.format(
@ -236,6 +241,37 @@ public class UpdateNameResolver implements DataFetcher<CompletableFuture<Boolean
"Unauthorized to perform this action. Please contact your DataHub administrator."); "Unauthorized to perform this action. Please contact your DataHub administrator.");
} }
// udpates editable dataset properties aspect's name field
private Boolean updateDatasetName(Urn targetUrn, UpdateNameInput input, QueryContext context) {
if (AuthorizationUtils.canEditProperties(targetUrn, context)) {
try {
if (input.getName() != null) {
final EditableDatasetProperties editableDatasetProperties =
new EditableDatasetProperties();
editableDatasetProperties.setName(input.getName());
final AuditStamp auditStamp = new AuditStamp();
Urn actor = UrnUtils.getUrn(context.getActorUrn());
auditStamp.setActor(actor, SetMode.IGNORE_NULL);
auditStamp.setTime(System.currentTimeMillis());
editableDatasetProperties.setLastModified(auditStamp);
persistAspect(
context.getOperationContext(),
targetUrn,
Constants.EDITABLE_DATASET_PROPERTIES_ASPECT_NAME,
editableDatasetProperties,
actor,
_entityService);
}
return true;
} catch (Exception e) {
throw new RuntimeException(
String.format("Failed to perform update against input %s", input), e);
}
}
throw new AuthorizationException(
"Unauthorized to perform this action. Please contact your DataHub administrator.");
}
private Boolean updateDataProductName( private Boolean updateDataProductName(
Urn targetUrn, UpdateNameInput input, QueryContext context) { Urn targetUrn, UpdateNameInput input, QueryContext context) {
try { try {

View File

@ -222,6 +222,7 @@ public class DatasetMapper implements ModelMapper<EntityResponse, Dataset> {
properties.setQualifiedName(gmsProperties.getQualifiedName()); properties.setQualifiedName(gmsProperties.getQualifiedName());
dataset.setProperties(properties); dataset.setProperties(properties);
dataset.setDescription(properties.getDescription()); dataset.setDescription(properties.getDescription());
dataset.setName(properties.getName());
if (gmsProperties.getUri() != null) { if (gmsProperties.getUri() != null) {
dataset.setUri(gmsProperties.getUri().toString()); dataset.setUri(gmsProperties.getUri().toString());
} }
@ -248,6 +249,9 @@ public class DatasetMapper implements ModelMapper<EntityResponse, Dataset> {
new EditableDatasetProperties(dataMap); new EditableDatasetProperties(dataMap);
final DatasetEditableProperties editableProperties = new DatasetEditableProperties(); final DatasetEditableProperties editableProperties = new DatasetEditableProperties();
editableProperties.setDescription(editableDatasetProperties.getDescription()); editableProperties.setDescription(editableDatasetProperties.getDescription());
if (editableDatasetProperties.getName() != null) {
editableProperties.setName(editableDatasetProperties.getName());
}
dataset.setEditableProperties(editableProperties); dataset.setEditableProperties(editableProperties);
} }

View File

@ -111,8 +111,13 @@ public class DatasetUpdateInputMapper
if (datasetUpdateInput.getEditableProperties() != null) { if (datasetUpdateInput.getEditableProperties() != null) {
final EditableDatasetProperties editableDatasetProperties = new EditableDatasetProperties(); final EditableDatasetProperties editableDatasetProperties = new EditableDatasetProperties();
if (datasetUpdateInput.getEditableProperties().getDescription() != null) {
editableDatasetProperties.setDescription( editableDatasetProperties.setDescription(
datasetUpdateInput.getEditableProperties().getDescription()); datasetUpdateInput.getEditableProperties().getDescription());
}
if (datasetUpdateInput.getEditableProperties().getName() != null) {
editableDatasetProperties.setName(datasetUpdateInput.getEditableProperties().getName());
}
editableDatasetProperties.setLastModified(auditStamp); editableDatasetProperties.setLastModified(auditStamp);
editableDatasetProperties.setCreated(auditStamp); editableDatasetProperties.setCreated(auditStamp);
proposals.add( proposals.add(

View File

@ -508,6 +508,11 @@ type FeatureFlagsConfig {
""" """
dataContractsEnabled: Boolean! dataContractsEnabled: Boolean!
"""
Whether dataset names are editable
"""
editableDatasetNameEnabled: Boolean!
""" """
If turned on, all siblings will be separated with no way to get to a "combined" sibling view If turned on, all siblings will be separated with no way to get to a "combined" sibling view
""" """

View File

@ -3482,6 +3482,11 @@ type DatasetEditableProperties {
Description of the Dataset Description of the Dataset
""" """
description: String description: String
"""
Editable name of the Dataset
"""
name: String
} }
""" """
@ -4850,6 +4855,10 @@ input DatasetEditablePropertiesUpdate {
Writable description aka documentation for a Dataset Writable description aka documentation for a Dataset
""" """
description: String! description: String!
"""
Editable name of the Dataset
"""
name: String
} }
""" """

View File

@ -220,6 +220,7 @@ export class DatasetEntity implements Entity<Dataset> {
}, },
]} ]}
sidebarSections={this.getSidebarSections()} sidebarSections={this.getSidebarSections()}
isNameEditable
/> />
); );
@ -283,7 +284,7 @@ export class DatasetEntity implements Entity<Dataset> {
return ( return (
<Preview <Preview
urn={data.urn} urn={data.urn}
name={data.properties?.name || data.name} name={data.editableProperties?.name || data.properties?.name || data.name}
origin={data.origin} origin={data.origin}
subtype={data.subTypes?.typeNames?.[0]} subtype={data.subTypes?.typeNames?.[0]}
description={data.editableProperties?.description || data.properties?.description} description={data.editableProperties?.description || data.properties?.description}
@ -311,7 +312,7 @@ export class DatasetEntity implements Entity<Dataset> {
return ( return (
<Preview <Preview
urn={data.urn} urn={data.urn}
name={data.properties?.name || data.name} name={data.editableProperties?.name || data.properties?.name || data.name}
origin={data.origin} origin={data.origin}
description={data.editableProperties?.description || data.properties?.description} description={data.editableProperties?.description || data.properties?.description}
platformName={ platformName={
@ -361,7 +362,7 @@ export class DatasetEntity implements Entity<Dataset> {
}; };
displayName = (data: Dataset) => { displayName = (data: Dataset) => {
return data?.properties?.name || data.name || data.urn; return data?.editableProperties?.name || data?.properties?.name || data.name || data.urn;
}; };
platformLogoUrl = (data: Dataset) => { platformLogoUrl = (data: Dataset) => {

View File

@ -17,6 +17,7 @@ import { capitalizeFirstLetterOnly } from '../../../../../shared/textUtil';
import { useUserContext } from '../../../../../context/useUserContext'; import { useUserContext } from '../../../../../context/useUserContext';
import { useEntityRegistry } from '../../../../../useEntityRegistry'; import { useEntityRegistry } from '../../../../../useEntityRegistry';
import EntityHeaderLoadingSection from './EntityHeaderLoadingSection'; import EntityHeaderLoadingSection from './EntityHeaderLoadingSection';
import { useIsEditableDatasetNameEnabled } from '../../../../../useAppConfig';
const TitleWrapper = styled.div` const TitleWrapper = styled.div`
display: flex; display: flex;
@ -71,6 +72,8 @@ export function getCanEditName(
return true; // TODO: add permissions for data products return true; // TODO: add permissions for data products
case EntityType.BusinessAttribute: case EntityType.BusinessAttribute:
return privileges?.manageBusinessAttributes; return privileges?.manageBusinessAttributes;
case EntityType.Dataset:
return entityData?.privileges?.canEditProperties;
default: default:
return false; return false;
} }
@ -94,8 +97,11 @@ export const EntityHeader = ({ headerDropdownItems, headerActionItems, isNameEdi
const entityName = entityData?.name; const entityName = entityData?.name;
const subType = capitalizeFirstLetterOnly(entityData?.subTypes?.typeNames?.[0]) || undefined; const subType = capitalizeFirstLetterOnly(entityData?.subTypes?.typeNames?.[0]) || undefined;
const isEditableDatasetNameEnabled = useIsEditableDatasetNameEnabled();
const canEditName = const canEditName =
isNameEditable && getCanEditName(entityType, entityData, me?.platformPrivileges as PlatformPrivileges); isEditableDatasetNameEnabled &&
isNameEditable &&
getCanEditName(entityType, entityData, me?.platformPrivileges as PlatformPrivileges);
const entityRegistry = useEntityRegistry(); const entityRegistry = useEntityRegistry();
return ( return (
@ -106,7 +112,7 @@ export const EntityHeader = ({ headerDropdownItems, headerActionItems, isNameEdi
<> <>
<PlatformContent /> <PlatformContent />
<TitleWrapper> <TitleWrapper>
<EntityName isNameEditable={canEditName} /> <EntityName isNameEditable={canEditName || false} />
{entityData?.deprecation?.deprecated && ( {entityData?.deprecation?.deprecated && (
<DeprecationPill <DeprecationPill
urn={urn} urn={urn}

View File

@ -28,6 +28,11 @@ export function useIsAppConfigContextLoaded() {
return appConfig.loaded; return appConfig.loaded;
} }
export function useIsEditableDatasetNameEnabled() {
const appConfig = useAppConfig();
return appConfig.config.featureFlags.editableDatasetNameEnabled;
}
export function useIsShowSeparateSiblingsEnabled() { export function useIsShowSeparateSiblingsEnabled() {
const appConfig = useAppConfig(); const appConfig = useAppConfig();
return appConfig.config.featureFlags.showSeparateSiblings; return appConfig.config.featureFlags.showSeparateSiblings;

View File

@ -54,6 +54,7 @@ export const DEFAULT_APP_CONFIG = {
platformBrowseV2: false, platformBrowseV2: false,
businessAttributeEntityEnabled: false, businessAttributeEntityEnabled: false,
dataContractsEnabled: false, dataContractsEnabled: false,
editableDatasetNameEnabled: false,
showSeparateSiblings: false, showSeparateSiblings: false,
}, },
}; };

View File

@ -69,6 +69,7 @@ query appConfig {
platformBrowseV2 platformBrowseV2
businessAttributeEntityEnabled businessAttributeEntityEnabled
dataContractsEnabled dataContractsEnabled
editableDatasetNameEnabled
showSeparateSiblings showSeparateSiblings
} }
} }

View File

@ -17,6 +17,7 @@ query getBrowseResults($input: BrowseInput!) {
description description
} }
editableProperties { editableProperties {
name
description description
} }
platform { platform {

View File

@ -251,6 +251,7 @@ fragment nonRecursiveDatasetFields on Dataset {
} }
} }
editableProperties { editableProperties {
name
description description
} }
ownership { ownership {

View File

@ -9,6 +9,7 @@ fragment entityPreview on Entity {
...platformFields ...platformFields
} }
editableProperties { editableProperties {
name
description description
} }
platformNativeType platformNativeType

View File

@ -335,6 +335,7 @@ fragment nonSiblingsDatasetSearchFields on Dataset {
...dataPlatformInstanceFields ...dataPlatformInstanceFields
} }
editableProperties { editableProperties {
name
description description
} }
access { access {

View File

@ -19,4 +19,13 @@ record EditableDatasetProperties includes ChangeAuditStamps {
"fieldName": "editedDescription", "fieldName": "editedDescription",
} }
description: optional string description: optional string
/**
* Editable display name of the Dataset
*/
@Searchable = {
"fieldType": "TEXT_PARTIAL",
"fieldName": "editedName",
}
name: optional string
} }

View File

@ -2328,6 +2328,15 @@
"fieldName" : "editedDescription", "fieldName" : "editedDescription",
"fieldType" : "TEXT" "fieldType" : "TEXT"
} }
}, {
"name" : "name",
"type" : "string",
"doc" : "Editable display name of the Dataset",
"optional" : true,
"Searchable" : {
"fieldName" : "editedName",
"fieldType" : "TEXT_PARTIAL"
}
} ], } ],
"Aspect" : { "Aspect" : {
"name" : "editableDatasetProperties" "name" : "editableDatasetProperties"

View File

@ -2328,6 +2328,15 @@
"fieldName" : "editedDescription", "fieldName" : "editedDescription",
"fieldType" : "TEXT" "fieldType" : "TEXT"
} }
}, {
"name" : "name",
"type" : "string",
"doc" : "Editable display name of the Dataset",
"optional" : true,
"Searchable" : {
"fieldName" : "editedName",
"fieldType" : "TEXT_PARTIAL"
}
} ], } ],
"Aspect" : { "Aspect" : {
"name" : "editableDatasetProperties" "name" : "editableDatasetProperties"