123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- import {useCallback, useState} from 'react';
- import styled from '@emotion/styled';
- import Button from 'sentry/components/button';
- import {t} from 'sentry/locale';
- import {LightFlamegraphTheme} from 'sentry/utils/profiling/flamegraph/flamegraphTheme';
- import {
- importDroppedProfile,
- ProfileGroup,
- } from 'sentry/utils/profiling/profile/importProfile';
- export interface ProfileDragDropImportProps {
- children: React.ReactNode;
- onImport: (profile: ProfileGroup) => void;
- }
- function ProfileDragDropImport({
- onImport,
- children,
- }: ProfileDragDropImportProps): React.ReactElement {
- const [dropState, setDropState] = useState<
- 'idle' | 'dragover' | 'processing' | 'errored'
- >('idle');
- const [errorMessage, setErrorMessage] = useState<string | null>(null);
- const onDrop = useCallback(
- (evt: React.DragEvent<HTMLDivElement>) => {
- evt.preventDefault();
- evt.stopPropagation();
- const file = evt.dataTransfer.items[0].getAsFile();
- if (file) {
- setDropState('processing');
- importDroppedProfile(file)
- .then(profile => {
- setDropState('idle');
- setErrorMessage(null);
- onImport(profile);
- })
- .catch(e => {
- setDropState('errored');
- setErrorMessage(e.message);
- });
- }
- },
- [onImport]
- );
- const onDragEnter = useCallback((evt: React.DragEvent<HTMLDivElement>) => {
- evt.preventDefault();
- evt.stopPropagation();
- setDropState('dragover');
- }, []);
- const onDragLeave = useCallback((evt: React.DragEvent<HTMLDivElement>) => {
- evt.preventDefault();
- evt.stopPropagation();
- setDropState('idle');
- }, []);
- // This is required to indicate that onDrop is supported on this element
- const onDragOver = useCallback((evt: React.DragEvent<HTMLDivElement>) => {
- evt.preventDefault();
- }, []);
- const onDismiss = useCallback(() => {
- setDropState('idle');
- setErrorMessage(null);
- }, []);
- return (
- <DragDropContainer onDragEnter={onDragEnter}>
- {dropState === 'idle' ? null : dropState === 'errored' ? (
- <Overlay>
- {t('Failed to import profile with error')}
- <p>{errorMessage}</p>
- <div>
- <Button onClick={onDismiss}>{t('Dismiss')}</Button>
- </div>
- </Overlay>
- ) : (
- <Overlay onDrop={onDrop} onDragOver={onDragOver} onDragLeave={onDragLeave}>
- {t('Drop profile here')}
- </Overlay>
- )}
- {children}
- </DragDropContainer>
- );
- }
- const DragDropContainer = styled('div')`
- display: flex;
- flex-direction: column;
- flex: 1 1 100%;
- `;
- const Overlay = styled('div')`
- position: absolute;
- left: 0;
- bottom: 0;
- width: 100%;
- height: calc(100% - ${LightFlamegraphTheme.SIZES.TIMELINE_HEIGHT}px);
- display: grid;
- grid: auto/50%;
- place-content: center;
- z-index: ${p => p.theme.zIndex.modal};
- text-align: center;
- background-color: ${p => p.theme.surface100};
- `;
- export {ProfileDragDropImport};
|