import {Fragment} from 'react'; import {browserHistory, RouteComponentProps} from 'react-router'; import { addErrorMessage, addLoadingMessage, clearIndicators, } from 'sentry/actionCreators/indicator'; import AsyncComponent from 'sentry/components/asyncComponent'; 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 Field from 'sentry/components/forms/field'; import {Panel, PanelAlert, PanelBody, PanelHeader} from 'sentry/components/panels'; import TextCopyInput from 'sentry/components/textCopyInput'; import {t} from 'sentry/locale'; import {ServiceHook} from 'sentry/types'; import getDynamicText from 'sentry/utils/getDynamicText'; import AsyncView from 'sentry/views/asyncView'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; import ServiceHookSettingsForm from 'sentry/views/settings/project/serviceHookSettingsForm'; type Params = {hookId: string; orgId: string; projectId: string}; type StatsProps = { params: Params; }; type StatsState = { stats: {total: number; ts: number}[] | null; } & AsyncComponent['state']; class HookStats extends AsyncComponent { getEndpoints(): ReturnType { const until = Math.floor(new Date().getTime() / 1000); const since = until - 3600 * 24 * 30; const {hookId, orgId, projectId} = this.props.params; return [ [ 'stats', `/projects/${orgId}/${projectId}/hooks/${hookId}/stats/`, { query: { since, until, resolution: '1d', }, }, ], ]; } renderBody() { const {stats} = this.state; 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 ? ( ) : ( )} ); } } type Props = RouteComponentProps; type State = { hook: ServiceHook | null; } & AsyncView['state']; export default class ProjectServiceHookDetails extends AsyncView { getEndpoints(): ReturnType { const {orgId, projectId, hookId} = this.props.params; return [['hook', `/projects/${orgId}/${projectId}/hooks/${hookId}/`]]; } onDelete = () => { const {orgId, projectId, hookId} = this.props.params; addLoadingMessage(t('Saving changes\u2026')); this.api.request(`/projects/${orgId}/${projectId}/hooks/${hookId}/`, { method: 'DELETE', success: () => { clearIndicators(); browserHistory.push(`/settings/${orgId}/projects/${projectId}/hooks/`); }, error: () => { addErrorMessage(t('Unable to remove application. Please try again.')); }, }); }; renderBody() { const {orgId, projectId, hookId} = this.props.params; const {hook} = this.state; 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. {getDynamicText({ value: hook.secret, fixed: 'a dynamic secret value', })} {t('Delete Hook')}
); } }