import {useEffect, useRef, useState} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import isEqual from 'lodash/isEqual'; import {Button} from 'sentry/components/button'; import {openConfirmModal} from 'sentry/components/confirm'; import SlideOverPanel from 'sentry/components/slideOverPanel'; import {IconClose} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import useMedia from 'sentry/utils/useMedia'; import useOrganization from 'sentry/utils/useOrganization'; import {useParams} from 'sentry/utils/useParams'; import { type DashboardDetails, type DashboardFilters, DisplayType, type Widget, WidgetType, } from 'sentry/views/dashboards/types'; import WidgetBuilderDatasetSelector from 'sentry/views/dashboards/widgetBuilder/components/datasetSelector'; import WidgetBuilderFilterBar from 'sentry/views/dashboards/widgetBuilder/components/filtersBar'; import WidgetBuilderGroupBySelector from 'sentry/views/dashboards/widgetBuilder/components/groupBySelector'; import WidgetBuilderNameAndDescription from 'sentry/views/dashboards/widgetBuilder/components/nameAndDescFields'; import {WidgetPreviewContainer} from 'sentry/views/dashboards/widgetBuilder/components/newWidgetBuilder'; import WidgetBuilderQueryFilterBuilder from 'sentry/views/dashboards/widgetBuilder/components/queryFilterBuilder'; import RPCToggle from 'sentry/views/dashboards/widgetBuilder/components/rpcToggle'; import SaveButton from 'sentry/views/dashboards/widgetBuilder/components/saveButton'; import WidgetBuilderSortBySelector from 'sentry/views/dashboards/widgetBuilder/components/sortBySelector'; import WidgetBuilderTypeSelector from 'sentry/views/dashboards/widgetBuilder/components/typeSelector'; import Visualize from 'sentry/views/dashboards/widgetBuilder/components/visualize'; import {useWidgetBuilderContext} from 'sentry/views/dashboards/widgetBuilder/contexts/widgetBuilderContext'; type WidgetBuilderSlideoutProps = { dashboard: DashboardDetails; dashboardFilters: DashboardFilters; isOpen: boolean; isWidgetInvalid: boolean; onClose: () => void; onQueryConditionChange: (valid: boolean) => void; onSave: ({index, widget}: {index: number; widget: Widget}) => void; setIsPreviewDraggable: (draggable: boolean) => void; }; function WidgetBuilderSlideout({ isOpen, onClose, onSave, onQueryConditionChange, dashboard, dashboardFilters, setIsPreviewDraggable, isWidgetInvalid, }: WidgetBuilderSlideoutProps) { const organization = useOrganization(); const {state} = useWidgetBuilderContext(); const [initialState] = useState(state); const [error, setError] = useState>({}); const {widgetIndex} = useParams(); const theme = useTheme(); const isEditing = widgetIndex !== undefined; const title = isEditing ? t('Edit Widget') : t('Create Custom Widget'); const isChartWidget = state.displayType !== DisplayType.BIG_NUMBER && state.displayType !== DisplayType.TABLE; const previewRef = useRef(null); const isSmallScreen = useMedia(`(max-width: ${theme.breakpoints.small})`); const showSortByStep = (isChartWidget && state.fields && state.fields.length > 0) || state.displayType === DisplayType.TABLE; useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { setIsPreviewDraggable(!entry!.isIntersecting); }, {threshold: 0} ); if (previewRef.current) { observer.observe(previewRef.current); } return () => observer.disconnect(); }, [setIsPreviewDraggable]); return ( {title} } onClick={() => { openConfirmModal({ bypass: isEqual(initialState, state), message: t('You have unsaved changes. Are you sure you want to leave?'), priority: 'danger', onConfirm: onClose, }); }} > {t('Close')}
{organization.features.includes('visibility-explore-dataset') && state.dataset === WidgetType.SPANS && (
)}
{isSmallScreen && (
)}
{isChartWidget && (
)} {showSortByStep && (
)}
); } export default WidgetBuilderSlideout; const CloseButton = styled(Button)` color: ${p => p.theme.gray300}; height: fit-content; &:hover { color: ${p => p.theme.gray400}; } z-index: 100; `; const SlideoutTitle = styled('h5')` margin: 0; `; const SlideoutHeaderWrapper = styled('div')` padding: ${space(3)} ${space(4)}; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid ${p => p.theme.border}; `; const SlideoutBodyWrapper = styled('div')` padding: ${space(4)}; `; const Section = styled('div')` margin-bottom: ${space(4)}; `;