Skip to content

Commit

Permalink
ref(ui): Replace various tabs w/ modern tabs (#83120)
Browse files Browse the repository at this point in the history
  • Loading branch information
evanpurkhiser authored and andrewshie-sentry committed Jan 22, 2025
1 parent d9be513 commit 13a41bb
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 94 deletions.
26 changes: 5 additions & 21 deletions static/app/components/layouts/thirds.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from '@emotion/styled';

import NavTabs from 'sentry/components/navTabs';
import {Tabs} from 'sentry/components/tabs';
import {space} from 'sentry/styles/space';

/**
Expand Down Expand Up @@ -95,27 +95,11 @@ export const Title = styled('h1')<{withMargins?: boolean}>`
`;

/**
* Styled Nav Tabs for use inside a Layout.Header component
* Styled Tabs for use inside a Layout.Header component
*/
export const HeaderNavTabs = styled(NavTabs)`
margin: 0;
border-bottom: 0 !important;
& > li {
margin-right: ${space(3)};
}
& > li > a {
display: flex;
align-items: center;
height: 1.25rem;
padding: ${space(1)} 0;
margin-bottom: 4px;
box-sizing: content-box;
}
& > li.active > a {
margin-bottom: 0;
}
`;
export const HeaderTabs = styled(Tabs)`
grid-column: 1 / -1;
` as typeof Tabs;

/**
* Base container for 66/33 containers.
Expand Down
31 changes: 18 additions & 13 deletions static/app/views/alerts/list/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import {LinkButton} from 'sentry/components/button';
import ButtonBar from 'sentry/components/buttonBar';
import CreateAlertButton from 'sentry/components/createAlertButton';
import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton';
import GlobalSelectionLink from 'sentry/components/globalSelectionLink';
import * as Layout from 'sentry/components/layouts/thirds';
import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionTooltip';
import {TabList} from 'sentry/components/tabs';
import {IconSettings} from 'sentry/icons';
import {t} from 'sentry/locale';
import ProjectsStore from 'sentry/stores/projectsStore';
import type {InjectedRouter} from 'sentry/types/legacyReactRouter';
import normalizeUrl from 'sentry/utils/url/normalizeUrl';
import useOrganization from 'sentry/utils/useOrganization';
import usePageFilters from 'sentry/utils/usePageFilters';

Expand All @@ -31,11 +32,12 @@ function AlertHeader({router, activeTab}: Props) {
};

const alertRulesLink = (
<li className={activeTab === 'rules' ? 'active' : ''}>
<GlobalSelectionLink to={`/organizations/${organization.slug}/alerts/rules/`}>
{t('Alert Rules')}
</GlobalSelectionLink>
</li>
<TabList.Item
key="rules"
to={normalizeUrl(`/organizations/${organization.slug}/alerts/rules/`)}
>
{t('Alert Rules')}
</TabList.Item>
);

return (
Expand Down Expand Up @@ -78,14 +80,17 @@ function AlertHeader({router, activeTab}: Props) {
/>
</ButtonBar>
</Layout.HeaderActions>
<Layout.HeaderNavTabs underlined>
{alertRulesLink}
<li className={activeTab === 'stream' ? 'active' : ''}>
<GlobalSelectionLink to={`/organizations/${organization.slug}/alerts/`}>
<Layout.HeaderTabs value={activeTab}>
<TabList hideBorder>
{alertRulesLink}
<TabList.Item
key="stream"
to={normalizeUrl(`/organizations/${organization.slug}/alerts/`)}
>
{t('History')}
</GlobalSelectionLink>
</li>
</Layout.HeaderNavTabs>
</TabList.Item>
</TabList>
</Layout.HeaderTabs>
</Layout.Header>
);
}
Expand Down
20 changes: 6 additions & 14 deletions static/app/views/discover/resultsHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,12 @@ class ResultsHeader extends Component<Props, State> {
>
{({hasFeature}) =>
hasFeature && (
<DatasetSelectorWrapper>
<DatasetSelectorTabs
eventView={eventView}
isHomepage={isHomepage}
savedQuery={savedQuery}
splitDecision={splitDecision}
/>
</DatasetSelectorWrapper>
<DatasetSelectorTabs
eventView={eventView}
isHomepage={isHomepage}
savedQuery={savedQuery}
splitDecision={splitDecision}
/>
)
}
</Feature>
Expand All @@ -269,10 +267,4 @@ const BannerWrapper = styled('div')`
grid-column: 1 / -1;
`;

// Force the dataset selector to have the entire width of the grid
// so it doesn't go into the overflow menu state when the window is small
const DatasetSelectorWrapper = styled('div')`
grid-column: 1 / -1;
`;

export default withApi(ResultsHeader);
7 changes: 4 additions & 3 deletions static/app/views/discover/savedQuery/datasetSelectorTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {TabList, Tabs} from 'sentry/components/tabs';
import * as Layout from 'sentry/components/layouts/thirds';
import {TabList} from 'sentry/components/tabs';
import {t} from 'sentry/locale';
import type {SavedQuery} from 'sentry/types/organization';
import type EventView from 'sentry/utils/discover/eventView';
Expand Down Expand Up @@ -126,7 +127,7 @@ export function DatasetSelectorTabs(props: Props) {
}

return (
<Tabs
<Layout.HeaderTabs
value={value}
onChange={newValue => {
const {to: nextEventView, modifiedQuery} = getValidEventViewForDataset(
Expand Down Expand Up @@ -156,6 +157,6 @@ export function DatasetSelectorTabs(props: Props) {
<TabList.Item key={option.value}>{option.label}</TabList.Item>
))}
</TabList>
</Tabs>
</Layout.HeaderTabs>
);
}
6 changes: 3 additions & 3 deletions static/app/views/insights/pages/domainViewHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {Breadcrumbs, type Crumb} from 'sentry/components/breadcrumbs';
import ButtonBar from 'sentry/components/buttonBar';
import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton';
import * as Layout from 'sentry/components/layouts/thirds';
import {TabList, Tabs} from 'sentry/components/tabs';
import {TabList} from 'sentry/components/tabs';
import type {TabListItemProps} from 'sentry/components/tabs/item';
import {IconBusiness} from 'sentry/icons';
import {space} from 'sentry/styles/space';
Expand Down Expand Up @@ -85,7 +85,7 @@ export function DomainViewHeader({
{additonalHeaderActions}
</ButtonBar>
</Layout.HeaderActions>
<Tabs value={tabValue} onChange={tabs?.onTabChange}>
<Layout.HeaderTabs value={tabValue} onChange={tabs?.onTabChange}>
{!hideDefaultTabs && (
<TabList hideBorder>
{tabList.map(tab => (
Expand All @@ -94,7 +94,7 @@ export function DomainViewHeader({
</TabList>
)}
{hideDefaultTabs && tabs && tabs.tabList}
</Tabs>
</Layout.HeaderTabs>
</Layout.Header>
</Fragment>
);
Expand Down
36 changes: 22 additions & 14 deletions static/app/views/organizationStats/header.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {FeatureFeedback} from 'sentry/components/featureFeedback';
import * as Layout from 'sentry/components/layouts/thirds';
import Link from 'sentry/components/links/link';
import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionTooltip';
import {TabList} from 'sentry/components/tabs';
import {t} from 'sentry/locale';
import type {Organization} from 'sentry/types/organization';
import normalizeUrl from 'sentry/utils/url/normalizeUrl';

type Props = {
activeTab: 'stats' | 'issues' | 'health';
Expand All @@ -29,21 +30,28 @@ function StatsHeader({organization, activeTab}: Props) {
<FeatureFeedback buttonProps={{size: 'sm'}} featureName="team-stats" />
)}
</Layout.HeaderActions>
<Layout.HeaderNavTabs underlined>
<li className={`${activeTab === 'stats' ? 'active' : ''}`}>
<Link to={`/organizations/${organization.slug}/stats/`}>{t('Usage')}</Link>
</li>
<li className={`${activeTab === 'issues' ? 'active' : ''}`}>
<Link to={`/organizations/${organization.slug}/stats/issues/`}>
<Layout.HeaderTabs value={activeTab}>
<TabList hideBorder>
<TabList.Item
key="stats"
to={normalizeUrl(`/organizations/${organization.slug}/stats/`)}
>
{t('Usage')}
</TabList.Item>
<TabList.Item
key="issues"
to={normalizeUrl(`/organizations/${organization.slug}/stats/issues/`)}
>
{t('Issues')}
</Link>
</li>
<li className={`${activeTab === 'health' ? 'active' : ''}`}>
<Link to={`/organizations/${organization.slug}/stats/health/`}>
</TabList.Item>
<TabList.Item
key="health"
to={normalizeUrl(`/organizations/${organization.slug}/stats/health/`)}
>
{t('Health')}
</Link>
</li>
</Layout.HeaderNavTabs>
</TabList.Item>
</TabList>
</Layout.HeaderTabs>
</Layout.Header>
);
}
Expand Down
35 changes: 13 additions & 22 deletions static/app/views/releases/detail/header/releaseHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import {CopyToClipboardButton} from 'sentry/components/copyToClipboardButton';
import IdBadge from 'sentry/components/idBadge';
import * as Layout from 'sentry/components/layouts/thirds';
import ExternalLink from 'sentry/components/links/externalLink';
import ListLink from 'sentry/components/links/listLink';
import NavTabs from 'sentry/components/navTabs';
import {TabList} from 'sentry/components/tabs';
import {Tooltip} from 'sentry/components/tooltip';
import Version from 'sentry/components/version';
import {URL_PARAM} from 'sentry/constants/pageFilters';
Expand All @@ -19,6 +18,7 @@ import {t} from 'sentry/locale';
import type {Organization} from 'sentry/types/organization';
import type {Release, ReleaseMeta, ReleaseProject} from 'sentry/types/release';
import {formatAbbreviatedNumber} from 'sentry/utils/formatters';
import normalizeUrl from 'sentry/utils/url/normalizeUrl';

import ReleaseActions from './releaseActions';

Expand Down Expand Up @@ -67,10 +67,11 @@ function ReleaseHeader({
},
];

const getTabUrl = (path: string) => ({
pathname: releasePath + path,
query: pick(location.query, Object.values(URL_PARAM)),
});
const getTabUrl = (path: string) =>
normalizeUrl({
pathname: releasePath + path,
query: pick(location.query, Object.values(URL_PARAM)),
});

const getActiveTabTo = () => {
// We are not doing strict version check because there would be a tiny page shift when switching between releases with paginator
Expand Down Expand Up @@ -131,19 +132,15 @@ function ReleaseHeader({
/>
</Layout.HeaderActions>

<Fragment>
<StyledNavTabs>
<Layout.HeaderTabs value={getActiveTabTo()}>
<TabList hideBorder>
{tabs.map(tab => (
<ListLink
key={tab.to}
to={getTabUrl(tab.to)}
isActive={() => getActiveTabTo() === tab.to}
>
<TabList.Item key={tab.to} to={getTabUrl(tab.to)}>
{tab.title}
</ListLink>
</TabList.Item>
))}
</StyledNavTabs>
</Fragment>
</TabList>
</Layout.HeaderTabs>
</Layout.Header>
);
}
Expand All @@ -162,12 +159,6 @@ const IconWrapper = styled('span')`
}
`;

const StyledNavTabs = styled(NavTabs)`
margin-bottom: 0;
/* Makes sure the tabs are pushed into another row */
width: 100%;
`;

const NavTabsBadge = styled(Badge)`
@media (max-width: ${p => p.theme.breakpoints.small}) {
display: none;
Expand Down
1 change: 0 additions & 1 deletion static/app/views/replays/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ function ReplaysListContainer() {
/>
</Layout.Title>
</Layout.HeaderContent>
<div /> {/* wraps the tabs below the page title */}
<ReplayTabs selected="replays" />
</Layout.Header>
<PageFiltersContainer>
Expand Down
7 changes: 4 additions & 3 deletions static/app/views/replays/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {useMemo} from 'react';

import {TabList, Tabs} from 'sentry/components/tabs';
import * as Layout from 'sentry/components/layouts/thirds';
import {TabList} from 'sentry/components/tabs';
import {t} from 'sentry/locale';
import normalizeUrl from 'sentry/utils/url/normalizeUrl';
import {useLocation} from 'sentry/utils/useLocation';
Expand Down Expand Up @@ -35,7 +36,7 @@ export default function ReplayTabs({selected}: Props) {
);

return (
<Tabs value={selected}>
<Layout.HeaderTabs value={selected}>
<TabList hideBorder>
{tabs.map(tab => (
<TabList.Item
Expand All @@ -51,6 +52,6 @@ export default function ReplayTabs({selected}: Props) {
</TabList.Item>
))}
</TabList>
</Tabs>
</Layout.HeaderTabs>
);
}

0 comments on commit 13a41bb

Please sign in to comment.