projectDataForwarding.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import {Fragment} from 'react';
  2. import {RouteComponentProps} from 'react-router';
  3. import Feature from 'sentry/components/acl/feature';
  4. import FeatureDisabled from 'sentry/components/acl/featureDisabled';
  5. import Alert from 'sentry/components/alert';
  6. import AsyncComponent from 'sentry/components/asyncComponent';
  7. import MiniBarChart from 'sentry/components/charts/miniBarChart';
  8. import EmptyMessage from 'sentry/components/emptyMessage';
  9. import ExternalLink from 'sentry/components/links/externalLink';
  10. import {Panel, PanelBody, PanelHeader} from 'sentry/components/panels';
  11. import PluginList from 'sentry/components/pluginList';
  12. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  13. import {t, tct} from 'sentry/locale';
  14. import {Organization, Plugin, Project, TimeseriesValue} from 'sentry/types';
  15. import {Series} from 'sentry/types/echarts';
  16. import withOrganization from 'sentry/utils/withOrganization';
  17. import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
  18. import TextBlock from 'sentry/views/settings/components/text/textBlock';
  19. import PermissionAlert from 'sentry/views/settings/project/permissionAlert';
  20. type RouteParams = {orgId: string; projectId: string};
  21. type StatProps = {
  22. params: RouteParams;
  23. };
  24. type StatState = AsyncComponent['state'] & {
  25. stats: TimeseriesValue[];
  26. };
  27. class DataForwardingStats extends AsyncComponent<StatProps, StatState> {
  28. getEndpoints(): ReturnType<AsyncComponent['getEndpoints']> {
  29. const {orgId, projectId} = this.props.params;
  30. const until = Math.floor(new Date().getTime() / 1000);
  31. const since = until - 3600 * 24 * 30;
  32. const options = {
  33. query: {
  34. since,
  35. until,
  36. resolution: '1d',
  37. stat: 'forwarded',
  38. },
  39. };
  40. return [['stats', `/projects/${orgId}/${projectId}/stats/`, options]];
  41. }
  42. renderBody() {
  43. const {projectId} = this.props.params;
  44. const {stats} = this.state;
  45. const series: Series = {
  46. seriesName: t('Forwarded'),
  47. data: stats.map(([timestamp, value]) => ({name: timestamp * 1000, value})),
  48. };
  49. const forwardedAny = series.data.some(({value}) => value > 0);
  50. return (
  51. <Panel>
  52. <SentryDocumentTitle title={t('Data Forwarding')} projectSlug={projectId} />
  53. <PanelHeader>{t('Forwarded events in the last 30 days (by day)')}</PanelHeader>
  54. <PanelBody withPadding>
  55. {forwardedAny ? (
  56. <MiniBarChart
  57. isGroupedByDate
  58. showTimeInTooltip
  59. labelYAxisExtents
  60. series={[series]}
  61. height={150}
  62. />
  63. ) : (
  64. <EmptyMessage
  65. title={t('Nothing forwarded in the last 30 days.')}
  66. description={t('Total events forwarded to third party integrations.')}
  67. />
  68. )}
  69. </PanelBody>
  70. </Panel>
  71. );
  72. }
  73. }
  74. type Props = RouteComponentProps<RouteParams, {}> & {
  75. organization: Organization;
  76. project: Project;
  77. };
  78. type State = AsyncComponent['state'] & {
  79. plugins: Plugin[];
  80. };
  81. class ProjectDataForwarding extends AsyncComponent<Props, State> {
  82. getEndpoints(): ReturnType<AsyncComponent['getEndpoints']> {
  83. const {orgId, projectId} = this.props.params;
  84. return [['plugins', `/projects/${orgId}/${projectId}/plugins/`]];
  85. }
  86. get forwardingPlugins() {
  87. return this.state.plugins.filter(
  88. p => p.type === 'data-forwarding' && p.hasConfiguration
  89. );
  90. }
  91. updatePlugin(plugin: Plugin, enabled: boolean) {
  92. const plugins = this.state.plugins.map(p => ({
  93. ...p,
  94. enabled: p.id === plugin.id ? enabled : p.enabled,
  95. }));
  96. this.setState({plugins});
  97. }
  98. onEnablePlugin = (plugin: Plugin) => this.updatePlugin(plugin, true);
  99. onDisablePlugin = (plugin: Plugin) => this.updatePlugin(plugin, false);
  100. renderBody() {
  101. const {params, organization, project} = this.props;
  102. const plugins = this.forwardingPlugins;
  103. const hasAccess = organization.access.includes('project:write');
  104. const pluginsPanel =
  105. plugins.length > 0 ? (
  106. <PluginList
  107. organization={organization}
  108. project={project}
  109. pluginList={plugins}
  110. onEnablePlugin={this.onEnablePlugin}
  111. onDisablePlugin={this.onDisablePlugin}
  112. />
  113. ) : (
  114. <Panel>
  115. <EmptyMessage
  116. title={t('There are no integrations available for data forwarding')}
  117. />
  118. </Panel>
  119. );
  120. return (
  121. <div data-test-id="data-forwarding-settings">
  122. <Feature
  123. features={['projects:data-forwarding']}
  124. hookName="feature-disabled:data-forwarding"
  125. >
  126. {({hasFeature, features}) => (
  127. <Fragment>
  128. <SettingsPageHeader title={t('Data Forwarding')} />
  129. <TextBlock>
  130. {tct(
  131. `Data Forwarding allows processed events to be sent to your
  132. favorite business intelligence tools. The exact payload and
  133. types of data depend on the integration you're using. Learn
  134. more about this functionality in our [link:documentation].`,
  135. {
  136. link: (
  137. <ExternalLink href="https://docs.sentry.io/product/data-management-settings/data-forwarding/" />
  138. ),
  139. }
  140. )}
  141. </TextBlock>
  142. <PermissionAlert />
  143. <Alert showIcon>
  144. {tct(
  145. `Sentry forwards [em:all applicable error events] to the provider, in
  146. some cases this may be a significant volume of data.`,
  147. {
  148. em: <strong />,
  149. }
  150. )}
  151. </Alert>
  152. {!hasFeature && (
  153. <FeatureDisabled
  154. alert
  155. featureName={t('Data Forwarding')}
  156. features={features}
  157. />
  158. )}
  159. <DataForwardingStats params={params} />
  160. {hasAccess && hasFeature && pluginsPanel}
  161. </Fragment>
  162. )}
  163. </Feature>
  164. </div>
  165. );
  166. }
  167. }
  168. export default withOrganization(ProjectDataForwarding);