lineChartWidget.stories.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import {Fragment} from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import moment from 'moment-timezone';
  5. import JSXNode from 'sentry/components/stories/jsxNode';
  6. import SideBySide from 'sentry/components/stories/sideBySide';
  7. import storyBook from 'sentry/stories/storyBook';
  8. import type {DateString} from 'sentry/types/core';
  9. import usePageFilters from 'sentry/utils/usePageFilters';
  10. import type {TimeseriesData} from '../common/types';
  11. import {LineChartWidget} from './lineChartWidget';
  12. import sampleDurationTimeSeries from './sampleDurationTimeSeries.json';
  13. import sampleThroughputTimeSeries from './sampleThroughputTimeSeries.json';
  14. const sampleDurationTimeSeries2 = {
  15. ...sampleDurationTimeSeries,
  16. field: 'p50(span.duration)',
  17. data: sampleDurationTimeSeries.data.map(datum => {
  18. return {
  19. ...datum,
  20. value: datum.value * 0.3 + 30 * Math.random(),
  21. };
  22. }),
  23. };
  24. export default storyBook(LineChartWidget, story => {
  25. story('Getting Started', () => {
  26. return (
  27. <Fragment>
  28. <p>
  29. <JSXNode name="LineChartWidget" /> is a Dashboard Widget Component. It displays
  30. a timeseries chart with one or more timeseries. Used to visualize data that
  31. changes over time in Project Details, Dashboards, Performance, and other UIs.
  32. </p>
  33. </Fragment>
  34. );
  35. });
  36. story('Visualization', () => {
  37. const {selection} = usePageFilters();
  38. const {datetime} = selection;
  39. const {start, end} = datetime;
  40. const throughputTimeSeries = toTimeSeriesSelection(
  41. sampleThroughputTimeSeries as unknown as TimeseriesData,
  42. start,
  43. end
  44. );
  45. const durationTimeSeries1 = toTimeSeriesSelection(
  46. sampleDurationTimeSeries as unknown as TimeseriesData,
  47. start,
  48. end
  49. );
  50. const durationTimeSeries2 = toTimeSeriesSelection(
  51. sampleDurationTimeSeries2,
  52. start,
  53. end
  54. );
  55. return (
  56. <Fragment>
  57. <p>
  58. The visualization of <JSXNode name="LineChartWidget" /> a line chart. It has
  59. some bells and whistles including automatic axes labels, and a hover tooltip.
  60. </p>
  61. <p>
  62. The <code>utc</code> prop controls whether the X Axis timestamps are shown in
  63. UTC or not
  64. </p>
  65. <SideBySide>
  66. <MediumWidget>
  67. <LineChartWidget
  68. title="eps()"
  69. description="Number of events per second"
  70. timeseries={[throughputTimeSeries]}
  71. meta={{
  72. fields: {
  73. 'eps()': 'rate',
  74. },
  75. units: {
  76. 'eps()': '1/second',
  77. },
  78. }}
  79. />
  80. </MediumWidget>
  81. <MediumWidget>
  82. <LineChartWidget
  83. title="span.duration"
  84. timeseries={[durationTimeSeries1, durationTimeSeries2]}
  85. utc
  86. meta={{
  87. fields: {
  88. 'p99(span.duration)': 'duration',
  89. 'p50(span.duration)': 'duration',
  90. },
  91. units: {
  92. 'p99(span.duration)': 'millisecond',
  93. 'p50(span.duration)': 'millisecond',
  94. },
  95. }}
  96. />
  97. </MediumWidget>
  98. </SideBySide>
  99. </Fragment>
  100. );
  101. });
  102. story('Colors', () => {
  103. const theme = useTheme();
  104. return (
  105. <Fragment>
  106. <p>
  107. You can control the color of each timeseries by setting the <code>color</code>{' '}
  108. attribute to a string that contains a valid hex color code.
  109. </p>
  110. <MediumWidget>
  111. <LineChartWidget
  112. title="error_rate()"
  113. description="Rate of Errors"
  114. timeseries={[
  115. {
  116. ...sampleThroughputTimeSeries,
  117. field: 'error_rate()',
  118. color: theme.error,
  119. } as unknown as TimeseriesData,
  120. ]}
  121. meta={{
  122. fields: {
  123. 'error_rate()': 'rate',
  124. },
  125. units: {
  126. 'error_rate()': '1/second',
  127. },
  128. }}
  129. />
  130. </MediumWidget>
  131. </Fragment>
  132. );
  133. });
  134. });
  135. const MediumWidget = styled('div')`
  136. width: 420px;
  137. `;
  138. function toTimeSeriesSelection(
  139. timeSeries: TimeseriesData,
  140. start: DateString | null,
  141. end: DateString | null
  142. ): TimeseriesData {
  143. return {
  144. ...timeSeries,
  145. data: timeSeries.data.filter(datum => {
  146. if (start && moment(datum.timestamp).isBefore(moment.utc(start))) {
  147. return false;
  148. }
  149. if (end && moment(datum.timestamp).isAfter(moment.utc(end))) {
  150. return false;
  151. }
  152. return true;
  153. }),
  154. };
  155. }