mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
192 lines
4.9 KiB
TypeScript
192 lines
4.9 KiB
TypeScript
import {useCallback, useMemo} from 'react';
|
|
import {useSortable} from '@dnd-kit/sortable';
|
|
import styled from '@emotion/styled';
|
|
|
|
import type {ButtonProps} from 'sentry/components/button';
|
|
import {Button} from 'sentry/components/button';
|
|
import DropdownButton from 'sentry/components/dropdownButton';
|
|
import type {MenuItemProps} from 'sentry/components/dropdownMenu';
|
|
import {DropdownMenu} from 'sentry/components/dropdownMenu';
|
|
import ExternalLink from 'sentry/components/links/externalLink';
|
|
import {IconAdd} from 'sentry/icons';
|
|
import {t} from 'sentry/locale';
|
|
import {space} from 'sentry/styles/space';
|
|
import {trackAnalytics} from 'sentry/utils/analytics';
|
|
import {hasDDMFeature} from 'sentry/utils/metrics/features';
|
|
import useOrganization from 'sentry/utils/useOrganization';
|
|
import {DataSet} from 'sentry/views/dashboards/widgetBuilder/utils';
|
|
|
|
import {DisplayType} from './types';
|
|
import WidgetWrapper from './widgetWrapper';
|
|
|
|
export const ADD_WIDGET_BUTTON_DRAG_ID = 'add-widget-button';
|
|
|
|
const initialStyles = {
|
|
x: 0,
|
|
y: 0,
|
|
scaleX: 1,
|
|
scaleY: 1,
|
|
};
|
|
|
|
type Props = {
|
|
onAddWidget: (dataset: DataSet) => void;
|
|
};
|
|
|
|
function AddWidget({onAddWidget}: Props) {
|
|
const {setNodeRef, transform} = useSortable({
|
|
disabled: true,
|
|
id: ADD_WIDGET_BUTTON_DRAG_ID,
|
|
transition: null,
|
|
});
|
|
|
|
const organization = useOrganization();
|
|
|
|
return (
|
|
<WidgetWrapper
|
|
key="add"
|
|
ref={setNodeRef}
|
|
displayType={DisplayType.BIG_NUMBER}
|
|
layoutId={ADD_WIDGET_BUTTON_DRAG_ID}
|
|
style={{originX: 0, originY: 0}}
|
|
animate={
|
|
transform
|
|
? {
|
|
x: transform.x,
|
|
y: transform.y,
|
|
scaleX: transform?.scaleX && transform.scaleX <= 1 ? transform.scaleX : 1,
|
|
scaleY: transform?.scaleY && transform.scaleY <= 1 ? transform.scaleY : 1,
|
|
}
|
|
: initialStyles
|
|
}
|
|
transition={{
|
|
duration: 0.25,
|
|
}}
|
|
>
|
|
{hasDDMFeature(organization) ? (
|
|
<InnerWrapper>
|
|
<AddWidgetButton
|
|
onAddWidget={onAddWidget}
|
|
aria-label="Add Widget"
|
|
data-test-id="widget-add"
|
|
/>
|
|
</InnerWrapper>
|
|
) : (
|
|
<InnerWrapper onClick={() => onAddWidget(DataSet.EVENTS)}>
|
|
<AddButton
|
|
data-test-id="widget-add"
|
|
icon={<IconAdd size="lg" isCircled color="inactive" />}
|
|
aria-label={t('Add widget')}
|
|
/>
|
|
</InnerWrapper>
|
|
)}
|
|
</WidgetWrapper>
|
|
);
|
|
}
|
|
|
|
const AddButton = styled(Button)`
|
|
border: none;
|
|
&,
|
|
&:focus,
|
|
&:active,
|
|
&:hover {
|
|
background: transparent;
|
|
box-shadow: none;
|
|
}
|
|
`;
|
|
|
|
export default AddWidget;
|
|
|
|
export function AddWidgetButton({onAddWidget, ...buttonProps}: Props & ButtonProps) {
|
|
const organization = useOrganization();
|
|
|
|
const handleAction = useCallback(
|
|
(dataset: DataSet) => {
|
|
trackAnalytics('dashboards_views.widget_library.opened', {
|
|
organization,
|
|
});
|
|
onAddWidget(dataset);
|
|
},
|
|
[organization, onAddWidget]
|
|
);
|
|
|
|
const items: MenuItemProps[] = useMemo(() => {
|
|
const menuItems = [
|
|
{
|
|
key: DataSet.EVENTS,
|
|
label: t('Errors and Transactions'),
|
|
onAction: () => handleAction(DataSet.EVENTS),
|
|
},
|
|
{
|
|
key: DataSet.ISSUES,
|
|
label: t('Issues'),
|
|
details: t('States, Assignment, Time, etc.'),
|
|
onAction: () => handleAction(DataSet.ISSUES),
|
|
},
|
|
];
|
|
|
|
if (organization.features.includes('dashboards-rh-widget')) {
|
|
menuItems.push({
|
|
key: DataSet.RELEASES,
|
|
label: t('Releases'),
|
|
details: t('Sessions, Crash rates, etc.'),
|
|
onAction: () => handleAction(DataSet.RELEASES),
|
|
});
|
|
}
|
|
|
|
if (hasDDMFeature(organization)) {
|
|
menuItems.push({
|
|
key: DataSet.METRICS,
|
|
label: t('Custom Metrics'),
|
|
onAction: () => handleAction(DataSet.METRICS),
|
|
});
|
|
}
|
|
|
|
return menuItems;
|
|
}, [handleAction, organization]);
|
|
|
|
return (
|
|
<DropdownMenu
|
|
items={items}
|
|
trigger={triggerProps => (
|
|
<DropdownButton
|
|
{...triggerProps}
|
|
{...buttonProps}
|
|
data-test-id="widget-add"
|
|
size="sm"
|
|
icon={<IconAdd isCircled />}
|
|
>
|
|
{t('Add Widget')}
|
|
</DropdownButton>
|
|
)}
|
|
menuTitle={
|
|
<MenuTitle>
|
|
{t('Dataset')}
|
|
<ExternalLink href="https://docs.sentry.io/product/dashboards/widget-builder/#choose-your-dataset">
|
|
{t('Learn more')}
|
|
</ExternalLink>
|
|
</MenuTitle>
|
|
}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const InnerWrapper = styled('div')<{onClick?: () => void}>`
|
|
width: 100%;
|
|
height: 110px;
|
|
border: 2px dashed ${p => p.theme.border};
|
|
border-radius: ${p => p.theme.borderRadius};
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
cursor: ${p => (p.onClick ? 'pointer' : '')};
|
|
`;
|
|
|
|
const MenuTitle = styled('span')`
|
|
display: flex;
|
|
gap: ${space(1)};
|
|
|
|
& > a {
|
|
font-weight: normal;
|
|
}
|
|
`;
|