Browse Source

feat(new-trace-drawer): Adding multi column layout to cards (#70179)

https://github.com/getsentry/sentry/assets/60121741/a83247bd-c58c-41a7-ae5b-e2767e69b04e

---------

Co-authored-by: Abdullah Khan <abdullahkhan@PG9Y57YDXQ.local>
Abdkhan14 10 months ago
parent
commit
f37fe60c22

+ 11 - 8
static/app/components/events/eventTags/util.tsx

@@ -179,17 +179,20 @@ const ISSUE_DETAILS_COLUMN_BREAKPOINTS = [
  * accurately describe the available space.
  */
 export function useIssueDetailsColumnCount(elementRef: RefObject<HTMLElement>): number {
-  const [columnCount, setColumnCount] = useState(1);
-
-  const element = elementRef.current;
-
-  const onResize = useCallback(() => {
-    const width = element?.clientWidth || 0;
+  const calculateColumnCount = useCallback(() => {
+    const width = elementRef.current?.clientWidth || 0;
     const breakpoint = ISSUE_DETAILS_COLUMN_BREAKPOINTS.find(
       ({minWidth}) => width >= minWidth
     );
-    setColumnCount(breakpoint?.columnCount ?? 1);
-  }, [element]);
+    return breakpoint?.columnCount ?? 1;
+  }, [elementRef]);
+
+  const [columnCount, setColumnCount] = useState(calculateColumnCount());
+
+  const onResize = useCallback(() => {
+    const count = calculateColumnCount();
+    setColumnCount(count);
+  }, [calculateColumnCount]);
 
   useResizeObserver({ref: elementRef, onResize});
 

+ 1 - 1
static/app/views/performance/newTraceDetails/trace.spec.tsx

@@ -39,7 +39,7 @@ class MockResizeObserver {
   }
 
   unobserve(_element: HTMLElement) {
-    throw new Error('not implemented');
+    return;
   }
 
   observe(element: HTMLElement) {

+ 2 - 2
static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx

@@ -109,7 +109,7 @@ export function SpanNodeDetails({
                 {issues.length > 0 ? (
                   <IssueList organization={organization} issues={issues} node={node} />
                 ) : null}
-                <div>
+                <TraceDrawerComponents.SectionCardGroup>
                   <SpanDescription
                     node={node}
                     organization={organization}
@@ -124,7 +124,7 @@ export function SpanNodeDetails({
                   <SpanHTTPInfo span={node.value} />
                   <Tags span={node.value} />
                   <SpanKeys node={node} />
-                </div>
+                </TraceDrawerComponents.SectionCardGroup>
                 {node.value._metrics_summary ? (
                   <CustomMetricsEventData
                     projectId={project?.id || ''}

+ 42 - 1
static/app/views/performance/newTraceDetails/traceDrawer/details/styles.tsx

@@ -1,4 +1,11 @@
-import {Fragment, type PropsWithChildren, useMemo, useState} from 'react';
+import {
+  Children,
+  Fragment,
+  type PropsWithChildren,
+  useMemo,
+  useRef,
+  useState,
+} from 'react';
 import styled from '@emotion/styled';
 import type {LocationDescriptor} from 'history';
 import startCase from 'lodash/startCase';
@@ -7,6 +14,7 @@ import * as qs from 'query-string';
 import {Button} from 'sentry/components/button';
 import {CopyToClipboardButton} from 'sentry/components/copyToClipboardButton';
 import {DropdownMenu, type MenuItemProps} from 'sentry/components/dropdownMenu';
+import {useIssueDetailsColumnCount} from 'sentry/components/events/eventTags/util';
 import {DataSection} from 'sentry/components/events/styles';
 import FileSize from 'sentry/components/fileSize';
 import type {LazyRenderProps} from 'sentry/components/lazyRender';
@@ -592,6 +600,37 @@ function SectionCard({
   );
 }
 
+function SectionCardGroup({children}: {children: React.ReactNode}) {
+  const containerRef = useRef<HTMLDivElement>(null);
+  const columnCount = useIssueDetailsColumnCount(containerRef);
+
+  const columns: React.ReactNode[] = [];
+  const cards = Children.toArray(children);
+
+  // Evenly distributing the cards into columns.
+  const columnSize = Math.ceil(cards.length / columnCount);
+  for (let i = 0; i < cards.length; i += columnSize) {
+    columns.push(<CardsColumn key={i}>{cards.slice(i, i + columnSize)}</CardsColumn>);
+  }
+
+  return (
+    <CardsWrapper columnCount={columnCount} ref={containerRef}>
+      {columns}
+    </CardsWrapper>
+  );
+}
+
+const CardsWrapper = styled('div')<{columnCount: number}>`
+  display: grid;
+  align-items: start;
+  grid-template-columns: repeat(${p => p.columnCount}, 1fr);
+  gap: 10px;
+`;
+
+const CardsColumn = styled('div')`
+  grid-column: span 1;
+`;
+
 function Description({
   value,
   linkTarget,
@@ -627,6 +666,7 @@ const DescriptionText = styled('span')`
 `;
 
 const Card = styled(Panel)`
+  margin-bottom: 10px;
   padding: ${space(0.75)};
   font-size: ${p => p.theme.fontSizeSmall};
 `;
@@ -692,6 +732,7 @@ const TraceDrawerComponents = {
   IssuesLink,
   SectionCard,
   Description,
+  SectionCardGroup,
 };
 
 export {TraceDrawerComponents};

+ 2 - 2
static/app/views/performance/newTraceDetails/traceDrawer/details/transaction/index.tsx

@@ -125,7 +125,7 @@ export function TransactionNodeDetails({
 
       <IssueList node={node} organization={organization} issues={issues} />
 
-      <div>
+      <TraceDrawerComponents.SectionCardGroup>
         <GeneralInfo
           node={node}
           onParentClick={onParentClick}
@@ -136,7 +136,7 @@ export function TransactionNodeDetails({
         <AdditionalData event={event} />
         <Measurements event={event} location={location} organization={organization} />
         <Sdk event={event} />
-      </div>
+      </TraceDrawerComponents.SectionCardGroup>
 
       <Request event={event} />
 

+ 2 - 2
static/app/views/performance/newTraceDetails/traceDrawer/details/transaction/sections/request.tsx

@@ -108,7 +108,7 @@ export function Request({event}: {event: EventTransaction}) {
       className="request"
     >
       {view === 'formatted' ? (
-        <Fragment>
+        <TraceDrawerComponents.SectionCardGroup>
           {defined(data.query) && Object.keys(data.query).length > 0 ? (
             <TraceDrawerComponents.SectionCard
               items={getRequestSectionItems(data.query, meta?.query)}
@@ -152,7 +152,7 @@ export function Request({event}: {event: EventTransaction}) {
               title={t('Environment')}
             />
           ) : null}
-        </Fragment>
+        </TraceDrawerComponents.SectionCardGroup>
       ) : (
         <TraceDrawerComponents.SectionCard items={curlItems} title={t('cURL')} />
       )}