import {InjectedRouter} from 'react-router';
import styled from '@emotion/styled';
import {Location} from 'history';
import {openDashboardWidgetQuerySelectorModal} from 'sentry/actionCreators/modal';
import Feature from 'sentry/components/acl/feature';
import Button from 'sentry/components/button';
import {openConfirmModal} from 'sentry/components/confirm';
import DropdownMenuControlV2 from 'sentry/components/dropdownMenuControlV2';
import {MenuItemProps} from 'sentry/components/dropdownMenuItemV2';
import {isWidgetViewerPath} from 'sentry/components/modals/widgetViewerModal/utils';
import Tag from 'sentry/components/tag';
import Tooltip from 'sentry/components/tooltip';
import {IconEllipsis, IconExpand} from 'sentry/icons';
import {t} from 'sentry/locale';
import space from 'sentry/styles/space';
import {Organization, PageFilters} from 'sentry/types';
import {Series} from 'sentry/types/echarts';
import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
import {TableDataWithTitle} from 'sentry/utils/discover/discoverQuery';
import {
getWidgetDiscoverUrl,
getWidgetIssueUrl,
isCustomMeasurementWidget,
} from 'sentry/views/dashboardsV2/utils';
import {Widget, WidgetType} from '../types';
import {WidgetViewerContext} from '../widgetViewer/widgetViewerContext';
import {useDashboardsMEPContext} from './dashboardsMEPContext';
type Props = {
location: Location;
organization: Organization;
router: InjectedRouter;
selection: PageFilters;
widget: Widget;
widgetLimitReached: boolean;
index?: string;
isPreview?: boolean;
onDelete?: () => void;
onDuplicate?: () => void;
onEdit?: () => void;
pageLinks?: string;
seriesData?: Series[];
showContextMenu?: boolean;
showWidgetViewerButton?: boolean;
tableData?: TableDataWithTitle[];
totalIssuesCount?: string;
};
function WidgetCardContextMenu({
organization,
selection,
widget,
widgetLimitReached,
onDelete,
onDuplicate,
onEdit,
showContextMenu,
isPreview,
showWidgetViewerButton,
router,
location,
index,
seriesData,
tableData,
pageLinks,
totalIssuesCount,
}: Props) {
const {isMetricsData} = useDashboardsMEPContext();
if (!showContextMenu) {
return null;
}
const menuOptions: MenuItemProps[] = [];
const usingCustomMeasurements = isCustomMeasurementWidget(widget);
const disabledKeys: string[] = usingCustomMeasurements ? ['open-in-discover'] : [];
const openWidgetViewerPath = (id: string | undefined) => {
if (!isWidgetViewerPath(location.pathname)) {
router.push({
pathname: `${location.pathname}${
location.pathname.endsWith('/') ? '' : '/'
}widget/${id}/`,
query: location.query,
});
}
};
if (isPreview) {
return (
{({setData}) => (
,
}}
placement="bottom right"
disabledKeys={[...disabledKeys, 'preview']}
/>
{showWidgetViewerButton && (
}
onClick={() => {
(seriesData || tableData) &&
setData({
seriesData,
tableData,
pageLinks,
totalIssuesCount,
});
openWidgetViewerPath(index);
}}
/>
)}
)}
);
}
if (
organization.features.includes('discover-basic') &&
widget.widgetType === WidgetType.DISCOVER
) {
// Open Widget in Discover
if (widget.queries.length) {
const discoverPath = getWidgetDiscoverUrl(
widget,
selection,
organization,
0,
isMetricsData
);
menuOptions.push({
key: 'open-in-discover',
label: usingCustomMeasurements ? (
{t('Open in Discover')}
) : (
t('Open in Discover')
),
to:
!usingCustomMeasurements && widget.queries.length === 1
? discoverPath
: undefined,
onAction: () => {
if (!usingCustomMeasurements) {
if (widget.queries.length === 1) {
trackAdvancedAnalyticsEvent('dashboards_views.open_in_discover.opened', {
organization,
widget_type: widget.displayType,
});
return;
}
trackAdvancedAnalyticsEvent('dashboards_views.query_selector.opened', {
organization,
widget_type: widget.displayType,
});
openDashboardWidgetQuerySelectorModal({organization, widget, isMetricsData});
}
},
});
}
}
if (widget.widgetType === WidgetType.ISSUE) {
const issuesLocation = getWidgetIssueUrl(widget, selection, organization);
menuOptions.push({
key: 'open-in-issues',
label: t('Open in Issues'),
to: issuesLocation,
});
}
if (organization.features.includes('dashboards-edit')) {
menuOptions.push({
key: 'duplicate-widget',
label: t('Duplicate Widget'),
onAction: () => onDuplicate?.(),
});
widgetLimitReached && disabledKeys.push('duplicate-widget');
menuOptions.push({
key: 'edit-widget',
label: t('Edit Widget'),
onAction: () => onEdit?.(),
});
menuOptions.push({
key: 'delete-widget',
label: t('Delete Widget'),
priority: 'danger',
onAction: () => {
openConfirmModal({
message: t('Are you sure you want to delete this widget?'),
priority: 'danger',
onConfirm: () => onDelete?.(),
});
},
});
}
if (!menuOptions.length) {
return null;
}
return (
{({setData}) => (
{isMetricsData === false && (
{t('Sampled')}
)}
,
}}
placement="bottom right"
disabledKeys={disabledKeys}
/>
{showWidgetViewerButton && (
}
onClick={() => {
setData({
seriesData,
tableData,
pageLinks,
totalIssuesCount,
});
openWidgetViewerPath(widget.id ?? index);
}}
/>
)}
)}
);
}
export default WidgetCardContextMenu;
const ContextWrapper = styled('div')`
display: flex;
align-items: center;
height: ${space(3)};
margin-left: ${space(1)};
`;
const StyledDropdownMenuControlV2 = styled(DropdownMenuControlV2)`
& > button {
z-index: auto;
}
`;
const OpenWidgetViewerButton = styled(Button)`
padding: ${space(0.75)} ${space(1)};
color: ${p => p.theme.textColor};
&:hover {
color: ${p => p.theme.textColor};
background: ${p => p.theme.surface400};
border-color: transparent;
}
`;
const SampledTag = styled(Tag)`
margin-right: ${space(0.5)};
`;