dashboardWidgetQuerySelectorModal.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import {Component, Fragment} from 'react';
  2. import {css} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import type {ModalRenderProps} from 'sentry/actionCreators/modal';
  5. import type {Client} from 'sentry/api';
  6. import {Button} from 'sentry/components/button';
  7. import Input from 'sentry/components/input';
  8. import Link from 'sentry/components/links/link';
  9. import {IconChevron, IconSearch} from 'sentry/icons';
  10. import {t} from 'sentry/locale';
  11. import {space} from 'sentry/styles/space';
  12. import type {Organization, PageFilters} from 'sentry/types';
  13. import {trackAnalytics} from 'sentry/utils/analytics';
  14. import withApi from 'sentry/utils/withApi';
  15. import withPageFilters from 'sentry/utils/withPageFilters';
  16. import type {Widget} from 'sentry/views/dashboards/types';
  17. import {getWidgetDiscoverUrl} from 'sentry/views/dashboards/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. trackAnalytics('dashboards_views.query_selector.selected', {
  58. organization,
  59. widget_type: widget.displayType,
  60. });
  61. }}
  62. aria-label={t('Open in Discover')}
  63. />
  64. </Link>
  65. </QueryContainer>
  66. </Fragment>
  67. );
  68. });
  69. return querySearchBars;
  70. }
  71. render() {
  72. const {Body, Header, widget} = this.props;
  73. return (
  74. <Fragment>
  75. <Header closeButton>
  76. <h4>{widget.title}</h4>
  77. </Header>
  78. <Body>
  79. <p>
  80. {t(
  81. 'Multiple queries were used to create this widget visualization. Which query would you like to view in Discover?'
  82. )}
  83. </p>
  84. {this.renderQueries()}
  85. </Body>
  86. </Fragment>
  87. );
  88. }
  89. }
  90. const StyledInput = styled(Input)`
  91. text-overflow: ellipsis;
  92. padding: 0px;
  93. box-shadow: none;
  94. height: auto;
  95. &:disabled {
  96. border: none;
  97. cursor: default;
  98. }
  99. `;
  100. const QueryContainer = styled('div')`
  101. display: flex;
  102. margin-bottom: ${space(1)};
  103. `;
  104. const OpenInDiscoverButton = styled(Button)`
  105. margin-left: ${space(1)};
  106. `;
  107. const Container = styled('div')`
  108. border: 1px solid ${p => p.theme.border};
  109. box-shadow: inset ${p => p.theme.dropShadowMedium};
  110. background: ${p => p.theme.backgroundSecondary};
  111. padding: 7px ${space(1)};
  112. position: relative;
  113. display: grid;
  114. grid-template-columns: max-content 1fr max-content;
  115. gap: ${space(1)};
  116. align-items: start;
  117. flex-grow: 1;
  118. border-radius: ${p => p.theme.borderRadius};
  119. `;
  120. const SearchLabel = styled('label')`
  121. display: flex;
  122. padding: ${space(0.5)} 0;
  123. margin: 0;
  124. color: ${p => p.theme.gray300};
  125. `;
  126. export const modalCss = css`
  127. width: 100%;
  128. max-width: 700px;
  129. margin: 70px auto;
  130. `;
  131. export default withApi(withPageFilters(DashboardWidgetQuerySelectorModal));