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(react): link glossary term to dataset page #2549

Merged
merged 2 commits into from
May 18, 2021
Merged
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 @@ -12,6 +12,7 @@
import com.linkedin.datahub.graphql.types.common.mappers.StatusMapper;
import com.linkedin.datahub.graphql.types.common.mappers.StringMapMapper;
import com.linkedin.datahub.graphql.types.tag.mappers.GlobalTagsMapper;
import com.linkedin.datahub.graphql.types.glossary.mappers.GlossaryTermsMapper;
import com.linkedin.datahub.graphql.types.mappers.ModelMapper;

/**
Expand Down Expand Up @@ -74,6 +75,9 @@ public Dataset apply(@Nonnull final com.linkedin.dataset.Dataset dataset) {
if (dataset.hasGlobalTags()) {
result.setGlobalTags(GlobalTagsMapper.map(dataset.getGlobalTags()));
}
if (dataset.hasGlossaryTerms()) {
result.setGlossaryTerms(GlossaryTermsMapper.map(dataset.getGlossaryTerms()));
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.linkedin.datahub.graphql.generated.SchemaField;
import com.linkedin.datahub.graphql.generated.SchemaFieldDataType;
import com.linkedin.datahub.graphql.types.tag.mappers.GlobalTagsMapper;
import com.linkedin.datahub.graphql.types.glossary.mappers.GlossaryTermsMapper;
import com.linkedin.datahub.graphql.types.mappers.ModelMapper;

import javax.annotation.Nonnull;
Expand All @@ -28,6 +29,9 @@ public SchemaField apply(@Nonnull final com.linkedin.schema.SchemaField input) {
if (input.hasGlobalTags()) {
result.setGlobalTags(GlobalTagsMapper.map(input.getGlobalTags()));
}
if (input.hasGlossaryTerms()) {
result.setGlossaryTerms(GlossaryTermsMapper.map(input.getGlossaryTerms()));
}
return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.linkedin.datahub.graphql.types.glossary.mappers;

import javax.annotation.Nonnull;
import java.util.stream.Collectors;

import com.linkedin.datahub.graphql.generated.GlossaryTerms;
import com.linkedin.common.GlossaryTermAssociation;
import com.linkedin.datahub.graphql.generated.GlossaryTerm;
import com.linkedin.datahub.graphql.types.mappers.ModelMapper;
import com.linkedin.datahub.graphql.types.glossary.GlossaryTermUtils;

/**
* Maps Pegasus {@link RecordTemplate} objects to objects conforming to the GQL schema.
*
* To be replaced by auto-generated mappers implementations
*/
public class GlossaryTermsMapper implements ModelMapper<com.linkedin.common.GlossaryTerms, GlossaryTerms> {

public static final GlossaryTermsMapper INSTANCE = new GlossaryTermsMapper();

public static GlossaryTerms map(@Nonnull final com.linkedin.common.GlossaryTerms glossaryTerms) {
return INSTANCE.apply(glossaryTerms);
}

@Override
public GlossaryTerms apply(@Nonnull final com.linkedin.common.GlossaryTerms glossaryTerms) {
com.linkedin.datahub.graphql.generated.GlossaryTerms result = new com.linkedin.datahub.graphql.generated.GlossaryTerms();
result.setTerms(glossaryTerms.getTerms().stream().map(this::mapGlossaryTermAssociation).collect(Collectors.toList()));
return result;
}

private com.linkedin.datahub.graphql.generated.GlossaryTermAssociation mapGlossaryTermAssociation(@Nonnull final GlossaryTermAssociation input) {
final com.linkedin.datahub.graphql.generated.GlossaryTermAssociation result = new com.linkedin.datahub.graphql.generated.GlossaryTermAssociation();
final GlossaryTerm resultGlossaryTerm = new GlossaryTerm();
resultGlossaryTerm.setUrn(input.getUrn().toString());
resultGlossaryTerm.setName(GlossaryTermUtils.getGlossaryTermName(input.getUrn().getNameEntity()));
result.setTerm(resultGlossaryTerm);
return result;
}

}
17 changes: 17 additions & 0 deletions datahub-graphql-core/src/main/resources/gms.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ type Dataset implements EntityWithRelationships & Entity {
The structured tags associated with the dataset
"""
globalTags: GlobalTags

"""
The structured glossary terms associated with the dataset
"""
glossaryTerms: GlossaryTerms
}

type GlossaryTerm implements Entity {
Expand Down Expand Up @@ -604,6 +609,10 @@ type SchemaField {
Tags associated with the field
"""
globalTags: GlobalTags
"""
Glossary terms associated with the field
"""
glossaryTerms: GlossaryTerms
}

type EditableSchemaMetadata {
Expand Down Expand Up @@ -1038,6 +1047,14 @@ type GlobalTags {
tags: [TagAssociation!]
}

type GlossaryTerms {
terms: [GlossaryTermAssociation!]
}

type GlossaryTermAssociation {
term: GlossaryTerm!
}

input SearchInput {
"""
Entity type to be searched
Expand Down
15 changes: 15 additions & 0 deletions datahub-web-react/src/Mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,21 @@ export const dataset3 = {
},
],
},
glossaryTerms: {
terms: [
{
term: {
type: EntityType.GlossaryTerm,
urn: 'urn:li:glossaryTerm:sample-glossary-term',
name: 'sample-glossary-term',
glossaryTermInfo: {
definition: 'sample definition',
termSource: 'sample term source',
},
},
},
],
},
upstreamLineage: null,
downstreamLineage: null,
institutionalMemory: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { GetChartDocument, useGetChartQuery, useUpdateChartMutation } from '../.
import ChartSources from './ChartSources';
import ChartDashboards from './ChartDashboards';
import { Message } from '../../../shared/Message';
import TagGroup from '../../../shared/tags/TagGroup';
import TagTermGroup from '../../../shared/tags/TagTermGroup';
import { Properties as PropertiesView } from '../../shared/Properties';
import analytics, { EventType, EntityActionType } from '../../../analytics';

Expand Down Expand Up @@ -99,7 +99,7 @@ export default function ChartProfile({ urn }: { urn: string }) {
{data && data.chart && (
<EntityProfile
tags={
<TagGroup
<TagTermGroup
editableTags={data.chart?.globalTags as GlobalTags}
canAdd
canRemove
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { EntityProfile } from '../../../shared/EntityProfile';
import DashboardHeader from './DashboardHeader';
import DashboardCharts from './DashboardCharts';
import { Message } from '../../../shared/Message';
import TagGroup from '../../../shared/tags/TagGroup';
import TagTermGroup from '../../../shared/tags/TagTermGroup';
import { Properties as PropertiesView } from '../../shared/Properties';
import analytics, { EventType, EntityActionType } from '../../../analytics';

Expand Down Expand Up @@ -98,7 +98,7 @@ export default function DashboardProfile({ urn }: { urn: string }) {
<EntityProfile
title={data.dashboard.info?.name || ''}
tags={
<TagGroup
<TagTermGroup
editableTags={data.dashboard?.globalTags as GlobalTags}
canAdd
canRemove
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { EntityProfile } from '../../../shared/EntityProfile';
import { DataFlow, EntityType, GlobalTags } from '../../../../types.generated';
import DataFlowHeader from './DataFlowHeader';
import { Message } from '../../../shared/Message';
import TagGroup from '../../../shared/tags/TagGroup';
import TagTermGroup from '../../../shared/tags/TagTermGroup';
import { Properties as PropertiesView } from '../../shared/Properties';
import { Ownership as OwnershipView } from '../../shared/Ownership';
import { useEntityRegistry } from '../../../useEntityRegistry';
Expand Down Expand Up @@ -85,7 +85,7 @@ export const DataFlowProfile = ({ urn }: { urn: string }): JSX.Element => {
{data && data.dataFlow && (
<EntityProfile
tags={
<TagGroup
<TagTermGroup
editableTags={data.dataFlow?.globalTags as GlobalTags}
canAdd
canRemove
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { EntityProfile } from '../../../shared/EntityProfile';
import { DataJob, EntityType, GlobalTags } from '../../../../types.generated';
import DataJobHeader from './DataJobHeader';
import { Message } from '../../../shared/Message';
import TagGroup from '../../../shared/tags/TagGroup';
import TagTermGroup from '../../../shared/tags/TagTermGroup';
import { Properties as PropertiesView } from '../../shared/Properties';
import { Ownership as OwnershipView } from '../../shared/Ownership';
import { useEntityRegistry } from '../../../useEntityRegistry';
Expand Down Expand Up @@ -85,7 +85,7 @@ export const DataJobProfile = ({ urn }: { urn: string }): JSX.Element => {
{data && data.dataJob && (
<EntityProfile
tags={
<TagGroup
<TagTermGroup
editableTags={data.dataJob?.globalTags as GlobalTags}
canAdd
canRemove
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import {
import { Ownership as OwnershipView } from '../../shared/Ownership';
import SchemaView from './schema/Schema';
import { EntityProfile } from '../../../shared/EntityProfile';
import { Dataset, EntityType, GlobalTags } from '../../../../types.generated';
import { Dataset, EntityType, GlobalTags, GlossaryTerms } from '../../../../types.generated';
import LineageView from './Lineage';
import { Properties as PropertiesView } from '../../shared/Properties';
import DocumentsView from './Documentation';
import DatasetHeader from './DatasetHeader';
import { Message } from '../../../shared/Message';
import TagGroup from '../../../shared/tags/TagGroup';
import TagTermGroup from '../../../shared/tags/TagTermGroup';
import useIsLineageMode from '../../../lineage/utils/useIsLineageMode';
import { useEntityRegistry } from '../../../useEntityRegistry';
import { useGetAuthenticatedUser } from '../../../useGetAuthenticatedUser';
Expand Down Expand Up @@ -151,8 +151,9 @@ export const DatasetProfile = ({ urn }: { urn: string }): JSX.Element => {
)}/${urn}?is_lineage_mode=${isLineageMode}`}
title={data.dataset.name}
tags={
<TagGroup
<TagTermGroup
editableTags={data.dataset?.globalTags as GlobalTags}
glossaryTerms={data.dataset?.glossaryTerms as GlossaryTerms}
canAdd
canRemove
updateTags={(globalTags) => {
Expand All @@ -166,6 +167,7 @@ export const DatasetProfile = ({ urn }: { urn: string }): JSX.Element => {
}}
/>
}
tagCardHeader={data.dataset?.glossaryTerms ? 'Tags & Terms' : 'Tags'}
tabs={getTabs(data.dataset as Dataset)}
header={getHeader(data.dataset as Dataset)}
onTabChange={(tab: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,25 @@ describe('DatasetProfile', () => {
'http://localhost/tag/urn:li:tag:abc-sample-tag',
);
});

it('renders business terms', async () => {
const { queryByText } = render(
<MockedProvider
mocks={mocks}
addTypename={false}
defaultOptions={{
watchQuery: { fetchPolicy: 'no-cache' },
query: { fetchPolicy: 'no-cache' },
}}
>
<TestPageContainer initialEntries={['/dataset/urn:li:dataset:3']}>
<DatasetProfile urn="urn:li:dataset:3" />
</TestPageContainer>
</MockedProvider>,
);

await waitFor(() => expect(queryByText('sample-glossary-term')).toBeInTheDocument());

expect(queryByText('Tags & Terms')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ describe('Schema', () => {
expect(queryAllByTestId('schema-raw-view')).toHaveLength(0);
});

it('renders tags', () => {
it('renders tags and terms', () => {
const { getByText } = render(
<TestPageContainer>
<Schema schema={sampleSchemaWithTags} updateEditableSchema={jest.fn()} />
</TestPageContainer>,
);
expect(getByText('Legacy')).toBeInTheDocument();
expect(getByText('sample-glossary-term')).toBeInTheDocument();
});

it('renders description', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import {
EditableSchemaFieldInfo,
EditableSchemaFieldInfoUpdate,
EntityType,
GlossaryTerms,
} from '../../../../../types.generated';
import TagGroup from '../../../../shared/tags/TagGroup';
import TagTermGroup from '../../../../shared/tags/TagTermGroup';
import { UpdateDatasetMutation } from '../../../../../graphql/dataset.generated';
import { convertTagsForUpdate } from '../../../../shared/tags/utils/convertTagsForUpdate';
import DescriptionField from './SchemaDescriptionField';
Expand Down Expand Up @@ -208,14 +209,15 @@ export default function SchemaView({ urn, schema, editableSchemaMetadata, update
);
};

const tagGroupRender = (tags: GlobalTags, record: SchemaField, rowIndex: number | undefined) => {
const tagAndTermRender = (tags: GlobalTags, record: SchemaField, rowIndex: number | undefined) => {
const relevantEditableFieldInfo = editableSchemaMetadata?.editableSchemaFieldInfo.find(
(candidateEditableFieldInfo) => candidateEditableFieldInfo.fieldPath === record.fieldPath,
);
return (
<TagGroup
<TagTermGroup
uneditableTags={tags}
editableTags={relevantEditableFieldInfo?.globalTags}
glossaryTerms={record.glossaryTerms as GlossaryTerms}
canRemove
canAdd={tagHoveredIndex === `${record.fieldPath}-${rowIndex}`}
onOpenModal={() => setTagHoveredIndex(undefined)}
Expand All @@ -242,12 +244,12 @@ export default function SchemaView({ urn, schema, editableSchemaMetadata, update
}),
};

const tagColumn = {
const tagAndTermColumn = {
width: 400,
title: 'Tags',
title: 'Tags & Terms',
dataIndex: 'globalTags',
key: 'tag',
render: tagGroupRender,
render: tagAndTermRender,
onCell: (record: SchemaField, rowIndex: number | undefined) => ({
onMouseEnter: () => {
setTagHoveredIndex(`${record.fieldPath}-${rowIndex}`);
Expand Down Expand Up @@ -277,7 +279,7 @@ export default function SchemaView({ urn, schema, editableSchemaMetadata, update
) : (
rows.length > 0 && (
<Table
columns={[...defaultColumns, descriptionColumn, tagColumn]}
columns={[...defaultColumns, descriptionColumn, tagAndTermColumn]}
dataSource={rows}
rowKey="fieldPath"
expandable={{ defaultExpandAllRows: true, expandRowByClick: true }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ export const sampleSchemaWithTags: Schema = {
},
],
},
glossaryTerms: {
terms: [
{
term: {
type: EntityType.GlossaryTerm,
urn: 'urn:li:glossaryTerm:sample-glossary-term',
name: 'sample-glossary-term',
glossaryTermInfo: {
definition: 'sample definition',
termSource: 'sample term source',
},
},
},
],
},
},
{
fieldPath: 'name',
Expand Down
4 changes: 2 additions & 2 deletions datahub-web-react/src/app/preview/DefaultPreviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import styled from 'styled-components';
import { GlobalTags, Owner } from '../../types.generated';
import { useEntityRegistry } from '../useEntityRegistry';
import AvatarsGroup from '../shared/avatar/AvatarsGroup';
import TagGroup from '../shared/tags/TagGroup';
import TagTermGroup from '../shared/tags/TagTermGroup';

interface Props {
name: string;
Expand Down Expand Up @@ -94,7 +94,7 @@ export default function DefaultPreviewCard({
<Typography.Text strong>{owners && owners.length > 0 ? 'Owned By' : ''}</Typography.Text>
<AvatarsGroup owners={owners} entityRegistry={entityRegistry} maxCount={4} />
</Space>
<TagGroup editableTags={tags} maxShow={3} />
<TagTermGroup editableTags={tags} maxShow={3} />
</Space>
</Row>
);
Expand Down
Loading