Skip to content

Commit

Permalink
[3/n] display link to editor in the asset catalog
Browse files Browse the repository at this point in the history
  • Loading branch information
benpankow committed May 8, 2024
1 parent 0d61b46 commit 2365c72
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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],
);
Expand Down
15 changes: 14 additions & 1 deletion js_modules/dagster-ui/packages/ui-core/src/assets/AssetView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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 (
<Box
flex={{direction: 'column', grow: 1}}
Expand All @@ -308,7 +318,10 @@ export const AssetView = ({assetKey, trace, headerBreadcrumbs}: Props) => {
</Box>
}
right={
<Box style={{margin: '-4px 0'}}>
<Box style={{margin: '-4px 0'}} flex={{direction: 'row', gap: 8}}>
{codeSource && codeSource.codeReferences && codeSource.codeReferences.length > 0 && (
<CodeLink codeLinkData={codeSource} />
)}
{definition && definition.isObservable ? (
<LaunchAssetObservationButton
primary
Expand Down
80 changes: 71 additions & 9 deletions js_modules/dagster-ui/packages/ui-core/src/code-links/CodeLink.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,80 @@
import {ExternalAnchorButton} from '@dagster-io/ui-components/src/components/Button';
import {Box, Menu, MenuItem, Popover} from '@dagster-io/ui-components';
import {Button, ExternalAnchorButton} from '@dagster-io/ui-components/src/components/Button';
import {Icon} from '@dagster-io/ui-components/src/components/Icon';
import * as React from 'react';

import {CodeLinkProtocolContext} from './CodeLinkProtocol';
import {CodeLinkProtocolContext, ProtocolData} from './CodeLinkProtocol';
import {CodeReferencesMetadataEntry, SourceLocation} from '../graphql/types';

export const CodeLink = ({file, lineNumber}: {file: string; lineNumber: number}) => {
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 (
<ExternalAnchorButton icon={<Icon name="open_in_new" />} href={codeLink}>
Open in editor
</ExternalAnchorButton>
<Box flex={{alignItems: 'center'}}>
{hasMultipleCodeSources ? (
<Popover
position="bottom-right"
content={
<Menu>
{sources.map((source) => (
<MenuItem
key={`${source.filePath}:${source.lineNumber}`}
text={getCodeReferenceEntryLabel(source)}
onClick={() => {
const codeLink = getCodeReferenceLink(codeLinkProtocol, source);
window.open(codeLink, '_blank');
}}
/>
))}
</Menu>
}
>
<Button
icon={<Icon name="expand_more" />}
style={{
minWidth: 'initial',
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
marginLeft: '-1px',
}}
>
Open in editor
</Button>
</Popover>
) : (
<ExternalAnchorButton
icon={<Icon name="open_in_new" />}
href={getCodeReferenceLink(codeLinkProtocol, sources[0] as SourceLocation)}
style={
hasMultipleCodeSources
? {
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
borderRight: '0px',
}
: {}
}
>
Open {getCodeReferenceEntryLabel(sources[0] as SourceLocation)} in editor
</ExternalAnchorButton>
)}
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ export const METADATA_ENTRY_FRAGMENT = gql`
repositoryName
locationName
}
... on CodeReferencesMetadataEntry {
codeReferences {
... on LocalFileCodeReference {
filePath
lineNumber
label
}
}
}
... on TableColumnLineageMetadataEntry {
lineage {
columnName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {StyledTableWithHeader} from '../assets/AssetEventMetadataEntriesTable';
import {AssetFeatureContext} from '../assets/AssetFeatureContext';
import {
AssetKeyInput,
CodeReferencesMetadataEntry,
MaterializationEvent,
TableColumnLineageMetadataEntry,
TableSchemaMetadataEntry,
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 2365c72

Please sign in to comment.