From 3d6f51611d2437650bf022a7067b61ed99906a2c Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Tue, 3 Sep 2024 15:09:16 -0500 Subject: [PATCH] fix(sidebar): restore feature flag --- static/app/components/demo/demoHeader.tsx | 8 +- static/app/components/sidebar/index.tsx | 114 +++++++++++++----- static/app/components/sidebar/sidebarItem.tsx | 57 +++++++-- .../app/components/sidebar/sidebarPanel.tsx | 8 +- .../utils/replays/hooks/useReplayLayout.tsx | 3 +- static/app/utils/theme.tsx | 6 +- .../app/views/replays/detail/layout/utils.tsx | 8 +- static/less/layout.less | 4 +- 8 files changed, 160 insertions(+), 48 deletions(-) diff --git a/static/app/components/demo/demoHeader.tsx b/static/app/components/demo/demoHeader.tsx index 3be364240fc74a..8b305e7b16964f 100644 --- a/static/app/components/demo/demoHeader.tsx +++ b/static/app/components/demo/demoHeader.tsx @@ -95,7 +95,13 @@ const Wrapper = styled('div')<{collapsed: boolean}>` white-space: nowrap; gap: ${space(4)}; - margin-left: calc(-1 * ${p => p.theme.sidebar.width}); + margin-left: calc( + -1 * ${p => (p.collapsed ? p.theme.sidebar.collapsedWidth : p.theme.sidebar.expandedWidth)} + ); + + .sidebar-v2 & { + margin-left: calc(-1 * ${p => p.theme.sidebar.v2_width}); + } position: fixed; width: 100%; diff --git a/static/app/components/sidebar/index.tsx b/static/app/components/sidebar/index.tsx index 0b0b61aa12241d..90e11181b8e4d8 100644 --- a/static/app/components/sidebar/index.tsx +++ b/static/app/components/sidebar/index.tsx @@ -2,6 +2,7 @@ import {Fragment, useCallback, useContext, useEffect} from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; +import {hideSidebar, showSidebar} from 'sentry/actionCreators/preferences'; import Feature from 'sentry/components/acl/feature'; import GuideAnchor from 'sentry/components/assistant/guideAnchor'; import {Chevron} from 'sentry/components/chevron'; @@ -35,6 +36,7 @@ import {t} from 'sentry/locale'; import ConfigStore from 'sentry/stores/configStore'; import DemoWalkthroughStore from 'sentry/stores/demoWalkthroughStore'; import HookStore from 'sentry/stores/hookStore'; +import PreferencesStore from 'sentry/stores/preferencesStore'; import SidebarPanelStore from 'sentry/stores/sidebarPanelStore'; import {useLegacyStore} from 'sentry/stores/useLegacyStore'; import {space} from 'sentry/styles/space'; @@ -113,10 +115,12 @@ function useOpenOnboardingSidebar(organization?: Organization) { function Sidebar() { const location = useLocation(); + const preferences = useLegacyStore(PreferencesStore); const activePanel = useLegacyStore(SidebarPanelStore); const organization = useOrganization({allowNull: true}); const {shouldAccordionFloat} = useContext(ExpandedContext); - const hasNewNav = true; + const hasNewNav = organization?.features.includes('navigation-sidebar-v2') ?? false; + const collapsed = hasNewNav ? true : !!preferences.collapsed; const hasOrganization = !!organization; const isSelfHostedErrorsOnly = ConfigStore.get('isSelfHostedErrorsOnly'); @@ -130,7 +134,7 @@ function Sidebar() { hasPanel, organization, hasNewNav, - collapsed: true, + collapsed, }; // Avoid showing superuser UI on self-hosted instances const showSuperuserWarning = () => { @@ -144,7 +148,13 @@ function Sidebar() { useOpenOnboardingSidebar(); - const toggleCollapse = useCallback(() => {}, []); + const toggleCollapse = useCallback(() => { + if (collapsed) { + showSidebar(); + } else { + hideSidebar(); + } + }, [collapsed]); // Close panel on any navigation useEffect(() => void hidePanel(), [location?.pathname]); @@ -165,17 +175,30 @@ function Sidebar() { }); }, [location?.hash]); + // Add sidebar collapse classname to body + useEffect(() => { + const bcl = document.body.classList; + + if (collapsed) { + bcl.add('collapsed'); + } else { + bcl.remove('collapsed'); + } + + return () => bcl.remove('collapsed'); + }, [collapsed]); + // Add sidebar hasNewNav classname to body useEffect(() => { const bcl = document.body.classList; if (hasNewNav) { - bcl.add('hasNewNav'); + bcl.add('sidebar-v2'); } else { - bcl.remove('hasNewNav'); + bcl.remove('sidebar-v2'); } - return () => bcl.remove('hasNewNav'); + return () => bcl.remove('sidebar-v2'); }, [hasNewNav]); const sidebarAnchor = isDemoWalkthrough() ? ( @@ -217,7 +240,7 @@ function Sidebar() { > } + icon={} label={{t('Discover')}} to={getDiscoverLandingUrl(organization)} id="discover-v2" @@ -236,7 +259,7 @@ function Sidebar() { } to={`/organizations/${organization.slug}/${moduleURLBuilder('db')}/`} id="performance-database" - icon={} + icon={} /> ); @@ -250,7 +273,7 @@ function Sidebar() { } to={`/organizations/${organization.slug}/${moduleURLBuilder('http')}/`} id="performance-http" - icon={} + icon={} /> ); @@ -264,7 +287,7 @@ function Sidebar() { } to={`/organizations/${organization.slug}/${moduleURLBuilder('cache')}/`} id="performance-cache" - icon={} + icon={} /> ); @@ -278,7 +301,7 @@ function Sidebar() { } to={`/organizations/${organization.slug}/${moduleURLBuilder('vital')}/`} id="performance-webvitals" - icon={} + icon={} /> ); @@ -292,7 +315,7 @@ function Sidebar() { } to={`/organizations/${organization.slug}/${moduleURLBuilder('queue')}/`} id="performance-queues" - icon={} + icon={} /> ); @@ -313,7 +336,7 @@ function Sidebar() { label={MODULE_TITLES.screen_load} to={`/organizations/${organization.slug}/${moduleURLBuilder('screen_load')}/`} id="performance-mobile-screens" - icon={} + icon={} /> ); @@ -325,7 +348,7 @@ function Sidebar() { label={MODULE_TITLES.app_start} to={`/organizations/${organization.slug}/${moduleURLBuilder('app_start')}/`} id="performance-mobile-app-startup" - icon={} + icon={} /> ); @@ -341,7 +364,7 @@ function Sidebar() { label={MODULE_TITLES['mobile-ui']} to={`/organizations/${organization.slug}/${moduleURLBuilder('mobile-ui')}/`} id="performance-mobile-ui" - icon={} + icon={} isAlpha /> @@ -358,7 +381,7 @@ function Sidebar() { label={MODULE_TITLES['mobile-screens']} to={`/organizations/${organization.slug}/${moduleURLBuilder('mobile-screens')}/`} id="performance-mobile-screens" - icon={} + icon={} /> ); @@ -370,7 +393,7 @@ function Sidebar() { label={{MODULE_TITLES.resource}} to={`/organizations/${organization.slug}/${moduleURLBuilder('resource')}/`} id="performance-browser-resources" - icon={} + icon={} /> ); @@ -382,7 +405,7 @@ function Sidebar() { label={{t('Traces')}} to={`/organizations/${organization.slug}/traces/`} id="performance-trace-explorer" - icon={} + icon={} isBeta /> @@ -392,7 +415,7 @@ function Sidebar() { } + icon={} label={MODULE_TITLES.ai} to={`/organizations/${organization.slug}/${moduleURLBuilder('ai')}/`} id="llm-monitoring" @@ -484,7 +507,7 @@ function Sidebar() { > } + icon={} label={t('Replays')} to={`/organizations/${organization.slug}/replays/`} id="replays" @@ -497,7 +520,7 @@ function Sidebar() { const metrics = hasOrganization && hasCustomMetrics(organization) && ( } + icon={} label={t('Metrics')} to={metricsPath} search={location?.pathname === normalizeUrl(metricsPath) ? location.search : ''} @@ -534,7 +557,7 @@ function Sidebar() { } + icon={} label={t('Profiles')} to={`/organizations/${organization.slug}/profiling/`} id="profiling" @@ -605,17 +628,19 @@ function Sidebar() { ); - const collapsed = true; - return ( - + - + {showSuperuserWarning() && !isExcludedOrg() && ( @@ -630,8 +655,25 @@ function Sidebar() { {projects} - {!isSelfHostedErrorsOnly && ( - + {!isSelfHostedErrorsOnly && !hasNewNav && ( + + + {explore} + {insights} + + + {performance} + {feedback} + {monitors} + {alerts} + {dashboards} + {releases} + + + )} + + {!isSelfHostedErrorsOnly && hasNewNav && ( + {explore} {insights} {performance} @@ -781,8 +823,15 @@ export const SidebarWrapper = styled('nav')<{collapsed: boolean; hasNewNav?: boo background: ${p => p.theme.sidebarGradient}; color: ${p => p.theme.sidebar.color}; line-height: 1; - padding: 16px 8px; - width: ${p => p.theme.sidebar.width}; + padding: 12px 0 2px; /* Allows for 32px avatars */ + width: ${p => + p.theme.sidebar[ + p.hasNewNav + ? 'semiCollapsedWidth' + : p.collapsed + ? 'collapsedWidth' + : 'expandedWidth' + ]}; position: fixed; top: ${p => (ConfigStore.get('demoMode') ? p.theme.demo.headerSize : 0)}; left: 0; @@ -792,6 +841,11 @@ export const SidebarWrapper = styled('nav')<{collapsed: boolean; hasNewNav?: boo border-right: solid 1px ${p => p.theme.sidebarBorder}; ${responsiveFlex}; + .sidebar-v2 & { + padding: ${space(1)} ${space(0.75)}; + width: ${p => p.theme.sidebar.v2_width}; + } + @media (max-width: ${p => p.theme.breakpoints.medium}) { top: 0; left: 0; diff --git a/static/app/components/sidebar/sidebarItem.tsx b/static/app/components/sidebar/sidebarItem.tsx index 2d78dbebf1e8f7..e34aa95c218074 100644 --- a/static/app/components/sidebar/sidebarItem.tsx +++ b/static/app/components/sidebar/sidebarItem.tsx @@ -387,19 +387,44 @@ const StyledSidebarItem = styled(Link, { shouldForwardProp: p => typeof p === 'string' && isPropValid(p), })` display: flex; - align-self: center; - justify-content: center; color: ${p => (p.isInFloatingAccordion ? p.theme.gray400 : 'inherit')}; position: relative; cursor: pointer; - font-size: 11px; - height: 52px; - width: 100%; + font-size: 15px; + height: ${p => (p.isInFloatingAccordion ? '35px' : p.hasNewNav ? '40px' : '30px')}; flex-shrink: 0; - flex-grow: 1; border-radius: ${p => p.theme.borderRadius}; transition: none; + ${p => + !p.hasNewNav && + css` + &:before { + display: block; + content: ''; + position: absolute; + top: 4px; + left: calc(-${space(2)} - 1px); + bottom: 6px; + width: 5px; + border-radius: 0 3px 3px 0; + background-color: transparent; + transition: 0.15s background-color linear; + } + `} + + @media (max-width: ${p => p.theme.breakpoints.medium}) { + &:before { + top: auto; + left: 5px; + bottom: -12px; + height: 5px; + width: auto; + right: 5px; + border-radius: 3px 3px 0 0; + } + } + &:hover, &:focus-visible { ${p => { @@ -424,6 +449,15 @@ const StyledSidebarItem = styled(Link, { box-shadow: inset 0 0 0 2px ${p => p.theme.purple300}; } + .sidebar-v2 & { + font-size: 11px; + align-self: center; + justify-content: center; + height: 52px; + width: 100%; + flex-grow: 1; + } + ${getActiveStyle}; `; @@ -524,7 +558,12 @@ const CollapsedFeatureBadge = styled(FeatureBadge)` `; const StyledInteractionStateLayer = styled(InteractionStateLayer)` - height: 53px; - width: 58px; - border-radius: ${p => p.theme.borderRadius}; + height: ${16 * 2 + 40}px; + width: 70px; + + .sidebar-v2 & { + height: 53px; + width: 58px; + border-radius: ${p => p.theme.borderRadius}; + } `; diff --git a/static/app/components/sidebar/sidebarPanel.tsx b/static/app/components/sidebar/sidebarPanel.tsx index e5e8f8357fc8cf..2f154f813dc27a 100644 --- a/static/app/components/sidebar/sidebarPanel.tsx +++ b/static/app/components/sidebar/sidebarPanel.tsx @@ -35,7 +35,13 @@ const PanelContainer = styled('div')` : css` width: 460px; top: 0; - left: ${p.theme.sidebar.width}; + left: ${p.collapsed + ? p.theme.sidebar.collapsedWidth + : p.theme.sidebar.expandedWidth}; + + .sidebar-v2 & { + left: ${p.theme.sidebar.v2_width}; + } `}; `; diff --git a/static/app/utils/replays/hooks/useReplayLayout.tsx b/static/app/utils/replays/hooks/useReplayLayout.tsx index 5abe5b8320c129..2e22d2ed630d60 100644 --- a/static/app/utils/replays/hooks/useReplayLayout.tsx +++ b/static/app/utils/replays/hooks/useReplayLayout.tsx @@ -68,8 +68,9 @@ function isLayout(val: string): val is LayoutKey { function useReplayLayout() { const collapsed = !!useLegacyStore(PreferencesStore).collapsed; - const defaultLayout = getDefaultLayout(collapsed); const organization = useOrganization(); + const hasNewNav = organization?.features.includes('navigation-sidebar-v2') ?? false; + const defaultLayout = getDefaultLayout(collapsed, hasNewNav); const {getParamValue, setParamValue} = useUrlParams('l_page', defaultLayout); diff --git a/static/app/utils/theme.tsx b/static/app/utils/theme.tsx index 3b5ea26d34928a..843801555090a0 100644 --- a/static/app/utils/theme.tsx +++ b/static/app/utils/theme.tsx @@ -806,8 +806,10 @@ const commonTheme = { badgeSize: '22px', smallBadgeSize: '11px', collapsedWidth: '70px', - width: '80px', - panelWidth: '150px', + semiCollapsedWidth: '100px', + expandedWidth: '220px', + v2_width: '80px', + v2_panelWidth: '150px', mobileHeightNumber: 54, mobileHeight: '54px', menuSpacing: '15px', diff --git a/static/app/views/replays/detail/layout/utils.tsx b/static/app/views/replays/detail/layout/utils.tsx index 4700a9d4c4982f..4610fdfa0e0391 100644 --- a/static/app/views/replays/detail/layout/utils.tsx +++ b/static/app/views/replays/detail/layout/utils.tsx @@ -1,10 +1,14 @@ import {LayoutKey} from 'sentry/utils/replays/hooks/useReplayLayout'; import theme from 'sentry/utils/theme'; -export const getDefaultLayout = (_collapsed: boolean): LayoutKey => { +export const getDefaultLayout = (collapsed: boolean, hasNewNav: boolean): LayoutKey => { const {innerWidth, innerHeight} = window; - const sidebarWidth = parseInt(theme.sidebar.width, 10); + let width = collapsed ? theme.sidebar.collapsedWidth : theme.sidebar.expandedWidth; + if (hasNewNav) { + width = theme.sidebar.v2_width; + } + const sidebarWidth = parseInt(width, 10); const mediumScreenWidth = parseInt(theme.breakpoints.medium, 10); diff --git a/static/less/layout.less b/static/less/layout.less index f42b2d1f8ad130..5dcb6a6b8b71d3 100644 --- a/static/less/layout.less +++ b/static/less/layout.less @@ -8,7 +8,7 @@ body { padding-left: @sidebar-collapsed-width; } - &.hasNewNav { + &.sidebar-v2 { padding-left: @sidebar-v2-width; } } @@ -44,7 +44,7 @@ body.narrow { padding-left: @sidebar-collapsed-width; } - &.hasNewNav { + &.sidebar-v2 { padding-left: calc(@sidebar-v2-width + @sidebar-v2-panel-width); &.collapsed {