import {Fragment} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import moment from 'moment-timezone'; import JSXNode from 'sentry/components/stories/jsxNode'; import SideBySide from 'sentry/components/stories/sideBySide'; import SizingWindow from 'sentry/components/stories/sizingWindow'; import storyBook from 'sentry/stories/storyBook'; import type {DateString} from 'sentry/types/core'; import usePageFilters from 'sentry/utils/usePageFilters'; import type {Release, TimeseriesData} from '../common/types'; import {LineChartWidget} from './lineChartWidget'; import sampleDurationTimeSeries from './sampleDurationTimeSeries.json'; import sampleThroughputTimeSeries from './sampleThroughputTimeSeries.json'; import {shiftTimeserieToNow} from './shiftTimeserieToNow'; const sampleDurationTimeSeries2 = { ...sampleDurationTimeSeries, field: 'p50(span.duration)', data: sampleDurationTimeSeries.data.map(datum => { return { ...datum, value: datum.value * 0.3 + 30 * Math.random(), }; }), }; export default storyBook(LineChartWidget, story => { story('Getting Started', () => { return (

is a Dashboard Widget Component. It displays a timeseries chart with one or more timeseries. Used to visualize data that changes over time in Project Details, Dashboards, Performance, and other UIs.

); }); story('Visualization', () => { const {selection} = usePageFilters(); const {datetime} = selection; const {start, end} = datetime; const throughputTimeSeries = toTimeSeriesSelection( sampleThroughputTimeSeries as unknown as TimeseriesData, start, end ); const durationTimeSeries1 = toTimeSeriesSelection( sampleDurationTimeSeries as unknown as TimeseriesData, start, end ); const durationTimeSeries2 = toTimeSeriesSelection( sampleDurationTimeSeries2, start, end ); return (

The visualization of a line chart. It has some bells and whistles including automatic axes labels, and a hover tooltip. Like other widgets, it automatically fills the parent element. The{' '} utc prop controls whether the X Axis timestamps are shown in UTC or not.

The dataCompletenessDelay prop indicates that this data is live, and the last few buckets might not have complete data. The delay is a number in seconds. Any data bucket that happens in that delay window will be plotted with a dotted line. By default the delay is 0.

); }); story('State', () => { return (

supports the usual loading and error states. The loading state shows a spinner. The error state shows a message, and an optional "Retry" button.

{}} />
); }); story('Colors', () => { const theme = useTheme(); return (

You can control the color of each timeseries by setting the color{' '} attribute to a string that contains a valid hex color code.

); }); story('Releases', () => { const releases = [ { version: 'ui@0.1.2', timestamp: sampleThroughputTimeSeries.data.at(2)?.timestamp, }, { version: 'ui@0.1.3', timestamp: sampleThroughputTimeSeries.data.at(20)?.timestamp, }, ].filter(hasTimestamp); return (

supports the releases prop. If passed in, the widget will plot every release as a vertical line that overlays the chart data. Clicking on a release line will open the release details page.

); }); }); const MediumWidget = styled('div')` width: 420px; height: 250px; `; const SmallWidget = styled('div')` width: 360px; height: 160px; `; const SmallSizingWindow = styled(SizingWindow)` width: 50%; height: 300px; `; function toTimeSeriesSelection( timeSeries: TimeseriesData, start: DateString | null, end: DateString | null ): TimeseriesData { return { ...timeSeries, data: timeSeries.data.filter(datum => { if (start && moment(datum.timestamp).isBefore(moment.utc(start))) { return false; } if (end && moment(datum.timestamp).isAfter(moment.utc(end))) { return false; } return true; }), }; } function hasTimestamp(release: Partial): release is Release { return Boolean(release?.timestamp); }