From d4dbf62ff9f11bdd53f72967aad46161d9f16574 Mon Sep 17 00:00:00 2001 From: Abdullah Khan <60121741+Abdkhan14@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:51:14 -0500 Subject: [PATCH] feat(new-trace) Rendering resource.img span assets in drawer (#81955) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Screenshot 2024-12-10 at 4 58 46 PM ------------------------ Screenshot 2024-12-10 at 5 00 33 PM --------- Co-authored-by: Abdullah Khan Co-authored-by: Ash <0Calories@users.noreply.github.com> Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com> --- .../resources/components/sampleImages.tsx | 15 ++- .../details/span/sections/description.tsx | 124 +++++++++++++++++- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/static/app/views/insights/browser/resources/components/sampleImages.tsx b/static/app/views/insights/browser/resources/components/sampleImages.tsx index a5c30b1f42599b..e8958b2801b756 100644 --- a/static/app/views/insights/browser/resources/components/sampleImages.tsx +++ b/static/app/views/insights/browser/resources/components/sampleImages.tsx @@ -156,16 +156,21 @@ function SampleImagesChartPanelBody(props: { ); } -function DisabledImages(props: {onClickShowLinks?: () => void}) { +export function DisabledImages(props: { + onClickShowLinks?: () => void; + projectSlug?: string; +}) { const {onClickShowLinks} = props; const organization = useOrganization(); const { selection: {projects: selectedProjects}, } = usePageFilters(); const {projects} = useProjects(); - const firstProjectSelected = projects.find( - project => project.id === selectedProjects[0].toString() - ); + const firstProjectSelected = props.projectSlug + ? { + slug: props.projectSlug, + } + : projects.find(project => project.id === selectedProjects[0]?.toString()); return (
@@ -244,7 +249,7 @@ function ImageContainer(props: { ); } -function MissingImage() { +export function MissingImage() { const theme = useTheme(); return ( diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/span/sections/description.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/span/sections/description.tsx index 9b7bfece01ec73..f9922ab83ebf1b 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/span/sections/description.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/span/sections/description.tsx @@ -1,4 +1,4 @@ -import {Fragment, useMemo} from 'react'; +import {Fragment, useMemo, useState} from 'react'; import styled from '@emotion/styled'; import type {Location} from 'history'; @@ -7,6 +7,7 @@ import {CodeSnippet} from 'sentry/components/codeSnippet'; import {CopyToClipboardButton} from 'sentry/components/copyToClipboardButton'; import SpanSummaryButton from 'sentry/components/events/interfaces/spans/spanSummaryButton'; import Link from 'sentry/components/links/link'; +import LoadingIndicator from 'sentry/components/loadingIndicator'; import LinkHint from 'sentry/components/structuredEventData/linkHint'; import {IconGraph} from 'sentry/icons/iconGraph'; import {t} from 'sentry/locale'; @@ -15,6 +16,13 @@ import type {Organization} from 'sentry/types/organization'; import type {Project} from 'sentry/types/project'; import {trackAnalytics} from 'sentry/utils/analytics'; import {SQLishFormatter} from 'sentry/utils/sqlish/SQLishFormatter'; +import {useLocalStorageState} from 'sentry/utils/useLocalStorageState'; +import ResourceSize from 'sentry/views/insights/browser/resources/components/resourceSize'; +import { + DisabledImages, + LOCAL_STORAGE_SHOW_LINKS, + MissingImage, +} from 'sentry/views/insights/browser/resources/components/sampleImages'; import {resolveSpanModule} from 'sentry/views/insights/common/utils/resolveSpanModule'; import { MissingFrame, @@ -28,6 +36,7 @@ import { import {ModuleName} from 'sentry/views/insights/types'; import {useHasTraceNewUi} from 'sentry/views/performance/newTraceDetails/useHasTraceNewUi'; import {spanDetailsRouteWithQuery} from 'sentry/views/performance/transactionSummary/transactionSpans/spanDetails/utils'; +import {usePerformanceGeneralProjectSettings} from 'sentry/views/performance/utils'; import type {TraceTree} from '../../../../traceModels/traceTree'; import type {TraceTreeNode} from '../../../../traceModels/traceTreeNode'; @@ -167,6 +176,8 @@ export function SpanDescription({ )} + ) : resolvedModule === ModuleName.RESOURCE && span.op === 'resource.img' ? ( + ) : ( {formattedDescription ? ( @@ -201,6 +212,112 @@ export function SpanDescription({ ); } +function ResourceImageDescription({ + formattedDescription, + node, +}: { + formattedDescription: string; + node: TraceTreeNode; +}) { + const projectID = node.event?.projectID ? Number(node.event?.projectID) : undefined; + const span = node.value; + + const {data: settings, isPending: isSettingsLoading} = + usePerformanceGeneralProjectSettings(Number(projectID)); + const isImagesEnabled = settings?.enable_images ?? false; + + const [showLinks, setShowLinks] = useLocalStorageState(LOCAL_STORAGE_SHOW_LINKS, false); + const size = span?.data?.['http.decoded_response_content_length']; + + return ( + + {isSettingsLoading ? ( + + ) : !isImagesEnabled ? ( + setShowLinks(true)} + projectSlug={span.project_slug} + /> + ) : ( + + )} + + ); +} + +function ResourceImage(props: { + fileName: string; + showImage: boolean; + size: number; + src: string; +}) { + const [hasError, setHasError] = useState(false); + + const {fileName, size, src, showImage = true} = props; + const isRelativeUrl = src.startsWith('/'); + + return ( + + + + {fileName} () + + + + {showImage && !isRelativeUrl && !hasError ? ( + + setHasError(true)} + src={src} + style={{ + width: '100%', + height: '100%', + objectFit: 'contain', + objectPosition: 'center', + }} + /> + + ) : ( + + )} + + ); +} + +const FilenameContainer = styled('div')` + width: 100%; + display: flex; + align-items: baseline; + gap: ${space(1)}; + justify-content: space-between; +`; + +const ImageWrapper = styled('div')` + width: 200px; + height: 180px; + margin: auto; +`; + +const ImageContainer = styled('div')` + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: ${space(0.5)}; +`; + const CodeSnippetWrapper = styled('div')` display: flex; flex-direction: column; @@ -363,3 +480,8 @@ const DescriptionWrapper = styled('div')` word-break: break-word; padding: ${space(1)}; `; + +const StyledDescriptionWrapper = styled(DescriptionWrapper)` + padding: ${space(1)}; + justify-content: center; +`;