import {Fragment} from 'react'; import {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import * as qs from 'query-string'; import onboardingImg from 'sentry-images/spot/onboarding-preview.svg'; import {Button, ButtonProps} from 'sentry/components/button'; import ButtonBar from 'sentry/components/buttonBar'; import EnvironmentPageFilter from 'sentry/components/environmentPageFilter'; import FeatureBadge from 'sentry/components/featureBadge'; import * as Layout from 'sentry/components/layouts/thirds'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import OnboardingPanel from 'sentry/components/onboardingPanel'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse'; import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionTooltip'; import Pagination from 'sentry/components/pagination'; import {PanelTable} from 'sentry/components/panels'; import ProjectPageFilter from 'sentry/components/projectPageFilter'; import SearchBar from 'sentry/components/searchBar'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {IconAdd} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {setApiQueryData, useApiQuery, useQueryClient} from 'sentry/utils/queryClient'; import {decodeScalar} from 'sentry/utils/queryString'; import useRouteAnalyticsEventNames from 'sentry/utils/routeAnalytics/useRouteAnalyticsEventNames'; import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useRouter from 'sentry/utils/useRouter'; import CronsFeedbackButton from './components/cronsFeedbackButton'; import {MonitorRow} from './components/row'; import {Monitor, MonitorEnvironment} from './types'; function NewMonitorButton(props: ButtonProps) { const organization = useOrganization(); const {selection} = usePageFilters(); return ( {props.children} ); } export default function Monitors({location}: RouteComponentProps<{}, {}>) { const organization = useOrganization(); const router = useRouter(); const queryClient = useQueryClient(); const monitorListQueryKey = [ `/organizations/${organization.slug}/monitors/`, {query: {...location.query, includeNew: true}}, ] as const; const { data: monitorList, getResponseHeader: monitorListHeaders, isLoading, } = useApiQuery(monitorListQueryKey, { staleTime: 0, }); useRouteAnalyticsEventNames('monitors.page_viewed', 'Monitors: Page Viewed'); useRouteAnalyticsParams({empty_state: !monitorList || monitorList.length === 0}); const monitorListPageLinks = monitorListHeaders?.('Link'); const handleSearch = (query: string) => { router.push({ pathname: location.pathname, query: normalizeDateTimeParams({ ...(location.query || {}), query, }), }); }; const renderMonitorRow = (monitor: Monitor, monitorEnv?: MonitorEnvironment) => ( { if (deletedEnv) { if (!monitorList) { return; } const deletedEnvMonitor = monitorList.find(m => m.slug === monitor.slug); if (!deletedEnvMonitor) { return; } deletedEnvMonitor.environments = deletedEnvMonitor.environments.filter( e => e.name !== deletedEnv.name ); setApiQueryData(queryClient, monitorListQueryKey, monitorList); } else { setApiQueryData( queryClient, monitorListQueryKey, monitorList?.filter(m => m.slug !== monitor.slug) ); } }} organization={organization} /> ); return ( {t('Cron Monitors')} }> {t('Add Monitor')} {isLoading ? ( ) : monitorList?.length ? ( {monitorList ?.map(monitor => monitor.environments.length > 0 ? monitor.environments.map(monitorEnv => renderMonitorRow(monitor, monitorEnv) ) : renderMonitorRow(monitor) ) .flat()} {monitorListPageLinks && } ) : ( }> {t('Let Sentry monitor your recurring jobs')} {t( "We'll tell you if your recurring jobs are running on schedule, failing, or succeeding." )} {t('Set up first cron monitor')} {t('Read docs')} )} ); } const Filters = styled('div')` display: grid; grid-template-columns: max-content 1fr; gap: ${space(1.5)}; margin-bottom: ${space(2)}; `; const StyledPanelTable = styled(PanelTable)` grid-template-columns: 1fr max-content 1fr max-content max-content max-content max-content; `; const ButtonList = styled(ButtonBar)` grid-template-columns: repeat(auto-fit, minmax(130px, max-content)); `;
{t( "We'll tell you if your recurring jobs are running on schedule, failing, or succeeding." )}