index.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import EmptyStateWarning from 'sentry/components/emptyStateWarning';
  2. import ErrorBoundary from 'sentry/components/errorBoundary';
  3. import * as Layout from 'sentry/components/layouts/thirds';
  4. import LoadingIndicator from 'sentry/components/loadingIndicator';
  5. import Pagination from 'sentry/components/pagination';
  6. import Panel from 'sentry/components/panels/panel';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import type {Activity, Organization} from 'sentry/types';
  10. import routeTitle from 'sentry/utils/routeTitle';
  11. import withOrganization from 'sentry/utils/withOrganization';
  12. import type {AsyncViewProps, AsyncViewState} from 'sentry/views/deprecatedAsyncView';
  13. import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
  14. import ActivityFeedItem from './activityFeedItem';
  15. interface Props extends AsyncViewProps {
  16. organization: Organization;
  17. }
  18. interface State extends AsyncViewState {
  19. activity: Activity[];
  20. }
  21. class OrganizationActivity extends DeprecatedAsyncView<Props, State> {
  22. getTitle() {
  23. const {organization} = this.props;
  24. return routeTitle(t('Activity'), organization.slug, false);
  25. }
  26. getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
  27. const {organization} = this.props;
  28. return [['activity', `/organizations/${organization.slug}/activity/`]];
  29. }
  30. renderLoading() {
  31. return this.renderBody();
  32. }
  33. renderEmpty() {
  34. return (
  35. <EmptyStateWarning>
  36. <p>{t('Nothing to show here, move along.')}</p>
  37. </EmptyStateWarning>
  38. );
  39. }
  40. renderError(error?: Error, disableLog = false): React.ReactNode {
  41. const {errors} = this.state;
  42. const notFound = Object.values(errors).find(resp => resp && resp.status === 404);
  43. if (notFound) {
  44. return this.renderBody();
  45. }
  46. return super.renderError(error, disableLog);
  47. }
  48. renderBody() {
  49. const {loading, activity, activityPageLinks} = this.state;
  50. return (
  51. <Layout.Page>
  52. <Layout.Header>
  53. <Layout.HeaderContent>
  54. <Layout.Title>{t('Activity')}</Layout.Title>
  55. </Layout.HeaderContent>
  56. </Layout.Header>
  57. <Layout.Body>
  58. <Layout.Main fullWidth>
  59. <Panel>
  60. {loading && <LoadingIndicator />}
  61. {!loading && !activity?.length && this.renderEmpty()}
  62. {!loading && activity?.length > 0 && (
  63. <div data-test-id="activity-feed-list">
  64. {activity.map(item => (
  65. <ErrorBoundary
  66. mini
  67. css={{marginBottom: space(1), borderRadius: 0}}
  68. key={item.id}
  69. >
  70. <ActivityFeedItem
  71. organization={this.props.organization}
  72. item={item}
  73. />
  74. </ErrorBoundary>
  75. ))}
  76. </div>
  77. )}
  78. </Panel>
  79. {activityPageLinks && (
  80. <Pagination pageLinks={activityPageLinks} {...this.props} />
  81. )}
  82. </Layout.Main>
  83. </Layout.Body>
  84. </Layout.Page>
  85. );
  86. }
  87. }
  88. export default withOrganization(OrganizationActivity);