Skip to content

Commit b35c18c

Browse files
authored
ref(projectDetails): Use SegmentedControl to select issues type (#43931)
**Before ——** <img width="901" alt="Screenshot 2023-01-31 at 3 12 32 PM" src="https://user-images.githubusercontent.com/44172267/215904961-e4ad7522-129b-45cc-8d6e-08796cadb160.png"> **After ——** <img width="901" alt="Screenshot 2023-01-31 at 3 12 01 PM" src="https://user-images.githubusercontent.com/44172267/215904888-cb31036d-91e0-40b4-91b8-5c1ceee60db6.png"> Part of #43865
1 parent b80bc69 commit b35c18c

File tree

2 files changed

+47
-37
lines changed

2 files changed

+47
-37
lines changed

static/app/views/projectDetail/projectIssues.spec.jsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {initializeOrg} from 'sentry-test/initializeOrg';
2-
import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
2+
import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
33

44
import ProjectIssues from 'sentry/views/projectDetail/projectIssues';
55

66
describe('ProjectDetail > ProjectIssues', function () {
7-
let endpointMock, filteredEndpointMock;
7+
let endpointMock, filteredEndpointMock, newIssuesEndpointMock;
88
const {organization, router, routerContext} = initializeOrg({
99
organization: {
1010
features: ['discover-basic'],
@@ -22,6 +22,11 @@ describe('ProjectDetail > ProjectIssues', function () {
2222
body: [TestStubs.Group(), TestStubs.Group({id: '2'})],
2323
});
2424

25+
newIssuesEndpointMock = MockApiClient.addMockResponse({
26+
url: `/organizations/${organization.slug}/issues/?limit=5&query=is%3Aunresolved%20is%3Afor_review&sort=freq&statsPeriod=14d`,
27+
body: [TestStubs.Group(), TestStubs.Group({id: '2'})],
28+
});
29+
2530
MockApiClient.addMockResponse({
2631
url: `/organizations/${organization.slug}/users/`,
2732
body: [],
@@ -67,6 +72,28 @@ describe('ProjectDetail > ProjectIssues', function () {
6772
});
6873
});
6974

75+
it('renders a segmented control', function () {
76+
render(<ProjectIssues organization={organization} location={router.location} />, {
77+
context: routerContext,
78+
organization,
79+
});
80+
81+
// "Unhandled" segment is selected
82+
const unhandledSegment = screen.getByRole('radio', {name: 'Unhandled 0'});
83+
expect(unhandledSegment).toBeInTheDocument();
84+
expect(unhandledSegment).toBeChecked();
85+
86+
// Select "New Issues" segment
87+
const newIssuesSegment = screen.getByRole('radio', {name: 'New Issues 0'});
88+
expect(newIssuesSegment).toBeInTheDocument();
89+
expect(newIssuesSegment).not.toBeChecked();
90+
91+
userEvent.click(newIssuesSegment);
92+
waitFor(() => expect(newIssuesSegment).toBeChecked());
93+
94+
expect(newIssuesEndpointMock).toHaveBeenCalled();
95+
});
96+
7097
it('renders a link to Discover', function () {
7198
render(<ProjectIssues organization={organization} location={router.location} />, {
7299
context: routerContext,

static/app/views/projectDetail/projectIssues.tsx

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import pick from 'lodash/pick';
66
import * as qs from 'query-string';
77

88
import {Client} from 'sentry/api';
9-
import {Button, ButtonLabel} from 'sentry/components/button';
9+
import {Button} from 'sentry/components/button';
1010
import ButtonBar from 'sentry/components/buttonBar';
1111
import DiscoverButton from 'sentry/components/discoverButton';
1212
import GroupList from 'sentry/components/issues/groupList';
1313
import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
1414
import Pagination from 'sentry/components/pagination';
1515
import {Panel, PanelBody} from 'sentry/components/panels';
1616
import QueryCount from 'sentry/components/queryCount';
17+
import {SegmentedControl} from 'sentry/components/segmentedControl';
1718
import {DEFAULT_RELATIVE_PERIODS, DEFAULT_STATS_PERIOD} from 'sentry/constants';
1819
import {URL_PARAM} from 'sentry/constants/pageFilters';
1920
import {t, tct} from 'sentry/locale';
@@ -59,8 +60,8 @@ type Props = {
5960
function ProjectIssues({organization, location, projectId, query, api}: Props) {
6061
const [pageLinks, setPageLinks] = useState<string | undefined>();
6162
const [onCursor, setOnCursor] = useState<(() => void) | undefined>();
62-
const [issuesType, setIssuesType] = useState<IssuesType | string>(
63-
(location.query.issuesType as string) || IssuesType.UNHANDLED
63+
const [issuesType, setIssuesType] = useState<IssuesType>(
64+
(location.query.issuesType as IssuesType) || IssuesType.UNHANDLED
6465
);
6566
const [issuesCount, setIssuesCount] = useState<Count>({
6667
all: 0,
@@ -241,20 +242,19 @@ function ProjectIssues({organization, location, projectId, query, api}: Props) {
241242
return (
242243
<Fragment>
243244
<ControlsWrapper>
244-
<StyledButtonBar active={issuesType} merged>
245+
<SegmentedControl
246+
aria-label={t('Issue type')}
247+
value={issuesType}
248+
onChange={value => handleIssuesTypeSelection(value)}
249+
size="xs"
250+
>
245251
{issuesTypes.map(({value, label, issueCount}) => (
246-
<Button
247-
key={value}
248-
barId={value}
249-
size="xs"
250-
onClick={() => handleIssuesTypeSelection(value)}
251-
data-test-id={`filter-${value}`}
252-
>
253-
{label}
252+
<SegmentedControl.Item key={value} textValue={label}>
253+
{label}&nbsp;
254254
<QueryCount count={issueCount} max={99} hideParens hideIfEmpty={false} />
255-
</Button>
255+
</SegmentedControl.Item>
256256
))}
257-
</StyledButtonBar>
257+
</SegmentedControl>
258258
<OpenInButtonBar gap={1}>
259259
<Button
260260
data-test-id="issues-open"
@@ -297,31 +297,14 @@ const ControlsWrapper = styled('div')`
297297
justify-content: space-between;
298298
margin-bottom: ${space(1)};
299299
flex-wrap: wrap;
300-
@media (max-width: ${p => p.theme.breakpoints.small}) {
301-
display: block;
302-
}
303-
`;
304-
305-
const StyledButtonBar = styled(ButtonBar)`
306-
grid-template-columns: repeat(4, 1fr);
307-
${ButtonLabel} {
308-
white-space: nowrap;
309-
gap: ${space(0.5)};
310-
span:last-child {
311-
color: ${p => p.theme.buttonCount};
312-
}
313-
}
314-
.active {
315-
${ButtonLabel} {
316-
span:last-child {
317-
color: ${p => p.theme.buttonCountActive};
318-
}
319-
}
320-
}
321300
`;
322301

323302
const OpenInButtonBar = styled(ButtonBar)`
324303
margin-top: ${space(1)};
304+
305+
@media (max-width: ${p => p.theme.breakpoints.small}) {
306+
width: 100%;
307+
}
325308
`;
326309

327310
const StyledPagination = styled(Pagination)`

0 commit comments

Comments
 (0)