widgetFrame.stories.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import JSXNode from 'sentry/components/stories/jsxNode';
  4. import SideBySide from 'sentry/components/stories/sideBySide';
  5. import {t} from 'sentry/locale';
  6. import storyBook from 'sentry/stories/storyBook';
  7. import {WidgetFrame} from 'sentry/views/dashboards/widgets/common/widgetFrame';
  8. export default storyBook(WidgetFrame, story => {
  9. story('Getting Started', () => {
  10. return (
  11. <Fragment>
  12. <p>
  13. <JSXNode name="WidgetFrame" /> is a container element used for all widgets in
  14. the Dashboards Widget Platform. It's mostly an under-the-hood component, but it
  15. can be useful to emulate widget-like states, like widget cards with actions.
  16. </p>
  17. </Fragment>
  18. );
  19. });
  20. story('Layout', () => {
  21. return (
  22. <Fragment>
  23. <p>
  24. <JSXNode name="WidgetFrame" /> supports a few basic props that control its
  25. content. This includes a title, a description, and the <code>children</code>.
  26. The title is automatically wrapped in a tooltip if it does not fit.
  27. </p>
  28. <SideBySide>
  29. <NormalWidget>
  30. <WidgetFrame
  31. title="Count"
  32. description="This counts up the amount of something that happens."
  33. />
  34. </NormalWidget>
  35. <NormalWidget>
  36. <WidgetFrame
  37. title="p95(measurements.lcp) / p95(measurements.inp)"
  38. description="This is a tough formula to reason about"
  39. />
  40. </NormalWidget>
  41. </SideBySide>
  42. </Fragment>
  43. );
  44. });
  45. story('Warnings', () => {
  46. return (
  47. <Fragment>
  48. <p>
  49. <JSXNode name="WidgetFrame" /> supports a <code>warnings</code> prop. If
  50. supplied, it shows a small warning icon next to the title. Hovering over the
  51. icon shows the warnings.
  52. </p>
  53. <SideBySide>
  54. <NormalWidget>
  55. <WidgetFrame
  56. title="count()"
  57. warnings={[
  58. 'We have automatically converted this widget to use sampled data.',
  59. 'Data for this metrics has not been extracted yet',
  60. ]}
  61. />
  62. </NormalWidget>
  63. </SideBySide>
  64. </Fragment>
  65. );
  66. });
  67. story('Badge', () => {
  68. return (
  69. <Fragment>
  70. <p>
  71. <JSXNode name="WidgetFrame" /> supports a <code>badgeProps</code> prop. If
  72. passed, a<code>Badge</code> component with the relevant props appears in the
  73. header. Note: Avoid using this! This is mostly used as an internal feature, for
  74. diagnosing widget state at a glance. We might remove this feature very soon.{' '}
  75. <i>Especially</i> avoid multiple badges.
  76. </p>
  77. <SideBySide>
  78. <NormalWidget>
  79. <WidgetFrame
  80. title="count()"
  81. badgeProps={[
  82. {
  83. text: 'Alpha',
  84. type: 'alpha',
  85. },
  86. {
  87. text: 'Sampled',
  88. type: 'default',
  89. },
  90. ]}
  91. warnings={[
  92. 'We have automatically converted this widget to use sampled data.',
  93. 'Data for this metrics has not been extracted yet',
  94. ]}
  95. />
  96. </NormalWidget>
  97. </SideBySide>
  98. </Fragment>
  99. );
  100. });
  101. story('Action Menu', () => {
  102. return (
  103. <Fragment>
  104. <p>
  105. <JSXNode name="WidgetFrame" /> supports an action menu. If only one action is
  106. passed, the single action is rendered as a small button. If multiple actions are
  107. passed, they are grouped into a dropdown menu. Menu actions appear on hover or
  108. keyboard focus. They can be disabled with the <code>actionsDisabled</code> prop,
  109. and supplemented with an optional <code>actionsMessage</code> prop that adds a
  110. tooltip.
  111. </p>
  112. <SideBySide>
  113. <NormalWidget>
  114. <WidgetFrame
  115. title="Count"
  116. description="This counts up the amount of something that happens."
  117. actions={[
  118. {
  119. key: 'see-more',
  120. label: t('See More'),
  121. onAction: () => {
  122. // eslint-disable-next-line no-console
  123. console.log('See more!');
  124. },
  125. },
  126. ]}
  127. />
  128. </NormalWidget>
  129. <NormalWidget>
  130. <WidgetFrame
  131. title="Count"
  132. actionsDisabled
  133. actionsMessage="Not possible here"
  134. description="This counts up the amount of something that happens."
  135. actions={[
  136. {
  137. key: 'see-more',
  138. label: t('See More'),
  139. onAction: () => {
  140. // eslint-disable-next-line no-console
  141. console.log('See more!');
  142. },
  143. },
  144. ]}
  145. />
  146. </NormalWidget>
  147. <NormalWidget>
  148. <WidgetFrame
  149. title="Count"
  150. description="This is a tough formula to reason about"
  151. actions={[
  152. {
  153. key: 'see-more',
  154. label: t('See More'),
  155. onAction: () => {
  156. // eslint-disable-next-line no-console
  157. console.log('See more!');
  158. },
  159. },
  160. {
  161. key: 'see-less',
  162. label: t('See Less'),
  163. onAction: () => {
  164. // eslint-disable-next-line no-console
  165. console.log('See less!');
  166. },
  167. },
  168. ]}
  169. />
  170. </NormalWidget>
  171. <NormalWidget>
  172. <WidgetFrame
  173. title="Count"
  174. actionsDisabled
  175. actionsMessage="Not available in this context"
  176. actions={[
  177. {
  178. key: 'see-more',
  179. label: t('See More'),
  180. onAction: () => {
  181. // eslint-disable-next-line no-console
  182. console.log('See more!');
  183. },
  184. },
  185. {
  186. key: 'see-less',
  187. label: t('See Less'),
  188. onAction: () => {
  189. // eslint-disable-next-line no-console
  190. console.log('See less!');
  191. },
  192. },
  193. ]}
  194. />
  195. </NormalWidget>
  196. </SideBySide>
  197. </Fragment>
  198. );
  199. });
  200. story('Full Screen View Button', () => {
  201. return (
  202. <Fragment>
  203. <p>
  204. <JSXNode name="WidgetFrame" /> supports a <code>onOpenFullScreenView</code>{' '}
  205. prop. This is a special action that always appears as an individual icon to the
  206. right of the normal actions.
  207. </p>
  208. <SideBySide>
  209. <NormalWidget>
  210. <WidgetFrame title="count()" onFullScreenViewClick={() => {}} />
  211. </NormalWidget>
  212. </SideBySide>
  213. </Fragment>
  214. );
  215. });
  216. });
  217. const NormalWidget = styled('div')`
  218. width: 250px;
  219. height: 100px;
  220. `;