import {Fragment, useCallback, useEffect, useMemo, useState} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import {FocusScope} from '@react-aria/focus'; import * as Sentry from '@sentry/react'; import {AnimatePresence} from 'framer-motion'; import GuideAnchor from 'sentry/components/assistant/guideAnchor'; import {Button} from 'sentry/components/button'; import {CompactSelect} from 'sentry/components/compactSelect'; import {openConfirmModal} from 'sentry/components/confirm'; import InputControl from 'sentry/components/input'; import {Overlay, PositionWrapper} from 'sentry/components/overlay'; import {Tooltip} from 'sentry/components/tooltip'; import {IconBookmark, IconDashboard, IconDelete, IconStar} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {trackAnalytics} from 'sentry/utils/analytics'; import useKeyPress from 'sentry/utils/useKeyPress'; import useOrganization from 'sentry/utils/useOrganization'; import useOverlay from 'sentry/utils/useOverlay'; import {useScratchpads} from 'sentry/views/ddm/scratchpadContext'; import {useCreateDashboard} from './useCreateDashboard'; export function ScratchpadSelector() { const scratchpads = useScratchpads(); const organization = useOrganization(); const createDashboard = useCreateDashboard(); const isDefault = useCallback( scratchpad => scratchpads.default === scratchpad.id, [scratchpads.default] ); const scratchpadOptions = useMemo( () => Object.values(scratchpads.all).map(scratchpad => ({ value: scratchpad.id, label: scratchpad.name, trailingItems: ( ), })), [scratchpads, isDefault, organization] ); const selectedScratchpad = scratchpads.selected ? scratchpads.all[scratchpads.selected] : undefined; return ( { scratchpads.add(name); }} mode={scratchpads.selected ? 'fork' : 'save'} /> { scratchpads.toggleSelected(option.value); }} triggerProps={{prefix: t('Scratchpad')}} emptyMessage="No scratchpads yet." disabled={false} /> ); } function SaveAsDropdown({ onSave, mode, }: { mode: 'save' | 'fork'; onSave: (name: string) => void; }) { const { isOpen, triggerProps, overlayProps, arrowProps, state: {setOpen}, } = useOverlay({}); const theme = useTheme(); const organization = useOrganization(); const [name, setName] = useState(''); const save = useCallback(() => { trackAnalytics('ddm.scratchpad.save', { organization, }); Sentry.metrics.increment('ddm.scratchpad.save'); onSave(name); setOpen(false); setName(''); }, [name, onSave, setOpen, organization]); const enterKeyPressed = useKeyPress('Enter'); useEffect(() => { if (isOpen && enterKeyPressed && name) { save(); } }, [enterKeyPressed, isOpen, name, save]); const isFork = mode === 'fork'; return (
{isOpen && ( setName(target.value)} /> { save(); }} > {mode === 'fork' ? t('Duplicate') : t('Save')} )}
); } const ScratchpadGroup = styled('div')` display: flex; gap: ${space(1)}; `; const StyledOverlay = styled(Overlay)` padding: ${space(1)}; `; const SaveAsButton = styled(Button)` width: 100%; `; const SaveAsInput = styled(InputControl)` margin-bottom: ${space(1)}; `; const StyledDropdownIcon = styled('span')<{danger?: boolean}>` padding: ${space(0.5)} ${space(0.5)} 0 ${space(0.5)}; opacity: 0.5; :hover { opacity: 0.9; color: ${p => (p.danger ? p.theme.red300 : p.theme.gray300)}; } `;