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);
}