Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui): Add release bubbles support to TimeSeriesWidgetVisualization #85270

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions static/app/components/charts/baseChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,19 @@ const getTooltipStyles = (p: {theme: Theme}) => css`
}

.tooltip-arrow {
&.arrow-top {
bottom: 100%;
top: auto;
border-bottom: 8px solid ${p.theme.backgroundElevated};
border-top: none;
&:before {
border-top: none;
border-bottom: 8px solid ${p.theme.translucentBorder};
bottom: -7px;
top: auto;
}
}

top: 100%;
left: 50%;
position: absolute;
Expand Down
16 changes: 4 additions & 12 deletions static/app/components/releases/releasesDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Fragment, type ReactElement} from 'react';
import styled from '@emotion/styled';

import {DateTime} from 'sentry/components/dateTime';
import {
EventDrawerBody,
EventDrawerContainer,
Expand All @@ -9,24 +10,14 @@ import {
Header,
NavigationCrumbs,
} from 'sentry/components/events/eventDrawer';
import {ReleaseDrawerTable} from 'sentry/components/releases/releasesDrawerTable';
import {t, tn} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Release} from 'sentry/views/dashboards/widgets/common/types';
import type {Bucket} from 'sentry/views/dashboards/widgets/timeSeriesWidget/releaseBubbles/types';
import type {TimeSeriesWidgetVisualizationProps} from 'sentry/views/dashboards/widgets/timeSeriesWidget/timeSeriesWidgetVisualization';
import {Widget} from 'sentry/views/dashboards/widgets/widget/widget';

import {DateTime} from '../dateTime';

import {ReleaseDrawerTable} from './releasesDrawerTable';

type Bucket = [
start: number,
placeholder: number,
end: number,
numReleases: number,
releases: Release[],
];

interface ReleasesDrawerProps {
/**
* This is a list of the release buckets used by eCharts to draw the release bubbles.
Expand Down Expand Up @@ -90,6 +81,7 @@ export function ReleasesDrawer({
Visualization={chartRenderer?.({
releases,
timeSeries: trimmedTimeSeries,
showReleaseLines: true,
})}
/>
</ChartContainer>
Expand Down
5 changes: 2 additions & 3 deletions static/app/components/releases/releasesDrawerTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import Count from 'sentry/components/count';
import GlobalSelectionLink from 'sentry/components/globalSelectionLink';
import type {GridColumnHeader, GridColumnOrder} from 'sentry/components/gridEditable';
import GridEditable from 'sentry/components/gridEditable';
import Pagination from 'sentry/components/pagination';
import renderSortableHeaderCell from 'sentry/components/replays/renderSortableHeaderCell';
import useQueryBasedColumnResize from 'sentry/components/replays/useQueryBasedColumnResize';
import useQueryBasedSorting from 'sentry/components/replays/useQueryBasedSorting';
import TextOverflow from 'sentry/components/textOverflow';
import {Tooltip} from 'sentry/components/tooltip';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
Expand All @@ -19,9 +21,6 @@ import useOrganization from 'sentry/utils/useOrganization';
import useOrganizationReleases from 'sentry/views/insights/sessions/queries/useOrganizationReleases';
import {getReleaseNewIssuesUrl} from 'sentry/views/releases/utils';

import Pagination from '../pagination';
import TextOverflow from '../textOverflow';

type ReleaseHealthItem = {
adoption_stage: string;
crash_free_sessions: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BUBBLE_SERIES_ID = '__release_bubble__';
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type {ElementEvent} from 'echarts';
import type {EChartsInstance} from 'echarts-for-react';

import type {Series} from 'sentry/types/echarts';
import {BUBBLE_SERIES_ID} from 'sentry/views/dashboards/widgets/timeSeriesWidget/releaseBubbles/constants';
import type {Bucket} from 'sentry/views/dashboards/widgets/timeSeriesWidget/releaseBubbles/types';

/**
* Attaches an event listener to eCharts that will "highlight" a release bubble
* as the mouse moves around the main chart.
*
* Note: you cannot listen to "mousemove" events on echarts as they only
* contain events when the mouse interacts with a data item. This needs to
* listen to zrender (i.e. the `getZr()`) events.
*/
export function createReleaseBubbleHighlighter(echartsInstance: EChartsInstance) {
const highlightedBuckets = new Set();
function handleMouseMove(params: ElementEvent) {
// Tracks movement across the chart and highlights the corresponding release bubble
const pointInPixel = [params.offsetX, params.offsetY];
const pointInGrid = echartsInstance.convertFromPixel('grid', pointInPixel);
const series = echartsInstance.getOption().series;
const seriesIndex = series.findIndex((s: Series) => s.id === BUBBLE_SERIES_ID);

// No release bubble series found (shouldn't happen)
if (seriesIndex === -1) {
return;
}
const bubbleSeries = series[seriesIndex];
const buckets = bubbleSeries?.data;

if (!buckets) {
return;
}

const bucketIndex = buckets.findIndex(([bucketStart, _, bucketEnd]: Bucket) => {
const ts = pointInGrid[0] ?? -1;
return ts >= bucketStart && ts < bucketEnd;
});

// Already highlighted, no need to do anything
if (highlightedBuckets.has(bucketIndex)) {
return;
}

// If next bucket is not already highlighted, clear all existing
// highlights.
if (!highlightedBuckets.has(bucketIndex)) {
highlightedBuckets.forEach(dataIndex => {
echartsInstance.dispatchAction({
type: 'downplay',
seriesIndex,
dataIndex,
});
});
highlightedBuckets.clear();
}

// A bucket was found, dispatch "highlight" action --
// this is styled via `renderReleaseBubble` -> `emphasis`
if (bucketIndex > -1) {
highlightedBuckets.add(bucketIndex);
echartsInstance.dispatchAction({
type: 'highlight',
seriesIndex,
dataIndex: bucketIndex,
});
}
}

echartsInstance.getZr().on('mousemove', handleMouseMove);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type {Release} from 'sentry/views/dashboards/widgets/common/types';

export type Bucket = [
start: number,
placeholder: number,
end: number,
numReleases: number,
releases: Release[],
];
Loading
Loading