Silences.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import React, { FC, useCallback, useEffect } from 'react';
  2. import { useDispatch } from 'react-redux';
  3. import { Redirect, Route, RouteChildrenProps, Switch, useLocation } from 'react-router-dom';
  4. import { Alert, LoadingPlaceholder, withErrorBoundary } from '@grafana/ui';
  5. import { Silence } from 'app/plugins/datasource/alertmanager/types';
  6. import { AlertManagerPicker } from './components/AlertManagerPicker';
  7. import { AlertingPageWrapper } from './components/AlertingPageWrapper';
  8. import { NoAlertManagerWarning } from './components/NoAlertManagerWarning';
  9. import SilencesEditor from './components/silences/SilencesEditor';
  10. import SilencesTable from './components/silences/SilencesTable';
  11. import { useAlertManagerSourceName } from './hooks/useAlertManagerSourceName';
  12. import { useAlertManagersByPermission } from './hooks/useAlertManagerSources';
  13. import { useUnifiedAlertingSelector } from './hooks/useUnifiedAlertingSelector';
  14. import { fetchAmAlertsAction, fetchSilencesAction } from './state/actions';
  15. import { SILENCES_POLL_INTERVAL_MS } from './utils/constants';
  16. import { AsyncRequestState, initialAsyncRequestState } from './utils/redux';
  17. const Silences: FC = () => {
  18. const alertManagers = useAlertManagersByPermission('instance');
  19. const [alertManagerSourceName, setAlertManagerSourceName] = useAlertManagerSourceName(alertManagers);
  20. const dispatch = useDispatch();
  21. const silences = useUnifiedAlertingSelector((state) => state.silences);
  22. const alertsRequests = useUnifiedAlertingSelector((state) => state.amAlerts);
  23. const alertsRequest = alertManagerSourceName
  24. ? alertsRequests[alertManagerSourceName] || initialAsyncRequestState
  25. : undefined;
  26. const location = useLocation();
  27. const isRoot = location.pathname.endsWith('/alerting/silences');
  28. useEffect(() => {
  29. function fetchAll() {
  30. if (alertManagerSourceName) {
  31. dispatch(fetchSilencesAction(alertManagerSourceName));
  32. dispatch(fetchAmAlertsAction(alertManagerSourceName));
  33. }
  34. }
  35. fetchAll();
  36. const interval = setInterval(() => fetchAll, SILENCES_POLL_INTERVAL_MS);
  37. return () => {
  38. clearInterval(interval);
  39. };
  40. }, [alertManagerSourceName, dispatch]);
  41. const { result, loading, error }: AsyncRequestState<Silence[]> =
  42. (alertManagerSourceName && silences[alertManagerSourceName]) || initialAsyncRequestState;
  43. const getSilenceById = useCallback((id: string) => result && result.find((silence) => silence.id === id), [result]);
  44. if (!alertManagerSourceName) {
  45. return isRoot ? (
  46. <AlertingPageWrapper pageId="silences">
  47. <NoAlertManagerWarning availableAlertManagers={alertManagers} />
  48. </AlertingPageWrapper>
  49. ) : (
  50. <Redirect to="/alerting/silences" />
  51. );
  52. }
  53. return (
  54. <AlertingPageWrapper pageId="silences">
  55. <AlertManagerPicker
  56. disabled={!isRoot}
  57. current={alertManagerSourceName}
  58. onChange={setAlertManagerSourceName}
  59. dataSources={alertManagers}
  60. />
  61. {error && !loading && (
  62. <Alert severity="error" title="Error loading silences">
  63. {error.message || 'Unknown error.'}
  64. </Alert>
  65. )}
  66. {alertsRequest?.error && !alertsRequest?.loading && (
  67. <Alert severity="error" title="Error loading Alertmanager alerts">
  68. {alertsRequest.error?.message || 'Unknown error.'}
  69. </Alert>
  70. )}
  71. {loading && <LoadingPlaceholder text="loading silences..." />}
  72. {result && !error && (
  73. <Switch>
  74. <Route exact path="/alerting/silences">
  75. <SilencesTable
  76. silences={result}
  77. alertManagerAlerts={alertsRequest?.result ?? []}
  78. alertManagerSourceName={alertManagerSourceName}
  79. />
  80. </Route>
  81. <Route exact path="/alerting/silence/new">
  82. <SilencesEditor alertManagerSourceName={alertManagerSourceName} />
  83. </Route>
  84. <Route exact path="/alerting/silence/:id/edit">
  85. {({ match }: RouteChildrenProps<{ id: string }>) => {
  86. return (
  87. match?.params.id && (
  88. <SilencesEditor
  89. silence={getSilenceById(match.params.id)}
  90. alertManagerSourceName={alertManagerSourceName}
  91. />
  92. )
  93. );
  94. }}
  95. </Route>
  96. </Switch>
  97. )}
  98. </AlertingPageWrapper>
  99. );
  100. };
  101. export default withErrorBoundary(Silences, { style: 'page' });