dashboardWidgetQuerySelectorModal.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import {Component, Fragment} from 'react';
  2. import {Link} from 'react-router';
  3. import {css} from '@emotion/react';
  4. import styled from '@emotion/styled';
  5. import {ModalRenderProps} from 'sentry/actionCreators/modal';
  6. import {Client} from 'sentry/api';
  7. import Button from 'sentry/components/button';
  8. import Input from 'sentry/components/forms/controls/input';
  9. import {IconChevron, IconSearch} from 'sentry/icons';
  10. import {t} from 'sentry/locale';
  11. import space from 'sentry/styles/space';
  12. import {Organization, PageFilters} from 'sentry/types';
  13. import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
  14. import withApi from 'sentry/utils/withApi';
  15. import withPageFilters from 'sentry/utils/withPageFilters';
  16. import {Widget} from 'sentry/views/dashboardsV2/types';
  17. import {getWidgetDiscoverUrl} from 'sentry/views/dashboardsV2/utils';
  18. export type DashboardWidgetQuerySelectorModalOptions = {
  19. organization: Organization;
  20. widget: Widget;
  21. isMetricsData?: boolean;
  22. };
  23. type Props = ModalRenderProps &
  24. DashboardWidgetQuerySelectorModalOptions & {
  25. api: Client;
  26. organization: Organization;
  27. selection: PageFilters;
  28. };
  29. class DashboardWidgetQuerySelectorModal extends Component<Props> {
  30. renderQueries() {
  31. const {organization, widget, selection, isMetricsData} = this.props;
  32. const querySearchBars = widget.queries.map((query, index) => {
  33. const discoverLocation = getWidgetDiscoverUrl(
  34. {
  35. ...widget,
  36. queries: [query],
  37. },
  38. selection,
  39. organization,
  40. 0,
  41. isMetricsData
  42. );
  43. return (
  44. <Fragment key={index}>
  45. <QueryContainer>
  46. <Container>
  47. <SearchLabel htmlFor="smart-search-input" aria-label={t('Search events')}>
  48. <IconSearch />
  49. </SearchLabel>
  50. <StyledInput value={query.conditions} disabled />
  51. </Container>
  52. <Link to={discoverLocation}>
  53. <OpenInDiscoverButton
  54. priority="primary"
  55. icon={<IconChevron size="xs" direction="right" />}
  56. onClick={() => {
  57. trackAdvancedAnalyticsEvent(
  58. 'dashboards_views.query_selector.selected',
  59. {
  60. organization,
  61. widget_type: widget.displayType,
  62. }
  63. );
  64. }}
  65. aria-label={t('Open in Discover')}
  66. />
  67. </Link>
  68. </QueryContainer>
  69. </Fragment>
  70. );
  71. });
  72. return querySearchBars;
  73. }
  74. render() {
  75. const {Body, Header, widget} = this.props;
  76. return (
  77. <Fragment>
  78. <Header closeButton>
  79. <h4>{widget.title}</h4>
  80. </Header>
  81. <Body>
  82. <p>
  83. {t(
  84. 'Multiple queries were used to create this widget visualization. Which query would you like to view in Discover?'
  85. )}
  86. </p>
  87. {this.renderQueries()}
  88. </Body>
  89. </Fragment>
  90. );
  91. }
  92. }
  93. const StyledInput = styled(Input)`
  94. text-overflow: ellipsis;
  95. padding: 0px;
  96. box-shadow: none;
  97. height: auto;
  98. &:disabled {
  99. border: none;
  100. cursor: default;
  101. }
  102. `;
  103. const QueryContainer = styled('div')`
  104. display: flex;
  105. margin-bottom: ${space(1)};
  106. `;
  107. const OpenInDiscoverButton = styled(Button)`
  108. margin-left: ${space(1)};
  109. `;
  110. const Container = styled('div')`
  111. border: 1px solid ${p => p.theme.border};
  112. box-shadow: inset ${p => p.theme.dropShadowLight};
  113. background: ${p => p.theme.backgroundSecondary};
  114. padding: 7px ${space(1)};
  115. position: relative;
  116. display: grid;
  117. grid-template-columns: max-content 1fr max-content;
  118. gap: ${space(1)};
  119. align-items: start;
  120. flex-grow: 1;
  121. border-radius: ${p => p.theme.borderRadius};
  122. `;
  123. const SearchLabel = styled('label')`
  124. display: flex;
  125. padding: ${space(0.5)} 0;
  126. margin: 0;
  127. color: ${p => p.theme.gray300};
  128. `;
  129. export const modalCss = css`
  130. width: 100%;
  131. max-width: 700px;
  132. margin: 70px auto;
  133. `;
  134. export default withApi(withPageFilters(DashboardWidgetQuerySelectorModal));