Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6d5ff8e
feat(charts): Adding new chart range selection hook
Nov 20, 2025
bd08ba3
:hammer_and_wrench: apply pre-commit fixes
getsantry[bot] Nov 20, 2025
acd1453
feat(explore-attr-breakdowns): Using new useChartXRangeSelection hook
Nov 21, 2025
f4b4f9c
feat(explore-attr-breakdowns): Removing old hook
Nov 21, 2025
2be7db5
feat(explore-attribute-breakdowns): Addressing cursor comments
Nov 21, 2025
1f7a760
Merge branch 'abdk/useChartXrangeSelection' into abdk/explore-attr-ne…
Nov 21, 2025
1fee70f
feat(explore-attribute-breakdowns): Minor cleanup
Nov 21, 2025
0dd6897
feat(explore-attribute-breakdowns): Fixing knip errors
Nov 21, 2025
a6ed0de
feat(explore-attr-breakdowns): Fixing eslint errors
Nov 21, 2025
8d6d577
Merge branch 'abdk/useChartXrangeSelection' into abdk/explore-attr-ne…
Nov 21, 2025
73d5e4b
feat(explore-attr-breakdowns): Fixing tests
Nov 21, 2025
c03426c
feat(charts): Addressing PR comments
Nov 21, 2025
bb4c733
Merge branch 'abdk/useChartXrangeSelection' into abdk/explore-attr-ne…
Nov 21, 2025
65fb51c
feat(explore-attrs-breakdown): Addressing PR suggestions
Nov 21, 2025
919b753
feat(explore-attrs-breakdown): Adding url persistence on absolute dat…
Nov 24, 2025
ea04bfd
feat(explore-attrs-breakdown): Iterating on functionality
Nov 24, 2025
499957d
feat(explore-attrs-breakdown): Iterating
Nov 24, 2025
a72ee28
feat(explore-attrs-breakdown): Iterating
Nov 24, 2025
8c898e4
feat(explore-attrs-breakdown): Fixing tests
Nov 24, 2025
423b520
feat(explore-attrs-breakdown): Resolving conflicts
Nov 24, 2025
1491b44
feat(explore-attrs-breakdown): Resolving conflicts
Nov 24, 2025
51114a0
feat(explore-attr-breakdowns): Persisting search
Nov 24, 2025
10e2130
feat(explore-attr-breakdowns): Adding new loading state UI (#103953)
Abdkhan14 Nov 25, 2025
4a273ec
feat(explore-attr-breakdowns): Resolving conflicts
Nov 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {ButtonBar} from '@sentry/scraps/button/buttonBar';
import {Flex} from '@sentry/scraps/layout';

import LoadingError from 'sentry/components/loadingError';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import Panel from 'sentry/components/panels/panel';
import BaseSearchBar from 'sentry/components/searchBar';
import {IconChevron} from 'sentry/icons/iconChevron';
Expand All @@ -16,6 +15,7 @@ import {space} from 'sentry/styles/space';
import type {NewQuery} from 'sentry/types/organization';
import EventView from 'sentry/utils/discover/eventView';
import {useApiQuery} from 'sentry/utils/queryClient';
import {useQueryParamState} from 'sentry/utils/url/useQueryParamState';
import {useDebouncedValue} from 'sentry/utils/useDebouncedValue';
import {useLocation} from 'sentry/utils/useLocation';
import useOrganization from 'sentry/utils/useOrganization';
Expand All @@ -37,7 +37,9 @@ export type AttributeDistribution = Array<{
}>;

export function AttributeDistribution() {
const [searchQuery, setSearchQuery] = useState('');
const [searchQuery, setSearchQuery] = useQueryParamState({
fieldName: 'attributeBreakdownsSearch',
});
const [page, setPage] = useState(0);

const query = useQueryParamsQuery();
Expand Down Expand Up @@ -89,7 +91,7 @@ export function AttributeDistribution() {

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

const filteredAttributeDistribution: AttributeDistribution = useMemo(() => {
const attributeDistribution =
Expand Down Expand Up @@ -137,76 +139,74 @@ export function AttributeDistribution() {
setPage(0);
}, [filteredAttributeDistribution]);

if (isAttributeBreakdownsError || isCohortCountError) {
return <LoadingError message={t('Failed to load attribute breakdowns')} />;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Error rendering changed from wrapped to unwrapped

Error handling logic changed: LoadingError now returns early without Panel and Flex wrappers that were present in the original implementation. Previously, errors displayed within the same container layout as normal content. This could cause visual inconsistency in how errors appear compared to the rest of the component layout and prior behavior.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be working on the error state next


return (
<Panel>
<Flex direction="column" gap="xl" padding="xl">
{isAttributeBreakdownsLoading || isCohortCountLoading ? (
<LoadingIndicator />
) : isAttributeBreakdownsError || isCohortCountError ? (
<LoadingError message={t('Failed to load attribute breakdowns')} />
) : (
<Fragment>
<ControlsContainer>
<StyledBaseSearchBar
placeholder={t('Search keys')}
onChange={q => {
setSearchQuery(q);
}}
query={debouncedSearchQuery}
size="sm"
/>
<AttributeBreakdownsComponent.FeedbackButton />
</ControlsContainer>
{filteredAttributeDistribution.length > 0 ? (
<Fragment>
<ChartsGrid>
{filteredAttributeDistribution
.slice(page * CHARTS_PER_PAGE, (page + 1) * CHARTS_PER_PAGE)
.map(attribute => (
<Chart
key={attribute.name}
attributeDistribution={attribute}
cohortCount={cohortCount}
theme={theme}
/>
))}
</ChartsGrid>
<PaginationContainer>
<ButtonBar merged gap="0">
<Button
icon={<IconChevron direction="left" />}
aria-label={t('Previous')}
size="sm"
disabled={page === 0}
onClick={() => {
setPage(page - 1);
}}
/>
<Button
icon={<IconChevron direction="right" />}
aria-label={t('Next')}
size="sm"
disabled={
page ===
Math.ceil(
(filteredAttributeDistribution?.length ?? 0) / CHARTS_PER_PAGE
) -
1
}
onClick={() => {
setPage(page + 1);
}}
<Fragment>
<ControlsContainer>
<StyledBaseSearchBar
placeholder={t('Search keys')}
onChange={q => {
setSearchQuery(q);
}}
Comment on lines +153 to +155
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
onChange={q => {
setSearchQuery(q);
}}
onChange={setSearchQuery}

query={debouncedSearchQuery}
size="sm"
/>
<AttributeBreakdownsComponent.FeedbackButton />
</ControlsContainer>
{isAttributeBreakdownsLoading || isCohortCountLoading ? (
<AttributeBreakdownsComponent.LoadingCharts />
) : filteredAttributeDistribution.length > 0 ? (
<Fragment>
<ChartsGrid>
{filteredAttributeDistribution
.slice(page * CHARTS_PER_PAGE, (page + 1) * CHARTS_PER_PAGE)
.map(attribute => (
<Chart
key={attribute.name}
attributeDistribution={attribute}
cohortCount={cohortCount}
theme={theme}
/>
</ButtonBar>
</PaginationContainer>
</Fragment>
) : (
<NoAttributesMessage>
{t('No matching attributes found')}
</NoAttributesMessage>
)}
</Fragment>
)}
))}
</ChartsGrid>
<PaginationContainer>
<ButtonBar merged gap="0">
<Button
icon={<IconChevron direction="left" />}
aria-label={t('Previous')}
size="sm"
disabled={page === 0}
onClick={() => {
setPage(page - 1);
}}
/>
<Button
icon={<IconChevron direction="right" />}
aria-label={t('Next')}
size="sm"
disabled={
page ===
Math.ceil(
(filteredAttributeDistribution?.length ?? 0) / CHARTS_PER_PAGE
) -
1
}
onClick={() => {
setPage(page + 1);
}}
/>
</ButtonBar>
</PaginationContainer>
</Fragment>
) : (
<NoAttributesMessage>{t('No matching attributes found')}</NoAttributesMessage>
)}
</Fragment>
</Flex>
</Panel>
);
Expand All @@ -215,7 +215,6 @@ export function AttributeDistribution() {
const ControlsContainer = styled('div')`
display: flex;
gap: ${space(0.5)};
margin-bottom: ${space(1)};
align-items: center;
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import {Flex} from '@sentry/scraps/layout';
import type {Selection} from 'sentry/components/charts/useChartXRangeSelection';
import {Text} from 'sentry/components/core/text';
import LoadingError from 'sentry/components/loadingError';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import Panel from 'sentry/components/panels/panel';
import BaseSearchBar from 'sentry/components/searchBar';
import {IconChevron} from 'sentry/icons/iconChevron';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import {getUserTimezone} from 'sentry/utils/dates';
import {useQueryParamState} from 'sentry/utils/url/useQueryParamState';
import {useDebouncedValue} from 'sentry/utils/useDebouncedValue';
import useAttributeBreakdownComparison from 'sentry/views/explore/hooks/useAttributeBreakdownComparison';
import {useQueryParamsVisualizes} from 'sentry/views/explore/queryParams/context';
Expand Down Expand Up @@ -46,14 +46,16 @@ export function CohortComparison({
aggregateFunction: yAxis,
range: selection.range,
});
const [searchQuery, setSearchQuery] = useState('');
const [searchQuery, setSearchQuery] = useQueryParamState({
fieldName: 'attributeBreakdownsSearch',
});
const sortingMethod: SortingMethod = 'rrr';
const [page, setPage] = useState(0);
const theme = useTheme();

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

const filteredRankedAttributes = useMemo(() => {
const attrs = data?.rankedAttributes;
Expand Down Expand Up @@ -126,26 +128,28 @@ export function CohortComparison({
};
}, [selection, yAxis]);

if (isError) {
return <LoadingError message={t('Failed to load attribute breakdowns')} />;
}

return (
<Panel data-explore-chart-selection-region>
<Flex direction="column" gap="xl" padding="xl">
<ControlsContainer>
<StyledBaseSearchBar
placeholder={t('Search keys')}
onChange={query => {
setSearchQuery(query);
}}
query={debouncedSearchQuery}
size="sm"
/>
<AttributeBreakdownsComponent.FeedbackButton />
</ControlsContainer>
{isLoading ? (
<LoadingIndicator />
) : isError ? (
<LoadingError message={t('Failed to load attribute breakdowns')} />
<AttributeBreakdownsComponent.LoadingCharts />
) : (
<Fragment>
<ControlsContainer>
<StyledBaseSearchBar
placeholder={t('Search keys')}
onChange={query => {
setSearchQuery(query);
}}
query={debouncedSearchQuery}
size="sm"
/>
<AttributeBreakdownsComponent.FeedbackButton />
</ControlsContainer>
{selectionHint && (
<SelectionHintContainer>
<SelectionHint color={theme.chart.getColorPalette(0)?.[0]}>
Expand Down Expand Up @@ -211,7 +215,6 @@ const ControlsContainer = styled('div')`
display: flex;
align-items: center;
gap: ${space(0.5)};
margin-bottom: ${space(1)};
`;

const StyledBaseSearchBar = styled(BaseSearchBar)`
Expand Down Expand Up @@ -241,7 +244,6 @@ const SelectionHintContainer = styled('div')`
display: flex;
flex-direction: column;
gap: ${space(0.5)};
margin-bottom: ${space(1)};
`;

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