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 businessAttributeEntityEnabled = false;
private boolean dataContractsEnabled = false;
private boolean editableDatasetNameEnabled = false;
private boolean showSeparateSiblings = false;
}

View File

@ -186,6 +186,7 @@ public class AppConfigResolver implements DataFetcher<CompletableFuture<AppConfi
.setNestedDomainsEnabled(_featureFlags.isNestedDomainsEnabled())
.setPlatformBrowseV2(_featureFlags.isPlatformBrowseV2())
.setDataContractsEnabled(_featureFlags.isDataContractsEnabled())
.setEditableDatasetNameEnabled(_featureFlags.isEditableDatasetNameEnabled())
.setShowSeparateSiblings(_featureFlags.isShowSeparateSiblings())
.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 com.linkedin.businessattribute.BusinessAttributeInfo;
import com.linkedin.common.AuditStamp;
import com.linkedin.common.urn.CorpuserUrn;
import com.linkedin.common.urn.Urn;
import com.linkedin.common.urn.UrnUtils;
import com.linkedin.data.template.SetMode;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
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.GlossaryUtils;
import com.linkedin.dataproduct.DataProductProperties;
import com.linkedin.dataset.EditableDatasetProperties;
import com.linkedin.domain.DomainProperties;
import com.linkedin.domain.Domains;
import com.linkedin.entity.client.EntityClient;
@ -70,6 +73,8 @@ public class UpdateNameResolver implements DataFetcher<CompletableFuture<Boolean
return updateDataProductName(targetUrn, input, context);
case Constants.BUSINESS_ATTRIBUTE_ENTITY_NAME:
return updateBusinessAttributeName(targetUrn, input, environment.getContext());
case Constants.DATASET_ENTITY_NAME:
return updateDatasetName(targetUrn, input, environment.getContext());
default:
throw new RuntimeException(
String.format(
@ -236,6 +241,37 @@ public class UpdateNameResolver implements DataFetcher<CompletableFuture<Boolean
"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(
Urn targetUrn, UpdateNameInput input, QueryContext context) {
try {

View File

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

View File

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

View File

@ -508,6 +508,11 @@ type FeatureFlagsConfig {
"""
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
"""

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -19,4 +19,13 @@ record EditableDatasetProperties includes ChangeAuditStamps {
"fieldName": "editedDescription",
}
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",
"fieldType" : "TEXT"
}
}, {
"name" : "name",
"type" : "string",
"doc" : "Editable display name of the Dataset",
"optional" : true,
"Searchable" : {
"fieldName" : "editedName",
"fieldType" : "TEXT_PARTIAL"
}
} ],
"Aspect" : {
"name" : "editableDatasetProperties"

View File

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