Skip to content

Commit

Permalink
feat(feedback): Add screenshots in feedback item (#66530)
Browse files Browse the repository at this point in the history
Adds ability to view screenshot attachments in feedbacks. The screenshot
preview and modal is the same as in issues, and the code is copied over
from EventTagsAndScreenshots. This will be modified when user feedback
is revamped.

Screenshot in feedback item:
<img width="955" alt="image"
src="https://github.com/getsentry/sentry/assets/55311782/1a704f26-6152-4471-be1e-766c7a0d9aa7">

Clicking on view screenshot:
<img width="714" alt="image"
src="https://github.com/getsentry/sentry/assets/55311782/6888821c-ae71-4ca8-a257-fb295e5464ce">

Relates to: #63749
  • Loading branch information
c298lee committed Mar 7, 2024
1 parent 57677ec commit 5c96e1c
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 0 deletions.
9 changes: 9 additions & 0 deletions static/app/components/feedback/feedbackItem/feedbackItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import FeedbackItemHeader from 'sentry/components/feedback/feedbackItem/feedback
import Section from 'sentry/components/feedback/feedbackItem/feedbackItemSection';
import FeedbackReplay from 'sentry/components/feedback/feedbackItem/feedbackReplay';
import FeedbackViewers from 'sentry/components/feedback/feedbackItem/feedbackViewers';
import {ScreenshotSection} from 'sentry/components/feedback/feedbackItem/screenshotSection';
import TagsSection from 'sentry/components/feedback/feedbackItem/tagsSection';
import PanelItem from 'sentry/components/panels/panelItem';
import {Flex} from 'sentry/components/profiling/flex';
Expand Down Expand Up @@ -54,6 +55,14 @@ export default function FeedbackItem({feedbackItem, eventData, tags}: Props) {
</Blockquote>
</Section>

{eventData && (
<ScreenshotSection
event={eventData}
organization={organization}
projectSlug={feedbackItem.project.slug}
/>
)}

{!crashReportId || (crashReportId && url) ? (
<Section icon={<IconLink size="xs" />} title={t('URL')}>
<TextCopyInput size="sm">
Expand Down
108 changes: 108 additions & 0 deletions static/app/components/feedback/feedbackItem/screenshotSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {useCallback, useMemo, useState} from 'react';

import {
useDeleteEventAttachmentOptimistic,
useFetchEventAttachments,
} from 'sentry/actionCreators/events';
import {openModal} from 'sentry/actionCreators/modal';
import Screenshot from 'sentry/components/events/eventTagsAndScreenshot/screenshot';
import Modal, {
modalCss,
} from 'sentry/components/events/eventTagsAndScreenshot/screenshot/modal';
import Section from 'sentry/components/feedback/feedbackItem/feedbackItemSection';
import {t} from 'sentry/locale';
import type {Organization} from 'sentry/types';
import type {Event} from 'sentry/types/event';
import type {EventAttachment} from 'sentry/types/group';
import {objectIsEmpty} from 'sentry/utils';

type Props = {
event: Event;
organization: Organization;
projectSlug: string;
};

export function ScreenshotSection({projectSlug, event, organization}: Props) {
const hasContext = !objectIsEmpty(event.user ?? {}) || !objectIsEmpty(event.contexts);
const {data: attachments} = useFetchEventAttachments({
orgSlug: organization.slug,
projectSlug,
eventId: event.id,
});
const {mutate: deleteAttachment} = useDeleteEventAttachmentOptimistic();
const screenshots = useMemo(() => {
return attachments ?? [];
}, [attachments]);

const [screenshotInFocus, setScreenshotInFocus] = useState<number>(0);

const handleDeleteScreenshot = useCallback(
(attachmentId: string) => {
deleteAttachment({
orgSlug: organization.slug,
projectSlug,
eventId: event.id,
attachmentId,
});
},
[deleteAttachment, event.id, organization.slug, projectSlug]
);

const handleOpenVisualizationModal = useCallback(
(eventAttachment: EventAttachment, downloadUrl: string) => {
function handleDelete() {
handleDeleteScreenshot(eventAttachment.id);
}

openModal(
modalProps => (
<Modal
{...modalProps}
event={event}
orgSlug={organization.slug}
projectSlug={projectSlug}
eventAttachment={eventAttachment}
downloadUrl={downloadUrl}
onDelete={handleDelete}
onDownload={() => undefined}
attachments={screenshots}
attachmentIndex={screenshotInFocus}
/>
),
{modalCss}
);
},
[
event,
handleDeleteScreenshot,
organization.slug,
projectSlug,
screenshotInFocus,
screenshots,
]
);

if (!hasContext && !screenshots.length) {
return null;
}

const showScreenshot = !!screenshots.length;
const screenshot = screenshots[screenshotInFocus];

return showScreenshot ? (
<Section title={t('Screenshot')}>
<Screenshot
organization={organization}
eventId={event.id}
projectSlug={projectSlug}
screenshot={screenshot}
onDelete={handleDeleteScreenshot}
onNext={() => setScreenshotInFocus(screenshotInFocus + 1)}
onPrevious={() => setScreenshotInFocus(screenshotInFocus - 1)}
screenshotInFocus={screenshotInFocus}
totalScreenshots={screenshots.length}
openVisualizationModal={handleOpenVisualizationModal}
/>
</Section>
) : null;
}

0 comments on commit 5c96e1c

Please sign in to comment.