scratchpad.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import styled from '@emotion/styled';
  2. import * as echarts from 'echarts/core';
  3. import {Button} from 'sentry/components/button';
  4. import Panel from 'sentry/components/panels/panel';
  5. import {IconAdd} from 'sentry/icons';
  6. import {space} from 'sentry/styles/space';
  7. import {trackAnalytics} from 'sentry/utils/analytics';
  8. import useOrganization from 'sentry/utils/useOrganization';
  9. import usePageFilters from 'sentry/utils/usePageFilters';
  10. import {DDM_CHART_GROUP, MIN_WIDGET_WIDTH} from 'sentry/views/ddm/constants';
  11. import {MetricWidget, useMetricWidgets} from './widget';
  12. export function MetricScratchpad() {
  13. const {widgets, onChange, addWidget} = useMetricWidgets();
  14. const {selection} = usePageFilters();
  15. const organization = useOrganization();
  16. const Wrapper =
  17. widgets.length === 1 ? StyledSingleWidgetWrapper : StyledMetricDashboard;
  18. echarts.connect(DDM_CHART_GROUP);
  19. return (
  20. <Wrapper>
  21. {widgets.map(widget => (
  22. <MetricWidget
  23. key={widget.position}
  24. widget={{
  25. ...widget,
  26. onChange: data => {
  27. onChange(widget.position, data);
  28. },
  29. }}
  30. datetime={selection.datetime}
  31. projects={selection.projects}
  32. environments={selection.environments}
  33. />
  34. ))}
  35. <AddWidgetPanel
  36. onClick={() => {
  37. trackAnalytics('ddm.widget.add', {
  38. organization,
  39. });
  40. addWidget();
  41. }}
  42. >
  43. <Button icon={<IconAdd isCircled />}>Add widget</Button>
  44. </AddWidgetPanel>
  45. </Wrapper>
  46. );
  47. }
  48. const StyledMetricDashboard = styled('div')`
  49. display: grid;
  50. grid-template-columns: repeat(3, minmax(${MIN_WIDGET_WIDTH}px, 1fr));
  51. gap: ${space(2)};
  52. @media (max-width: ${props => props.theme.breakpoints.xxlarge}) {
  53. grid-template-columns: repeat(2, minmax(${MIN_WIDGET_WIDTH}px, 1fr));
  54. }
  55. @media (max-width: ${props => props.theme.breakpoints.xlarge}) {
  56. grid-template-columns: repeat(1, minmax(${MIN_WIDGET_WIDTH}px, 1fr));
  57. }
  58. grid-auto-rows: 1fr;
  59. `;
  60. const StyledSingleWidgetWrapper = styled('div')`
  61. display: grid;
  62. grid-template-columns: minmax(${MIN_WIDGET_WIDTH}px, 90%) minmax(180px, 10%);
  63. @media (max-width: ${props => props.theme.breakpoints.xlarge}) {
  64. grid-template-columns: repeat(1, minmax(${MIN_WIDGET_WIDTH}px, 1fr));
  65. }
  66. gap: ${space(2)};
  67. grid-auto-rows: 1fr;
  68. `;
  69. const AddWidgetPanel = styled(Panel)`
  70. width: 100%;
  71. height: 100%;
  72. margin-bottom: 0;
  73. padding: ${space(4)};
  74. font-size: ${p => p.theme.fontSizeExtraLarge};
  75. display: flex;
  76. justify-content: center;
  77. align-items: center;
  78. border: 1px dashed ${p => p.theme.border};
  79. &:hover {
  80. background-color: ${p => p.theme.backgroundSecondary};
  81. cursor: pointer;
  82. }
  83. `;