mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
238 lines
6.7 KiB
TypeScript
238 lines
6.7 KiB
TypeScript
import {useMemo} from 'react';
|
|
import styled from '@emotion/styled';
|
|
import * as Sentry from '@sentry/react';
|
|
|
|
import {openAddToDashboardModal, openModal} from 'sentry/actionCreators/modal';
|
|
import {navigateTo} from 'sentry/actionCreators/navigation';
|
|
import Feature from 'sentry/components/acl/feature';
|
|
import type {MenuItemProps} from 'sentry/components/dropdownMenu';
|
|
import {DropdownMenu} from 'sentry/components/dropdownMenu';
|
|
import {
|
|
IconClose,
|
|
IconCopy,
|
|
IconDashboard,
|
|
IconEllipsis,
|
|
IconSettings,
|
|
IconSiren,
|
|
} from 'sentry/icons';
|
|
import {t} from 'sentry/locale';
|
|
import type {Organization} from 'sentry/types';
|
|
import {trackAnalytics} from 'sentry/utils/analytics';
|
|
import {isCustomMeasurement, isCustomMetric} from 'sentry/utils/metrics';
|
|
import {
|
|
convertToDashboardWidget,
|
|
encodeWidgetQuery,
|
|
getWidgetAsQueryParams,
|
|
getWidgetQuery,
|
|
} from 'sentry/utils/metrics/dashboard';
|
|
import {hasDDMFeature} from 'sentry/utils/metrics/features';
|
|
import type {MetricDisplayType, MetricsQuery} from 'sentry/utils/metrics/types';
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
import useRouter from 'sentry/utils/useRouter';
|
|
import {useDDMContext} from 'sentry/views/ddm/context';
|
|
import {CreateAlertModal} from 'sentry/views/ddm/createAlertModal';
|
|
import {OrganizationContext} from 'sentry/views/organizationContext';
|
|
|
|
type ContextMenuProps = {
|
|
displayType: MetricDisplayType;
|
|
metricsQuery: MetricsQuery;
|
|
widgetIndex: number;
|
|
};
|
|
|
|
export function MetricQueryContextMenu({
|
|
metricsQuery,
|
|
displayType,
|
|
widgetIndex,
|
|
}: ContextMenuProps) {
|
|
const organization = useOrganization();
|
|
const router = useRouter();
|
|
const {removeWidget, duplicateWidget, widgets} = useDDMContext();
|
|
const createAlert = useMemo(
|
|
() => getCreateAlert(organization, metricsQuery),
|
|
[metricsQuery, organization]
|
|
);
|
|
const createDashboardWidget = useCreateDashboardWidget(
|
|
organization,
|
|
metricsQuery,
|
|
displayType
|
|
);
|
|
|
|
const canDelete = widgets.length > 1;
|
|
|
|
const items = useMemo<MenuItemProps[]>(
|
|
() => [
|
|
{
|
|
leadingItems: [<IconCopy key="icon" />],
|
|
key: 'duplicate',
|
|
label: t('Duplicate'),
|
|
onAction: () => {
|
|
trackAnalytics('ddm.widget.duplicate', {
|
|
organization,
|
|
});
|
|
Sentry.metrics.increment('ddm.widget.duplicate');
|
|
duplicateWidget(widgetIndex);
|
|
},
|
|
},
|
|
{
|
|
leadingItems: [<IconSiren key="icon" />],
|
|
key: 'add-alert',
|
|
label: t('Create Alert'),
|
|
disabled: !createAlert,
|
|
onAction: () => {
|
|
trackAnalytics('ddm.create-alert', {
|
|
organization,
|
|
source: 'widget',
|
|
});
|
|
Sentry.metrics.increment('ddm.widget.alert');
|
|
createAlert?.();
|
|
},
|
|
},
|
|
{
|
|
leadingItems: [<IconDashboard key="icon" />],
|
|
key: 'add-dashboard',
|
|
label: (
|
|
<Feature
|
|
organization={organization}
|
|
hookName="feature-disabled:dashboards-edit"
|
|
features="dashboards-edit"
|
|
>
|
|
{({hasFeature}) => (
|
|
<AddToDashboardItem disabled={!hasFeature}>
|
|
{t('Add to Dashboard')}
|
|
</AddToDashboardItem>
|
|
)}
|
|
</Feature>
|
|
),
|
|
disabled: !createDashboardWidget,
|
|
onAction: () => {
|
|
if (!organization.features.includes('dashboards-edit')) {
|
|
return;
|
|
}
|
|
trackAnalytics('ddm.add-to-dashboard', {
|
|
organization,
|
|
source: 'widget',
|
|
});
|
|
Sentry.metrics.increment('ddm.widget.dashboard');
|
|
createDashboardWidget?.();
|
|
},
|
|
},
|
|
{
|
|
leadingItems: [<IconSettings key="icon" />],
|
|
key: 'settings',
|
|
label: t('Metric Settings'),
|
|
disabled: !isCustomMetric({mri: metricsQuery.mri}),
|
|
onAction: () => {
|
|
trackAnalytics('ddm.widget.settings', {
|
|
organization,
|
|
});
|
|
Sentry.metrics.increment('ddm.widget.settings');
|
|
navigateTo(
|
|
`/settings/projects/:projectId/metrics/${encodeURIComponent(
|
|
metricsQuery.mri
|
|
)}`,
|
|
router
|
|
);
|
|
},
|
|
},
|
|
{
|
|
leadingItems: [<IconClose key="icon" />],
|
|
key: 'delete',
|
|
label: t('Remove Query'),
|
|
disabled: !canDelete,
|
|
onAction: () => {
|
|
Sentry.metrics.increment('ddm.widget.delete');
|
|
removeWidget(widgetIndex);
|
|
},
|
|
},
|
|
],
|
|
[
|
|
createAlert,
|
|
createDashboardWidget,
|
|
metricsQuery.mri,
|
|
canDelete,
|
|
organization,
|
|
duplicateWidget,
|
|
widgetIndex,
|
|
router,
|
|
removeWidget,
|
|
]
|
|
);
|
|
|
|
if (!hasDDMFeature(organization)) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<DropdownMenu
|
|
items={items}
|
|
triggerProps={{
|
|
'aria-label': t('Widget actions'),
|
|
size: 'md',
|
|
showChevron: false,
|
|
icon: <IconEllipsis direction="down" size="sm" />,
|
|
}}
|
|
position="bottom-end"
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function getCreateAlert(organization: Organization, metricsQuery: MetricsQuery) {
|
|
if (
|
|
!metricsQuery.mri ||
|
|
!metricsQuery.op ||
|
|
isCustomMeasurement(metricsQuery) ||
|
|
!organization.access.includes('alerts:write')
|
|
) {
|
|
return undefined;
|
|
}
|
|
return function () {
|
|
return openModal(deps => (
|
|
<OrganizationContext.Provider value={organization}>
|
|
<CreateAlertModal metricsQuery={metricsQuery} {...deps} />
|
|
</OrganizationContext.Provider>
|
|
));
|
|
};
|
|
}
|
|
|
|
export function useCreateDashboardWidget(
|
|
organization: Organization,
|
|
metricsQuery: MetricsQuery,
|
|
displayType?: MetricDisplayType
|
|
) {
|
|
const router = useRouter();
|
|
const {projects, environments, datetime} = metricsQuery;
|
|
|
|
return useMemo(() => {
|
|
if (!metricsQuery.mri || !metricsQuery.op || isCustomMeasurement(metricsQuery)) {
|
|
return undefined;
|
|
}
|
|
|
|
const widgetQuery = getWidgetQuery(metricsQuery);
|
|
const urlWidgetQuery = encodeWidgetQuery(widgetQuery);
|
|
const widgetAsQueryParams = getWidgetAsQueryParams(
|
|
metricsQuery,
|
|
urlWidgetQuery,
|
|
displayType
|
|
);
|
|
|
|
return () =>
|
|
openAddToDashboardModal({
|
|
organization,
|
|
selection: {
|
|
projects,
|
|
environments,
|
|
datetime,
|
|
},
|
|
widget: convertToDashboardWidget(metricsQuery, displayType),
|
|
router,
|
|
widgetAsQueryParams,
|
|
location: router.location,
|
|
actions: ['add-and-open-dashboard', 'add-and-stay-on-current-page'],
|
|
});
|
|
}, [metricsQuery, datetime, displayType, environments, organization, projects, router]);
|
|
}
|
|
|
|
const AddToDashboardItem = styled('div')<{disabled: boolean}>`
|
|
color: ${p => (p.disabled ? p.theme.disabled : p.theme.textColor)};
|
|
`;
|