toolbarSaveAs.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import styled from '@emotion/styled';
  2. import Feature from 'sentry/components/acl/feature';
  3. import {Button} from 'sentry/components/button';
  4. import {DropdownMenu, type MenuItemProps} from 'sentry/components/dropdownMenu';
  5. import {t} from 'sentry/locale';
  6. import {dedupeArray} from 'sentry/utils/dedupeArray';
  7. import {parseFunction, prettifyParsedFunction} from 'sentry/utils/discover/fields';
  8. import useOrganization from 'sentry/utils/useOrganization';
  9. import usePageFilters from 'sentry/utils/usePageFilters';
  10. import useProjects from 'sentry/utils/useProjects';
  11. import {Dataset} from 'sentry/views/alerts/rules/metric/types';
  12. import {
  13. useExploreQuery,
  14. useExploreVisualizes,
  15. } from 'sentry/views/explore/contexts/pageParamsContext';
  16. import {useAddToDashboard} from 'sentry/views/explore/hooks/useAddToDashboard';
  17. import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval';
  18. import {ToolbarSection} from 'sentry/views/explore/toolbar/styles';
  19. import {getAlertsUrl} from 'sentry/views/insights/common/utils/getAlertsUrl';
  20. export function ToolbarSaveAs() {
  21. const {addToDashboard} = useAddToDashboard();
  22. const organization = useOrganization();
  23. const {projects} = useProjects();
  24. const pageFilters = usePageFilters();
  25. const query = useExploreQuery();
  26. const visualizes = useExploreVisualizes();
  27. const visualizeYAxes = visualizes.flatMap(v => v.yAxes);
  28. const [interval] = useChartInterval();
  29. const project =
  30. projects.length === 1
  31. ? projects[0]
  32. : projects.find(p => p.id === `${pageFilters.selection.projects[0]}`);
  33. const alertsUrls = visualizeYAxes.map((yAxis, index) => ({
  34. key: `${yAxis}-${index}`,
  35. label: yAxis,
  36. to: getAlertsUrl({
  37. project,
  38. query,
  39. pageFilters: pageFilters.selection,
  40. aggregate: yAxis,
  41. orgSlug: organization.slug,
  42. dataset: Dataset.EVENTS_ANALYTICS_PLATFORM,
  43. interval,
  44. }),
  45. }));
  46. const items: MenuItemProps[] = [];
  47. if (organization.features.includes('alerts-eap')) {
  48. items.push({
  49. key: 'create-alert',
  50. label: t('An Alert for'),
  51. children: alertsUrls ?? [],
  52. disabled: !alertsUrls || alertsUrls.length === 0,
  53. isSubmenu: true,
  54. });
  55. }
  56. if (organization.features.includes('dashboards-eap')) {
  57. const disableAddToDashboard = !organization.features.includes('dashboards-edit');
  58. const chartOptions = visualizes.map((chart, index) => {
  59. const dedupedYAxes = dedupeArray(chart.yAxes);
  60. const formattedYAxes = dedupedYAxes.map(yaxis => {
  61. const func = parseFunction(yaxis);
  62. return func ? prettifyParsedFunction(func) : undefined;
  63. });
  64. return {
  65. key: chart.label,
  66. label: t('%s - %s', chart.label, formattedYAxes.filter(Boolean).join(', ')),
  67. onAction: !disableAddToDashboard ? () => addToDashboard(index) : undefined,
  68. };
  69. });
  70. items.push({
  71. key: 'add-to-dashboard',
  72. textValue: t('A Dashboard widget'),
  73. isSubmenu: chartOptions.length > 1 ? true : false,
  74. label: (
  75. <Feature
  76. hookName="feature-disabled:dashboards-edit"
  77. features="organizations:dashboards-edit"
  78. renderDisabled={() => <DisabledText>{t('A Dashboard widget')}</DisabledText>}
  79. >
  80. {t('A Dashboard widget')}
  81. </Feature>
  82. ),
  83. disabled: disableAddToDashboard,
  84. children: chartOptions.length > 1 ? chartOptions : undefined,
  85. onAction:
  86. !disableAddToDashboard && chartOptions.length
  87. ? () => addToDashboard(0)
  88. : undefined, // This is hardcoding
  89. });
  90. }
  91. if (items.length === 0) {
  92. return null;
  93. }
  94. return (
  95. <ToolbarSection data-test-id="section-save-as">
  96. <DropdownMenu
  97. items={items}
  98. trigger={triggerProps => (
  99. <SaveAsButton
  100. {...triggerProps}
  101. aria-label={t('Save as')}
  102. onClick={e => {
  103. e.stopPropagation();
  104. e.preventDefault();
  105. triggerProps.onClick?.(e);
  106. }}
  107. >
  108. {`${t('Save as')}\u2026`}
  109. </SaveAsButton>
  110. )}
  111. />
  112. </ToolbarSection>
  113. );
  114. }
  115. const DisabledText = styled('span')`
  116. color: ${p => p.theme.disabled};
  117. `;
  118. const SaveAsButton = styled(Button)`
  119. width: 100%;
  120. `;