File tree Expand file tree Collapse file tree 10 files changed +365
-0
lines changed
views/explore/multiQueryMode Expand file tree Collapse file tree 10 files changed +365
-0
lines changed Original file line number Diff line number Diff line change @@ -2,6 +2,10 @@ import styled from '@emotion/styled';
22
33import { space } from 'sentry/styles/space' ;
44
5+ // Note: This component is also used in Explore multi-query mode
6+ // static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx
7+ // and static/app/views/explore/multiQueryMode/queryConstructors/visualize.tsx
8+ // and not just for PageFilters as the name indicates.
59const PageFilterBar = styled ( 'div' ) < { condensed ?: boolean } > `
610 display: flex;
711 position: relative;
Original file line number Diff line number Diff line change @@ -1901,6 +1901,10 @@ function buildRoutes() {
19011901 >
19021902 < IndexRoute component = { make ( ( ) => import ( 'sentry/views/traces/content' ) ) } />
19031903 { traceViewRoute }
1904+ < Route
1905+ path = "multi-query/"
1906+ component = { make ( ( ) => import ( 'sentry/views/explore/multiQueryMode' ) ) }
1907+ />
19041908 </ Route >
19051909 ) ;
19061910
Original file line number Diff line number Diff line change 1+ import styled from '@emotion/styled' ;
2+
3+ import * as Layout from 'sentry/components/layouts/thirds' ;
4+ import { DatePageFilter } from 'sentry/components/organizations/datePageFilter' ;
5+ import { EnvironmentPageFilter } from 'sentry/components/organizations/environmentPageFilter' ;
6+ import PageFilterBar from 'sentry/components/organizations/pageFilterBar' ;
7+ import { ProjectPageFilter } from 'sentry/components/organizations/projectPageFilter' ;
8+ import { space } from 'sentry/styles/space' ;
9+ import { useExploreDataset } from 'sentry/views/explore/contexts/pageParamsContext' ;
10+ import { SpanTagsProvider } from 'sentry/views/explore/contexts/spanTagsContext' ;
11+ import { QueryRow } from 'sentry/views/explore/multiQueryMode/queryRow' ;
12+
13+ function Content ( ) {
14+ return (
15+ < Layout . Body >
16+ < Layout . Main fullWidth >
17+ < StyledPageFilterBar condensed >
18+ < ProjectPageFilter />
19+ < EnvironmentPageFilter />
20+ < DatePageFilter />
21+ </ StyledPageFilterBar >
22+ < QueryRow />
23+ </ Layout . Main >
24+ </ Layout . Body >
25+ ) ;
26+ }
27+
28+ export function MultiQueryModeContent ( ) {
29+ const dataset = useExploreDataset ( ) ;
30+ return (
31+ < SpanTagsProvider dataset = { dataset } enabled >
32+ < Content />
33+ </ SpanTagsProvider >
34+ ) ;
35+ }
36+
37+ const StyledPageFilterBar = styled ( PageFilterBar ) `
38+ margin-bottom: ${ space ( 2 ) } ;
39+ ` ;
Original file line number Diff line number Diff line change 1+ import Feature from 'sentry/components/acl/feature' ;
2+ import Breadcrumbs from 'sentry/components/breadcrumbs' ;
3+ import * as Layout from 'sentry/components/layouts/thirds' ;
4+ import { NoAccess } from 'sentry/components/noAccess' ;
5+ import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container' ;
6+ import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle' ;
7+ import { t } from 'sentry/locale' ;
8+ import useOrganization from 'sentry/utils/useOrganization' ;
9+ import { MultiQueryModeContent } from 'sentry/views/explore/multiQueryMode/content' ;
10+ import { generateTracesRoute } from 'sentry/views/traces/utils' ;
11+
12+ export default function MultiQueryMode ( ) {
13+ const organization = useOrganization ( ) ;
14+
15+ return (
16+ < Feature
17+ features = "explore-multi-query"
18+ organization = { organization }
19+ renderDisabled = { NoAccess }
20+ >
21+ < SentryDocumentTitle title = { t ( 'Multi Query Mode' ) } orgSlug = { organization . slug } >
22+ < Layout . Header >
23+ < Layout . HeaderContent >
24+ < Breadcrumbs
25+ crumbs = { [
26+ {
27+ label : t ( 'Explore' ) ,
28+ to : generateTracesRoute ( { orgSlug : organization . slug } ) ,
29+ } ,
30+ {
31+ label : t ( 'Multi Query Mode' ) ,
32+ } ,
33+ ] }
34+ />
35+ < Layout . Title > { t ( 'Multi Query Mode' ) } </ Layout . Title >
36+ </ Layout . HeaderContent >
37+ </ Layout . Header >
38+ < Layout . Page >
39+ < PageFiltersContainer >
40+ < MultiQueryModeContent />
41+ </ PageFiltersContainer >
42+ </ Layout . Page >
43+ </ SentryDocumentTitle >
44+ </ Feature >
45+ ) ;
46+ }
Original file line number Diff line number Diff line change 1+ import { useMemo } from 'react' ;
2+ import styled from '@emotion/styled' ;
3+
4+ import { CompactSelect , type SelectOption } from 'sentry/components/compactSelect' ;
5+ import { t } from 'sentry/locale' ;
6+ import { useSpanTags } from 'sentry/views/explore/contexts/spanTagsContext' ;
7+ import {
8+ Section ,
9+ SectionHeader ,
10+ SectionLabel ,
11+ } from 'sentry/views/explore/multiQueryMode/queryConstructors/styles' ;
12+
13+ export function GroupBySection ( ) {
14+ const tags = useSpanTags ( ) ;
15+
16+ const enabledOptions : Array < SelectOption < string > > = useMemo ( ( ) => {
17+ const potentialOptions = Object . keys ( tags ) . filter ( key => key !== 'id' ) ;
18+ potentialOptions . sort ( ) ;
19+
20+ return potentialOptions . map ( key => ( {
21+ label : key ,
22+ value : key ,
23+ textValue : key ,
24+ } ) ) ;
25+ } , [ tags ] ) ;
26+
27+ return (
28+ < Section data-test-id = "section-group-by" >
29+ < SectionHeader >
30+ < SectionLabel underlined = { false } > { t ( 'Group By' ) } </ SectionLabel >
31+ </ SectionHeader >
32+ < StyledCompactSelect multiple options = { enabledOptions } clearable searchable />
33+ </ Section >
34+ ) ;
35+ }
36+
37+ const StyledCompactSelect = styled ( CompactSelect ) `
38+ width: 100%;
39+ > button {
40+ width: 100%;
41+ }
42+ ` ;
Original file line number Diff line number Diff line change 1+ import { EAPSpanSearchQueryBuilder } from 'sentry/components/performance/spanSearchQueryBuilder' ;
2+ import { t } from 'sentry/locale' ;
3+ import usePageFilters from 'sentry/utils/usePageFilters' ;
4+ import { useSpanTags } from 'sentry/views/explore/contexts/spanTagsContext' ;
5+ import {
6+ Section ,
7+ SectionHeader ,
8+ SectionLabel ,
9+ } from 'sentry/views/explore/multiQueryMode/queryConstructors/styles' ;
10+
11+ export function SearchBarSection ( ) {
12+ const { selection} = usePageFilters ( ) ;
13+ const numberTags = useSpanTags ( 'number' ) ;
14+ const stringTags = useSpanTags ( 'string' ) ;
15+
16+ return (
17+ < Section data-test-id = "section-filter" >
18+ < SectionHeader >
19+ < SectionLabel underlined = { false } > { t ( 'Filter' ) } </ SectionLabel >
20+ </ SectionHeader >
21+ < EAPSpanSearchQueryBuilder
22+ projects = { selection . projects }
23+ initialQuery = { '' }
24+ onSearch = { ( ) => { } }
25+ searchSource = "explore"
26+ numberTags = { numberTags }
27+ stringTags = { stringTags }
28+ />
29+ </ Section >
30+ ) ;
31+ }
Original file line number Diff line number Diff line change 1+ import { Fragment , useMemo } from 'react' ;
2+
3+ import { CompactSelect , type SelectOption } from 'sentry/components/compactSelect' ;
4+ import PageFilterBar from 'sentry/components/organizations/pageFilterBar' ;
5+ import { Tooltip } from 'sentry/components/tooltip' ;
6+ import { t } from 'sentry/locale' ;
7+ import type { Sort } from 'sentry/utils/discover/fields' ;
8+ import {
9+ Section ,
10+ SectionHeader ,
11+ SectionLabel ,
12+ } from 'sentry/views/explore/multiQueryMode/queryConstructors/styles' ;
13+
14+ export function SortBySection ( ) {
15+ const kindOptions : Array < SelectOption < Sort [ 'kind' ] > > = useMemo ( ( ) => {
16+ return [
17+ {
18+ label : 'Desc' ,
19+ value : 'desc' ,
20+ textValue : t ( 'Descending' ) ,
21+ } ,
22+ {
23+ label : 'Asc' ,
24+ value : 'asc' ,
25+ textValue : t ( 'Ascending' ) ,
26+ } ,
27+ ] ;
28+ } , [ ] ) ;
29+
30+ return (
31+ < Section data-test-id = "section-sort-by" >
32+ < SectionHeader >
33+ < Tooltip
34+ position = "right"
35+ title = { t ( 'Results you see first and last in your samples or aggregates.' ) }
36+ >
37+ < SectionLabel > { t ( 'Sort By' ) } </ SectionLabel >
38+ </ Tooltip >
39+ </ SectionHeader >
40+ < Fragment >
41+ < PageFilterBar >
42+ < CompactSelect options = { [ ] } value = { undefined } onChange = { _newSortField => { } } />
43+ < CompactSelect
44+ options = { kindOptions }
45+ value = { undefined }
46+ onChange = { _newSortKind => { } }
47+ />
48+ </ PageFilterBar >
49+ </ Fragment >
50+ </ Section >
51+ ) ;
52+ }
Original file line number Diff line number Diff line change 1+ import styled from '@emotion/styled' ;
2+
3+ import { space } from 'sentry/styles/space' ;
4+ import { defined } from 'sentry/utils' ;
5+
6+ export const Section = styled ( 'div' ) `
7+ margin-bottom: ${ space ( 2 ) } ;
8+ ` ;
9+
10+ export const SectionHeader = styled ( 'div' ) `
11+ display: flex;
12+ flex-direction: row;
13+ justify-content: space-between;
14+ align-items: baseline;
15+ margin-bottom: ${ space ( 0.5 ) } ;
16+ ` ;
17+
18+ export const SectionLabel = styled ( 'h6' ) < { disabled ?: boolean ; underlined ?: boolean } > `
19+ color: ${ p => ( p . disabled ? p . theme . gray300 : p . theme . gray500 ) } ;
20+ height: ${ p => p . theme . form . md . height } ;
21+ min-height: ${ p => p . theme . form . md . minHeight } ;
22+ font-size: ${ p => p . theme . form . md . fontSize } ;
23+ margin: 0;
24+ ${ p =>
25+ ! defined ( p . underlined ) || p . underlined
26+ ? `text-decoration: underline dotted ${ p . disabled ? p . theme . gray300 : p . theme . gray300 } `
27+ : '' } ;
28+ ` ;
Original file line number Diff line number Diff line change 1+ import { Fragment , useMemo } from 'react' ;
2+
3+ import { CompactSelect , type SelectOption } from 'sentry/components/compactSelect' ;
4+ import PageFilterBar from 'sentry/components/organizations/pageFilterBar' ;
5+ import { Tooltip } from 'sentry/components/tooltip' ;
6+ import { t } from 'sentry/locale' ;
7+ import { ALLOWED_EXPLORE_VISUALIZE_AGGREGATES } from 'sentry/utils/fields' ;
8+ import { useSpanTags } from 'sentry/views/explore/contexts/spanTagsContext' ;
9+ import {
10+ Section ,
11+ SectionHeader ,
12+ SectionLabel ,
13+ } from 'sentry/views/explore/multiQueryMode/queryConstructors/styles' ;
14+
15+ export function VisualizeSection ( ) {
16+ const numberTags = useSpanTags ( 'number' ) ;
17+
18+ const fieldOptions : Array < SelectOption < string > > = useMemo ( ( ) => {
19+ const options = Object . values ( numberTags ) . map ( tag => {
20+ return {
21+ label : tag . name ,
22+ value : tag . key ,
23+ textValue : tag . name ,
24+ } ;
25+ } ) ;
26+
27+ options . sort ( ( a , b ) => {
28+ if ( a . label < b . label ) {
29+ return - 1 ;
30+ }
31+
32+ if ( a . label > b . label ) {
33+ return 1 ;
34+ }
35+
36+ return 0 ;
37+ } ) ;
38+
39+ return options ;
40+ } , [ numberTags ] ) ;
41+
42+ const aggregateOptions : Array < SelectOption < string > > = useMemo ( ( ) => {
43+ return ALLOWED_EXPLORE_VISUALIZE_AGGREGATES . map ( aggregate => {
44+ return {
45+ label : aggregate ,
46+ value : aggregate ,
47+ textValue : aggregate ,
48+ } ;
49+ } ) ;
50+ } , [ ] ) ;
51+
52+ return (
53+ < Section data-test-id = "section-visualize" >
54+ < SectionHeader >
55+ < Tooltip
56+ position = "right"
57+ title = { t (
58+ 'Primary metric that appears in your chart. You can also overlay a series onto an existing chart or add an equation.'
59+ ) }
60+ >
61+ < SectionLabel > { t ( 'Visualize' ) } </ SectionLabel >
62+ </ Tooltip >
63+ </ SectionHeader >
64+ < Fragment >
65+ < PageFilterBar >
66+ < CompactSelect
67+ searchable
68+ options = { fieldOptions }
69+ value = { '' }
70+ onChange = { _newField => { } }
71+ />
72+ < CompactSelect
73+ options = { aggregateOptions }
74+ value = { '' }
75+ onChange = { _newAggregate => { } }
76+ />
77+ </ PageFilterBar >
78+ </ Fragment >
79+ </ Section >
80+ ) ;
81+ }
Original file line number Diff line number Diff line change 1+ import styled from '@emotion/styled' ;
2+
3+ import { space } from 'sentry/styles/space' ;
4+ import { GroupBySection } from 'sentry/views/explore/multiQueryMode/queryConstructors/groupBy' ;
5+ import { SearchBarSection } from 'sentry/views/explore/multiQueryMode/queryConstructors/search' ;
6+ import { SortBySection } from 'sentry/views/explore/multiQueryMode/queryConstructors/sortBy' ;
7+ import { VisualizeSection } from 'sentry/views/explore/multiQueryMode/queryConstructors/visualize' ;
8+
9+ export function QueryRow ( ) {
10+ return (
11+ < QueryConstructionSection >
12+ < SearchBarSection />
13+ < DropDownGrid >
14+ < VisualizeSection />
15+ < GroupBySection />
16+ < SortBySection />
17+ </ DropDownGrid >
18+ </ QueryConstructionSection >
19+ ) ;
20+ }
21+
22+ const QueryConstructionSection = styled ( 'div' ) `
23+ display: grid;
24+ width: 100%;
25+
26+ @media (min-width: ${ p => p . theme . breakpoints . large } ) {
27+ grid-template-columns: minmax(400px, 1fr) 1fr;
28+ margin-bottom: 0;
29+ gap: ${ space ( 2 ) } ;
30+ }
31+ ` ;
32+
33+ const DropDownGrid = styled ( 'div' ) `
34+ display: grid;
35+ grid-template-columns: repeat(3, 1fr);
36+ margin-bottom: 0;
37+ gap: ${ space ( 2 ) } ;
38+ ` ;
You can’t perform that action at this time.
0 commit comments