index.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import {Fragment} from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import {openWidgetBuilderOverwriteModal} from 'sentry/actionCreators/modal';
  5. import type {OverwriteWidgetModalProps} from 'sentry/components/modals/widgetBuilder/overwriteWidgetModal';
  6. import {t} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. import type {Organization} from 'sentry/types/organization';
  9. import {DisplayType} from 'sentry/views/dashboards/types';
  10. import type {WidgetTemplate} from 'sentry/views/dashboards/widgetLibrary/data';
  11. import {getTopNConvertedDefaultWidgets} from 'sentry/views/dashboards/widgetLibrary/data';
  12. import {normalizeQueries} from '../utils';
  13. import {Card} from './card';
  14. interface Props {
  15. bypassOverwriteModal: boolean;
  16. onWidgetSelect: (widget: WidgetTemplate) => void;
  17. organization: Organization;
  18. selectedWidgetId: string | null;
  19. }
  20. export function WidgetLibrary({
  21. bypassOverwriteModal,
  22. onWidgetSelect,
  23. selectedWidgetId,
  24. organization,
  25. }: Props) {
  26. const theme = useTheme();
  27. const defaultWidgets = getTopNConvertedDefaultWidgets(organization);
  28. function getLibrarySelectionHandler(
  29. widget: OverwriteWidgetModalProps['widget'],
  30. iconColor: OverwriteWidgetModalProps['iconColor']
  31. ) {
  32. return function handleWidgetSelect() {
  33. if (bypassOverwriteModal) {
  34. onWidgetSelect(widget);
  35. return;
  36. }
  37. openWidgetBuilderOverwriteModal({
  38. onConfirm: () => onWidgetSelect(widget),
  39. widget,
  40. iconColor,
  41. });
  42. };
  43. }
  44. return (
  45. <Fragment>
  46. <Header>{t('Widget Library')}</Header>
  47. <WidgetLibraryWrapper>
  48. {defaultWidgets.map((widget, index) => {
  49. const iconColor = theme.charts.getColorPalette(defaultWidgets.length - 2)[
  50. index
  51. ];
  52. const displayType =
  53. widget.displayType === DisplayType.TOP_N
  54. ? DisplayType.TABLE
  55. : widget.displayType;
  56. const normalizedQueries = normalizeQueries({
  57. displayType,
  58. queries: widget.queries,
  59. widgetType: widget.widgetType,
  60. organization: organization,
  61. });
  62. const newWidget = {
  63. ...widget,
  64. displayType,
  65. queries: normalizedQueries,
  66. };
  67. return (
  68. <CardHoverWrapper
  69. selected={selectedWidgetId === widget.id}
  70. key={widget.title}
  71. onClick={getLibrarySelectionHandler(newWidget, iconColor)}
  72. >
  73. <Card widget={newWidget} iconColor={iconColor} />
  74. </CardHoverWrapper>
  75. );
  76. })}
  77. </WidgetLibraryWrapper>
  78. </Fragment>
  79. );
  80. }
  81. const WidgetLibraryWrapper = styled('div')`
  82. display: flex;
  83. flex-direction: column;
  84. `;
  85. const Header = styled('h5')`
  86. /* to be aligned with the 30px of Layout.main padding */
  87. padding-left: calc(${space(2)} - ${space(0.25)});
  88. `;
  89. const CardHoverWrapper = styled('div')<{selected: boolean}>`
  90. /* to be aligned with the 30px of Layout.main padding - 1px of the widget item border */
  91. padding: calc(${space(2)} - 3px);
  92. border: 1px solid transparent;
  93. border-radius: ${p => p.theme.borderRadius};
  94. transition: border-color 0.3s ease;
  95. cursor: pointer;
  96. &:hover {
  97. border-color: ${p => p.theme.gray100};
  98. }
  99. ${p => p.selected && `border-color: ${p.theme.gray200};`}
  100. `;