diff --git a/static/app/components/sidebar/index.tsx b/static/app/components/sidebar/index.tsx index 305e8c8655a1bf..0f9f105e32edcd 100644 --- a/static/app/components/sidebar/index.tsx +++ b/static/app/components/sidebar/index.tsx @@ -53,7 +53,12 @@ import {useLocation} from 'sentry/utils/useLocation'; import useMedia from 'sentry/utils/useMedia'; import useOrganization from 'sentry/utils/useOrganization'; import {makeAlertsPathname} from 'sentry/views/alerts/pathnames'; +import {AgentInsightsFeature} from 'sentry/views/insights/agentMonitoring/utils/features'; import {MODULE_BASE_URLS} from 'sentry/views/insights/common/utils/useModuleURL'; +import { + AGENTS_LANDING_SUB_PATH, + AGENTS_SIDEBAR_LABEL, +} from 'sentry/views/insights/pages/agents/settings'; import { AI_LANDING_SUB_PATH, AI_SIDEBAR_LABEL, @@ -380,13 +385,26 @@ function Sidebar() { id="performance-domains-mobile" icon={} /> - } - /> + ( + } + /> + )} + > + } + /> + ); diff --git a/static/app/routes.tsx b/static/app/routes.tsx index 6de4b01a93ad69..8511087af5e12e 100644 --- a/static/app/routes.tsx +++ b/static/app/routes.tsx @@ -17,6 +17,7 @@ import AuthLayout from 'sentry/views/auth/layout'; import {automationRoutes} from 'sentry/views/automations/routes'; import {detectorRoutes} from 'sentry/views/detectors/routes'; import {MODULE_BASE_URLS} from 'sentry/views/insights/common/utils/useModuleURL'; +import {AGENTS_LANDING_SUB_PATH} from 'sentry/views/insights/pages/agents/settings'; import {AI_LANDING_SUB_PATH} from 'sentry/views/insights/pages/ai/settings'; import {BACKEND_LANDING_SUB_PATH} from 'sentry/views/insights/pages/backend/settings'; import {FRONTEND_LANDING_SUB_PATH} from 'sentry/views/insights/pages/frontend/settings'; @@ -1797,6 +1798,16 @@ function buildRoutes() { {traceViewRoute} {moduleRoutes} + + import('sentry/views/insights/agentMonitoring/views/agentsOverviewPage') + )} + /> + {transactionSummaryRoutes} + {traceViewRoute} + {moduleRoutes} + import('sentry/views/projects/'))}> {projectsChildRoutes} diff --git a/static/app/utils/analytics/insightAnalyticEvents.tsx b/static/app/utils/analytics/insightAnalyticEvents.tsx index 855fc0b322777e..fd0c77a1a8047d 100644 --- a/static/app/utils/analytics/insightAnalyticEvents.tsx +++ b/static/app/utils/analytics/insightAnalyticEvents.tsx @@ -23,6 +23,7 @@ export type InsightEventParameters = { 'insight.general.select_region_value': {regions: string[]}; 'insight.general.table_paginate': {direction: string; source: string}; 'insight.general.table_sort': {direction: string; field: string; source: string}; + 'insight.page_loads.agents': {has_ever_sent_data: boolean; view: DomainView}; 'insight.page_loads.ai': {has_ever_sent_data: boolean; view: DomainView}; 'insight.page_loads.app_start': {has_ever_sent_data: boolean; view: DomainView}; 'insight.page_loads.assets': {has_ever_sent_data: boolean; view: DomainView}; @@ -55,6 +56,7 @@ export type InsightEventKey = keyof InsightEventParameters; export const insightEventMap: Record = { 'insights.page_loads.overview': 'Insights: Overview Page Load', 'insight.page_loads.ai': 'Insights: AI Page Load', + 'insight.page_loads.agents': 'Insights: Agents Page Load', 'insight.page_loads.app_start': 'Insights: App Start Page Load', 'insight.page_loads.assets': 'Insights: Assets Page Load', 'insight.page_loads.cache': 'Insights: Cache Page Load', diff --git a/static/app/views/insights/agentMonitoring/settings.ts b/static/app/views/insights/agentMonitoring/settings.ts new file mode 100644 index 00000000000000..cac0d93346e5f8 --- /dev/null +++ b/static/app/views/insights/agentMonitoring/settings.ts @@ -0,0 +1,11 @@ +import {t} from 'sentry/locale'; + +export const MODULE_TITLE = t('Overview'); +export const BASE_URL = ''; + +export const DATA_TYPE = t('Agent'); +export const DATA_TYPE_PLURAL = t('Agents'); + +export const MODULE_DOC_LINK = 'https://docs.sentry.io/product/insights/ai/'; + +export const MODULE_FEATURES = ['insights-addon-modules', 'agents-insights']; diff --git a/static/app/views/insights/agentMonitoring/utils/features.tsx b/static/app/views/insights/agentMonitoring/utils/features.tsx new file mode 100644 index 00000000000000..ce893506b9f76a --- /dev/null +++ b/static/app/views/insights/agentMonitoring/utils/features.tsx @@ -0,0 +1,17 @@ +import Feature from 'sentry/components/acl/feature'; +import {NoAccess} from 'sentry/components/noAccess'; +import type {Organization} from 'sentry/types/organization'; + +export function hasAgentInsights(organization: Organization) { + return organization.features.includes('agents-insights'); +} + +type AgentInsightsFeatureProps = Omit[0], 'features'>; + +export function AgentInsightsFeature(props: AgentInsightsFeatureProps) { + return ( + + {props.children} + + ); +} diff --git a/static/app/views/insights/agentMonitoring/views/agentsOverviewPage.tsx b/static/app/views/insights/agentMonitoring/views/agentsOverviewPage.tsx new file mode 100644 index 00000000000000..c0218da5fb4adb --- /dev/null +++ b/static/app/views/insights/agentMonitoring/views/agentsOverviewPage.tsx @@ -0,0 +1,57 @@ +import styled from '@emotion/styled'; + +import * as Layout from 'sentry/components/layouts/thirds'; +import {AgentInsightsFeature} from 'sentry/views/insights/agentMonitoring/utils/features'; +import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; +import {ModulePageFilterBar} from 'sentry/views/insights/common/components/modulePageFilterBar'; +import {ModulePageProviders} from 'sentry/views/insights/common/components/modulePageProviders'; +import {ModuleBodyUpsellHook} from 'sentry/views/insights/common/components/moduleUpsellHookWrapper'; +import {AgentsPageHeader} from 'sentry/views/insights/pages/agents/agentsPageHeader'; +import {ModuleName} from 'sentry/views/insights/types'; + +function AgentsMonitoringPage() { + return ( + + + + + + + + + + + Agent Monitoring Dashboard + + + + + + + ); +} + +function PageWithProviders() { + return ( + + + + + + ); +} + +const DashboardPlaceholder = styled('div')` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: ${p => p.theme.gray300}; + font-size: ${p => p.theme.fontSizeLarge}; + font-weight: ${p => p.theme.fontWeightBold}; +`; + +export default PageWithProviders; diff --git a/static/app/views/insights/common/components/modulesOnboarding.tsx b/static/app/views/insights/common/components/modulesOnboarding.tsx index 85ce0d7f57d7af..df1060d77359b4 100644 --- a/static/app/views/insights/common/components/modulesOnboarding.tsx +++ b/static/app/views/insights/common/components/modulesOnboarding.tsx @@ -307,6 +307,13 @@ const EMPTY_STATE_CONTENT: Record = { imageSrc: llmPreviewImg, supportedSdks: ['python'], }, + agents: { + heading: t('TODO'), + description: t('TODO'), + valuePropDescription: t('Mobile UI load insights include:'), + valuePropPoints: [], + imageSrc: screenLoadsPreviewImg, + }, 'mobile-ui': { heading: t('TODO'), description: t('TODO'), diff --git a/static/app/views/insights/common/queries/useHasFirstSpan.tsx b/static/app/views/insights/common/queries/useHasFirstSpan.tsx index cdd1ede6ba6637..392033cb223202 100644 --- a/static/app/views/insights/common/queries/useHasFirstSpan.tsx +++ b/static/app/views/insights/common/queries/useHasFirstSpan.tsx @@ -11,6 +11,7 @@ const excludedModuleNames = [ ModuleName.CRONS, ModuleName.UPTIME, ModuleName.SESSIONS, + ModuleName.AGENTS, ] as const; type ExcludedModuleNames = (typeof excludedModuleNames)[number]; diff --git a/static/app/views/insights/common/utils/useModuleURL.tsx b/static/app/views/insights/common/utils/useModuleURL.tsx index c5b9cc07f43c57..353444f781f7d8 100644 --- a/static/app/views/insights/common/utils/useModuleURL.tsx +++ b/static/app/views/insights/common/utils/useModuleURL.tsx @@ -1,5 +1,6 @@ import normalizeUrl from 'sentry/utils/url/normalizeUrl'; import useOrganization from 'sentry/utils/useOrganization'; +import {BASE_URL as AGENTS_BASE_URL} from 'sentry/views/insights/agentMonitoring/settings'; import {BASE_URL as RESOURCES_BASE_URL} from 'sentry/views/insights/browser/resources/settings'; import {BASE_URL as VITALS_BASE_URL} from 'sentry/views/insights/browser/webVitals/settings'; import {BASE_URL as CACHE_BASE_URL} from 'sentry/views/insights/cache/settings'; @@ -33,6 +34,7 @@ export const MODULE_BASE_URLS: Record = { [ModuleName.VITAL]: VITALS_BASE_URL, [ModuleName.RESOURCE]: RESOURCES_BASE_URL, [ModuleName.AI]: AI_BASE_URL, + [ModuleName.AGENTS]: AGENTS_BASE_URL, [ModuleName.MOBILE_UI]: MOBILE_UI_BASE_URL, [ModuleName.MOBILE_VITALS]: MOBILE_SCREENS_BASE_URL, [ModuleName.SCREEN_RENDERING]: SCREEN_RENDERING_BASE_URL, diff --git a/static/app/views/insights/common/views/spans/selectors/actionSelector.tsx b/static/app/views/insights/common/views/spans/selectors/actionSelector.tsx index 395d2f3748926c..07faca7fa8ac42 100644 --- a/static/app/views/insights/common/views/spans/selectors/actionSelector.tsx +++ b/static/app/views/insights/common/views/spans/selectors/actionSelector.tsx @@ -132,5 +132,6 @@ const LABEL_FOR_MODULE_NAME: Record = { 'mobile-vitals': t('Action'), 'screen-rendering': t('Action'), ai: 'Action', + agents: t('Action'), sessions: t('Action'), }; diff --git a/static/app/views/insights/pages/agents/agentsPageHeader.tsx b/static/app/views/insights/pages/agents/agentsPageHeader.tsx new file mode 100644 index 00000000000000..cfe1835270a090 --- /dev/null +++ b/static/app/views/insights/pages/agents/agentsPageHeader.tsx @@ -0,0 +1,51 @@ +import normalizeUrl from 'sentry/utils/url/normalizeUrl'; +import useOrganization from 'sentry/utils/useOrganization'; +import { + AGENTS_LANDING_SUB_PATH, + AGENTS_LANDING_TITLE, + MODULES, +} from 'sentry/views/insights/pages/agents/settings'; +import { + DomainViewHeader, + type Props as HeaderProps, +} from 'sentry/views/insights/pages/domainViewHeader'; +import {DOMAIN_VIEW_BASE_URL} from 'sentry/views/insights/pages/settings'; + +type Props = { + breadcrumbs?: HeaderProps['additionalBreadCrumbs']; + headerActions?: HeaderProps['additonalHeaderActions']; + headerTitle?: HeaderProps['headerTitle']; + hideDefaultTabs?: HeaderProps['hideDefaultTabs']; + module?: HeaderProps['selectedModule']; + tabs?: HeaderProps['tabs']; +}; + +export function AgentsPageHeader({ + module, + headerTitle, + headerActions, + breadcrumbs, + tabs, + hideDefaultTabs, +}: Props) { + const {slug} = useOrganization(); + + const agentsBaseUrl = normalizeUrl( + `/organizations/${slug}/${DOMAIN_VIEW_BASE_URL}/${AGENTS_LANDING_SUB_PATH}` + ); + + return ( + + ); +} diff --git a/static/app/views/insights/pages/agents/settings.ts b/static/app/views/insights/pages/agents/settings.ts new file mode 100644 index 00000000000000..fd5ef5f7d64b94 --- /dev/null +++ b/static/app/views/insights/pages/agents/settings.ts @@ -0,0 +1,8 @@ +import {t} from 'sentry/locale'; +import {ModuleName} from 'sentry/views/insights/types'; + +export const AGENTS_LANDING_SUB_PATH = 'agents'; +export const AGENTS_LANDING_TITLE = t('Agents'); +export const AGENTS_SIDEBAR_LABEL = t('Agents'); + +export const MODULES = [ModuleName.AGENTS]; diff --git a/static/app/views/insights/settings.ts b/static/app/views/insights/settings.ts index b27be8d60d6848..a574dd92e08585 100644 --- a/static/app/views/insights/settings.ts +++ b/static/app/views/insights/settings.ts @@ -1,4 +1,11 @@ import {t} from 'sentry/locale'; +import { + DATA_TYPE as AGENTS_DATA_TYPE, + DATA_TYPE_PLURAL as AGENTS_DATA_TYPE_PLURAL, + MODULE_DOC_LINK as AGENTS_MODULE_DOC_LINK, + MODULE_FEATURES as AGENTS_MODULE_FEATURES, + MODULE_TITLE as AGENTS_MODULE_TITLE, +} from 'sentry/views/insights/agentMonitoring/settings'; import { DATA_TYPE as RESOURCE_DATA_TYPE, DATA_TYPE_PLURAL as RESOURCE_DATA_TYPE_PLURAL, @@ -128,6 +135,7 @@ export const MODULE_TITLES: Record = { [ModuleName.VITAL]: VITALS_MODULE_TITLE, [ModuleName.RESOURCE]: RESOURCES_MODULE_TITLE, [ModuleName.AI]: AI_MODULE_TITLE, + [ModuleName.AGENTS]: AGENTS_MODULE_TITLE, [ModuleName.MOBILE_UI]: MOBILE_UI_MODULE_TITLE, [ModuleName.MOBILE_VITALS]: MOBILE_SCREENS_MODULE_TITLE, [ModuleName.SCREEN_RENDERING]: SCREEN_RENDERING_MODULE_TITLE, @@ -147,6 +155,7 @@ export const MODULE_DATA_TYPES: Record = { [ModuleName.VITAL]: WEB_VITALS_DATA_TYPE, [ModuleName.RESOURCE]: RESOURCE_DATA_TYPE, [ModuleName.AI]: AI_DATA_TYPE, + [ModuleName.AGENTS]: AGENTS_DATA_TYPE, [ModuleName.MOBILE_UI]: t('Mobile UI'), [ModuleName.MOBILE_VITALS]: MOBILE_SCREENS_DATA_TYPE, [ModuleName.SCREEN_RENDERING]: SCREEN_RENDERING_DATA_TYPE, @@ -166,6 +175,7 @@ export const MODULE_DATA_TYPES_PLURAL: Record = { [ModuleName.VITAL]: WEB_VITALS_DATA_TYPE_PLURAL, [ModuleName.RESOURCE]: RESOURCE_DATA_TYPE_PLURAL, [ModuleName.AI]: AI_DATA_TYPE_PLURAL, + [ModuleName.AGENTS]: AGENTS_DATA_TYPE_PLURAL, [ModuleName.MOBILE_UI]: t('Mobile UI'), [ModuleName.MOBILE_VITALS]: MOBILE_SCREENS_DATA_TYPE_PLURAL, [ModuleName.SCREEN_RENDERING]: SCREEN_RENDERING_DATA_TYPE_PLURAL, @@ -188,6 +198,7 @@ export const MODULE_PRODUCT_DOC_LINKS = { [ModuleName.VITAL]: VITALS_MODULE_DOC_LINK, [ModuleName.RESOURCE]: RESOURCES_MODULE_DOC_LINK, [ModuleName.AI]: AI_MODULE_DOC_LINK, + [ModuleName.AGENTS]: AGENTS_MODULE_DOC_LINK, [ModuleName.MOBILE_UI]: MODULE_UI_DOC_LINK, [ModuleName.MOBILE_VITALS]: MODULE_SCREENS_DOC_LINK, [ModuleName.SCREEN_RENDERING]: SCREEN_RENDERING_MODULE_DOC_LINK, @@ -212,6 +223,7 @@ export const MODULE_FEATURE_MAP: Record = { [ModuleName.CACHE]: CACHE_MODULE_FEATURES, [ModuleName.QUEUE]: QUEUE_MODULE_FEATURES, [ModuleName.AI]: AI_MODULE_FEATURES, + [ModuleName.AGENTS]: AGENTS_MODULE_FEATURES, [ModuleName.SCREEN_LOAD]: SCREEN_LOADS_MODULE_FEATURES, [ModuleName.MOBILE_UI]: MOBILE_UI_MODULE_FEATURES, [ModuleName.MOBILE_VITALS]: [MOBILE_SCREENS_MODULE_FEATURE], @@ -234,6 +246,7 @@ export const MODULE_FEATURE_VISIBLE_MAP: Record = { [ModuleName.CACHE]: ['insights-entry-points'], [ModuleName.QUEUE]: ['insights-entry-points'], [ModuleName.AI]: ['insights-entry-points'], + [ModuleName.AGENTS]: ['insights-entry-points'], [ModuleName.SCREEN_LOAD]: ['insights-entry-points'], [ModuleName.MOBILE_UI]: ['insights-entry-points'], [ModuleName.MOBILE_VITALS]: ['insights-entry-points'], diff --git a/static/app/views/insights/types.tsx b/static/app/views/insights/types.tsx index af3bf96a61592f..6b42fa5cc13d01 100644 --- a/static/app/views/insights/types.tsx +++ b/static/app/views/insights/types.tsx @@ -11,6 +11,7 @@ export enum ModuleName { APP_START = 'app_start', RESOURCE = 'resource', AI = 'ai', + AGENTS = 'agents', MOBILE_UI = 'mobile-ui', MOBILE_VITALS = 'mobile-vitals', SCREEN_RENDERING = 'screen-rendering', diff --git a/static/app/views/nav/secondary/sections/insights/insightsSecondaryNav.tsx b/static/app/views/nav/secondary/sections/insights/insightsSecondaryNav.tsx index c2d32f728fb20e..d1119cf93bf5a0 100644 --- a/static/app/views/nav/secondary/sections/insights/insightsSecondaryNav.tsx +++ b/static/app/views/nav/secondary/sections/insights/insightsSecondaryNav.tsx @@ -8,7 +8,12 @@ import type {Project} from 'sentry/types/project'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; +import {AgentInsightsFeature} from 'sentry/views/insights/agentMonitoring/utils/features'; import {MODULE_BASE_URLS} from 'sentry/views/insights/common/utils/useModuleURL'; +import { + AGENTS_LANDING_SUB_PATH, + AGENTS_SIDEBAR_LABEL, +} from 'sentry/views/insights/pages/agents/settings'; import { AI_LANDING_SUB_PATH, AI_SIDEBAR_LABEL, @@ -91,12 +96,25 @@ export function InsightsSecondaryNav() { > {MOBILE_SIDEBAR_LABEL} - ( + + {AI_SIDEBAR_LABEL} + + )} > - {AI_SIDEBAR_LABEL} - + + {AGENTS_SIDEBAR_LABEL} + +