diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEventMetadataEntriesTable.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEventMetadataEntriesTable.tsx
index 8f3d6a7d28673..c25d230244ddc 100644
--- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEventMetadataEntriesTable.tsx
+++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetEventMetadataEntriesTable.tsx
@@ -24,7 +24,11 @@ import {
} from './types/useRecentAssetEvents.types';
import {Timestamp} from '../app/time/Timestamp';
import {HIDDEN_METADATA_ENTRY_LABELS, MetadataEntry} from '../metadata/MetadataEntry';
-import {isCanonicalColumnLineageEntry, isCanonicalColumnSchemaEntry} from '../metadata/TableSchema';
+import {
+ isCanonicalCodeSourceEntry,
+ isCanonicalColumnLineageEntry,
+ isCanonicalColumnSchemaEntry,
+} from '../metadata/TableSchema';
import {MetadataEntryFragment} from '../metadata/types/MetadataEntryFragment.types';
import {titleForRun} from '../runs/RunUtils';
import {repoAddressAsHumanString} from '../workspace/repoAddressAsString';
@@ -131,7 +135,8 @@ export const AssetEventMetadataEntriesTable = ({
(row) =>
!HIDDEN_METADATA_ENTRY_LABELS.has(row.entry.label) &&
!(isCanonicalColumnSchemaEntry(row.entry) && hideTableSchema) &&
- !isCanonicalColumnLineageEntry(row.entry),
+ !isCanonicalColumnLineageEntry(row.entry) &&
+ !isCanonicalCodeSourceEntry(row.entry),
),
[allRows, filter, hideTableSchema],
);
diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx
index 53b7f5bc69041..81c88a8da38ba 100644
--- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx
+++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx
@@ -8,6 +8,7 @@ import {useSetRecoilState} from 'recoil';
import {AssetEvents} from './AssetEvents';
import {AssetFeatureContext} from './AssetFeatureContext';
+import {metadataForAssetNode} from './AssetMetadata';
import {ASSET_NODE_DEFINITION_FRAGMENT, AssetNodeDefinition} from './AssetNodeDefinition';
import {ASSET_NODE_INSTIGATORS_FRAGMENT, AssetNodeInstigatorTag} from './AssetNodeInstigatorTag';
import {AssetNodeLineage} from './AssetNodeLineage';
@@ -51,8 +52,11 @@ import {
} from '../asset-graph/Utils';
import {useAssetGraphData} from '../asset-graph/useAssetGraphData';
import {StaleReasonsTag} from '../assets/Stale';
+import {CodeLink} from '../code-links/CodeLink';
import {AssetComputeKindTag} from '../graph/OpTags';
+import {CodeReferencesMetadataEntry} from '../graphql/types';
import {useQueryPersistedState} from '../hooks/useQueryPersistedState';
+import {isCanonicalCodeSourceEntry} from '../metadata/TableSchema';
import {RepositoryLink} from '../nav/RepositoryLink';
import {PageLoadTrace} from '../performance';
import {useBlockTraceOnQueryResult} from '../performance/TraceContext';
@@ -284,6 +288,12 @@ export const AssetView = ({assetKey, trace, headerBreadcrumbs}: Props) => {
refresh,
);
+ const assetMetadata = definition && metadataForAssetNode(definition).assetMetadata;
+ const codeSource = assetMetadata?.find((m) => isCanonicalCodeSourceEntry(m)) as
+ | CodeReferencesMetadataEntry
+ | undefined;
+ console.log(codeSource);
+
return (
{
}
right={
-
+
+ {codeSource && codeSource.codeReferences && codeSource.codeReferences.length > 0 && (
+
+ )}
{definition && definition.isObservable ? (
{
+const getCodeReferenceEntryLabel = (codeReference: SourceLocation): string => {
+ return codeReference.label || (codeReference.filePath.split('/').pop() as string);
+};
+
+const getCodeReferenceLink = (
+ codeLinkProtocol: ProtocolData,
+ codeReference: SourceLocation,
+): string => {
+ return codeLinkProtocol.protocol
+ .replace('{FILE}', codeReference.filePath)
+ .replace('{LINE}', codeReference.lineNumber.toString());
+};
+
+export const CodeLink = ({codeLinkData}: {codeLinkData: CodeReferencesMetadataEntry}) => {
const [codeLinkProtocol, _] = React.useContext(CodeLinkProtocolContext);
- const codeLink = codeLinkProtocol.protocol
- .replace('{FILE}', file)
- .replace('{LINE}', lineNumber.toString());
+ const sources = codeLinkData.codeReferences;
+
+ const hasMultipleCodeSources = sources.length > 1;
+
return (
- } href={codeLink}>
- Open in editor
-
+
+ {hasMultipleCodeSources ? (
+
+ {sources.map((source) => (
+
+ ) : (
+ }
+ href={getCodeReferenceLink(codeLinkProtocol, sources[0] as SourceLocation)}
+ style={
+ hasMultipleCodeSources
+ ? {
+ borderTopRightRadius: 0,
+ borderBottomRightRadius: 0,
+ borderRight: '0px',
+ }
+ : {}
+ }
+ >
+ Open {getCodeReferenceEntryLabel(sources[0] as SourceLocation)} in editor
+
+ )}
+
);
};
diff --git a/js_modules/dagster-ui/packages/ui-core/src/code-links/CodeLinkProtocol.tsx b/js_modules/dagster-ui/packages/ui-core/src/code-links/CodeLinkProtocol.tsx
index f9a815508b82c..994a8e2c591cd 100644
--- a/js_modules/dagster-ui/packages/ui-core/src/code-links/CodeLinkProtocol.tsx
+++ b/js_modules/dagster-ui/packages/ui-core/src/code-links/CodeLinkProtocol.tsx
@@ -21,7 +21,7 @@ const POPULAR_PROTOCOLS: {[name: string]: string} = {
const DEFAULT_PROTOCOL = {protocol: Object.keys(POPULAR_PROTOCOLS)[0]!, custom: false};
-type ProtocolData = {
+export type ProtocolData = {
protocol: string;
custom: boolean;
};
diff --git a/js_modules/dagster-ui/packages/ui-core/src/metadata/MetadataEntryFragment.tsx b/js_modules/dagster-ui/packages/ui-core/src/metadata/MetadataEntryFragment.tsx
index 3d9f581fcee68..d29898e18d266 100644
--- a/js_modules/dagster-ui/packages/ui-core/src/metadata/MetadataEntryFragment.tsx
+++ b/js_modules/dagster-ui/packages/ui-core/src/metadata/MetadataEntryFragment.tsx
@@ -54,6 +54,15 @@ export const METADATA_ENTRY_FRAGMENT = gql`
repositoryName
locationName
}
+ ... on CodeReferencesMetadataEntry {
+ codeReferences {
+ ... on LocalFileCodeReference {
+ filePath
+ lineNumber
+ label
+ }
+ }
+ }
... on TableColumnLineageMetadataEntry {
lineage {
columnName
diff --git a/js_modules/dagster-ui/packages/ui-core/src/metadata/TableSchema.tsx b/js_modules/dagster-ui/packages/ui-core/src/metadata/TableSchema.tsx
index cc2f1d08e5f10..644d510beb769 100644
--- a/js_modules/dagster-ui/packages/ui-core/src/metadata/TableSchema.tsx
+++ b/js_modules/dagster-ui/packages/ui-core/src/metadata/TableSchema.tsx
@@ -18,6 +18,7 @@ import {StyledTableWithHeader} from '../assets/AssetEventMetadataEntriesTable';
import {AssetFeatureContext} from '../assets/AssetFeatureContext';
import {
AssetKeyInput,
+ CodeReferencesMetadataEntry,
MaterializationEvent,
TableColumnLineageMetadataEntry,
TableSchemaMetadataEntry,
@@ -49,6 +50,11 @@ export const isCanonicalColumnLineageEntry = (
): m is TableColumnLineageMetadataEntry =>
m.__typename === 'TableColumnLineageMetadataEntry' && m.label === 'dagster/column_lineage';
+export const isCanonicalCodeSourceEntry = (
+ m: MetadataEntryLabelOnly,
+): m is CodeReferencesMetadataEntry =>
+ m && m.__typename === 'CodeReferencesMetadataEntry' && m.label === 'dagster/code_references';
+
export const TableSchemaAssetContext = createContext<{
assetKey: AssetKeyInput | undefined;
materializationMetadataEntries: MetadataEntryLabelOnly[] | undefined;