index.tsx 3.3 KB

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