Skip to content

Commit a24acb6

Browse files
authored
Merge branch 'datahub-project:master' into master
2 parents 39689a1 + 4e48e09 commit a24acb6

File tree

94 files changed

+2900
-391
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+2900
-391
lines changed

build.gradle

+3
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,11 @@ project.ext.externalDependency = [
226226
'opentelemetryApi': 'io.opentelemetry:opentelemetry-api:' + openTelemetryVersion,
227227
'opentelemetrySdk': 'io.opentelemetry:opentelemetry-sdk:' + openTelemetryVersion,
228228
'opentelemetrySdkTrace': 'io.opentelemetry:opentelemetry-sdk-trace:' + openTelemetryVersion,
229+
'opentelemetrySdkMetrics': 'io.opentelemetry:opentelemetry-sdk-metrics:' + openTelemetryVersion,
229230
'opentelemetryAutoConfig': 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:' + openTelemetryVersion,
230231
'opentelemetryExporter': 'io.opentelemetry:opentelemetry-exporter-otlp:' + openTelemetryVersion,
232+
'openTelemetryExporterLogging': 'io.opentelemetry:opentelemetry-exporter-logging:' + openTelemetryVersion,
233+
'openTelemetryExporterCommon': 'io.opentelemetry:opentelemetry-exporter-otlp-common:' + openTelemetryVersion,
231234
'opentelemetryAnnotations': 'io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:2.11.0',
232235
'opentracingJdbc':'io.opentracing.contrib:opentracing-jdbc:0.2.15',
233236
'parquet': 'org.apache.parquet:parquet-avro:1.15.1',

datahub-frontend/play.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ dependencies {
9595
compileOnly externalDependency.lombok
9696
runtimeOnly externalDependency.guicePlay
9797
runtimeOnly externalDependency.opentelemetryExporter
98+
runtimeOnly externalDependency.openTelemetryExporterLogging
99+
runtimeOnly externalDependency.openTelemetryExporterCommon
98100
runtimeOnly (externalDependency.playDocs) {
99101
exclude group: 'com.typesafe.akka', module: "akka-http-core_$playScalaVersion"
100102
}

datahub-upgrade/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ dependencies {
7272
implementation externalDependency.springCore
7373
implementation externalDependency.springKafka
7474
runtimeOnly externalDependency.opentelemetryExporter
75+
runtimeOnly externalDependency.openTelemetryExporterLogging
76+
runtimeOnly externalDependency.openTelemetryExporterCommon
7577

7678
runtimeOnly externalDependency.logbackClassic
7779
runtimeOnly externalDependency.mariadbConnector

datahub-web-react/src/app/entity/shared/components/styled/StructuredProperty/StructuredPropertyInput.tsx

+18-8
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
import React from 'react';
21
import { PropertyCardinality, StdDataType, StructuredPropertyEntity } from '@src/types.generated';
3-
import SingleSelectInput from './SingleSelectInput';
4-
import MultiSelectInput from './MultiSelectInput';
5-
import StringInput from './StringInput';
6-
import RichTextInput from './RichTextInput';
2+
import React from 'react';
3+
import StructuredPropertySearchSelectUrnInput from '../../../entityForm/prompts/StructuredPropertyPrompt/UrnInput/StructuredPropertySearchSelectUrnInput';
4+
import UrnInput from '../../../entityForm/prompts/StructuredPropertyPrompt/UrnInput/UrnInput';
75
import DateInput from './DateInput';
6+
import MultiSelectInput from './MultiSelectInput';
87
import NumberInput from './NumberInput';
9-
import UrnInput from '../../../entityForm/prompts/StructuredPropertyPrompt/UrnInput/UrnInput';
8+
import RichTextInput from './RichTextInput';
9+
import SingleSelectInput from './SingleSelectInput';
10+
import StringInput from './StringInput';
1011

1112
interface Props {
1213
structuredProperty: StructuredPropertyEntity;
1314
selectedValues: (string | number | null)[];
1415
selectSingleValue: (value: string | number) => void;
1516
toggleSelectedValue: (value: string | number) => void;
1617
updateSelectedValues: (value: (string | number | null)[]) => void;
18+
canUseSearchSelectUrnInput?: boolean;
1719
}
1820

1921
export default function StructuredPropertyInput({
@@ -22,6 +24,7 @@ export default function StructuredPropertyInput({
2224
selectedValues,
2325
toggleSelectedValue,
2426
updateSelectedValues,
27+
canUseSearchSelectUrnInput = false,
2528
}: Props) {
2629
const { allowedValues, cardinality, valueType } = structuredProperty.definition;
2730

@@ -66,10 +69,17 @@ export default function StructuredPropertyInput({
6669
updateSelectedValues={updateSelectedValues}
6770
/>
6871
)}
69-
{!allowedValues && valueType.info.type === StdDataType.Urn && (
72+
{!allowedValues && valueType.info.type === StdDataType.Urn && canUseSearchSelectUrnInput && (
73+
<StructuredPropertySearchSelectUrnInput
74+
structuredProperty={structuredProperty}
75+
selectedValues={selectedValues as string[]}
76+
updateSelectedValues={updateSelectedValues}
77+
/>
78+
)}
79+
{!allowedValues && valueType.info.type === StdDataType.Urn && !canUseSearchSelectUrnInput && (
7080
<UrnInput
7181
structuredProperty={structuredProperty}
72-
selectedValues={selectedValues}
82+
selectedValues={selectedValues as string[]}
7383
updateSelectedValues={updateSelectedValues}
7484
/>
7585
)}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { SearchSelectUrnInput } from '@src/app/entityV2/shared/components/styled/search/SearchSelectUrnInput';
2+
import React, { useMemo } from 'react';
3+
import { EntityType, PropertyCardinality, StructuredPropertyEntity } from '../../../../../../../types.generated';
4+
5+
interface StructuredPropertySearchSelectUrnInputProps {
6+
structuredProperty: StructuredPropertyEntity;
7+
selectedValues: string[];
8+
updateSelectedValues: (values: string[] | number[]) => void;
9+
}
10+
11+
// Wrapper component that extracts information from StructuredProperty
12+
export default function StructuredPropertySearchSelectUrnInput({
13+
structuredProperty,
14+
selectedValues,
15+
updateSelectedValues,
16+
}: StructuredPropertySearchSelectUrnInputProps) {
17+
// Get the allowed entity types from the structured property
18+
const allowedEntityTypes = useMemo(() => {
19+
return (
20+
structuredProperty.definition.typeQualifier?.allowedTypes?.map(
21+
(allowedType) => allowedType.info.type as EntityType,
22+
) || []
23+
);
24+
}, [structuredProperty]);
25+
26+
const isMultiple = structuredProperty.definition.cardinality === PropertyCardinality.Multiple;
27+
28+
return (
29+
<SearchSelectUrnInput
30+
allowedEntityTypes={allowedEntityTypes}
31+
isMultiple={isMultiple}
32+
selectedValues={selectedValues}
33+
updateSelectedValues={updateSelectedValues}
34+
/>
35+
);
36+
}

datahub-web-react/src/app/entity/shared/entityForm/prompts/StructuredPropertyPrompt/UrnInput/UrnInput.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { Select } from 'antd';
33
import React from 'react';
44
import styled from 'styled-components';
55
import { StructuredPropertyEntity } from '../../../../../../../types.generated';
6-
import useUrnInput from './useUrnInput';
76
import SelectedEntity from './SelectedEntity';
7+
import useUrnInput from './useUrnInput';
88

99
const EntitySelect = styled(Select)`
1010
width: 75%;

datahub-web-react/src/app/entity/shared/tabs/Properties/Edit/EditStructuredPropertyModal.tsx

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
import { Button } from '@src/alchemy-components';
12
import analytics, { EventType } from '@src/app/analytics';
3+
import { ModalButtonContainer } from '@src/app/shared/button/styledComponents';
24
import { Modal, message } from 'antd';
35
import React, { useEffect, useMemo } from 'react';
46
import styled from 'styled-components';
5-
import { Button } from '@src/alchemy-components';
6-
import { ModalButtonContainer } from '@src/app/shared/button/styledComponents';
77
import { useUpsertStructuredPropertiesMutation } from '../../../../../../graphql/structuredProperties.generated';
8-
import { EntityType, PropertyValueInput, StructuredPropertyEntity } from '../../../../../../types.generated';
8+
import {
9+
EntityType,
10+
PropertyValueInput,
11+
StdDataType,
12+
StructuredPropertyEntity,
13+
} from '../../../../../../types.generated';
914
import handleGraphQLError from '../../../../../shared/handleGraphQLError';
1015
import StructuredPropertyInput from '../../../components/styled/StructuredProperty/StructuredPropertyInput';
1116
import { useEditStructuredProperty } from '../../../components/styled/StructuredProperty/useEditStructuredProperty';
@@ -27,6 +32,9 @@ interface Props {
2732
isAddMode?: boolean;
2833
}
2934

35+
const SEARCH_SELECT_MODAL_WIDTH = 1400;
36+
const DEFAULT_MODAL_WIDTH = 650;
37+
3038
export default function EditStructuredPropertyModal({
3139
isOpen,
3240
structuredProperty,
@@ -44,6 +52,7 @@ export default function EditStructuredPropertyModal({
4452
const { selectedValues, selectSingleValue, toggleSelectedValue, updateSelectedValues, setSelectedValues } =
4553
useEditStructuredProperty(initialValues);
4654
const [upsertStructuredProperties] = useUpsertStructuredPropertiesMutation();
55+
const { allowedValues } = structuredProperty.definition;
4756

4857
useEffect(() => {
4958
setSelectedValues(initialValues);
@@ -99,12 +108,15 @@ export default function EditStructuredPropertyModal({
99108
});
100109
}
101110

111+
const isUrnInput = structuredProperty.definition.valueType.info.type === StdDataType.Urn && !allowedValues;
112+
102113
return (
103114
<Modal
104115
title={`${isAddMode ? 'Add property' : 'Edit property'} ${structuredProperty?.definition?.displayName}`}
105116
onCancel={closeModal}
106117
open={isOpen}
107-
width={650}
118+
// Urn input is a special case that requires a wider modal since it employs a search select component
119+
width={isUrnInput ? SEARCH_SELECT_MODAL_WIDTH : DEFAULT_MODAL_WIDTH}
108120
footer={
109121
<ModalButtonContainer>
110122
<Button variant="text" onClick={closeModal} color="gray">
@@ -125,6 +137,7 @@ export default function EditStructuredPropertyModal({
125137
<Description>{structuredProperty.definition.description}</Description>
126138
)}
127139
<StructuredPropertyInput
140+
canUseSearchSelectUrnInput
128141
structuredProperty={structuredProperty}
129142
selectedValues={selectedValues}
130143
selectSingleValue={selectSingleValue}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import { Icon } from '@src/alchemy-components';
2+
import { EntityAndType } from '@src/app/entity/shared/types';
3+
import { extractTypeFromUrn } from '@src/app/entity/shared/utils';
4+
import { SearchSelect } from '@src/app/entityV2/shared/components/styled/search/SearchSelect';
5+
import { useHydratedEntityMap } from '@src/app/entityV2/shared/tabs/Properties/useHydratedEntityMap';
6+
import { EntityLink } from '@src/app/homeV2/reference/sections/EntityLink';
7+
import { EntityType } from '@src/types.generated';
8+
import { Skeleton } from 'antd';
9+
import React, { useEffect, useMemo, useState } from 'react';
10+
import styled from 'styled-components';
11+
12+
const Container = styled.div`
13+
display: flex;
14+
width: 100%;
15+
min-height: 500px;
16+
height: 70vh;
17+
border: 1px solid #f0f0f0;
18+
border-radius: 4px;
19+
`;
20+
21+
const SearchSection = styled.div`
22+
flex: 2;
23+
height: 100%;
24+
overflow: hidden;
25+
display: flex;
26+
flex-direction: column;
27+
`;
28+
29+
const SubSearchSection = styled.div`
30+
flex: 1;
31+
height: 100%;
32+
overflow: hidden;
33+
display: flex;
34+
flex-direction: column;
35+
`;
36+
37+
const CurrentSection = styled.div`
38+
flex: 1;
39+
width: 40%;
40+
border-left: 1px solid #f0f0f0;
41+
display: flex;
42+
flex-direction: column;
43+
`;
44+
45+
const SectionHeader = styled.div`
46+
padding-left: 20px;
47+
margin-top: 10px;
48+
font-size: 16px;
49+
font-weight: 500;
50+
color: #666;
51+
`;
52+
53+
const ScrollableContent = styled.div`
54+
flex: 1;
55+
overflow: auto;
56+
padding: 20px;
57+
`;
58+
59+
const SelectedItem = styled.div`
60+
display: flex;
61+
padding: 8px;
62+
border-radius: 4px;
63+
margin-bottom: 8px;
64+
align-items: center;
65+
border: 1px solid #f0f0f0;
66+
justify-content: space-between;
67+
68+
&:hover {
69+
background-color: #fafafa;
70+
}
71+
`;
72+
73+
const IconWrapper = styled.div`
74+
cursor: pointer;
75+
`;
76+
77+
const INITIAL_SELECTED_ENTITIES = [] as EntityAndType[];
78+
79+
// New interface for the generic component
80+
interface SearchSelectUrnInputProps {
81+
allowedEntityTypes: EntityType[];
82+
isMultiple: boolean;
83+
selectedValues: string[];
84+
updateSelectedValues: (values: string[] | number[]) => void;
85+
}
86+
87+
// Generic component that doesn't depend on StructuredProperty
88+
export function SearchSelectUrnInput({
89+
allowedEntityTypes,
90+
isMultiple,
91+
selectedValues,
92+
updateSelectedValues,
93+
}: SearchSelectUrnInputProps) {
94+
const [tempSelectedEntities, setTempSelectedEntities] = useState<EntityAndType[]>(INITIAL_SELECTED_ENTITIES);
95+
96+
// Convert the selected values (urns) to EntityAndType format for SearchSelect
97+
const selectedEntities = useMemo(
98+
() => selectedValues.map((urn) => ({ urn, type: extractTypeFromUrn(urn) })),
99+
[selectedValues],
100+
);
101+
102+
// only run this once
103+
useEffect(() => {
104+
if (tempSelectedEntities === INITIAL_SELECTED_ENTITIES) {
105+
setTempSelectedEntities(selectedEntities);
106+
}
107+
}, [selectedEntities, setTempSelectedEntities, tempSelectedEntities]);
108+
109+
// call updateSelectedValues when tempSelectedEntities changes
110+
useEffect(() => {
111+
if (tempSelectedEntities !== INITIAL_SELECTED_ENTITIES) {
112+
updateSelectedValues(tempSelectedEntities.map((entity) => entity.urn));
113+
}
114+
// this is excluded from the dependency array because updateSelectedValues is reconstructed
115+
// by the parent component on every render
116+
// eslint-disable-next-line react-hooks/exhaustive-deps
117+
}, [tempSelectedEntities]);
118+
119+
const removeEntity = (entity: EntityAndType) => {
120+
setTempSelectedEntities(tempSelectedEntities.filter((e) => e.urn !== entity.urn));
121+
};
122+
123+
const hydratedEntityMap = useHydratedEntityMap(tempSelectedEntities.map((entity) => entity.urn));
124+
125+
return (
126+
<Container>
127+
<SearchSection>
128+
<SectionHeader>Search Values</SectionHeader>
129+
<SubSearchSection>
130+
<SearchSelect
131+
fixedEntityTypes={allowedEntityTypes}
132+
selectedEntities={tempSelectedEntities}
133+
setSelectedEntities={setTempSelectedEntities}
134+
limit={isMultiple ? undefined : 1}
135+
/>
136+
</SubSearchSection>
137+
</SearchSection>
138+
<CurrentSection>
139+
<SectionHeader>Selected Values</SectionHeader>
140+
<ScrollableContent>
141+
{tempSelectedEntities.length === 0 ? (
142+
<div>No values selected</div>
143+
) : (
144+
tempSelectedEntities.map((entity) => (
145+
<SelectedItem key={entity.urn}>
146+
{hydratedEntityMap[entity.urn] ? (
147+
<EntityLink entity={hydratedEntityMap[entity.urn]} />
148+
) : (
149+
<Skeleton.Input active />
150+
)}
151+
<IconWrapper>
152+
<Icon icon="X" source="phosphor" onClick={() => removeEntity(entity)} />
153+
</IconWrapper>
154+
</SelectedItem>
155+
))
156+
)}
157+
</ScrollableContent>
158+
</CurrentSection>
159+
</Container>
160+
);
161+
}

0 commit comments

Comments
 (0)