Skip to content
Closed
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 @@ -88,9 +88,27 @@ import {
} from '../../FoldersEditor/constants';
import { validateFolders } from '../../FoldersEditor/folderValidation';
import FoldersEditor from '../../FoldersEditor';
import { useDatasetLineage } from 'src/hooks/apiResources';
import { LineageView } from 'src/features/lineage';

const extensionsRegistry = getExtensionsRegistry();

// Functional wrapper component for lineage tab (needed because hooks can't be used in class components)
function DatasetLineageTab({ datasourceId }) {
const lineageResource = useDatasetLineage(datasourceId);

// Show loading state if datasourceId is not available
if (!datasourceId) {
return <Loading />;
}

return <LineageView lineageResource={lineageResource} entityType="dataset" />;
}

DatasetLineageTab.propTypes = {
datasourceId: PropTypes.number,
};

const DatasourceContainer = styled.div`
.change-warning {
margin: 16px 10px 0;
Expand Down Expand Up @@ -217,6 +235,7 @@ const TABS_KEYS = {
COLUMNS: 'COLUMNS',
CALCULATED_COLUMNS: 'CALCULATED_COLUMNS',
USAGE: 'USAGE',
LINEAGE: 'LINEAGE',
FOLDERS: 'FOLDERS',
SETTINGS: 'SETTINGS',
SPATIAL: 'SPATIAL',
Expand Down Expand Up @@ -2068,6 +2087,15 @@ class DatasourceEditor extends PureComponent {
</StyledTableTabWrapper>
),
},
{
key: TABS_KEYS.LINEAGE,
label: t('Lineage'),
children: (
<StyledTableTabWrapper>
<DatasetLineageTab datasourceId={datasource.id} />
</StyledTableTabWrapper>
),
},
...(isFeatureEnabled(FeatureFlag.DatasetFolders)
? [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { getActiveFilters } from 'src/dashboard/util/activeDashboardFilters';
import { getUrlParam } from 'src/utils/urlUtils';
import { MenuKeys, RootState } from 'src/dashboard/types';
import { HeaderDropdownProps } from 'src/dashboard/components/Header/types';
import { LineageModal } from 'src/features/lineage';

export const useHeaderActionsMenu = ({
customCss,
Expand Down Expand Up @@ -217,6 +218,24 @@ export const useHeaderActionsMenu = ({
key: MenuKeys.EditProperties,
label: t('Edit properties'),
});

// View lineage
if (dashboardId) {
menuItems.push(
createModalMenuItem(
MenuKeys.ViewLineage,
<LineageModal
entityType="dashboard"
entityId={dashboardId}
triggerNode={
<div data-test="view-lineage-menu-item">
{t('View lineage')}
</div>
}
/>,
),
);
}
}

// Divider
Expand Down
1 change: 1 addition & 0 deletions superset-frontend/src/dashboard/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,5 @@ export enum MenuKeys {
ManageEmailReports = 'manage_email_reports',
ExportPivotXlsx = 'export_pivot_xlsx',
EmbedCode = 'embed_code',
ViewLineage = 'view_lineage',
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { useStreamingExport } from 'src/components/StreamingExportModal';
import ViewQueryModal from '../controls/ViewQueryModal';
import EmbedCodeContent from '../EmbedCodeContent';
import { useDashboardsMenuItems } from './DashboardsSubMenu';
import { LineageModal } from 'src/features/lineage';

export const SEARCH_THRESHOLD = 10;

Expand Down Expand Up @@ -79,6 +80,7 @@ const MENU_KEYS = {
EDIT_REPORT: 'edit_report',
DELETE_REPORT: 'delete_report',
VIEW_QUERY: 'view_query',
VIEW_LINEAGE: 'view_lineage',
RUN_IN_SQL_LAB: 'run_in_sql_lab',
};

Expand Down Expand Up @@ -859,6 +861,23 @@ export const useExploreAdditionalActionsMenu = (
onClick: () => setIsDropdownVisible(false),
});

// View lineage
if (slice?.slice_id) {
menuItems.push({
key: MENU_KEYS.VIEW_LINEAGE,
label: (
<LineageModal
entityType="chart"
entityId={slice.slice_id}
triggerNode={
<div data-test="view-lineage-menu-item">{t('View lineage')}</div>
}
/>
),
onClick: () => setIsDropdownVisible(false),
});
}

// Run in SQL Lab
if (datasource) {
menuItems.push({
Expand Down
128 changes: 79 additions & 49 deletions superset-frontend/src/features/charts/ChartCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Chart from 'src/types/Chart';
import { FacePile } from 'src/components';
import { handleChartDelete, CardStyles } from 'src/views/CRUD/utils';
import { assetUrl } from 'src/utils/assetUrl';
import { LineageModal } from 'src/features/lineage';

interface ChartCardProps {
chart: Chart;
Expand Down Expand Up @@ -72,6 +73,7 @@ export default function ChartCard({
const canEdit = hasPerm('can_write');
const canDelete = hasPerm('can_write');
const canExport = hasPerm('can_export');
const canRead = hasPerm('can_read');
const menuItems: MenuItem[] = [];

if (canEdit) {
Expand All @@ -96,6 +98,29 @@ export default function ChartCard({
});
}

if (canRead) {
menuItems.push({
key: 'lineage',
label: (
<LineageModal
entityType="chart"
entityId={chart.id}
triggerNode={
<div>
<Icons.ShareAltOutlined
iconSize="l"
css={css`
vertical-align: text-top;
`}
/>{' '}
{t('View Lineage')}
</div>
}
/>
),
});
}

if (canExport) {
menuItems.push({
key: 'export',
Expand Down Expand Up @@ -162,54 +187,59 @@ export default function ChartCard({
}

return (
<CardStyles
onClick={() => {
if (!bulkSelectEnabled && chart.url) {
history.push(chart.url);
}
}}
>
<ListViewCard
loading={loading}
title={chart.slice_name}
certifiedBy={chart.certified_by}
certificationDetails={chart.certification_details}
cover={
!isFeatureEnabled(FeatureFlag.Thumbnails) || !showThumbnails ? (
<></>
) : null
}
url={bulkSelectEnabled ? undefined : chart.url}
imgURL={chart.thumbnail_url || ''}
imgFallbackURL={assetUrl(
'/static/assets/images/chart-card-fallback.svg',
)}
description={t('Modified %s', chart.changed_on_delta_humanized)}
coverLeft={<FacePile users={chart.owners || []} />}
coverRight={<Label>{chart.datasource_name_text}</Label>}
linkComponent={Link}
actions={
<ListViewCard.Actions
onClick={e => {
e.stopPropagation();
e.preventDefault();
}}
>
{userId && (
<FaveStar
itemId={chart.id}
saveFaveStar={saveFavoriteStatus}
isStarred={favoriteStatus}
/>
)}
<Dropdown menu={{ items: menuItems }} trigger={['click', 'hover']}>
<Button buttonSize="xsmall" type="link" buttonStyle="link">
<Icons.MoreOutlined iconSize="xl" />
</Button>
</Dropdown>
</ListViewCard.Actions>
}
/>
</CardStyles>
<>
<CardStyles
onClick={() => {
if (!bulkSelectEnabled && chart.url) {
history.push(chart.url);
}
}}
>
<ListViewCard
loading={loading}
title={chart.slice_name}
certifiedBy={chart.certified_by}
certificationDetails={chart.certification_details}
cover={
!isFeatureEnabled(FeatureFlag.Thumbnails) || !showThumbnails ? (
<></>
) : null
}
url={bulkSelectEnabled ? undefined : chart.url}
imgURL={chart.thumbnail_url || ''}
imgFallbackURL={assetUrl(
'/static/assets/images/chart-card-fallback.svg',
)}
description={t('Modified %s', chart.changed_on_delta_humanized)}
coverLeft={<FacePile users={chart.owners || []} />}
coverRight={<Label>{chart.datasource_name_text}</Label>}
linkComponent={Link}
actions={
<ListViewCard.Actions
onClick={e => {
e.stopPropagation();
e.preventDefault();
}}
>
{userId && (
<FaveStar
itemId={chart.id}
saveFaveStar={saveFavoriteStatus}
isStarred={favoriteStatus}
/>
)}
<Dropdown
menu={{ items: menuItems }}
trigger={['click', 'hover']}
>
<Button buttonSize="xsmall" type="link" buttonStyle="link">
<Icons.MoreOutlined iconSize="xl" />
</Button>
</Dropdown>
</ListViewCard.Actions>
}
/>
</CardStyles>
</>
);
}
Loading
Loading