index.tsx 3.5 KB

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