Skip to content

Commit 245bf3a

Browse files
Abdkhan14Abdullah Khangetsantry[bot]
authored
feat(explore-attr-breakdowns): Persisting search (#103918)
- I will be consolidating code between the two views in following PRs --------- Co-authored-by: Abdullah Khan <[email protected]> Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
1 parent a3be62c commit 245bf3a

File tree

3 files changed

+236
-89
lines changed

3 files changed

+236
-89
lines changed

static/app/views/explore/components/attributeBreakdowns/attributeDistributionContent.tsx

Lines changed: 69 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {ButtonBar} from '@sentry/scraps/button/buttonBar';
77
import {Flex} from '@sentry/scraps/layout';
88

99
import LoadingError from 'sentry/components/loadingError';
10-
import LoadingIndicator from 'sentry/components/loadingIndicator';
1110
import Panel from 'sentry/components/panels/panel';
1211
import BaseSearchBar from 'sentry/components/searchBar';
1312
import {IconChevron} from 'sentry/icons/iconChevron';
@@ -16,6 +15,7 @@ import {space} from 'sentry/styles/space';
1615
import type {NewQuery} from 'sentry/types/organization';
1716
import EventView from 'sentry/utils/discover/eventView';
1817
import {useApiQuery} from 'sentry/utils/queryClient';
18+
import {useQueryParamState} from 'sentry/utils/url/useQueryParamState';
1919
import {useDebouncedValue} from 'sentry/utils/useDebouncedValue';
2020
import {useLocation} from 'sentry/utils/useLocation';
2121
import useOrganization from 'sentry/utils/useOrganization';
@@ -37,7 +37,9 @@ export type AttributeDistribution = Array<{
3737
}>;
3838

3939
export function AttributeDistribution() {
40-
const [searchQuery, setSearchQuery] = useState('');
40+
const [searchQuery, setSearchQuery] = useQueryParamState({
41+
fieldName: 'attributeBreakdownsSearch',
42+
});
4143
const [page, setPage] = useState(0);
4244

4345
const query = useQueryParamsQuery();
@@ -89,7 +91,7 @@ export function AttributeDistribution() {
8991

9092
// Debouncing the search query here to ensure smooth typing, by delaying the re-mounts a little as the user types.
9193
// query here to ensure smooth typing, by delaying the re-mounts a little as the user types.
92-
const debouncedSearchQuery = useDebouncedValue(searchQuery, 100);
94+
const debouncedSearchQuery = useDebouncedValue(searchQuery ?? '', 100);
9395

9496
const filteredAttributeDistribution: AttributeDistribution = useMemo(() => {
9597
const attributeDistribution =
@@ -137,76 +139,74 @@ export function AttributeDistribution() {
137139
setPage(0);
138140
}, [filteredAttributeDistribution]);
139141

142+
if (isAttributeBreakdownsError || isCohortCountError) {
143+
return <LoadingError message={t('Failed to load attribute breakdowns')} />;
144+
}
145+
140146
return (
141147
<Panel>
142148
<Flex direction="column" gap="xl" padding="xl">
143-
{isAttributeBreakdownsLoading || isCohortCountLoading ? (
144-
<LoadingIndicator />
145-
) : isAttributeBreakdownsError || isCohortCountError ? (
146-
<LoadingError message={t('Failed to load attribute breakdowns')} />
147-
) : (
148-
<Fragment>
149-
<ControlsContainer>
150-
<StyledBaseSearchBar
151-
placeholder={t('Search keys')}
152-
onChange={q => {
153-
setSearchQuery(q);
154-
}}
155-
query={debouncedSearchQuery}
156-
size="sm"
157-
/>
158-
<AttributeBreakdownsComponent.FeedbackButton />
159-
</ControlsContainer>
160-
{filteredAttributeDistribution.length > 0 ? (
161-
<Fragment>
162-
<ChartsGrid>
163-
{filteredAttributeDistribution
164-
.slice(page * CHARTS_PER_PAGE, (page + 1) * CHARTS_PER_PAGE)
165-
.map(attribute => (
166-
<Chart
167-
key={attribute.name}
168-
attributeDistribution={attribute}
169-
cohortCount={cohortCount}
170-
theme={theme}
171-
/>
172-
))}
173-
</ChartsGrid>
174-
<PaginationContainer>
175-
<ButtonBar merged gap="0">
176-
<Button
177-
icon={<IconChevron direction="left" />}
178-
aria-label={t('Previous')}
179-
size="sm"
180-
disabled={page === 0}
181-
onClick={() => {
182-
setPage(page - 1);
183-
}}
184-
/>
185-
<Button
186-
icon={<IconChevron direction="right" />}
187-
aria-label={t('Next')}
188-
size="sm"
189-
disabled={
190-
page ===
191-
Math.ceil(
192-
(filteredAttributeDistribution?.length ?? 0) / CHARTS_PER_PAGE
193-
) -
194-
1
195-
}
196-
onClick={() => {
197-
setPage(page + 1);
198-
}}
149+
<Fragment>
150+
<ControlsContainer>
151+
<StyledBaseSearchBar
152+
placeholder={t('Search keys')}
153+
onChange={q => {
154+
setSearchQuery(q);
155+
}}
156+
query={debouncedSearchQuery}
157+
size="sm"
158+
/>
159+
<AttributeBreakdownsComponent.FeedbackButton />
160+
</ControlsContainer>
161+
{isAttributeBreakdownsLoading || isCohortCountLoading ? (
162+
<AttributeBreakdownsComponent.LoadingCharts />
163+
) : filteredAttributeDistribution.length > 0 ? (
164+
<Fragment>
165+
<ChartsGrid>
166+
{filteredAttributeDistribution
167+
.slice(page * CHARTS_PER_PAGE, (page + 1) * CHARTS_PER_PAGE)
168+
.map(attribute => (
169+
<Chart
170+
key={attribute.name}
171+
attributeDistribution={attribute}
172+
cohortCount={cohortCount}
173+
theme={theme}
199174
/>
200-
</ButtonBar>
201-
</PaginationContainer>
202-
</Fragment>
203-
) : (
204-
<NoAttributesMessage>
205-
{t('No matching attributes found')}
206-
</NoAttributesMessage>
207-
)}
208-
</Fragment>
209-
)}
175+
))}
176+
</ChartsGrid>
177+
<PaginationContainer>
178+
<ButtonBar merged gap="0">
179+
<Button
180+
icon={<IconChevron direction="left" />}
181+
aria-label={t('Previous')}
182+
size="sm"
183+
disabled={page === 0}
184+
onClick={() => {
185+
setPage(page - 1);
186+
}}
187+
/>
188+
<Button
189+
icon={<IconChevron direction="right" />}
190+
aria-label={t('Next')}
191+
size="sm"
192+
disabled={
193+
page ===
194+
Math.ceil(
195+
(filteredAttributeDistribution?.length ?? 0) / CHARTS_PER_PAGE
196+
) -
197+
1
198+
}
199+
onClick={() => {
200+
setPage(page + 1);
201+
}}
202+
/>
203+
</ButtonBar>
204+
</PaginationContainer>
205+
</Fragment>
206+
) : (
207+
<NoAttributesMessage>{t('No matching attributes found')}</NoAttributesMessage>
208+
)}
209+
</Fragment>
210210
</Flex>
211211
</Panel>
212212
);
@@ -215,7 +215,6 @@ export function AttributeDistribution() {
215215
const ControlsContainer = styled('div')`
216216
display: flex;
217217
gap: ${space(0.5)};
218-
margin-bottom: ${space(1)};
219218
align-items: center;
220219
`;
221220

static/app/views/explore/components/attributeBreakdowns/cohortComparisonContent.tsx

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import {Flex} from '@sentry/scraps/layout';
1010
import type {Selection} from 'sentry/components/charts/useChartXRangeSelection';
1111
import {Text} from 'sentry/components/core/text';
1212
import LoadingError from 'sentry/components/loadingError';
13-
import LoadingIndicator from 'sentry/components/loadingIndicator';
1413
import Panel from 'sentry/components/panels/panel';
1514
import BaseSearchBar from 'sentry/components/searchBar';
1615
import {IconChevron} from 'sentry/icons/iconChevron';
1716
import {t} from 'sentry/locale';
1817
import {space} from 'sentry/styles/space';
1918
import {getUserTimezone} from 'sentry/utils/dates';
19+
import {useQueryParamState} from 'sentry/utils/url/useQueryParamState';
2020
import {useDebouncedValue} from 'sentry/utils/useDebouncedValue';
2121
import useAttributeBreakdownComparison from 'sentry/views/explore/hooks/useAttributeBreakdownComparison';
2222
import {useQueryParamsVisualizes} from 'sentry/views/explore/queryParams/context';
@@ -46,14 +46,16 @@ export function CohortComparison({
4646
aggregateFunction: yAxis,
4747
range: selection.range,
4848
});
49-
const [searchQuery, setSearchQuery] = useState('');
49+
const [searchQuery, setSearchQuery] = useQueryParamState({
50+
fieldName: 'attributeBreakdownsSearch',
51+
});
5052
const sortingMethod: SortingMethod = 'rrr';
5153
const [page, setPage] = useState(0);
5254
const theme = useTheme();
5355

5456
// Debouncing the search query here to ensure smooth typing, by delaying the re-mounts a little as the user types.
5557
// query here to ensure smooth typing, by delaying the re-mounts a little as the user types.
56-
const debouncedSearchQuery = useDebouncedValue(searchQuery, 100);
58+
const debouncedSearchQuery = useDebouncedValue(searchQuery ?? '', 100);
5759

5860
const filteredRankedAttributes = useMemo(() => {
5961
const attrs = data?.rankedAttributes;
@@ -126,26 +128,28 @@ export function CohortComparison({
126128
};
127129
}, [selection, yAxis]);
128130

131+
if (isError) {
132+
return <LoadingError message={t('Failed to load attribute breakdowns')} />;
133+
}
134+
129135
return (
130136
<Panel data-explore-chart-selection-region>
131137
<Flex direction="column" gap="xl" padding="xl">
138+
<ControlsContainer>
139+
<StyledBaseSearchBar
140+
placeholder={t('Search keys')}
141+
onChange={query => {
142+
setSearchQuery(query);
143+
}}
144+
query={debouncedSearchQuery}
145+
size="sm"
146+
/>
147+
<AttributeBreakdownsComponent.FeedbackButton />
148+
</ControlsContainer>
132149
{isLoading ? (
133-
<LoadingIndicator />
134-
) : isError ? (
135-
<LoadingError message={t('Failed to load attribute breakdowns')} />
150+
<AttributeBreakdownsComponent.LoadingCharts />
136151
) : (
137152
<Fragment>
138-
<ControlsContainer>
139-
<StyledBaseSearchBar
140-
placeholder={t('Search keys')}
141-
onChange={query => {
142-
setSearchQuery(query);
143-
}}
144-
query={debouncedSearchQuery}
145-
size="sm"
146-
/>
147-
<AttributeBreakdownsComponent.FeedbackButton />
148-
</ControlsContainer>
149153
{selectionHint && (
150154
<SelectionHintContainer>
151155
<SelectionHint color={theme.chart.getColorPalette(0)?.[0]}>
@@ -211,7 +215,6 @@ const ControlsContainer = styled('div')`
211215
display: flex;
212216
align-items: center;
213217
gap: ${space(0.5)};
214-
margin-bottom: ${space(1)};
215218
`;
216219

217220
const StyledBaseSearchBar = styled(BaseSearchBar)`
@@ -241,7 +244,6 @@ const SelectionHintContainer = styled('div')`
241244
display: flex;
242245
flex-direction: column;
243246
gap: ${space(0.5)};
244-
margin-bottom: ${space(1)};
245247
`;
246248

247249
const SelectionHint = styled(Text)<{color?: string}>`

0 commit comments

Comments
 (0)