serviceIncidents.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import {Component, Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import * as Sentry from '@sentry/react';
  4. import {loadIncidents} from 'app/actionCreators/serviceIncidents';
  5. import Button from 'app/components/button';
  6. import {IconWarning} from 'app/icons';
  7. import {t} from 'app/locale';
  8. import space from 'app/styles/space';
  9. import {SentryServiceStatus} from 'app/types';
  10. import List from '../list';
  11. import ListItem from '../list/listItem';
  12. import SidebarItem from './sidebarItem';
  13. import SidebarPanel from './sidebarPanel';
  14. import SidebarPanelEmpty from './sidebarPanelEmpty';
  15. import SidebarPanelItem from './sidebarPanelItem';
  16. import {CommonSidebarProps} from './types';
  17. type Props = CommonSidebarProps;
  18. type State = {
  19. status: SentryServiceStatus | null;
  20. };
  21. class ServiceIncidents extends Component<Props, State> {
  22. state: State = {
  23. status: null,
  24. };
  25. componentDidMount() {
  26. this.fetchData();
  27. }
  28. async fetchData() {
  29. try {
  30. const status = await loadIncidents();
  31. this.setState({status});
  32. } catch (e) {
  33. Sentry.withScope(scope => {
  34. scope.setLevel(Sentry.Severity.Warning);
  35. scope.setFingerprint(['ServiceIncidents-fetchData']);
  36. Sentry.captureException(e);
  37. });
  38. }
  39. }
  40. render() {
  41. const {currentPanel, onShowPanel, hidePanel, collapsed, orientation} = this.props;
  42. const {status} = this.state;
  43. if (!status) {
  44. return null;
  45. }
  46. const active = currentPanel === 'statusupdate';
  47. const isEmpty = !status.incidents || status.incidents.length === 0;
  48. if (isEmpty) {
  49. return null;
  50. }
  51. return (
  52. <Fragment>
  53. <SidebarItem
  54. id="statusupdate"
  55. orientation={orientation}
  56. collapsed={collapsed}
  57. active={active}
  58. icon={<IconWarning size="md" />}
  59. label={t('Service status')}
  60. onClick={onShowPanel}
  61. />
  62. {active && status && (
  63. <SidebarPanel
  64. orientation={orientation}
  65. title={t('Recent service updates')}
  66. hidePanel={hidePanel}
  67. collapsed={collapsed}
  68. >
  69. {isEmpty && (
  70. <SidebarPanelEmpty>
  71. {t('There are no incidents to report')}
  72. </SidebarPanelEmpty>
  73. )}
  74. <IncidentList className="incident-list">
  75. {status.incidents.map(incident => (
  76. <SidebarPanelItem
  77. title={incident.name}
  78. message={t('Latest updates')}
  79. key={incident.id}
  80. >
  81. {incident.updates ? (
  82. <List>
  83. {incident.updates.map((update, key) => (
  84. <ListItem key={key}>{update}</ListItem>
  85. ))}
  86. </List>
  87. ) : null}
  88. <ActionBar>
  89. <Button href={incident.url} size="small" external>
  90. {t('Learn more')}
  91. </Button>
  92. </ActionBar>
  93. </SidebarPanelItem>
  94. ))}
  95. </IncidentList>
  96. </SidebarPanel>
  97. )}
  98. </Fragment>
  99. );
  100. }
  101. }
  102. export default ServiceIncidents;
  103. const IncidentList = styled('div')``;
  104. const ActionBar = styled('div')`
  105. margin-top: ${space(2)};
  106. `;