Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(ui): Adding incidents to ML Model + ML Feature Entities #11684

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3137,7 +3137,8 @@ private void configureIncidentResolvers(final RuntimeWiring.Builder builder) {

// Add incidents attribute to all entities that support it
final List<String> entitiesWithIncidents =
ImmutableList.of("Dataset", "DataJob", "DataFlow", "Dashboard", "Chart");
ImmutableList.of(
"Dataset", "DataJob", "DataFlow", "Dashboard", "Chart", "MLModel", "MLFeature");
for (String entity : entitiesWithIncidents) {
builder.type(
entity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ private EntityType mapResourceTypeToEntityType(final String resourceType) {
.getResourceType()
.equals(resourceType)) {
return EntityType.BUSINESS_ATTRIBUTE;
} else if (com.linkedin.metadata.authorization.PoliciesConfig.ML_MODEL_PRIVILEGES
.getResourceType()
.equals(resourceType)) {
return EntityType.MLMODEL;
} else if (com.linkedin.metadata.authorization.PoliciesConfig.ML_FEATURE_PRIVILEGES
.getResourceType()
.equals(resourceType)) {
return EntityType.MLFEATURE;
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.linkedin.datahub.graphql.concurrency.GraphQLConcurrencyUtils;
import com.linkedin.datahub.graphql.generated.Entity;
import com.linkedin.datahub.graphql.generated.EntityPrivileges;
import com.linkedin.datahub.graphql.resolvers.incident.IncidentUtils;
import com.linkedin.datahub.graphql.resolvers.mutate.util.EmbedUtils;
import com.linkedin.datahub.graphql.resolvers.mutate.util.GlossaryUtils;
import com.linkedin.entity.client.EntityClient;
Expand Down Expand Up @@ -141,5 +142,6 @@ private void addCommonPrivileges(
@Nonnull EntityPrivileges result, @Nonnull Urn urn, @Nonnull QueryContext context) {
result.setCanEditLineage(canEditEntityLineage(urn, context));
result.setCanEditProperties(AuthorizationUtils.canEditProperties(urn, context));
result.setCanEditIncidents(IncidentUtils.isAuthorizedToEditIncidentForResource(urn, context));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.linkedin.datahub.graphql.resolvers.incident;

import com.datahub.authorization.ConjunctivePrivilegeGroup;
import com.datahub.authorization.DisjunctivePrivilegeGroup;
import com.google.common.collect.ImmutableList;
import com.linkedin.common.urn.Urn;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.metadata.authorization.PoliciesConfig;

public class IncidentUtils {
public static boolean isAuthorizedToEditIncidentForResource(
final Urn resourceUrn, final QueryContext context) {
final DisjunctivePrivilegeGroup orPrivilegeGroups =
new DisjunctivePrivilegeGroup(
ImmutableList.of(
AuthorizationUtils.ALL_PRIVILEGES_GROUP,
new ConjunctivePrivilegeGroup(
ImmutableList.of(PoliciesConfig.EDIT_ENTITY_INCIDENTS_PRIVILEGE.getType()))));

return AuthorizationUtils.isAuthorized(
context, resourceUrn.getEntityType(), resourceUrn.toString(), orPrivilegeGroups);
}

private IncidentUtils() {}
}
5 changes: 5 additions & 0 deletions datahub-graphql-core/src/main/resources/auth.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ type EntityPrivileges {
Whether or not a user can update the properties for the entity (e.g. dataset)
"""
canEditProperties: Boolean

"""
Whether or not a user can update incidents for the entity
"""
canEditIncidents: Boolean
}

"""
Expand Down
38 changes: 38 additions & 0 deletions datahub-graphql-core/src/main/resources/incident.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,42 @@ extend type Chart {
Optional start offset, defaults to 20.
"""
count: Int): EntityIncidentsResult
}

extend type MLModel {
"""
Incidents associated with the ML Model
"""
incidents(
"""
Optional incident state to filter by, defaults to any state.
"""
state: IncidentState,
"""
Optional start offset, defaults to 0.
"""
start: Int,
"""
Optional start offset, defaults to 20.
"""
count: Int): EntityIncidentsResult
}

extend type MLFeature {
"""
Incidents associated with the ML Feature
"""
incidents(
"""
Optional incident state to filter by, defaults to any state.
"""
state: IncidentState,
"""
Optional start offset, defaults to 0.
"""
start: Int,
"""
Optional start offset, defaults to 20.
"""
count: Int): EntityIncidentsResult
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { EntityMenuItems } from '../shared/EntityDropdown/EntityDropdown';
import DataProductSection from '../shared/containers/profile/sidebar/DataProduct/DataProductSection';
import { getDataProduct } from '../shared/utils';
import { PropertiesTab } from '../shared/tabs/Properties/PropertiesTab';
import { IncidentTab } from '../shared/tabs/Incident/IncidentTab';
import SidebarStructuredPropsSection from '../shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection';

/**
Expand Down Expand Up @@ -95,6 +96,14 @@ export class MLFeatureEntity implements Entity<MlFeature> {
name: 'Properties',
component: PropertiesTab,
},
{
name: 'Incidents',
component: IncidentTab,
getDynamicName: (_, mlFeature) => {
const activeIncidentCount = mlFeature?.mlFeature?.activeIncidents.total;
return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`;
},
},
]}
sidebarSections={this.getSidebarSections()}
/>
Expand Down
9 changes: 9 additions & 0 deletions datahub-web-react/src/app/entity/mlModel/MLModelEntity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { DocumentationTab } from '../shared/tabs/Documentation/DocumentationTab'
import MlModelFeaturesTab from './profile/MlModelFeaturesTab';
import { EntityMenuItems } from '../shared/EntityDropdown/EntityDropdown';
import DataProductSection from '../shared/containers/profile/sidebar/DataProduct/DataProductSection';
import { IncidentTab } from '../shared/tabs/Incident/IncidentTab';
import SidebarStructuredPropsSection from '../shared/containers/profile/sidebar/StructuredProperties/SidebarStructuredPropsSection';

/**
Expand Down Expand Up @@ -126,6 +127,14 @@ export class MLModelEntity implements Entity<MlModel> {
name: 'Properties',
component: PropertiesTab,
},
{
name: 'Incidents',
component: IncidentTab,
getDynamicName: (_, mlModel) => {
const activeIncidentCount = mlModel?.mlModel?.activeIncidents.total;
return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`;
},
},
]}
sidebarSections={this.getSidebarSections()}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { Button, Empty, List, Select, Typography } from 'antd';
import { Button, Empty, List, Select, Tooltip, Typography } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import { useGetEntityIncidentsQuery } from '../../../../../graphql/incident.generated';
import TabToolbar from '../../components/styled/TabToolbar';
Expand Down Expand Up @@ -78,18 +78,30 @@ export const IncidentTab = () => {
title: incident?.title,
}));

const canEditIncidents = (data?.entity as any)?.privileges?.canEditIncidents || false;

return (
<>
<Header>
<TabToolbar>
<Button icon={<PlusOutlined />} onClick={() => setIsRaiseIncidentModalVisible(true)} type="text">
Raise Incident
</Button>
<AddIncidentModal
refetch={refetch}
open={isRaiseIncidentModalVisible}
onClose={() => setIsRaiseIncidentModalVisible(false)}
/>
<Tooltip
showArrow={false}
title={!canEditIncidents && 'You do not have permission to create an incidents for this asset'}
>
<Button
icon={<PlusOutlined />}
onClick={() => canEditIncidents && setIsRaiseIncidentModalVisible(true)}
type="text"
disabled={!canEditIncidents}
>
Raise Incident
</Button>
<AddIncidentModal
refetch={refetch}
open={isRaiseIncidentModalVisible}
onClose={() => setIsRaiseIncidentModalVisible(false)}
/>
</Tooltip>
</TabToolbar>
<Summary>
<IncidentSummary summary={getIncidentsStatusSummary(allIncidents)} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const AddIncidentModal = ({ open, onClose, refetch }: AddIncidentProps) =
time: Date.now(),
actor: user?.urn,
},
tags: null,
};
message.success({ content: 'Incident Added', duration: 2 });
analytics.event({
Expand Down
1 change: 1 addition & 0 deletions datahub-web-react/src/graphql/fragments.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,7 @@ fragment entityPrivileges on EntityPrivileges {
canManageEntity
canManageChildren
canEditProperties
canEditIncidents
}

fragment businessAttribute on BusinessAttributeAssociation {
Expand Down
16 changes: 16 additions & 0 deletions datahub-web-react/src/graphql/incident.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,21 @@ query getEntityIncidents($urn: String!, $start: Int!, $count: Int!, $state: Inci
...incidentsFields
}
}
... on MLFeature {
incidents(start: $start, count: $count, state: $state) {
...incidentsFields
}
privileges {
canEditIncidents
}
}
... on MLModel {
incidents(start: $start, count: $count, state: $state) {
...incidentsFields
}
privileges {
canEditIncidents
}
}
}
}
3 changes: 3 additions & 0 deletions datahub-web-react/src/graphql/mlFeature.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ query getMLFeature($urn: String!) {
forms {
...formsFields
}
activeIncidents: incidents(start: 0, count: 1, state: ACTIVE) {
total
}
}
}
3 changes: 3 additions & 0 deletions datahub-web-react/src/graphql/mlModel.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ query getMLModel($urn: String!) {
forms {
...formsFields
}
activeIncidents: incidents(start: 0, count: 1, state: ACTIVE) {
total
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ record IncidentInfo {
@Relationship = {
"/*": {
"name": "IncidentOn",
"entityTypes": [ "dataset", "chart", "dashboard", "dataFlow", "dataJob", "schemaField" ]
"entityTypes": [ "dataset", "chart", "dashboard", "dataFlow", "dataJob", "schemaField", "mlModel", "mlFeature" ]
}
}
@Searchable = {
Expand Down
2 changes: 2 additions & 0 deletions metadata-models/src/main/resources/entity-registry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ entities:
- structuredProperties
- forms
- testResults
- incidentsSummary
- name: mlModelGroup
category: core
keyAspect: mlModelGroupKey
Expand Down Expand Up @@ -425,6 +426,7 @@ entities:
- structuredProperties
- forms
- testResults
- incidentsSummary
- name: mlPrimaryKey
category: core
keyAspect: mlPrimaryKeyKey
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,10 +733,25 @@ public class PoliciesConfig {
// ERModelRelationship Privileges
public static final ResourcePrivileges ER_MODEL_RELATIONSHIP_PRIVILEGES =
ResourcePrivileges.of(
"erModelRelationship",
"ERModelRelationship",
"update privileges for ermodelrelations",
"ER Model Relationships",
"",
"Privileges for ER Model Relationships",
COMMON_ENTITY_PRIVILEGES);

public static final ResourcePrivileges ML_FEATURE_PRIVILEGES =
ResourcePrivileges.of(
"mlFeature",
"ML Feature",
"ML Features ingested to DataHub.",
COMMON_ENTITY_PRIVILEGES);

public static final ResourcePrivileges ML_MODEL_PRIVILEGES =
ResourcePrivileges.of(
"mlModel",
"ML Model",
"ML Models ingested to DataHub.",
COMMON_ENTITY_PRIVILEGES);

public static final ResourcePrivileges BUSINESS_ATTRIBUTE_PRIVILEGES =
ResourcePrivileges.of(
"businessAttribute",
Expand Down Expand Up @@ -767,7 +782,9 @@ public class PoliciesConfig {
DATA_PRODUCT_PRIVILEGES,
ER_MODEL_RELATIONSHIP_PRIVILEGES,
BUSINESS_ATTRIBUTE_PRIVILEGES,
STRUCTURED_PROPERTIES_PRIVILEGES);
STRUCTURED_PROPERTIES_PRIVILEGES,
ML_FEATURE_PRIVILEGES,
ML_MODEL_PRIVILEGES);

// Merge all entity specific resource privileges to create a superset of all resource privileges
public static final ResourcePrivileges ALL_RESOURCE_PRIVILEGES =
Expand Down
Loading