mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-16 04:28:01 +00:00
feat(application): editing application assignment via UI (#13739)
This commit is contained in:
parent
6b8dfb0aa8
commit
476ac881a3
@ -2864,6 +2864,18 @@ public class GmsGraphQLEngine {
|
||||
.dataFetcher(
|
||||
"aspects", new WeaklyTypedAspectsResolver(entityClient, entityRegistry))
|
||||
.dataFetcher("relationships", new EntityRelationshipsResultResolver(graphClient)));
|
||||
builder.type(
|
||||
"ApplicationAssociation",
|
||||
typeWiring ->
|
||||
typeWiring.dataFetcher(
|
||||
"application",
|
||||
new LoadableTypeResolver<>(
|
||||
applicationType,
|
||||
(env) ->
|
||||
((com.linkedin.datahub.graphql.generated.ApplicationAssociation)
|
||||
env.getSource())
|
||||
.getApplication()
|
||||
.getUrn())));
|
||||
}
|
||||
|
||||
private void configureAssertionResolvers(final RuntimeWiring.Builder builder) {
|
||||
|
||||
@ -6,6 +6,7 @@ import com.linkedin.datahub.graphql.QueryContext;
|
||||
import com.linkedin.datahub.graphql.featureflags.FeatureFlags;
|
||||
import com.linkedin.datahub.graphql.generated.AnalyticsConfig;
|
||||
import com.linkedin.datahub.graphql.generated.AppConfig;
|
||||
import com.linkedin.datahub.graphql.generated.ApplicationConfig;
|
||||
import com.linkedin.datahub.graphql.generated.AuthConfig;
|
||||
import com.linkedin.datahub.graphql.generated.ChromeExtensionConfig;
|
||||
import com.linkedin.datahub.graphql.generated.EntityProfileConfig;
|
||||
@ -187,6 +188,12 @@ public class AppConfigResolver implements DataFetcher<CompletableFuture<AppConfi
|
||||
}
|
||||
visualConfig.setTheme(themeConfig);
|
||||
}
|
||||
if (_visualConfiguration != null && _visualConfiguration.getApplication() != null) {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setShowSidebarSectionWhenEmpty(
|
||||
_visualConfiguration.getApplication().isShowSidebarSectionWhenEmpty());
|
||||
visualConfig.setApplication(applicationConfig);
|
||||
}
|
||||
appConfig.setVisualConfig(visualConfig);
|
||||
|
||||
final TelemetryConfig telemetryConfig = new TelemetryConfig();
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
package com.linkedin.datahub.graphql.types.application;
|
||||
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
|
||||
import com.linkedin.datahub.graphql.QueryContext;
|
||||
import com.linkedin.datahub.graphql.generated.Application;
|
||||
import com.linkedin.datahub.graphql.generated.ApplicationAssociation;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Maps Pegasus {@link RecordTemplate} objects to objects conforming to the GQL schema.
|
||||
*
|
||||
* <p>To be replaced by auto-generated mappers implementations
|
||||
*/
|
||||
public class ApplicationAssociationMapper {
|
||||
|
||||
public static final ApplicationAssociationMapper INSTANCE = new ApplicationAssociationMapper();
|
||||
|
||||
public static ApplicationAssociation map(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull final com.linkedin.application.Applications applications,
|
||||
@Nonnull final String entityUrn) {
|
||||
return INSTANCE.apply(context, applications, entityUrn);
|
||||
}
|
||||
|
||||
public ApplicationAssociation apply(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull final com.linkedin.application.Applications applications,
|
||||
@Nonnull final String entityUrn) {
|
||||
if (applications.getApplications().size() > 0
|
||||
&& (context == null
|
||||
|| canView(context.getOperationContext(), applications.getApplications().get(0)))) {
|
||||
ApplicationAssociation association = new ApplicationAssociation();
|
||||
association.setApplication(
|
||||
Application.builder()
|
||||
.setType(EntityType.APPLICATION)
|
||||
.setUrn(applications.getApplications().get(0).toString())
|
||||
.build());
|
||||
association.setAssociatedUrn(entityUrn);
|
||||
return association;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -82,7 +82,8 @@ public class ChartType
|
||||
BROWSE_PATHS_V2_ASPECT_NAME,
|
||||
SUB_TYPES_ASPECT_NAME,
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME);
|
||||
FORMS_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME);
|
||||
private static final Set<String> FACET_FIELDS =
|
||||
ImmutableSet.of("access", "queryType", "tool", "type");
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.chart.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.chart.EditableChartProperties;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
@ -32,6 +33,7 @@ import com.linkedin.datahub.graphql.generated.Container;
|
||||
import com.linkedin.datahub.graphql.generated.DataPlatform;
|
||||
import com.linkedin.datahub.graphql.generated.Dataset;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.AuditStampMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.CustomPropertiesMapper;
|
||||
@ -148,6 +150,9 @@ public class ChartMapper implements ModelMapper<EntityResponse, Chart> {
|
||||
FORMS_ASPECT_NAME,
|
||||
((entity, dataMap) ->
|
||||
entity.setForms(FormsMapper.map(new Forms(dataMap), entityUrn.toString()))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(chart, dataMap) -> mapApplicationAssociation(context, chart, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), Chart.class);
|
||||
@ -305,4 +310,10 @@ public class ChartMapper implements ModelMapper<EntityResponse, Chart> {
|
||||
final Domains domains = new Domains(dataMap);
|
||||
chart.setDomain(DomainAssociationMapper.map(context, domains, chart.getUrn()));
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context, @Nonnull Chart chart, @Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
chart.setApplication(ApplicationAssociationMapper.map(context, applications, chart.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +82,8 @@ public class DashboardType
|
||||
DATA_PRODUCTS_ASPECT_NAME,
|
||||
BROWSE_PATHS_V2_ASPECT_NAME,
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME);
|
||||
FORMS_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME);
|
||||
private static final Set<String> FACET_FIELDS = ImmutableSet.of("access", "tool");
|
||||
|
||||
private final EntityClient _entityClient;
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.dashboard.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
import com.linkedin.common.Deprecation;
|
||||
@ -29,6 +30,7 @@ import com.linkedin.datahub.graphql.generated.DashboardInfo;
|
||||
import com.linkedin.datahub.graphql.generated.DashboardProperties;
|
||||
import com.linkedin.datahub.graphql.generated.DataPlatform;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.chart.mappers.InputFieldsMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.AuditStampMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
@ -148,6 +150,9 @@ public class DashboardMapper implements ModelMapper<EntityResponse, Dashboard> {
|
||||
FORMS_ASPECT_NAME,
|
||||
((entity, dataMap) ->
|
||||
entity.setForms(FormsMapper.map(new Forms(dataMap), entityUrn.toString()))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(dashboard, dataMap) -> mapApplicationAssociation(context, dashboard, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), Dashboard.class);
|
||||
@ -297,4 +302,13 @@ public class DashboardMapper implements ModelMapper<EntityResponse, Dashboard> {
|
||||
final Domains domains = new Domains(dataMap);
|
||||
dashboard.setDomain(DomainAssociationMapper.map(context, domains, dashboard.getUrn()));
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull Dashboard dashboard,
|
||||
@Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
dashboard.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, dashboard.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +79,8 @@ public class DataFlowType
|
||||
BROWSE_PATHS_V2_ASPECT_NAME,
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
SUB_TYPES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME);
|
||||
FORMS_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME);
|
||||
private static final Set<String> FACET_FIELDS = ImmutableSet.of("orchestrator", "cluster");
|
||||
private final EntityClient _entityClient;
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.dataflow.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
import com.linkedin.common.Deprecation;
|
||||
@ -24,6 +25,7 @@ import com.linkedin.datahub.graphql.generated.DataFlowInfo;
|
||||
import com.linkedin.datahub.graphql.generated.DataFlowProperties;
|
||||
import com.linkedin.datahub.graphql.generated.DataPlatform;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.CustomPropertiesMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper;
|
||||
@ -128,6 +130,9 @@ public class DataFlowMapper implements ModelMapper<EntityResponse, DataFlow> {
|
||||
SUB_TYPES_ASPECT_NAME,
|
||||
(entity, dataMap) ->
|
||||
entity.setSubTypes(SubTypesMapper.map(context, new SubTypes(dataMap))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(dataFlow, dataMap) -> mapApplicationAssociation(context, dataFlow, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), DataFlow.class);
|
||||
@ -231,4 +236,11 @@ public class DataFlowMapper implements ModelMapper<EntityResponse, DataFlow> {
|
||||
// Currently we only take the first domain if it exists.
|
||||
dataFlow.setDomain(DomainAssociationMapper.map(context, domains, dataFlow.getUrn()));
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context, @Nonnull DataFlow dataFlow, @Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
dataFlow.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, dataFlow.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +81,8 @@ public class DataJobType
|
||||
SUB_TYPES_ASPECT_NAME,
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME,
|
||||
DATA_TRANSFORM_LOGIC_ASPECT_NAME);
|
||||
DATA_TRANSFORM_LOGIC_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME);
|
||||
private static final Set<String> FACET_FIELDS = ImmutableSet.of("flow");
|
||||
private final EntityClient _entityClient;
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canV
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.*;
|
||||
import com.linkedin.common.urn.Urn;
|
||||
import com.linkedin.data.DataMap;
|
||||
@ -18,6 +19,7 @@ import com.linkedin.datahub.graphql.generated.DataJobInputOutput;
|
||||
import com.linkedin.datahub.graphql.generated.DataJobProperties;
|
||||
import com.linkedin.datahub.graphql.generated.Dataset;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.*;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.util.SystemMetadataUtils;
|
||||
import com.linkedin.datahub.graphql.types.domain.DomainAssociationMapper;
|
||||
@ -137,6 +139,8 @@ public class DataJobMapper implements ModelMapper<EntityResponse, DataJob> {
|
||||
}
|
||||
});
|
||||
|
||||
mapApplicationAssociation(context, entityResponse.getAspects(), result);
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(result, DataJob.class);
|
||||
} else {
|
||||
@ -223,4 +227,14 @@ public class DataJobMapper implements ModelMapper<EntityResponse, DataJob> {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void mapApplicationAssociation(
|
||||
final QueryContext context, final EnvelopedAspectMap aspectMap, final DataJob dataJob) {
|
||||
if (aspectMap.containsKey(APPLICATION_MEMBERSHIP_ASPECT_NAME)) {
|
||||
final Applications applications =
|
||||
new Applications(aspectMap.get(APPLICATION_MEMBERSHIP_ASPECT_NAME).getValue().data());
|
||||
dataJob.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, dataJob.getUrn()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.linkedin.datahub.graphql.types.dataproduct;
|
||||
|
||||
import static com.linkedin.metadata.Constants.APPLICATION_MEMBERSHIP_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.DATA_PRODUCT_ENTITY_NAME;
|
||||
import static com.linkedin.metadata.Constants.DATA_PRODUCT_PROPERTIES_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.DOMAINS_ASPECT_NAME;
|
||||
@ -53,7 +54,8 @@ public class DataProductType
|
||||
DOMAINS_ASPECT_NAME,
|
||||
INSTITUTIONAL_MEMORY_ASPECT_NAME,
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME);
|
||||
FORMS_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME);
|
||||
private final EntityClient _entityClient;
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.linkedin.datahub.graphql.types.dataproduct.mappers;
|
||||
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.APPLICATION_MEMBERSHIP_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.DATA_PRODUCT_PROPERTIES_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.DOMAINS_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.FORMS_ASPECT_NAME;
|
||||
@ -10,6 +11,7 @@ import static com.linkedin.metadata.Constants.INSTITUTIONAL_MEMORY_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.OWNERSHIP_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.STRUCTURED_PROPERTIES_ASPECT_NAME;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.Forms;
|
||||
import com.linkedin.common.GlobalTags;
|
||||
import com.linkedin.common.GlossaryTerms;
|
||||
@ -22,6 +24,7 @@ import com.linkedin.datahub.graphql.QueryContext;
|
||||
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
|
||||
import com.linkedin.datahub.graphql.generated.DataProduct;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.CustomPropertiesMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.InstitutionalMemoryMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.OwnershipMapper;
|
||||
@ -98,6 +101,9 @@ public class DataProductMapper implements ModelMapper<EntityResponse, DataProduc
|
||||
FORMS_ASPECT_NAME,
|
||||
((entity, dataMap) ->
|
||||
entity.setForms(FormsMapper.map(new Forms(dataMap), entityUrn.toString()))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(dataProduct, dataMap) -> mapApplicationAssociation(context, dataProduct, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(result, DataProduct.class);
|
||||
@ -130,4 +136,13 @@ public class DataProductMapper implements ModelMapper<EntityResponse, DataProduc
|
||||
|
||||
dataProduct.setProperties(properties);
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull DataProduct dataProduct,
|
||||
@Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
dataProduct.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, dataProduct.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +90,7 @@ public class DatasetType
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME,
|
||||
SUB_TYPES_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
VERSION_PROPERTIES_ASPECT_NAME);
|
||||
|
||||
private static final Set<String> FACET_FIELDS = ImmutableSet.of("origin", "platform");
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.dataset.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.Access;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
@ -29,6 +30,7 @@ import com.linkedin.datahub.graphql.generated.Dataset;
|
||||
import com.linkedin.datahub.graphql.generated.DatasetEditableProperties;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.generated.FabricType;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.CustomPropertiesMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper;
|
||||
@ -142,6 +144,9 @@ public class DatasetMapper implements ModelMapper<EntityResponse, Dataset> {
|
||||
GlossaryTermsMapper.map(context, new GlossaryTerms(dataMap), entityUrn)));
|
||||
mappingHelper.mapToResult(context, CONTAINER_ASPECT_NAME, DatasetMapper::mapContainers);
|
||||
mappingHelper.mapToResult(context, DOMAINS_ASPECT_NAME, DatasetMapper::mapDomains);
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(dataset, dataMap) -> mapApplicationAssociation(context, dataset, dataMap));
|
||||
mappingHelper.mapToResult(
|
||||
DEPRECATION_ASPECT_NAME,
|
||||
(dataset, dataMap) ->
|
||||
@ -151,6 +156,8 @@ public class DatasetMapper implements ModelMapper<EntityResponse, Dataset> {
|
||||
(dataset, dataMap) ->
|
||||
dataset.setDataPlatformInstance(
|
||||
DataPlatformInstanceAspectMapper.map(context, new DataPlatformInstance(dataMap))));
|
||||
mappingHelper.mapToResult(
|
||||
"applications", (dataset, dataMap) -> mapApplicationAssociation(context, dataset, dataMap));
|
||||
mappingHelper.mapToResult(
|
||||
SIBLINGS_ASPECT_NAME,
|
||||
(dataset, dataMap) ->
|
||||
@ -301,4 +308,11 @@ public class DatasetMapper implements ModelMapper<EntityResponse, Dataset> {
|
||||
final Domains domains = new Domains(dataMap);
|
||||
dataset.setDomain(DomainAssociationMapper.map(context, domains, dataset.getUrn()));
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context, @Nonnull Dataset dataset, @Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
dataset.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, dataset.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.linkedin.datahub.graphql.types.glossary;
|
||||
|
||||
import static com.linkedin.metadata.Constants.APPLICATION_MEMBERSHIP_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.FORMS_ASPECT_NAME;
|
||||
import static com.linkedin.metadata.Constants.GLOSSARY_NODE_ENTITY_NAME;
|
||||
import static com.linkedin.metadata.Constants.GLOSSARY_NODE_INFO_ASPECT_NAME;
|
||||
@ -48,7 +49,8 @@ public class GlossaryNodeType
|
||||
GLOSSARY_NODE_INFO_ASPECT_NAME,
|
||||
OWNERSHIP_ASPECT_NAME,
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME);
|
||||
FORMS_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME);
|
||||
|
||||
private final EntityClient _entityClient;
|
||||
|
||||
|
||||
@ -59,7 +59,8 @@ public class GlossaryTermType
|
||||
DOMAINS_ASPECT_NAME,
|
||||
DEPRECATION_ASPECT_NAME,
|
||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||
FORMS_ASPECT_NAME);
|
||||
FORMS_ASPECT_NAME,
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME);
|
||||
|
||||
private final EntityClient _entityClient;
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.glossary.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.Deprecation;
|
||||
import com.linkedin.common.Forms;
|
||||
import com.linkedin.common.InstitutionalMemory;
|
||||
@ -14,6 +15,7 @@ import com.linkedin.datahub.graphql.QueryContext;
|
||||
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.generated.GlossaryTerm;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DeprecationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.InstitutionalMemoryMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.OwnershipMapper;
|
||||
@ -96,6 +98,9 @@ public class GlossaryTermMapper implements ModelMapper<EntityResponse, GlossaryT
|
||||
FORMS_ASPECT_NAME,
|
||||
((entity, dataMap) ->
|
||||
entity.setForms(FormsMapper.map(new Forms(dataMap), entityUrn.toString()))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(glossaryTerm, dataMap) -> mapApplicationAssociation(context, glossaryTerm, dataMap));
|
||||
|
||||
// If there's no name property, resort to the legacy name computation.
|
||||
if (result.getGlossaryTermInfo() != null && result.getGlossaryTermInfo().getName() == null) {
|
||||
@ -124,4 +129,13 @@ public class GlossaryTermMapper implements ModelMapper<EntityResponse, GlossaryT
|
||||
final Domains domains = new Domains(dataMap);
|
||||
glossaryTerm.setDomain(DomainAssociationMapper.map(context, domains, glossaryTerm.getUrn()));
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull GlossaryTerm glossaryTerm,
|
||||
@Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
glossaryTerm.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, glossaryTerm.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.mlmodel.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
import com.linkedin.common.Deprecation;
|
||||
@ -21,6 +22,7 @@ import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.generated.MLFeature;
|
||||
import com.linkedin.datahub.graphql.generated.MLFeatureDataType;
|
||||
import com.linkedin.datahub.graphql.generated.MLFeatureEditableProperties;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DeprecationMapper;
|
||||
@ -122,6 +124,9 @@ public class MLFeatureMapper implements ModelMapper<EntityResponse, MLFeature> {
|
||||
FORMS_ASPECT_NAME,
|
||||
((entity, dataMap) ->
|
||||
entity.setForms(FormsMapper.map(new Forms(dataMap), entityUrn.toString()))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(mlFeature, dataMap) -> mapApplicationAssociation(context, mlFeature, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), MLFeature.class);
|
||||
@ -175,4 +180,13 @@ public class MLFeatureMapper implements ModelMapper<EntityResponse, MLFeature> {
|
||||
}
|
||||
entity.setEditableProperties(editableProperties);
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull MLFeature mlFeature,
|
||||
@Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
mlFeature.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, mlFeature.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.mlmodel.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
import com.linkedin.common.Deprecation;
|
||||
@ -21,6 +22,7 @@ import com.linkedin.datahub.graphql.generated.DataPlatform;
|
||||
import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.generated.MLFeatureTable;
|
||||
import com.linkedin.datahub.graphql.generated.MLFeatureTableEditableProperties;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DeprecationMapper;
|
||||
@ -123,6 +125,9 @@ public class MLFeatureTableMapper implements ModelMapper<EntityResponse, MLFeatu
|
||||
FORMS_ASPECT_NAME,
|
||||
((entity, dataMap) ->
|
||||
entity.setForms(FormsMapper.map(new Forms(dataMap), entityUrn.toString()))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(mlFeatureTable, dataMap) -> mapApplicationAssociation(context, mlFeatureTable, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), MLFeatureTable.class);
|
||||
@ -178,4 +183,13 @@ public class MLFeatureTableMapper implements ModelMapper<EntityResponse, MLFeatu
|
||||
}
|
||||
entity.setEditableProperties(editableProperties);
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull MLFeatureTable mlFeatureTable,
|
||||
@Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
mlFeatureTable.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, mlFeatureTable.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.mlmodel.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
import com.linkedin.common.Deprecation;
|
||||
@ -21,6 +22,7 @@ import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.generated.FabricType;
|
||||
import com.linkedin.datahub.graphql.generated.MLModelGroup;
|
||||
import com.linkedin.datahub.graphql.generated.MLModelGroupEditableProperties;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DeprecationMapper;
|
||||
@ -117,6 +119,9 @@ public class MLModelGroupMapper implements ModelMapper<EntityResponse, MLModelGr
|
||||
FORMS_ASPECT_NAME,
|
||||
((entity, dataMap) ->
|
||||
entity.setForms(FormsMapper.map(new Forms(dataMap), entityUrn.toString()))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(mlModelGroup, dataMap) -> mapApplicationAssociation(context, mlModelGroup, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), MLModelGroup.class);
|
||||
@ -172,4 +177,13 @@ public class MLModelGroupMapper implements ModelMapper<EntityResponse, MLModelGr
|
||||
}
|
||||
entity.setEditableProperties(editableProperties);
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context,
|
||||
@Nonnull MLModelGroup mlModelGroup,
|
||||
@Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
mlModelGroup.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, mlModelGroup.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.linkedin.datahub.graphql.types.mlmodel.mappers;
|
||||
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.canView;
|
||||
import static com.linkedin.metadata.Constants.*;
|
||||
|
||||
import com.linkedin.application.Applications;
|
||||
import com.linkedin.common.BrowsePathsV2;
|
||||
import com.linkedin.common.Cost;
|
||||
import com.linkedin.common.DataPlatformInstance;
|
||||
@ -24,6 +25,7 @@ import com.linkedin.datahub.graphql.generated.EntityType;
|
||||
import com.linkedin.datahub.graphql.generated.FabricType;
|
||||
import com.linkedin.datahub.graphql.generated.MLModel;
|
||||
import com.linkedin.datahub.graphql.generated.MLModelEditableProperties;
|
||||
import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.CostMapper;
|
||||
import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper;
|
||||
@ -187,6 +189,9 @@ public class MLModelMapper implements ModelMapper<EntityResponse, MLModel> {
|
||||
(entity, dataMap) ->
|
||||
entity.setVersionProperties(
|
||||
VersionPropertiesMapper.map(context, new VersionProperties(dataMap))));
|
||||
mappingHelper.mapToResult(
|
||||
APPLICATION_MEMBERSHIP_ASPECT_NAME,
|
||||
(mlModel, dataMap) -> mapApplicationAssociation(context, mlModel, dataMap));
|
||||
|
||||
if (context != null && !canView(context.getOperationContext(), entityUrn)) {
|
||||
return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), MLModel.class);
|
||||
@ -249,4 +254,11 @@ public class MLModelMapper implements ModelMapper<EntityResponse, MLModel> {
|
||||
}
|
||||
entity.setEditableProperties(editableProperties);
|
||||
}
|
||||
|
||||
private static void mapApplicationAssociation(
|
||||
@Nullable final QueryContext context, @Nonnull MLModel mlModel, @Nonnull DataMap dataMap) {
|
||||
final Applications applications = new Applications(dataMap);
|
||||
mlModel.setApplication(
|
||||
ApplicationAssociationMapper.map(context, applications, mlModel.getUrn()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,6 +357,21 @@ type VisualConfig {
|
||||
Configuration for custom theme-ing
|
||||
"""
|
||||
theme: ThemeConfig
|
||||
|
||||
"""
|
||||
Configuration for the application sidebar section
|
||||
"""
|
||||
application: ApplicationConfig
|
||||
}
|
||||
|
||||
"""
|
||||
Configuration for the application sidebar section
|
||||
"""
|
||||
type ApplicationConfig {
|
||||
"""
|
||||
Whether to show the application sidebar section even when empty
|
||||
"""
|
||||
showSidebarSectionWhenEmpty: Boolean
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
@ -1689,6 +1689,11 @@ type Dataset implements EntityWithRelationships & Entity & BrowsableEntity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the dataset
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
The forms associated with the Dataset
|
||||
"""
|
||||
@ -2136,6 +2141,11 @@ type VersionedDataset implements Entity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
Experimental! The resolved health status of the asset
|
||||
"""
|
||||
@ -2353,6 +2363,11 @@ type GlossaryTerm implements Entity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the glossary term
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
References to internal resources related to the Glossary Term
|
||||
"""
|
||||
@ -2997,6 +3012,11 @@ type Container implements Entity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
The deprecation status of the container
|
||||
"""
|
||||
@ -5463,6 +5483,11 @@ type Notebook implements Entity & BrowsableEntity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
The specific instance of the data platform that this entity belongs to
|
||||
"""
|
||||
@ -5750,6 +5775,11 @@ type Dashboard implements EntityWithRelationships & Entity & BrowsableEntity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
The specific instance of the data platform that this entity belongs to
|
||||
"""
|
||||
@ -6088,6 +6118,11 @@ type Chart implements EntityWithRelationships & Entity & BrowsableEntity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
The specific instance of the data platform that this entity belongs to
|
||||
"""
|
||||
@ -6487,6 +6522,11 @@ type DataFlow implements EntityWithRelationships & Entity & BrowsableEntity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
The specific instance of the data platform that this entity belongs to
|
||||
"""
|
||||
@ -6739,6 +6779,11 @@ type DataJob implements EntityWithRelationships & Entity & BrowsableEntity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
Granular API for querying edges extending from this entity
|
||||
"""
|
||||
@ -10028,6 +10073,11 @@ type MLModel implements EntityWithRelationships & Entity & BrowsableEntity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
An additional set of of read write properties
|
||||
"""
|
||||
@ -10160,6 +10210,11 @@ type MLModelGroup implements EntityWithRelationships & Entity & BrowsableEntity
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
An additional set of of read write properties
|
||||
"""
|
||||
@ -10342,6 +10397,11 @@ type MLFeature implements EntityWithRelationships & Entity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
An additional set of of read write properties
|
||||
"""
|
||||
@ -10596,6 +10656,11 @@ type MLPrimaryKey implements EntityWithRelationships & Entity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
An additional set of of read write properties
|
||||
"""
|
||||
@ -10745,6 +10810,11 @@ type MLFeatureTable implements EntityWithRelationships & Entity & BrowsableEntit
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the entity
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
An additional set of of read write properties
|
||||
"""
|
||||
@ -11104,6 +11174,18 @@ type SubTypes {
|
||||
typeNames: [String!]
|
||||
}
|
||||
|
||||
type ApplicationAssociation {
|
||||
"""
|
||||
The application related to the assocaited urn
|
||||
"""
|
||||
application: Application!
|
||||
|
||||
"""
|
||||
Reference back to the tagged urn for tracking purposes e.g. when sibling nodes are merged together
|
||||
"""
|
||||
associatedUrn: String!
|
||||
}
|
||||
|
||||
type DomainAssociation {
|
||||
"""
|
||||
The domain related to the assocaited urn
|
||||
@ -12705,6 +12787,11 @@ type DataProduct implements Entity {
|
||||
"""
|
||||
domain: DomainAssociation
|
||||
|
||||
"""
|
||||
The application associated with the data product
|
||||
"""
|
||||
application: ApplicationAssociation
|
||||
|
||||
"""
|
||||
Tags used for searching Data Product
|
||||
"""
|
||||
|
||||
@ -333,6 +333,7 @@ export const dataset1 = {
|
||||
},
|
||||
],
|
||||
domain: null,
|
||||
application: null,
|
||||
container: null,
|
||||
health: [],
|
||||
assertions: null,
|
||||
@ -429,6 +430,7 @@ export const dataset2 = {
|
||||
},
|
||||
],
|
||||
domain: null,
|
||||
application: null,
|
||||
container: null,
|
||||
health: [],
|
||||
assertions: null,
|
||||
@ -670,6 +672,7 @@ export const dataset3 = {
|
||||
},
|
||||
],
|
||||
domain: null,
|
||||
application: null,
|
||||
container: null,
|
||||
lineage: null,
|
||||
relationships: null,
|
||||
@ -1410,6 +1413,7 @@ export const dataFlow1 = {
|
||||
},
|
||||
},
|
||||
domain: null,
|
||||
application: null,
|
||||
deprecation: null,
|
||||
autoRenderAspects: [],
|
||||
activeIncidents: null,
|
||||
@ -1497,6 +1501,7 @@ export const dataJob1 = {
|
||||
],
|
||||
},
|
||||
domain: null,
|
||||
application: null,
|
||||
status: null,
|
||||
deprecation: null,
|
||||
autoRenderAspects: [],
|
||||
@ -1663,6 +1668,7 @@ export const dataJob2 = {
|
||||
],
|
||||
},
|
||||
domain: null,
|
||||
application: null,
|
||||
upstream: null,
|
||||
downstream: null,
|
||||
deprecation: null,
|
||||
@ -1736,6 +1742,7 @@ export const dataJob3 = {
|
||||
],
|
||||
},
|
||||
domain: null,
|
||||
application: null,
|
||||
upstream: null,
|
||||
downstream: null,
|
||||
status: null,
|
||||
|
||||
@ -100,6 +100,10 @@ export enum EntityCapabilityType {
|
||||
* Assigning Business Attribute to a entity
|
||||
*/
|
||||
BUSINESS_ATTRIBUTES,
|
||||
/**
|
||||
* Assigning an application to a entity
|
||||
*/
|
||||
APPLICATIONS,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -24,6 +24,10 @@ export enum EntityActionItem {
|
||||
* Batch add a Data Product to a set of assets
|
||||
*/
|
||||
BATCH_ADD_DATA_PRODUCT,
|
||||
/**
|
||||
* Batch add an Application to a set of assets
|
||||
*/
|
||||
BATCH_ADD_APPLICATION,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
|
||||
@ -4,6 +4,7 @@ import React from 'react';
|
||||
import { FetchedEntity } from '@app/lineage/types';
|
||||
|
||||
import {
|
||||
ApplicationAssociation,
|
||||
BrowsePathV2,
|
||||
Container,
|
||||
CustomPropertiesEntry,
|
||||
@ -91,6 +92,7 @@ export type GenericEntityProperties = {
|
||||
glossaryTerms?: Maybe<GlossaryTerms>;
|
||||
ownership?: Maybe<Ownership>;
|
||||
domain?: Maybe<DomainAssociation>;
|
||||
application?: Maybe<ApplicationAssociation>;
|
||||
dataProduct?: Maybe<EntityRelationshipsResult>;
|
||||
platform?: Maybe<DataPlatform>;
|
||||
dataPlatformInstance?: Maybe<DataPlatformInstance>;
|
||||
|
||||
@ -96,6 +96,10 @@ export enum EntityCapabilityType {
|
||||
* Lineage information of an entity
|
||||
*/
|
||||
LINEAGE,
|
||||
/**
|
||||
* Assigning the entity to an application
|
||||
*/
|
||||
APPLICATIONS,
|
||||
}
|
||||
|
||||
export interface EntityMenuActions {
|
||||
|
||||
@ -24,6 +24,7 @@ import { SidebarGlossaryTermsSection } from '@app/entityV2/shared/containers/pro
|
||||
import { SidebarTagsSection } from '@app/entityV2/shared/containers/profile/sidebar/SidebarTagsSection';
|
||||
import StatusSection from '@app/entityV2/shared/containers/profile/sidebar/shared/StatusSection';
|
||||
import { getDataForEntityType } from '@app/entityV2/shared/containers/profile/utils';
|
||||
import { EntityActionItem } from '@app/entityV2/shared/entity/EntityActions';
|
||||
import SidebarNotesSection from '@app/entityV2/shared/sidebarSection/SidebarNotesSection';
|
||||
import SidebarStructuredProperties from '@app/entityV2/shared/sidebarSection/SidebarStructuredProperties';
|
||||
import { DocumentationTab } from '@app/entityV2/shared/tabs/Documentation/DocumentationTab';
|
||||
@ -98,7 +99,7 @@ export class ApplicationEntity implements Entity<Application> {
|
||||
useEntityQuery={useGetApplicationQuery}
|
||||
useUpdateQuery={undefined}
|
||||
getOverrideProperties={this.getOverridePropertiesFromEntity}
|
||||
headerActionItems={new Set([])}
|
||||
headerActionItems={new Set([EntityActionItem.BATCH_ADD_APPLICATION])}
|
||||
headerDropdownItems={headerDropdownItems}
|
||||
isNameEditable
|
||||
tabs={[
|
||||
|
||||
@ -20,6 +20,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { SubType, TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import SidebarChartHeaderSection from '@app/entityV2/shared/containers/profile/sidebar/Chart/Header/SidebarChartHeaderSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
@ -231,6 +232,9 @@ export class ChartEntity implements Entity<Chart> {
|
||||
{
|
||||
component: SidebarDomainSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: DataProductSection,
|
||||
},
|
||||
@ -386,6 +390,7 @@ export class ChartEntity implements Entity<Chart> {
|
||||
EntityCapabilityType.TEST,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.HEALTH,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import SidebarDashboardHeaderSection from '@app/entityV2/shared/containers/profile/sidebar/Dashboard/Header/SidebarDashboardHeaderSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
@ -225,6 +226,9 @@ export class DashboardEntity implements Entity<Dashboard> {
|
||||
{
|
||||
component: SidebarDomainSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: DataProductSection,
|
||||
},
|
||||
@ -393,6 +397,7 @@ export class DashboardEntity implements Entity<Dashboard> {
|
||||
EntityCapabilityType.TEST,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.HEALTH,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
@ -141,6 +142,9 @@ export class DataFlowEntity implements Entity<DataFlow> {
|
||||
{
|
||||
component: SidebarDomainSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: DataProductSection,
|
||||
},
|
||||
@ -257,6 +261,7 @@ export class DataFlowEntity implements Entity<DataFlow> {
|
||||
EntityCapabilityType.TEST,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.HEALTH,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import SidebarLineageSection from '@app/entityV2/shared/containers/profile/sidebar/Lineage/SidebarLineageSection';
|
||||
@ -50,7 +51,6 @@ const headerDropdownItems = new Set([
|
||||
EntityMenuItems.SHARE,
|
||||
EntityMenuItems.UPDATE_DEPRECATION,
|
||||
EntityMenuItems.ANNOUNCE,
|
||||
EntityMenuItems.EXTERNAL_URL,
|
||||
]);
|
||||
|
||||
/**
|
||||
@ -162,6 +162,7 @@ export class DataJobEntity implements Entity<DataJob> {
|
||||
{ component: SidebarDataJobTransformationLogicSection },
|
||||
{ component: SidebarOwnerSection },
|
||||
{ component: SidebarDomainSection },
|
||||
{ component: SidebarApplicationSection },
|
||||
{ component: DataProductSection },
|
||||
{ component: SidebarGlossaryTermsSection },
|
||||
{ component: SidebarTagsSection },
|
||||
@ -323,6 +324,7 @@ export class DataJobEntity implements Entity<DataJob> {
|
||||
EntityCapabilityType.TEST,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.HEALTH,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfileTab } from '@app/entityV2/shared/constants';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import { SidebarViewDefinitionSection } from '@app/entityV2/shared/containers/profile/sidebar/Dataset/View/SidebarViewDefinitionSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
@ -154,6 +155,9 @@ export class DataProductEntity implements Entity<DataProduct> {
|
||||
updateOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
// TODO: Is someone actually using the below code?
|
||||
{
|
||||
component: SidebarViewDefinitionSection,
|
||||
@ -262,6 +266,7 @@ export class DataProductEntity implements Entity<DataProduct> {
|
||||
EntityCapabilityType.GLOSSARY_TERMS,
|
||||
EntityCapabilityType.TAGS,
|
||||
EntityCapabilityType.DOMAINS,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { SubType, TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import SidebarDatasetHeaderSection from '@app/entityV2/shared/containers/profile/sidebar/Dataset/Header/SidebarDatasetHeaderSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
@ -188,7 +189,6 @@ export class DatasetEntity implements Entity<Dataset> {
|
||||
name: 'Lineage',
|
||||
component: LineageTab,
|
||||
icon: PartitionOutlined,
|
||||
supportsFullsize: true,
|
||||
},
|
||||
{
|
||||
name: 'Access',
|
||||
@ -287,6 +287,7 @@ export class DatasetEntity implements Entity<Dataset> {
|
||||
{ component: SidebarLineageSection },
|
||||
{ component: SidebarOwnerSection },
|
||||
{ component: SidebarDomainSection },
|
||||
{ component: SidebarApplicationSection },
|
||||
{ component: DataProductSection },
|
||||
{ component: SidebarTagsSection },
|
||||
{ component: SidebarGlossaryTermsSection },
|
||||
@ -514,6 +515,7 @@ export class DatasetEntity implements Entity<Dataset> {
|
||||
EntityCapabilityType.TEST,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.HEALTH,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
import StatusSection from '@app/entityV2/shared/containers/profile/sidebar/shared/StatusSection';
|
||||
import { getDataForEntityType } from '@app/entityV2/shared/containers/profile/utils';
|
||||
@ -133,6 +134,9 @@ class GlossaryNodeEntity implements Entity<GlossaryNode> {
|
||||
{
|
||||
component: SidebarOwnerSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: SidebarStructuredProperties,
|
||||
},
|
||||
@ -197,6 +201,7 @@ class GlossaryNodeEntity implements Entity<GlossaryNode> {
|
||||
EntityCapabilityType.OWNERS,
|
||||
EntityCapabilityType.DEPRECATION,
|
||||
EntityCapabilityType.SOFT_DELETE,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
import SidebarEntityHeader from '@app/entityV2/shared/containers/profile/sidebar/SidebarEntityHeader';
|
||||
@ -172,6 +173,9 @@ export class GlossaryTermEntity implements Entity<GlossaryTerm> {
|
||||
hideOwnerType: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: SidebarStructuredProperties,
|
||||
},
|
||||
@ -239,6 +243,7 @@ export class GlossaryTermEntity implements Entity<GlossaryTerm> {
|
||||
EntityCapabilityType.OWNERS,
|
||||
EntityCapabilityType.DEPRECATION,
|
||||
EntityCapabilityType.SOFT_DELETE,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
@ -154,6 +155,9 @@ export class MLFeatureEntity implements Entity<MlFeature> {
|
||||
{
|
||||
component: SidebarDomainSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: DataProductSection,
|
||||
},
|
||||
@ -269,6 +273,7 @@ export class MLFeatureEntity implements Entity<MlFeature> {
|
||||
EntityCapabilityType.SOFT_DELETE,
|
||||
EntityCapabilityType.DATA_PRODUCTS,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
@ -136,6 +137,9 @@ export class MLFeatureTableEntity implements Entity<MlFeatureTable> {
|
||||
{
|
||||
component: SidebarDomainSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: DataProductSection,
|
||||
},
|
||||
@ -235,6 +239,7 @@ export class MLFeatureTableEntity implements Entity<MlFeatureTable> {
|
||||
EntityCapabilityType.SOFT_DELETE,
|
||||
EntityCapabilityType.DATA_PRODUCTS,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
@ -161,6 +162,9 @@ export class MLModelEntity implements Entity<MlModel> {
|
||||
{
|
||||
component: SidebarDomainSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: DataProductSection,
|
||||
},
|
||||
@ -257,6 +261,7 @@ export class MLModelEntity implements Entity<MlModel> {
|
||||
EntityCapabilityType.SOFT_DELETE,
|
||||
EntityCapabilityType.DATA_PRODUCTS,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import { EntityMenuItems } from '@app/entityV2/shared/EntityDropdown/EntityMenuA
|
||||
import { TYPE_ICON_CLASS_NAME } from '@app/entityV2/shared/components/subtypes';
|
||||
import { EntityProfile } from '@app/entityV2/shared/containers/profile/EntityProfile';
|
||||
import { SidebarAboutSection } from '@app/entityV2/shared/containers/profile/sidebar/AboutSection/SidebarAboutSection';
|
||||
import { SidebarApplicationSection } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SidebarApplicationSection';
|
||||
import DataProductSection from '@app/entityV2/shared/containers/profile/sidebar/DataProduct/DataProductSection';
|
||||
import { SidebarDomainSection } from '@app/entityV2/shared/containers/profile/sidebar/Domain/SidebarDomainSection';
|
||||
import { SidebarOwnerSection } from '@app/entityV2/shared/containers/profile/sidebar/Ownership/sidebar/SidebarOwnerSection';
|
||||
@ -136,6 +137,9 @@ export class MLModelGroupEntity implements Entity<MlModelGroup> {
|
||||
{
|
||||
component: SidebarDomainSection,
|
||||
},
|
||||
{
|
||||
component: SidebarApplicationSection,
|
||||
},
|
||||
{
|
||||
component: DataProductSection,
|
||||
},
|
||||
@ -232,6 +236,7 @@ export class MLModelGroupEntity implements Entity<MlModelGroup> {
|
||||
EntityCapabilityType.SOFT_DELETE,
|
||||
EntityCapabilityType.DATA_PRODUCTS,
|
||||
EntityCapabilityType.LINEAGE,
|
||||
EntityCapabilityType.APPLICATIONS,
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
@ -172,6 +172,10 @@ export const EMPTY_MESSAGES = {
|
||||
title: 'No product yet',
|
||||
description: 'Group related entities based on shared characteristics by adding them to a Data Product.',
|
||||
},
|
||||
application: {
|
||||
title: 'No application yet',
|
||||
description: 'Associate entities with applications to track ownership and lifecycle.',
|
||||
},
|
||||
contains: {
|
||||
title: 'Does not Contain any Glossary Terms',
|
||||
description: 'Terms can contain other terms to represent a "Has A" style relationship.',
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
import { Modal, Select, Typography, message } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { useBatchSetApplicationMutation, useGetApplicationsListQuery } from '@graphql/application.generated';
|
||||
import { Application, EntityType } from '@types';
|
||||
|
||||
interface Props {
|
||||
urns: string[];
|
||||
onCloseModal: () => void;
|
||||
refetch?: () => void;
|
||||
}
|
||||
|
||||
export const SetApplicationModal = ({ urns, onCloseModal, refetch }: Props) => {
|
||||
const [applicationUrn, setApplicationUrn] = useState<string | undefined>(undefined);
|
||||
const { data, loading, error } = useGetApplicationsListQuery({
|
||||
variables: {
|
||||
input: {
|
||||
start: 0,
|
||||
count: 1000,
|
||||
query: '',
|
||||
types: [EntityType.Application],
|
||||
},
|
||||
},
|
||||
});
|
||||
const [batchSetApplicationMutation] = useBatchSetApplicationMutation();
|
||||
|
||||
const onOk = () => {
|
||||
if (!applicationUrn) {
|
||||
return;
|
||||
}
|
||||
batchSetApplicationMutation({
|
||||
variables: {
|
||||
input: {
|
||||
applicationUrn,
|
||||
resourceUrns: urns,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
message.success({ content: 'Application set', duration: 2 });
|
||||
refetch?.();
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
message.destroy();
|
||||
if (e instanceof Error) {
|
||||
message.error({ content: `Failed to set application: \n ${e.message || ''}`, duration: 3 });
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
onCloseModal();
|
||||
});
|
||||
};
|
||||
|
||||
const applicationOptions =
|
||||
data?.searchAcrossEntities?.searchResults
|
||||
?.map((r) => r.entity)
|
||||
.filter((entity): entity is Application => entity.__typename === 'Application')
|
||||
.map((appEntity) => {
|
||||
return {
|
||||
value: appEntity.urn,
|
||||
label: appEntity.properties?.name || '',
|
||||
};
|
||||
}) || [];
|
||||
|
||||
return (
|
||||
<Modal title="Set Application" open onOk={onOk} onCancel={onCloseModal} closable>
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: '100%' }}
|
||||
placeholder="Select an application"
|
||||
onChange={(value) => setApplicationUrn(value)}
|
||||
filterOption={(input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
|
||||
options={applicationOptions}
|
||||
loading={loading}
|
||||
/>
|
||||
{error && <Typography.Text type="danger">Failed to load applications: {error.message}</Typography.Text>}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,145 @@
|
||||
import AddRoundedIcon from '@mui/icons-material/AddRounded';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
import { Modal, message } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { useEntityData, useMutationUrn, useRefetch } from '@app/entity/shared/EntityContext';
|
||||
import { EMPTY_MESSAGES } from '@app/entityV2/shared/constants';
|
||||
import { SetApplicationModal } from '@app/entityV2/shared/containers/profile/sidebar/Applications/SetApplicationModal';
|
||||
import EmptySectionText from '@app/entityV2/shared/containers/profile/sidebar/EmptySectionText';
|
||||
import SectionActionButton from '@app/entityV2/shared/containers/profile/sidebar/SectionActionButton';
|
||||
import { SidebarSection } from '@app/entityV2/shared/containers/profile/sidebar/SidebarSection';
|
||||
import { ApplicationLink } from '@app/shared/tags/ApplicationLink';
|
||||
import { useAppConfig } from '@app/useAppConfig';
|
||||
|
||||
import { useBatchSetApplicationMutation } from '@graphql/application.generated';
|
||||
|
||||
const Content = styled.div`
|
||||
display: flex;
|
||||
align-items: start;
|
||||
justify-content: start;
|
||||
flex-wrap: wrap;
|
||||
text-wrap: wrap;
|
||||
`;
|
||||
|
||||
const ApplicationLinkWrapper = styled.div`
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
interface PropertiesProps {
|
||||
updateOnly?: boolean;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
readOnly?: boolean;
|
||||
properties?: PropertiesProps;
|
||||
}
|
||||
|
||||
export const SidebarApplicationSection = ({ readOnly, properties }: Props) => {
|
||||
const {
|
||||
config: { visualConfig },
|
||||
} = useAppConfig();
|
||||
const updateOnly = properties?.updateOnly;
|
||||
const { entityData } = useEntityData();
|
||||
const refetch = useRefetch();
|
||||
const urn = useMutationUrn();
|
||||
const [batchSetApplicationMutation] = useBatchSetApplicationMutation();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const application = entityData?.application?.application;
|
||||
const canEditApplication = !!entityData?.privileges?.canEditProperties;
|
||||
|
||||
console.log('application', application);
|
||||
|
||||
if (!application && !visualConfig.application?.showSidebarSectionWhenEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const removeApplication = () => {
|
||||
batchSetApplicationMutation({
|
||||
variables: {
|
||||
input: {
|
||||
applicationUrn: null,
|
||||
resourceUrns: [urn],
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
message.success({ content: 'Removed Application.', duration: 2 });
|
||||
refetch?.();
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
message.destroy();
|
||||
if (e instanceof Error) {
|
||||
message.error({ content: `Failed to remove application: \n ${e.message || ''}`, duration: 3 });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onRemoveApplication = () => {
|
||||
Modal.confirm({
|
||||
title: `Confirm Application Removal`,
|
||||
content: `Are you sure you want to remove this application?`,
|
||||
onOk() {
|
||||
removeApplication();
|
||||
},
|
||||
onCancel() {},
|
||||
okText: 'Yes',
|
||||
maskClosable: true,
|
||||
closable: true,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="sidebar-application-section">
|
||||
<SidebarSection
|
||||
title="Application"
|
||||
content={
|
||||
<Content>
|
||||
{application && (
|
||||
<ApplicationLinkWrapper>
|
||||
<ApplicationLink
|
||||
application={application}
|
||||
closable={!readOnly && !updateOnly && canEditApplication}
|
||||
readOnly={readOnly}
|
||||
onClose={(e) => {
|
||||
e.preventDefault();
|
||||
onRemoveApplication();
|
||||
}}
|
||||
fontSize={12}
|
||||
/>
|
||||
</ApplicationLinkWrapper>
|
||||
)}
|
||||
{(!application || !!updateOnly) && (
|
||||
<>{!application && <EmptySectionText message={EMPTY_MESSAGES.application.title} />}</>
|
||||
)}
|
||||
</Content>
|
||||
}
|
||||
extra={
|
||||
!readOnly && (
|
||||
<SectionActionButton
|
||||
dataTestId="add-applications-button"
|
||||
button={application ? <EditOutlinedIcon /> : <AddRoundedIcon />}
|
||||
onClick={(event) => {
|
||||
setShowModal(true);
|
||||
event.stopPropagation();
|
||||
}}
|
||||
actionPrivilege={canEditApplication}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
{showModal && (
|
||||
<SetApplicationModal
|
||||
urns={[urn]}
|
||||
refetch={refetch}
|
||||
onCloseModal={() => {
|
||||
setShowModal(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -11,6 +11,7 @@ import { SearchSelectModal } from '@app/entityV2/shared/components/styled/search
|
||||
import { handleBatchError } from '@app/entityV2/shared/utils';
|
||||
import { useEntityRegistry } from '@app/useEntityRegistry';
|
||||
|
||||
import { useBatchSetApplicationMutation } from '@graphql/application.generated';
|
||||
import { useBatchSetDataProductMutation } from '@graphql/dataProduct.generated';
|
||||
import { useBatchAddTermsMutation, useBatchSetDomainMutation } from '@graphql/mutations.generated';
|
||||
import { EntityType } from '@types';
|
||||
@ -36,6 +37,10 @@ export enum EntityActionItem {
|
||||
* Add a new Glossary Node as child
|
||||
*/
|
||||
ADD_CHILD_GLOSSARY_NODE,
|
||||
/**
|
||||
* Batch add an Application to a set of assets
|
||||
*/
|
||||
BATCH_ADD_APPLICATION,
|
||||
}
|
||||
|
||||
const ButtonWrapper = styled.div`
|
||||
@ -72,9 +77,11 @@ function EntityActions(props: Props) {
|
||||
const [isBatchSetDataProductModalVisible, setIsBatchSetDataProductModalVisible] = useState(false);
|
||||
const [isCreateTermModalVisible, setIsCreateTermModalVisible] = useState(false);
|
||||
const [isCreateNodeModalVisible, setIsCreateNodeModalVisible] = useState(false);
|
||||
const [isBatchSetApplicationModalVisible, setIsBatchSetApplicationModalVisible] = useState(false);
|
||||
const [batchAddTermsMutation] = useBatchAddTermsMutation();
|
||||
const [batchSetDomainMutation] = useBatchSetDomainMutation();
|
||||
const [batchSetDataProductMutation] = useBatchSetDataProductMutation();
|
||||
const [batchSetApplicationMutation] = useBatchSetApplicationMutation();
|
||||
|
||||
// eslint-disable-next-line
|
||||
const batchAddGlossaryTerms = (entityUrns: Array<string>) => {
|
||||
@ -186,6 +193,40 @@ function EntityActions(props: Props) {
|
||||
});
|
||||
};
|
||||
|
||||
const batchSetApplication = (entityUrns: Array<string>) => {
|
||||
batchSetApplicationMutation({
|
||||
variables: {
|
||||
input: {
|
||||
applicationUrn: urn,
|
||||
resourceUrns: entityUrns,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(({ errors }) => {
|
||||
if (!errors) {
|
||||
setIsBatchSetApplicationModalVisible(false);
|
||||
message.loading({ content: 'Updating...', duration: 3 });
|
||||
setTimeout(() => {
|
||||
message.success({
|
||||
content: `Added assets to Application!`,
|
||||
duration: 3,
|
||||
});
|
||||
refetchForEntity?.();
|
||||
setShouldRefetchEmbeddedListSearch?.(true);
|
||||
}, 3000);
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
message.destroy();
|
||||
message.error(
|
||||
handleBatchError(entityUrns, e, {
|
||||
content: `Failed to add assets to Application. An unknown error occurred.`,
|
||||
duration: 3,
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const { entityData } = useEntityData();
|
||||
const canCreateGlossaryEntity = !!entityData?.privileges?.canManageChildren;
|
||||
|
||||
@ -245,6 +286,13 @@ function EntityActions(props: Props) {
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{actionItems.has(EntityActionItem.BATCH_ADD_APPLICATION) && (
|
||||
<Tooltip title="Add Assets to Application" showArrow={false} placement="bottom">
|
||||
<Button variant="outline" onClick={() => setIsBatchSetApplicationModalVisible(true)}>
|
||||
<LinkOutlined /> Add to Assets
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</ButtonWrapper>
|
||||
{isBatchAddGlossaryTermModalVisible && (
|
||||
<SearchSelectModal
|
||||
@ -268,6 +316,17 @@ function EntityActions(props: Props) {
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isBatchSetApplicationModalVisible && (
|
||||
<SearchSelectModal
|
||||
titleText="Add assets to Application"
|
||||
continueText="Add"
|
||||
onContinue={batchSetApplication}
|
||||
onCancel={() => setIsBatchSetApplicationModalVisible(false)}
|
||||
fixedEntityTypes={Array.from(
|
||||
entityRegistry.getTypesWithSupportedCapabilities(EntityCapabilityType.APPLICATIONS),
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isBatchSetDataProductModalVisible && (
|
||||
<SearchSelectModal
|
||||
titleText="Add assets to Data Product"
|
||||
|
||||
36
datahub-web-react/src/app/shared/tags/ApplicationLink.tsx
Normal file
36
datahub-web-react/src/app/shared/tags/ApplicationLink.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import { Tag } from 'antd';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { useEntityRegistry } from '@app/useEntityRegistry';
|
||||
|
||||
import { Application } from '@types';
|
||||
|
||||
const StyledTag = styled(Tag)`
|
||||
&& {
|
||||
margin: 2px;
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
application: Application;
|
||||
closable?: boolean;
|
||||
onClose?: (e) => void;
|
||||
readOnly?: boolean;
|
||||
fontSize?: number;
|
||||
}
|
||||
|
||||
export const ApplicationLink = ({ application, closable, onClose, readOnly, fontSize }: Props) => {
|
||||
const entityRegistry = useEntityRegistry();
|
||||
const applicationPath = entityRegistry.getPathName(application.type);
|
||||
const applicationUrl = `/${applicationPath}/${encodeURIComponent(application.urn)}`;
|
||||
|
||||
return (
|
||||
<Link to={applicationUrl}>
|
||||
<StyledTag closable={!readOnly && closable} onClose={onClose} style={{ fontSize }}>
|
||||
{application.properties?.name || application.urn}
|
||||
</StyledTag>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@ -52,6 +52,9 @@ query appConfig {
|
||||
theme {
|
||||
themeId
|
||||
}
|
||||
application {
|
||||
showSidebarSectionWhenEmpty
|
||||
}
|
||||
}
|
||||
telemetryConfig {
|
||||
enableThirdPartyLogging
|
||||
|
||||
@ -49,6 +49,9 @@ query getChart($urn: String!) {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
deprecation {
|
||||
...deprecationFields
|
||||
|
||||
@ -448,7 +448,9 @@ fragment nonRecursiveDatasetFields on Dataset {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
...entityDataProduct
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
container {
|
||||
...entityContainer
|
||||
}
|
||||
@ -491,6 +493,9 @@ fragment nonRecursiveDataFlowFields on DataFlow {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
deprecation {
|
||||
...deprecationFields
|
||||
@ -517,6 +522,9 @@ fragment nonRecursiveDataJobFields on DataJob {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
deprecation {
|
||||
...deprecationFields
|
||||
@ -562,6 +570,9 @@ fragment dataJobFields on DataJob {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
deprecation {
|
||||
...deprecationFields
|
||||
@ -640,6 +651,9 @@ fragment dashboardFields on Dashboard {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
parentContainers {
|
||||
...parentContainersFields
|
||||
@ -736,6 +750,9 @@ fragment nonRecursiveMLFeature on MLFeature {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
tags {
|
||||
...globalTagsFields
|
||||
@ -887,6 +904,9 @@ fragment nonRecursiveMLFeatureTable on MLFeatureTable {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
tags {
|
||||
...globalTagsFields
|
||||
@ -1079,6 +1099,9 @@ fragment nonRecursiveMLModel on MLModel {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
tags {
|
||||
...globalTagsFields
|
||||
@ -1123,6 +1146,9 @@ fragment nonRecursiveMLModelGroupFields on MLModelGroup {
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
application {
|
||||
...entityApplication
|
||||
}
|
||||
...entityDataProduct
|
||||
tags {
|
||||
...globalTagsFields
|
||||
@ -1266,6 +1292,33 @@ fragment entityDomain on DomainAssociation {
|
||||
associatedUrn
|
||||
}
|
||||
|
||||
fragment entityApplication on ApplicationAssociation {
|
||||
application {
|
||||
urn
|
||||
type
|
||||
properties {
|
||||
name
|
||||
description
|
||||
externalUrl
|
||||
}
|
||||
ownership {
|
||||
...ownershipFields
|
||||
}
|
||||
tags {
|
||||
...globalTagsFields
|
||||
}
|
||||
glossaryTerms {
|
||||
...glossaryTerms
|
||||
}
|
||||
domain {
|
||||
...entityDomain
|
||||
}
|
||||
children: relationships(input: { types: ["AssociatedWith"], direction: INCOMING, start: 0, count: 0 }) {
|
||||
total
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment entityDataProduct on Entity {
|
||||
dataProduct: relationships(input: { types: ["DataProductContains"], direction: INCOMING, start: 0, count: 1 }) {
|
||||
relationships {
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package com.linkedin.metadata.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ApplicationConfig {
|
||||
/**
|
||||
* Whether to show the application sidebar section even when empty - will add noise to the UI for
|
||||
* teams that don't use applications.
|
||||
*/
|
||||
public boolean showSidebarSectionWhenEmpty;
|
||||
}
|
||||
@ -31,4 +31,6 @@ public class VisualConfiguration {
|
||||
|
||||
/** Boolean flag enabled shows the full title of an entity in lineage view by default */
|
||||
public boolean showFullTitleInLineage;
|
||||
|
||||
public ApplicationConfig application;
|
||||
}
|
||||
|
||||
@ -189,6 +189,8 @@ visualConfig:
|
||||
entityProfile:
|
||||
# we only support default tab for domains right now. In order to implement for other entities, update React code
|
||||
domainDefaultTab: ${DOMAIN_DEFAULT_TAB:} # set to DOCUMENTATION_TAB to show documentation tab first
|
||||
application:
|
||||
showSidebarSectionWhenEmpty: ${APPLICATION_SHOW_SIDEBAR_SECTION_WHEN_EMPTY:false}
|
||||
searchResult:
|
||||
enableNameHighlight: ${SEARCH_RESULT_NAME_HIGHLIGHT_ENABLED:true} # Enables visual highlighting on search result names/descriptions.
|
||||
|
||||
|
||||
@ -1,9 +1,26 @@
|
||||
import { aliasQuery, hasOperationName } from "../utils";
|
||||
|
||||
describe("applications", () => {
|
||||
beforeEach(() => {
|
||||
cy.setIsThemeV2Enabled(true);
|
||||
Cypress.on("uncaught:exception", (err, runnable) => false);
|
||||
cy.intercept("POST", "/api/v2/graphql", (req) => {
|
||||
aliasQuery(req, "appConfig");
|
||||
});
|
||||
});
|
||||
|
||||
const setApplicationFeatureFlag = (isOn) => {
|
||||
cy.intercept("POST", "/api/v2/graphql", (req) => {
|
||||
if (hasOperationName(req, "appConfig")) {
|
||||
req.alias = "gqlappConfigQuery";
|
||||
req.on("response", (res) => {
|
||||
res.body.data.appConfig.visualConfig.application.showSidebarSectionWhenEmpty =
|
||||
isOn;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
it("can see elements inside the application", () => {
|
||||
cy.login();
|
||||
cy.goToApplication(
|
||||
@ -12,4 +29,61 @@ describe("applications", () => {
|
||||
cy.contains("cypress_logging_events");
|
||||
cy.contains("1 - 1 of 1");
|
||||
});
|
||||
|
||||
it("can see application sidebar section always when filled", () => {
|
||||
cy.login();
|
||||
setApplicationFeatureFlag(false);
|
||||
cy.goToDataset(
|
||||
"urn:li:dataset:(urn:li:dataPlatform:hive,cypress_logging_events,PROD)",
|
||||
"cypress_logging_events",
|
||||
);
|
||||
|
||||
cy.contains("Cypress Accounts Application");
|
||||
});
|
||||
|
||||
it("can see application sidebar section when empty if feature flag is on", () => {
|
||||
cy.login();
|
||||
setApplicationFeatureFlag(true);
|
||||
cy.goToDataset(
|
||||
"urn:li:dataset:(urn:li:dataPlatform:bigquery,cypress_project.jaffle_shop.customers,PROD)",
|
||||
"customers",
|
||||
);
|
||||
|
||||
cy.contains("No application yet");
|
||||
});
|
||||
|
||||
it("cannot see application sidebar section when empty if feature flag is off", () => {
|
||||
cy.login();
|
||||
setApplicationFeatureFlag(false);
|
||||
cy.goToDataset(
|
||||
"urn:li:dataset:(urn:li:dataPlatform:bigquery,cypress_project.jaffle_shop.customers,PROD)",
|
||||
"customers",
|
||||
);
|
||||
|
||||
cy.ensureTextNotPresent("No application yet");
|
||||
});
|
||||
|
||||
it("can add and remove application to dataset", () => {
|
||||
cy.login();
|
||||
setApplicationFeatureFlag(true);
|
||||
cy.goToDataset(
|
||||
"urn:li:dataset:(urn:li:dataPlatform:bigquery,cypress_project.jaffle_shop.customers,PROD)",
|
||||
"customers",
|
||||
);
|
||||
cy.clickOptionWithTestId("add-applications-button");
|
||||
cy.contains("Select an application").click({ force: true });
|
||||
cy.focused().type("Cypress Accounts Application");
|
||||
cy.get(".ant-select-item").contains("Cypress Accounts Application").click();
|
||||
cy.clickOptionWithText("OK");
|
||||
cy.waitTextVisible("Application set");
|
||||
cy.contains("Cypress Accounts Application");
|
||||
|
||||
cy.removeApplicationFromDataset(
|
||||
"urn:li:dataset:(urn:li:dataPlatform:bigquery,cypress_project.jaffle_shop.customers,PROD)",
|
||||
"customers",
|
||||
"urn:li:application:d63587c6-cacc-4590-851c-4f51ca429b51/Assets",
|
||||
);
|
||||
|
||||
cy.ensureTextNotPresent("Cypress Accounts Application");
|
||||
});
|
||||
});
|
||||
|
||||
@ -440,6 +440,15 @@ Cypress.Commands.add(
|
||||
},
|
||||
);
|
||||
|
||||
Cypress.Commands.add(
|
||||
"removeApplicationFromDataset",
|
||||
(urn, dataset_name, application_urn) => {
|
||||
cy.goToDataset(urn, dataset_name);
|
||||
cy.get(`.sidebar-application-section .anticon-close`).click();
|
||||
cy.clickOptionWithText("Yes");
|
||||
},
|
||||
);
|
||||
|
||||
Cypress.Commands.add("openEntityTab", (tab) => {
|
||||
const selector = `div[id$="${tab}"]:nth-child(1)`;
|
||||
cy.get(selector).click();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user