Skip to content
Open
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 @@ -89,6 +89,8 @@ import {
import { DatabaseSelector } from '../../../DatabaseSelector';
import CollectionTable from '../CollectionTable';
import Fieldset from '../Fieldset';
import { useDatasetLineage } from 'src/hooks/apiResources';
import { LineageView } from 'src/features/lineage';
import Field from '../Field';
import { fetchSyncedColumns, updateColumns } from '../../utils';
import DatasetUsageTab from './components/DatasetUsageTab';
Expand Down Expand Up @@ -425,6 +427,16 @@ const StyledTableTabWrapper = styled.div`
}
`;

// Functional wrapper for the lineage tab, since hooks can't be used directly in
// the DatasourceEditor class component.
function DatasetLineageTab({ datasourceId }: { datasourceId?: number }) {
const lineageResource = useDatasetLineage(datasourceId ?? 0);
if (!datasourceId) {
return <Loading />;
}
return <LineageView lineageResource={lineageResource} entityType="dataset" />;
}

const DefaultColumnSettingsContainer = styled.div`
${({ theme }) => css`
margin-bottom: ${theme.sizeUnit * 4}px;
Expand Down Expand Up @@ -477,6 +489,7 @@ const TABS_KEYS = {
COLUMNS: 'COLUMNS',
CALCULATED_COLUMNS: 'CALCULATED_COLUMNS',
USAGE: 'USAGE',
LINEAGE: 'LINEAGE',
FOLDERS: 'FOLDERS',
SETTINGS: 'SETTINGS',
SPATIAL: 'SPATIAL',
Expand Down Expand Up @@ -2515,6 +2528,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 @@ -37,6 +37,7 @@ import { getUrlParam } from 'src/utils/urlUtils';
import { MenuKeys, RootState } from 'src/dashboard/types';
import { HeaderDropdownProps } from 'src/dashboard/components/Header/types';
import { usePermissions } from 'src/hooks/usePermissions';
import { LineageModal } from 'src/features/lineage';

export const useHeaderActionsMenu = ({
customCss,
Expand Down Expand Up @@ -234,6 +235,23 @@ export const useHeaderActionsMenu = ({
});
}

// View lineage (available in both view and edit mode; lineage is
// read-only information about the dashboard's upstream assets)
if (dashboardId) {
menuItems.push(
createModalMenuItem(
MenuKeys.ViewLineage,
<LineageModal
entityType="dashboard"
entityId={dashboardId}
triggerNode={
<div data-test="view-lineage-menu-item">{t('View lineage')}</div>
}
/>,
),
);
}

// Edit properties
if (editMode) {
menuItems.push({
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 @@ -393,4 +393,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 @@ -72,6 +72,7 @@ import { ReportObject } from 'src/features/reports/types';
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 @@ -102,6 +103,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 @@ -1028,6 +1030,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 @@ -36,6 +36,7 @@ import { handleChartDelete, CardStyles } from 'src/views/CRUD/utils';
import { assetUrl } from 'src/utils/assetUrl';
import type { ListViewFetchDataConfig as FetchDataConfig } from 'src/components';
import { TableTab } from 'src/views/CRUD/types';
import { LineageModal } from 'src/features/lineage';

interface ChartCardProps {
chart: Chart;
Expand Down Expand Up @@ -76,6 +77,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 @@ -100,6 +102,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 @@ -167,54 +192,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