mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Remove react-enable (#77955)
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import React from 'react';
|
||||
import { Disable, Enable } from 'react-enable';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { withErrorBoundary } from '@grafana/ui';
|
||||
import { SafeDynamicImport } from 'app/core/components/DynamicImports/SafeDynamicImport';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
|
||||
import { AlertingPageWrapper } from './components/AlertingPageWrapper';
|
||||
import { AlertingFeature } from './features';
|
||||
|
||||
const DetailViewV1 = SafeDynamicImport(() => import('./components/rule-viewer/RuleViewer.v1'));
|
||||
const DetailViewV2 = SafeDynamicImport(() => import('./components/rule-viewer/v2/RuleViewer.v2'));
|
||||
@@ -16,17 +15,12 @@ type RuleViewerProps = GrafanaRouteComponentProps<{
|
||||
sourceName: string;
|
||||
}>;
|
||||
|
||||
const RuleViewer = (props: RuleViewerProps): JSX.Element => {
|
||||
return (
|
||||
<AlertingPageWrapper>
|
||||
<Enable feature={AlertingFeature.DetailsViewV2}>
|
||||
<DetailViewV2 {...props} />
|
||||
</Enable>
|
||||
<Disable feature={AlertingFeature.DetailsViewV2}>
|
||||
<DetailViewV1 {...props} />
|
||||
</Disable>
|
||||
</AlertingPageWrapper>
|
||||
);
|
||||
};
|
||||
const newAlertDetailView = Boolean(config.featureToggles.alertingDetailsViewV2) === true;
|
||||
|
||||
const RuleViewer = (props: RuleViewerProps): JSX.Element => (
|
||||
<AlertingPageWrapper>
|
||||
{newAlertDetailView ? <DetailViewV2 {...props} /> : <DetailViewV1 {...props} />}
|
||||
</AlertingPageWrapper>
|
||||
);
|
||||
|
||||
export default withErrorBoundary(RuleViewer, { style: 'page' });
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import Mousetrap from 'mousetrap';
|
||||
import React, { PropsWithChildren, useEffect, useState } from 'react';
|
||||
import { Features, ToggleFeatures } from 'react-enable';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { useLocation } from 'react-use';
|
||||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
|
||||
import FEATURES from '../features';
|
||||
import { AlertmanagerProvider, useAlertmanager } from '../state/AlertmanagerContext';
|
||||
|
||||
import { AlertManagerPicker } from './AlertManagerPicker';
|
||||
import { NoAlertManagerWarning } from './NoAlertManagerWarning';
|
||||
|
||||
const SHOW_TOGGLES_KEY_COMBO = 'ctrl+1';
|
||||
const combokeys = new Mousetrap(document.body);
|
||||
|
||||
/**
|
||||
* This is the main alerting page wrapper, used by the alertmanager page wrapper and the alert rules list view
|
||||
*/
|
||||
@@ -25,25 +19,10 @@ interface AlertingPageWrapperProps extends PropsWithChildren {
|
||||
actions?: React.ReactNode;
|
||||
}
|
||||
export const AlertingPageWrapper = ({ children, pageId, pageNav, actions, isLoading }: AlertingPageWrapperProps) => {
|
||||
const [showFeatureToggle, setShowFeatureToggles] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
combokeys.bind(SHOW_TOGGLES_KEY_COMBO, () => {
|
||||
setShowFeatureToggles((show) => !show);
|
||||
});
|
||||
|
||||
return () => {
|
||||
combokeys.unbind(SHOW_TOGGLES_KEY_COMBO);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Features features={FEATURES}>
|
||||
<Page pageNav={pageNav} navId={pageId} actions={actions}>
|
||||
<Page.Contents isLoading={isLoading}>{children}</Page.Contents>
|
||||
</Page>
|
||||
{showFeatureToggle ? <ToggleFeatures defaultOpen={true} /> : null}
|
||||
</Features>
|
||||
<Page pageNav={pageNav} navId={pageId} actions={actions}>
|
||||
<Page.Contents isLoading={isLoading}>{children}</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { FeatureDescription } from 'react-enable/dist/FeatureState';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
export enum AlertingFeature {
|
||||
NotificationPoliciesV2MatchingInstances = 'notification-policies.v2.matching-instances',
|
||||
DetailsViewV2 = 'details-view.v2',
|
||||
ContactPointsV2 = 'contact-points.v2',
|
||||
}
|
||||
|
||||
const FEATURES: FeatureDescription[] = [
|
||||
{
|
||||
name: AlertingFeature.NotificationPoliciesV2MatchingInstances,
|
||||
defaultValue: config.featureToggles.alertingNotificationsPoliciesMatchingInstances,
|
||||
},
|
||||
{
|
||||
name: AlertingFeature.DetailsViewV2,
|
||||
defaultValue: false,
|
||||
},
|
||||
];
|
||||
export default FEATURES;
|
||||
@@ -1,11 +1,7 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import * as comlink from 'comlink';
|
||||
import React from 'react';
|
||||
import { Features } from 'react-enable';
|
||||
import { FeatureDescription } from 'react-enable/dist/FeatureState';
|
||||
|
||||
import { createWorker } from './createRouteGroupsMatcherWorker';
|
||||
import { AlertingFeature } from './features';
|
||||
import { useRouteGroupsMatcher } from './useRouteGroupsMatcher';
|
||||
|
||||
jest.mock('./createRouteGroupsMatcherWorker');
|
||||
@@ -20,24 +16,8 @@ beforeEach(() => {
|
||||
});
|
||||
|
||||
describe('useRouteGroupsMatcher', () => {
|
||||
it('should not load web worker if the feature flag is disabled', function () {
|
||||
const featureFlag = getInstancePreviewFeature(false);
|
||||
|
||||
const { result } = renderHook(() => useRouteGroupsMatcher(), {
|
||||
wrapper: ({ children }) => <Features features={[featureFlag]}>{children}</Features>,
|
||||
});
|
||||
|
||||
expect(createWorkerMock).not.toHaveBeenCalled();
|
||||
expect(wrapMock).not.toHaveBeenCalled();
|
||||
expect(result.current.getRouteGroupsMap).toBeDefined();
|
||||
});
|
||||
|
||||
it('should load web worker if the feature flag is enabled', function () {
|
||||
const featureFlag = getInstancePreviewFeature(true);
|
||||
|
||||
const { result } = renderHook(() => useRouteGroupsMatcher(), {
|
||||
wrapper: ({ children }) => <Features features={[featureFlag]}>{children}</Features>,
|
||||
});
|
||||
const { result } = renderHook(() => useRouteGroupsMatcher());
|
||||
|
||||
expect(createWorkerMock).toHaveBeenCalledTimes(1);
|
||||
expect(wrapMock).toHaveBeenCalledTimes(1);
|
||||
@@ -45,14 +25,11 @@ describe('useRouteGroupsMatcher', () => {
|
||||
});
|
||||
|
||||
it('getMatchedRouteGroups should throw error if loading worker failed', async function () {
|
||||
const featureFlag = getInstancePreviewFeature(true);
|
||||
createWorkerMock.mockImplementation(() => {
|
||||
throw new DOMException('Failed to load worker');
|
||||
});
|
||||
|
||||
const { result } = renderHook(() => useRouteGroupsMatcher(), {
|
||||
wrapper: ({ children }) => <Features features={[featureFlag]}>{children}</Features>,
|
||||
});
|
||||
const { result } = renderHook(() => useRouteGroupsMatcher());
|
||||
|
||||
expect(createWorkerMock).toHaveBeenCalledTimes(1);
|
||||
expect(wrapMock).toHaveBeenCalledTimes(0); // When loading worker failed we shouldn't call wrap
|
||||
@@ -61,10 +38,3 @@ describe('useRouteGroupsMatcher', () => {
|
||||
}).rejects.toThrowError(Error);
|
||||
});
|
||||
});
|
||||
|
||||
function getInstancePreviewFeature(enabled: boolean): FeatureDescription {
|
||||
return {
|
||||
name: AlertingFeature.NotificationPoliciesV2MatchingInstances,
|
||||
defaultValue: enabled,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as comlink from 'comlink';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useEnabled } from 'react-enable';
|
||||
|
||||
import { logError } from '@grafana/runtime';
|
||||
|
||||
@@ -9,7 +8,6 @@ import { Labels } from '../../../types/unified-alerting-dto';
|
||||
|
||||
import { logInfo } from './Analytics';
|
||||
import { createWorker } from './createRouteGroupsMatcherWorker';
|
||||
import { AlertingFeature } from './features';
|
||||
import type { RouteGroupsMatcher } from './routeGroupsMatcher';
|
||||
|
||||
let routeMatcher: comlink.Remote<RouteGroupsMatcher> | undefined;
|
||||
@@ -45,74 +43,57 @@ function loadWorker() {
|
||||
return { disposeWorker };
|
||||
}
|
||||
|
||||
function validateWorker(
|
||||
toggleEnabled: boolean,
|
||||
matcher: typeof routeMatcher
|
||||
): asserts matcher is comlink.Remote<RouteGroupsMatcher> {
|
||||
if (!toggleEnabled) {
|
||||
throw new Error('Matching routes preview is disabled');
|
||||
}
|
||||
|
||||
function validateWorker(matcher: typeof routeMatcher): asserts matcher is comlink.Remote<RouteGroupsMatcher> {
|
||||
if (!routeMatcher) {
|
||||
throw new Error('Route Matcher has not been initialized');
|
||||
}
|
||||
}
|
||||
|
||||
export function useRouteGroupsMatcher() {
|
||||
const workerPreviewEnabled = useEnabled(AlertingFeature.NotificationPoliciesV2MatchingInstances);
|
||||
|
||||
useEffect(() => {
|
||||
if (workerPreviewEnabled) {
|
||||
const { disposeWorker } = loadWorker();
|
||||
return disposeWorker;
|
||||
}
|
||||
const { disposeWorker } = loadWorker();
|
||||
return disposeWorker;
|
||||
|
||||
return () => null;
|
||||
}, [workerPreviewEnabled]);
|
||||
}, []);
|
||||
|
||||
const getRouteGroupsMap = useCallback(
|
||||
async (rootRoute: RouteWithID, alertGroups: AlertmanagerGroup[]) => {
|
||||
validateWorker(workerPreviewEnabled, routeMatcher);
|
||||
const getRouteGroupsMap = useCallback(async (rootRoute: RouteWithID, alertGroups: AlertmanagerGroup[]) => {
|
||||
validateWorker(routeMatcher);
|
||||
|
||||
const startTime = performance.now();
|
||||
const startTime = performance.now();
|
||||
|
||||
const result = await routeMatcher.getRouteGroupsMap(rootRoute, alertGroups);
|
||||
const result = await routeMatcher.getRouteGroupsMap(rootRoute, alertGroups);
|
||||
|
||||
const timeSpent = performance.now() - startTime;
|
||||
const timeSpent = performance.now() - startTime;
|
||||
|
||||
logInfo(`Route Groups Matched in ${timeSpent} ms`, {
|
||||
matchingTime: timeSpent.toString(),
|
||||
alertGroupsCount: alertGroups.length.toString(),
|
||||
// Counting all nested routes might be too time-consuming, so we only count the first level
|
||||
topLevelRoutesCount: rootRoute.routes?.length.toString() ?? '0',
|
||||
});
|
||||
logInfo(`Route Groups Matched in ${timeSpent} ms`, {
|
||||
matchingTime: timeSpent.toString(),
|
||||
alertGroupsCount: alertGroups.length.toString(),
|
||||
// Counting all nested routes might be too time-consuming, so we only count the first level
|
||||
topLevelRoutesCount: rootRoute.routes?.length.toString() ?? '0',
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
[workerPreviewEnabled]
|
||||
);
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
const matchInstancesToRoute = useCallback(
|
||||
async (rootRoute: RouteWithID, instancesToMatch: Labels[]) => {
|
||||
validateWorker(workerPreviewEnabled, routeMatcher);
|
||||
const matchInstancesToRoute = useCallback(async (rootRoute: RouteWithID, instancesToMatch: Labels[]) => {
|
||||
validateWorker(routeMatcher);
|
||||
|
||||
const startTime = performance.now();
|
||||
const startTime = performance.now();
|
||||
|
||||
const result = await routeMatcher.matchInstancesToRoute(rootRoute, instancesToMatch);
|
||||
const result = await routeMatcher.matchInstancesToRoute(rootRoute, instancesToMatch);
|
||||
|
||||
const timeSpent = performance.now() - startTime;
|
||||
const timeSpent = performance.now() - startTime;
|
||||
|
||||
logInfo(`Instances Matched in ${timeSpent} ms`, {
|
||||
matchingTime: timeSpent.toString(),
|
||||
instancesToMatchCount: instancesToMatch.length.toString(),
|
||||
// Counting all nested routes might be too time-consuming, so we only count the first level
|
||||
topLevelRoutesCount: rootRoute.routes?.length.toString() ?? '0',
|
||||
});
|
||||
logInfo(`Instances Matched in ${timeSpent} ms`, {
|
||||
matchingTime: timeSpent.toString(),
|
||||
instancesToMatchCount: instancesToMatch.length.toString(),
|
||||
// Counting all nested routes might be too time-consuming, so we only count the first level
|
||||
topLevelRoutesCount: rootRoute.routes?.length.toString() ?? '0',
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
[workerPreviewEnabled]
|
||||
);
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
return { getRouteGroupsMap, matchInstancesToRoute };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user