import React, {Fragment} from 'react'; import styled from '@emotion/styled'; import Alert from 'sentry/components/alert'; import {Breadcrumbs} from 'sentry/components/breadcrumbs'; import ButtonBar from 'sentry/components/buttonBar'; import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton'; import * as Layout from 'sentry/components/layouts/thirds'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionTooltip'; import SearchBar from 'sentry/components/searchBar'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {browserHistory} from 'sentry/utils/browserHistory'; import {decodeScalar, decodeSorts} from 'sentry/utils/queryString'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import {useOnboardingProject} from 'sentry/views/performance/browser/webVitals/utils/useOnboardingProject'; import {DurationChart} from 'sentry/views/performance/database/durationChart'; import {NoDataMessage} from 'sentry/views/performance/database/noDataMessage'; import {isAValidSort, QueriesTable} from 'sentry/views/performance/database/queriesTable'; import { MODULE_DESCRIPTION, MODULE_DOC_LINK, MODULE_TITLE, } from 'sentry/views/performance/database/settings'; import {ThroughputChart} from 'sentry/views/performance/database/throughputChart'; import {useSelectedDurationAggregate} from 'sentry/views/performance/database/useSelectedDurationAggregate'; import * as ModuleLayout from 'sentry/views/performance/moduleLayout'; import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders'; import Onboarding from 'sentry/views/performance/onboarding'; import {useModuleBreadcrumbs} from 'sentry/views/performance/utils/useModuleBreadcrumbs'; import {useSynchronizeCharts} from 'sentry/views/starfish/components/chart'; import {useSpanMetrics} from 'sentry/views/starfish/queries/useDiscover'; import {useSpanMetricsSeries} from 'sentry/views/starfish/queries/useDiscoverSeries'; import {ModuleName, SpanMetricsField} from 'sentry/views/starfish/types'; import {QueryParameterNames} from 'sentry/views/starfish/views/queryParameters'; import {ActionSelector} from 'sentry/views/starfish/views/spans/selectors/actionSelector'; import {DomainSelector} from 'sentry/views/starfish/views/spans/selectors/domainSelector'; export function DatabaseLandingPage() { const organization = useOrganization(); const moduleName = ModuleName.DB; const location = useLocation(); const onboardingProject = useOnboardingProject(); const [selectedAggregate] = useSelectedDurationAggregate(); const spanDescription = decodeScalar(location.query?.['span.description'], ''); const spanAction = decodeScalar(location.query?.['span.action']); const spanDomain = decodeScalar(location.query?.['span.domain']); const sortField = decodeScalar(location.query?.[QueryParameterNames.SPANS_SORT]); let sort = decodeSorts(sortField).filter(isAValidSort)[0]; if (!sort) { sort = DEFAULT_SORT; } const handleSearch = (newQuery: string) => { browserHistory.push({ ...location, query: { ...location.query, 'span.description': newQuery === '' ? undefined : newQuery, [QueryParameterNames.SPANS_CURSOR]: undefined, }, }); }; const chartFilters = { 'span.module': ModuleName.DB, has: 'span.description', }; const tableFilters = { 'span.module': ModuleName.DB, 'span.action': spanAction, 'span.domain': spanDomain, 'span.description': spanDescription ? `*${spanDescription}*` : undefined, has: 'span.description', }; const cursor = decodeScalar(location.query?.[QueryParameterNames.SPANS_CURSOR]); const queryListResponse = useSpanMetrics( { search: MutableSearch.fromQueryObject(tableFilters), fields: [ 'project.id', 'span.group', 'span.description', 'spm()', 'avg(span.self_time)', 'sum(span.self_time)', 'time_spent_percentage()', ], sorts: [sort], limit: LIMIT, cursor, }, 'api.starfish.use-span-list' ); const { isLoading: isThroughputDataLoading, data: throughputData, error: throughputError, } = useSpanMetricsSeries( { search: MutableSearch.fromQueryObject(chartFilters), yAxis: ['spm()'], }, 'api.starfish.span-landing-page-metrics-chart' ); const { isLoading: isDurationDataLoading, data: durationData, error: durationError, } = useSpanMetricsSeries( { search: MutableSearch.fromQueryObject(chartFilters), yAxis: [`${selectedAggregate}(${SpanMetricsField.SPAN_SELF_TIME})`], }, 'api.starfish.span-landing-page-metrics-chart' ); const isCriticalDataLoading = isThroughputDataLoading || isDurationDataLoading || queryListResponse.isLoading; const isAnyCriticalDataAvailable = (queryListResponse.data ?? []).length > 0 || durationData[`${selectedAggregate}(span.self_time)`].data?.some( ({value}) => value > 0 ) || throughputData['spm()'].data?.some(({value}) => value > 0); useSynchronizeCharts([!isThroughputDataLoading && !isDurationDataLoading]); const crumbs = useModuleBreadcrumbs('db'); return ( {MODULE_TITLE} {!onboardingProject && !isCriticalDataLoading && ( )} {onboardingProject && ( )} {!onboardingProject && ( )} ); } const DEFAULT_SORT = { field: 'time_spent_percentage()' as const, kind: 'desc' as const, }; function AlertBanner(props) { return ; } const FilterOptionsContainer = styled('div')` display: flex; flex-wrap: wrap; gap: ${space(2)}; @media (min-width: ${p => p.theme.breakpoints.small}) { flex-wrap: nowrap; } `; const SelectorContainer = styled('div')` flex-basis: 100%; @media (min-width: ${p => p.theme.breakpoints.small}) { flex-basis: auto; } `; const LIMIT: number = 25; function PageWithProviders() { return ( ); } export default PageWithProviders;