Browse Source

ref(replays): Refactor the replay layout impl to use more gap + grid (#48874)

Uses grid a little more instead of margins, this helps to show a little
more of the `outline`, but only on one side.

| Note | Before | After |
| --- | --- | --- |
| Gap instead of margin between |
![before](https://github.com/getsentry/sentry/assets/187460/f57bf83a-5ceb-4105-8054-d9fa4d652e57)
|
![after](https://github.com/getsentry/sentry/assets/187460/293b4888-24c4-4ea6-a07e-9b84a5ee4fb0)
|
| From flex to grid | ![before -
flex](https://github.com/getsentry/sentry/assets/187460/e07541cf-2bf5-400d-bcee-542825ace388)
| ![after -
grid](https://github.com/getsentry/sentry/assets/187460/76b7a101-8bac-442a-a01b-ec6da67a7d5c)
|
| 3/4 outline sides work great | ![before -
outline](https://github.com/getsentry/sentry/assets/187460/7ca76458-80f3-49fa-8854-051df3781efc)
| ![after -
outline](https://github.com/getsentry/sentry/assets/187460/e69acdb4-742e-41bb-bdac-6e2b61204538)


Test Notes:

I checked that overflow & scrolling continue to work for each of the
FocusArea tabs.
The Issues tab did need a new wrapper around it (without the wrapper the
table title was getting really tall)
Also, I checked that the Breadcrumbs and Tags sections scroll and work
well.
The Tags section is simpler now with a flex layout and one less div than
before.
Ryan Albrecht 1 year ago
parent
commit
c4d27813ea

+ 6 - 2
static/app/components/replays/breadcrumbs/replayTimeline.tsx

@@ -33,7 +33,7 @@ function ReplayTimeline({}: Props) {
   const networkSpans = replay.getNetworkSpans();
 
   return (
-    <Panel ref={elem} {...mouseTrackingProps}>
+    <StyledPanel ref={elem} {...mouseTrackingProps}>
       <Resizeable>
         {({width}) => (
           <Stacked>
@@ -58,10 +58,14 @@ function ReplayTimeline({}: Props) {
           </Stacked>
         )}
       </Resizeable>
-    </Panel>
+    </StyledPanel>
   );
 }
 
+const StyledPanel = styled(Panel)`
+  margin: 0;
+`;
+
 const UnderTimestamp = styled('div')<{paddingTop: string}>`
   /* Weird size to put equal space above/below a <small> node that MajorGridlines emits */
   padding-top: ${p => p.paddingTop};

+ 3 - 3
static/app/views/replays/detail/console/index.tsx

@@ -13,7 +13,7 @@ import type {Crumb} from 'sentry/types/breadcrumbs';
 import ConsoleFilters from 'sentry/views/replays/detail/console/consoleFilters';
 import ConsoleLogRow from 'sentry/views/replays/detail/console/consoleLogRow';
 import useConsoleFilters from 'sentry/views/replays/detail/console/useConsoleFilters';
-import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
+import FluidGrid from 'sentry/views/replays/detail/layout/fluidGrid';
 import NoRowRenderer from 'sentry/views/replays/detail/noRowRenderer';
 import TabItemContainer from 'sentry/views/replays/detail/tabItemContainer';
 import useVirtualizedList from 'sentry/views/replays/detail/useVirtualizedList';
@@ -81,7 +81,7 @@ function Console({breadcrumbs, startTimestampMs}: Props) {
   };
 
   return (
-    <FluidHeight>
+    <FluidGrid>
       <ConsoleFilters breadcrumbs={breadcrumbs} {...filterProps} />
       <TabItemContainer>
         {breadcrumbs ? (
@@ -111,7 +111,7 @@ function Console({breadcrumbs, startTimestampMs}: Props) {
           <Placeholder height="100%" />
         )}
       </TabItemContainer>
-    </FluidHeight>
+    </FluidGrid>
   );
 }
 

+ 3 - 3
static/app/views/replays/detail/domMutations/index.tsx

@@ -14,7 +14,7 @@ import type ReplayReader from 'sentry/utils/replays/replayReader';
 import DomFilters from 'sentry/views/replays/detail/domMutations/domFilters';
 import DomMutationRow from 'sentry/views/replays/detail/domMutations/domMutationRow';
 import useDomFilters from 'sentry/views/replays/detail/domMutations/useDomFilters';
-import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
+import FluidGrid from 'sentry/views/replays/detail/layout/fluidGrid';
 import NoRowRenderer from 'sentry/views/replays/detail/noRowRenderer';
 import TabItemContainer from 'sentry/views/replays/detail/tabItemContainer';
 import useVirtualizedList from 'sentry/views/replays/detail/useVirtualizedList';
@@ -71,7 +71,7 @@ function DomMutations({replay, startTimestampMs}: Props) {
   };
 
   return (
-    <FluidHeight>
+    <FluidGrid>
       <DomFilters actions={actions} {...filterProps} />
       <TabItemContainer>
         {isLoading || !actions ? (
@@ -101,7 +101,7 @@ function DomMutations({replay, startTimestampMs}: Props) {
           </AutoSizer>
         )}
       </TabItemContainer>
-    </FluidHeight>
+    </FluidGrid>
   );
 }
 

+ 0 - 1
static/app/views/replays/detail/filtersGrid.tsx

@@ -9,7 +9,6 @@ const FiltersGrid = styled('div')`
   grid-template-columns:
     repeat(${p => Children.toArray(p.children).length - 1}, max-content)
     1fr;
-  margin-bottom: ${space(1)};
   @media (max-width: ${p => p.theme.breakpoints.small}) {
     margin-top: ${space(1)};
   }

+ 25 - 22
static/app/views/replays/detail/issueList.tsx

@@ -17,6 +17,7 @@ import theme from 'sentry/utils/theme';
 import useApi from 'sentry/utils/useApi';
 import useMedia from 'sentry/utils/useMedia';
 import useOrganization from 'sentry/utils/useOrganization';
+import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
 
 type Props = {
   projectId: string;
@@ -83,28 +84,30 @@ function IssueList({projectId, replayId}: Props) {
   });
 
   return (
-    <ReplayCountContext.Provider value={counts}>
-      <StyledPanelTable
-        isEmpty={state.issues.length === 0}
-        emptyMessage={t('No Issues are related')}
-        isLoading={state.fetching}
-        headers={
-          isScreenLarge ? columns : columns.filter(column => column !== t('Graph'))
-        }
-      >
-        {state.issues
-          // prioritize the replay issues first
-          .sort(a => (a.project.id === projectId ? -1 : 1))
-          .map(issue => (
-            <TableRow
-              key={issue.id}
-              isScreenLarge={isScreenLarge}
-              issue={issue}
-              organization={organization}
-            />
-          )) || null}
-      </StyledPanelTable>
-    </ReplayCountContext.Provider>
+    <FluidHeight>
+      <ReplayCountContext.Provider value={counts}>
+        <StyledPanelTable
+          isEmpty={state.issues.length === 0}
+          emptyMessage={t('No Issues are related')}
+          isLoading={state.fetching}
+          headers={
+            isScreenLarge ? columns : columns.filter(column => column !== t('Graph'))
+          }
+        >
+          {state.issues
+            // prioritize the replay issues first
+            .sort(a => (a.project.id === projectId ? -1 : 1))
+            .map(issue => (
+              <TableRow
+                key={issue.id}
+                isScreenLarge={isScreenLarge}
+                issue={issue}
+                organization={organization}
+              />
+            )) || null}
+        </StyledPanelTable>
+      </ReplayCountContext.Provider>
+    </FluidHeight>
   );
 }
 

+ 16 - 0
static/app/views/replays/detail/layout/fluidGrid.tsx

@@ -0,0 +1,16 @@
+import styled from '@emotion/styled';
+
+import {space} from 'sentry/styles/space';
+
+/**
+ * The default grid template is `max-content 1fr`, feel free to extend the
+ * component with `styled()` and override it.
+ */
+const FluidGrid = styled('section')`
+  display: grid;
+  grid-template-rows: max-content 1fr;
+  gap: ${space(1)};
+  height: 100%;
+`;
+
+export default FluidGrid;

+ 0 - 33
static/app/views/replays/detail/layout/fluidPanel.tsx

@@ -1,33 +0,0 @@
-import {LegacyRef, ReactChild} from 'react';
-import styled from '@emotion/styled';
-
-type Props = {
-  children: ReactChild;
-  bodyRef?: LegacyRef<HTMLDivElement> | undefined;
-  bottom?: ReactChild;
-  className?: string;
-  title?: ReactChild;
-};
-
-function FluidPanel({className, children, bottom, title, bodyRef}: Props) {
-  return (
-    <FluidContainer className={className}>
-      {title}
-      <OverflowBody ref={bodyRef}>{children}</OverflowBody>
-      {bottom}
-    </FluidContainer>
-  );
-}
-
-const FluidContainer = styled('section')`
-  display: grid;
-  grid-template-rows: auto 1fr auto;
-  height: 100%;
-`;
-
-const OverflowBody = styled('div')`
-  height: 100%;
-  overflow: auto;
-`;
-
-export default FluidPanel;

+ 8 - 12
static/app/views/replays/detail/layout/index.tsx

@@ -6,8 +6,8 @@ import ReplayView from 'sentry/components/replays/replayView';
 import {space} from 'sentry/styles/space';
 import useFullscreen from 'sentry/utils/replays/hooks/useFullscreen';
 import {LayoutKey} from 'sentry/utils/replays/hooks/useReplayLayout';
+import FluidGrid from 'sentry/views/replays/detail/layout/fluidGrid';
 import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
-import FluidPanel from 'sentry/views/replays/detail/layout/fluidPanel';
 import FocusArea from 'sentry/views/replays/detail/layout/focusArea';
 import FocusTabs from 'sentry/views/replays/detail/layout/focusTabs';
 import MeasureSize from 'sentry/views/replays/detail/layout/measureSize';
@@ -56,17 +56,19 @@ function ReplayLayout({layout = LayoutKey.topbar}: Props) {
 
   const focusArea = (
     <ErrorBoundary mini>
-      <FluidPanel title={<SmallMarginFocusTabs />}>
+      <FluidGrid>
+        <FocusTabs />
         <FocusArea />
-      </FluidPanel>
+      </FluidGrid>
     </ErrorBoundary>
   );
 
   const sidebarArea = (
     <ErrorBoundary mini>
-      <FluidPanel title={<SmallMarginSideTabs />}>
+      <FluidGrid>
+        <SideTabs />
         <SidebarArea />
-      </FluidPanel>
+      </FluidGrid>
     </ErrorBoundary>
   );
 
@@ -167,18 +169,12 @@ const BodyContent = styled('main')`
   width: 100%;
   height: 100%;
   display: grid;
+  gap: ${space(2)};
   grid-template-rows: auto 1fr;
   overflow: hidden;
   padding: ${space(2)};
 `;
 
-const SmallMarginFocusTabs = styled(FocusTabs)`
-  margin-bottom: ${space(1)};
-`;
-const SmallMarginSideTabs = styled(SideTabs)`
-  margin-bottom: ${space(1)};
-`;
-
 const VideoSection = styled(FluidHeight)`
   background: ${p => p.theme.background};
   gap: ${space(1)};

+ 3 - 2
static/app/views/replays/detail/network/index.tsx

@@ -11,6 +11,7 @@ import useCrumbHandlers from 'sentry/utils/replays/hooks/useCrumbHandlers';
 import useOrganization from 'sentry/utils/useOrganization';
 import {useResizableDrawer} from 'sentry/utils/useResizableDrawer';
 import useUrlParams from 'sentry/utils/useUrlParams';
+import FluidGrid from 'sentry/views/replays/detail/layout/fluidGrid';
 import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
 import NetworkDetails from 'sentry/views/replays/detail/network/details';
 import {ReqRespBodiesAlert} from 'sentry/views/replays/detail/network/details/onboarding';
@@ -172,7 +173,7 @@ function NetworkList({
   };
 
   return (
-    <FluidHeight>
+    <FluidGrid>
       <NetworkFilters networkSpans={networkSpans} {...filterProps} />
       <Feature
         features={['session-replay-network-details']}
@@ -250,7 +251,7 @@ function NetworkList({
           </Feature>
         </SplitPanel>
       </NetworkTable>
-    </FluidHeight>
+    </FluidGrid>
   );
 }
 

+ 7 - 3
static/app/views/replays/detail/tagPanel/index.tsx

@@ -11,7 +11,7 @@ import ReplayTagsTableRow from 'sentry/components/replays/replayTagsTableRow';
 import {t} from 'sentry/locale';
 import useOrganization from 'sentry/utils/useOrganization';
 import {normalizeUrl} from 'sentry/utils/withDomainRequired';
-import FluidPanel from 'sentry/views/replays/detail/layout/fluidPanel';
+import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
 
 const notTags = [
   'browser.name',
@@ -61,7 +61,7 @@ function TagPanel() {
 
   return (
     <Panel>
-      <FluidPanel>
+      <OverflowFluidHeight>
         {tags.length ? (
           <KeyValueTable noMargin>
             {tags.map(([key, values]) => (
@@ -76,7 +76,7 @@ function TagPanel() {
         ) : (
           <EmptyMessage>{t('No tags for this replay were found.')}</EmptyMessage>
         )}
-      </FluidPanel>
+      </OverflowFluidHeight>
     </Panel>
   );
 }
@@ -88,4 +88,8 @@ const Panel = styled(BasePanel)`
   margin-bottom: 0;
 `;
 
+const OverflowFluidHeight = styled(FluidHeight)`
+  overflow: auto;
+`;
+
 export default TagPanel;