diff --git a/static/app/components/charts/chartWidgetLoader.tsx b/static/app/components/charts/chartWidgetLoader.tsx index 33e9b93cb70ef9..39a52e908db981 100644 --- a/static/app/components/charts/chartWidgetLoader.tsx +++ b/static/app/components/charts/chartWidgetLoader.tsx @@ -165,6 +165,14 @@ const CHART_MAP = { ), overviewRequestsChartWidget: () => import('sentry/views/insights/common/components/widgets/overviewRequestsChartWidget'), + overviewAgentsRunsChartWidget: () => + import( + 'sentry/views/insights/common/components/widgets/overviewAgentsRunsChartWidget' + ), + overviewAgentsDurationChartWidget: () => + import( + 'sentry/views/insights/common/components/widgets/overviewAgentsDurationChartWidget' + ), } satisfies Record Promise<{default: React.FC}>>; /** diff --git a/static/app/views/insights/agentMonitoring/utils/query.tsx b/static/app/views/insights/agentMonitoring/utils/query.tsx new file mode 100644 index 00000000000000..aeb93efa7290a0 --- /dev/null +++ b/static/app/views/insights/agentMonitoring/utils/query.tsx @@ -0,0 +1,7 @@ +// These are the span op we are currently ingesting. +// They will probably change. +const AI_PIPELINE_OPS = ['ai.pipeline.generateText', 'ai.pipeline.generateObject']; + +export const getAgentRunsFilter = () => { + return `span.op:[${AI_PIPELINE_OPS.join(',')}]`; +}; diff --git a/static/app/views/insights/agentMonitoring/views/agentsOverviewPage.tsx b/static/app/views/insights/agentMonitoring/views/agentsOverviewPage.tsx index 0f449a66e6c003..a2038a1d97156f 100644 --- a/static/app/views/insights/agentMonitoring/views/agentsOverviewPage.tsx +++ b/static/app/views/insights/agentMonitoring/views/agentsOverviewPage.tsx @@ -26,8 +26,11 @@ import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLay import {ModulePageProviders} from 'sentry/views/insights/common/components/modulePageProviders'; import {ModuleBodyUpsellHook} from 'sentry/views/insights/common/components/moduleUpsellHookWrapper'; import {ToolRibbon} from 'sentry/views/insights/common/components/ribbon'; +import OverviewAgentsDurationChartWidget from 'sentry/views/insights/common/components/widgets/overviewAgentsDurationChartWidget'; +import OverviewAgentsRunsChartWidget from 'sentry/views/insights/common/components/widgets/overviewAgentsRunsChartWidget'; import {useOnboardingProject} from 'sentry/views/insights/common/queries/useOnboardingProject'; import {AgentsPageHeader} from 'sentry/views/insights/pages/agents/agentsPageHeader'; +import {IssuesWidget} from 'sentry/views/insights/pages/platform/shared/issuesWidget'; import {WidgetGrid} from 'sentry/views/insights/pages/platform/shared/styles'; import {useTransactionNameQuery} from 'sentry/views/insights/pages/platform/shared/useTransactionNameQuery'; import {ModuleName} from 'sentry/views/insights/types'; @@ -76,13 +79,13 @@ function AgentsMonitoringPage() { - + - + - + diff --git a/static/app/views/insights/common/components/widgets/overviewAgentsDurationChartWidget.tsx b/static/app/views/insights/common/components/widgets/overviewAgentsDurationChartWidget.tsx new file mode 100644 index 00000000000000..8eea64a25b30d3 --- /dev/null +++ b/static/app/views/insights/common/components/widgets/overviewAgentsDurationChartWidget.tsx @@ -0,0 +1,17 @@ +import {t} from 'sentry/locale'; +import {getAgentRunsFilter} from 'sentry/views/insights/agentMonitoring/utils/query'; +import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types'; +import BaseLatencyWidget from 'sentry/views/insights/pages/platform/shared/baseLatencyWidget'; + +export default function OverviewAgentsDurationChartWidget( + props: LoadableChartWidgetProps +) { + return ( + + ); +} diff --git a/static/app/views/insights/common/components/widgets/overviewAgentsRunsChartWidget.tsx b/static/app/views/insights/common/components/widgets/overviewAgentsRunsChartWidget.tsx new file mode 100644 index 00000000000000..ee1760ad806b30 --- /dev/null +++ b/static/app/views/insights/common/components/widgets/overviewAgentsRunsChartWidget.tsx @@ -0,0 +1,16 @@ +import {t} from 'sentry/locale'; +import {getAgentRunsFilter} from 'sentry/views/insights/agentMonitoring/utils/query'; +import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types'; +import {BaseTrafficWidget} from 'sentry/views/insights/pages/platform/shared/baseTrafficWidget'; + +export default function OverviewAgentsRunsChartWidget(props: LoadableChartWidgetProps) { + return ( + + ); +} diff --git a/static/app/views/insights/pages/platform/shared/baseLatencyWidget.tsx b/static/app/views/insights/pages/platform/shared/baseLatencyWidget.tsx new file mode 100644 index 00000000000000..e7e4cb07045135 --- /dev/null +++ b/static/app/views/insights/pages/platform/shared/baseLatencyWidget.tsx @@ -0,0 +1,107 @@ +import {useMemo} from 'react'; + +import {openInsightChartModal} from 'sentry/actionCreators/modal'; +import {t} from 'sentry/locale'; +import useOrganization from 'sentry/utils/useOrganization'; +import {Line} from 'sentry/views/dashboards/widgets/timeSeriesWidget/plottables/line'; +import {TimeSeriesWidgetVisualization} from 'sentry/views/dashboards/widgets/timeSeriesWidget/timeSeriesWidgetVisualization'; +import {Widget} from 'sentry/views/dashboards/widgets/widget/widget'; +import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; +import {ChartType} from 'sentry/views/insights/common/components/chart'; +import type {LoadableChartWidgetProps} from 'sentry/views/insights/common/components/widgets/types'; +import {useEAPSeries} from 'sentry/views/insights/common/queries/useDiscoverSeries'; +import {convertSeriesToTimeseries} from 'sentry/views/insights/common/utils/convertSeriesToTimeseries'; +import {Referrer} from 'sentry/views/insights/pages/platform/laravel/referrers'; +import {usePageFilterChartParams} from 'sentry/views/insights/pages/platform/laravel/utils'; +import {WidgetVisualizationStates} from 'sentry/views/insights/pages/platform/laravel/widgetVisualizationStates'; +import {useReleaseBubbleProps} from 'sentry/views/insights/pages/platform/shared/getReleaseBubbleProps'; +import {ModalChartContainer} from 'sentry/views/insights/pages/platform/shared/styles'; +import {Toolbar} from 'sentry/views/insights/pages/platform/shared/toolbar'; +import {useTransactionNameQuery} from 'sentry/views/insights/pages/platform/shared/useTransactionNameQuery'; + +interface BaseLatencyWidgetProps extends LoadableChartWidgetProps { + title: string; + baseQuery?: string; +} + +export default function BaseLatencyWidget({ + title, + baseQuery, + ...props +}: BaseLatencyWidgetProps) { + const organization = useOrganization(); + const {query} = useTransactionNameQuery(); + const pageFilterChartParams = usePageFilterChartParams({ + pageFilters: props.pageFilters, + }); + const releaseBubbleProps = useReleaseBubbleProps(props); + + const fullQuery = `${baseQuery} ${query}`.trim(); + + const {data, isLoading, error} = useEAPSeries( + { + ...pageFilterChartParams, + search: fullQuery, + yAxis: ['avg(span.duration)', 'p95(span.duration)'], + referrer: Referrer.DURATION_CHART, + }, + Referrer.DURATION_CHART, + props.pageFilters + ); + + const plottables = useMemo(() => { + return Object.keys(data).map(key => { + const series = data[key as keyof typeof data]; + return new Line(convertSeriesToTimeseries(series)); + }); + }, [data]); + + const isEmpty = plottables.every(plottable => plottable.isEmpty); + + const visualization = ( + + ); + + return ( + } + Visualization={visualization} + Actions={ + organization.features.includes('visibility-explore-view') && + !isEmpty && ( + { + openInsightChartModal({ + title: t('API Latency'), + children: {visualization}, + }); + }} + /> + ) + } + /> + ); +}