import {Fragment, useState} from 'react'; import { addErrorMessage, addLoadingMessage, clearIndicators, } from 'sentry/actionCreators/indicator'; import {Button} from 'sentry/components/button'; import MiniBarChart from 'sentry/components/charts/miniBarChart'; import EmptyMessage from 'sentry/components/emptyMessage'; import ErrorBoundary from 'sentry/components/errorBoundary'; import FieldGroup from 'sentry/components/forms/fieldGroup'; import LoadingError from 'sentry/components/loadingError'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import Panel from 'sentry/components/panels/panel'; import PanelAlert from 'sentry/components/panels/panelAlert'; import PanelBody from 'sentry/components/panels/panelBody'; import PanelHeader from 'sentry/components/panels/panelHeader'; import TextCopyInput from 'sentry/components/textCopyInput'; import {t} from 'sentry/locale'; import type {ServiceHook} from 'sentry/types/integrations'; import {useApiQuery, useMutation} from 'sentry/utils/queryClient'; import normalizeUrl from 'sentry/utils/url/normalizeUrl'; import useApi from 'sentry/utils/useApi'; import {useNavigate} from 'sentry/utils/useNavigate'; import useOrganization from 'sentry/utils/useOrganization'; import {useParams} from 'sentry/utils/useParams'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; import ServiceHookSettingsForm from 'sentry/views/settings/project/serviceHookSettingsForm'; function HookStats() { const organization = useOrganization(); const {hookId, projectId} = useParams<{hookId: string; projectId: string}>(); const [until] = useState(() => Math.floor(new Date().getTime() / 1000)); const since = until - 3600 * 24 * 30; const { data: stats, isPending, isError, refetch, } = useApiQuery>( [ `/projects/${organization.slug}/${projectId}/hooks/${hookId}/stats/`, { query: { since, until, resolution: '1d', }, }, ], {staleTime: 0} ); if (isPending) { return ; } if (isError) { return ; } if (stats === null) { return null; } let emptyStats = true; const series = { seriesName: t('Events'), data: stats.map(p => { if (p.total) { emptyStats = false; } return { name: p.ts * 1000, value: p.total, }; }), }; return ( {t('Events in the last 30 days (by day)')} {!emptyStats ? ( ) : ( )} ); } export default function ProjectServiceHookDetails() { const organization = useOrganization(); const {hookId, projectId} = useParams<{hookId: string; projectId: string}>(); const api = useApi({persistInFlight: true}); const navigate = useNavigate(); const { data: hook, isPending, isError, refetch, } = useApiQuery( [`/projects/${organization.slug}/${projectId}/hooks/${hookId}/`], {staleTime: 0} ); const deleteMutation = useMutation({ mutationFn: () => { return api.requestPromise( `/projects/${organization.slug}/${projectId}/hooks/${hookId}/`, { method: 'DELETE', } ); }, onMutate: () => { addLoadingMessage(t('Saving changes\u2026')); }, onSuccess: () => { clearIndicators(); navigate( normalizeUrl(`/settings/${organization.slug}/projects/${projectId}/hooks/`) ); }, onError: () => { addErrorMessage(t('Unable to remove application. Please try again.')); }, }); if (isPending) { return ; } if (isError) { return ; } if (!hook) { return null; } return ( {t('Event Validation')} Sentry will send the X-ServiceHook-Signature header built using{' '} HMAC(SHA256, [secret], [payload]). You should always verify this signature before trusting the information provided in the webhook. {hook.secret} {t('Delete Hook')}
); }