index.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import * as React from 'react';
  2. import {useState} from 'react';
  3. import {css} from '@emotion/react';
  4. import styled from '@emotion/styled';
  5. import {ModalRenderProps} from 'sentry/actionCreators/modal';
  6. import Tooltip from 'sentry/components/tooltip';
  7. import {t, tct} from 'sentry/locale';
  8. import {Organization} from 'sentry/types';
  9. import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
  10. import {assignTempId} from 'sentry/views/dashboardsV2/layoutUtils';
  11. import {DashboardDetails, MAX_WIDGETS, Widget} from 'sentry/views/dashboardsV2/types';
  12. import {WidgetTemplate} from 'sentry/views/dashboardsV2/widgetLibrary/data';
  13. import Button from '../../button';
  14. import ButtonBar from '../../buttonBar';
  15. import DashboardWidgetLibraryTab from './libraryTab';
  16. import {TAB, TabsButtonBar} from './tabsButtonBar';
  17. export type DashboardWidgetLibraryModalOptions = {
  18. dashboard: DashboardDetails;
  19. onAddWidget: (widgets: Widget[]) => void;
  20. organization: Organization;
  21. customWidget?: Widget;
  22. initialSelectedWidgets?: WidgetTemplate[];
  23. };
  24. type Props = ModalRenderProps & DashboardWidgetLibraryModalOptions;
  25. function DashboardWidgetLibraryModal({
  26. Header,
  27. Body,
  28. Footer,
  29. dashboard,
  30. organization,
  31. customWidget,
  32. initialSelectedWidgets,
  33. closeModal,
  34. onAddWidget,
  35. }: Props) {
  36. const [selectedWidgets, setSelectedWidgets] = useState<WidgetTemplate[]>(
  37. initialSelectedWidgets ? initialSelectedWidgets : []
  38. );
  39. const [errored, setErrored] = useState(false);
  40. function handleSubmit() {
  41. onAddWidget([...dashboard.widgets, ...selectedWidgets.map(assignTempId)]);
  42. closeModal();
  43. }
  44. const overLimit = dashboard.widgets.length + selectedWidgets.length > MAX_WIDGETS;
  45. return (
  46. <React.Fragment>
  47. <Header closeButton>
  48. <h4>{t('Add Widget(s)')}</h4>
  49. </Header>
  50. <Body>
  51. <TabsButtonBar
  52. activeTab={TAB.Library}
  53. organization={organization}
  54. dashboard={dashboard}
  55. selectedWidgets={selectedWidgets}
  56. customWidget={customWidget}
  57. onAddWidget={onAddWidget}
  58. />
  59. <DashboardWidgetLibraryTab
  60. selectedWidgets={selectedWidgets}
  61. errored={errored}
  62. setSelectedWidgets={setSelectedWidgets}
  63. setErrored={setErrored}
  64. />
  65. </Body>
  66. <Footer>
  67. <ButtonBar gap={1}>
  68. <Button
  69. external
  70. href="https://docs.sentry.io/product/dashboards/widget-library/"
  71. >
  72. {t('Read the docs')}
  73. </Button>
  74. <Tooltip
  75. title={tct(
  76. 'Exceeds max widgets ([maxWidgets]) per dashboard. Plese unselect [unselectWidgets] widget(s).',
  77. {
  78. maxWidgets: MAX_WIDGETS,
  79. unselectWidgets:
  80. dashboard.widgets.length + selectedWidgets.length - MAX_WIDGETS,
  81. }
  82. )}
  83. disabled={!!!overLimit}
  84. >
  85. <StyledButton
  86. data-test-id="confirm-widgets"
  87. priority="primary"
  88. disabled={overLimit}
  89. type="button"
  90. onClick={() => {
  91. if (!!!selectedWidgets.length) {
  92. setErrored(true);
  93. return;
  94. }
  95. trackAdvancedAnalyticsEvent('dashboards_views.widget_library.add', {
  96. organization,
  97. num_widgets: selectedWidgets.length,
  98. });
  99. selectedWidgets.forEach(selectedWidget => {
  100. trackAdvancedAnalyticsEvent(
  101. 'dashboards_views.widget_library.add_widget',
  102. {
  103. organization,
  104. title: selectedWidget.title,
  105. }
  106. );
  107. });
  108. handleSubmit();
  109. }}
  110. >
  111. {selectedWidgets.length
  112. ? tct('Add ([numWidgets])', {numWidgets: selectedWidgets.length})
  113. : t('Add')}
  114. </StyledButton>
  115. </Tooltip>
  116. </ButtonBar>
  117. </Footer>
  118. </React.Fragment>
  119. );
  120. }
  121. export const modalCss = css`
  122. width: 100%;
  123. max-width: 700px;
  124. margin: 70px auto;
  125. `;
  126. const StyledButton = styled(Button)`
  127. min-width: 90px;
  128. `;
  129. export default DashboardWidgetLibraryModal;