Chore: Improve how mock API is enabled/disabled (#104675)
This commit is contained in:
+1
-1
@@ -480,7 +480,7 @@ playwright.config.ts @grafana/plugins-platform-frontend
|
||||
/public/app/core/components/TimelineChart/ @grafana/dataviz-squad
|
||||
/public/app/core/components/Form/ @grafana/grafana-frontend-platform
|
||||
/public/app/core/components/OptionsUI/ @grafana/dashboards-squad @grafana/dataviz-squad
|
||||
|
||||
/public/app/mock-api-utils.ts @grafana/grafana-frontend-platform
|
||||
|
||||
/public/app/core/history/ @grafana/observability-traces-and-profiling
|
||||
/public/app/features/admin/ @grafana/identity-access-team
|
||||
|
||||
@@ -2122,9 +2122,6 @@ alert_rules_state = "paused"
|
||||
# Should UI tests fail when console log/warn/erroring?
|
||||
# Does not affect the result when running on CI - only for allowing devs to choose this behaviour locally
|
||||
fail_tests_on_console = true
|
||||
# Whether or not to enable the MSW mock API, which intercepts requests and returns mock data
|
||||
# Should only be used for local development or demo purposes
|
||||
mock_api = false
|
||||
# Whether to enable betterer eslint rules for local development
|
||||
# Useful if you want to always see betterer rules that we're trying to fix so they're more prevalent
|
||||
betterer_eslint_rules = false
|
||||
|
||||
+4
-5
@@ -62,6 +62,7 @@ import { PluginPage } from './core/components/Page/PluginPage';
|
||||
import { GrafanaContextType, useReturnToPreviousInternal } from './core/context/GrafanaContext';
|
||||
import { initializeCrashDetection } from './core/crash';
|
||||
import { initializeI18n } from './core/internationalization';
|
||||
import { postInitTasks, preInitTasks } from './core/lifecycle-hooks';
|
||||
import { setMonacoEnv } from './core/monacoEnv';
|
||||
import { interceptLinkClicks } from './core/navigation/patch/interceptLinkClicks';
|
||||
import { CorrelationsService } from './core/services/CorrelationsService';
|
||||
@@ -72,7 +73,6 @@ import { Echo } from './core/services/echo/Echo';
|
||||
import { reportPerformance } from './core/services/echo/EchoSrv';
|
||||
import { KeybindingSrv } from './core/services/keybindingSrv';
|
||||
import { startMeasure, stopMeasure } from './core/utils/metrics';
|
||||
import { initDevFeatures } from './dev';
|
||||
import { initAlerting } from './features/alerting/unified/initAlerting';
|
||||
import { initAuthConfig } from './features/auth-config';
|
||||
import { getTimeSrv } from './features/dashboard/services/TimeSrv';
|
||||
@@ -115,15 +115,12 @@ const extensionsExports = extensionsIndex.keys().map((key) => {
|
||||
return extensionsIndex(key);
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
initDevFeatures();
|
||||
}
|
||||
|
||||
export class GrafanaApp {
|
||||
context!: GrafanaContextType;
|
||||
|
||||
async init() {
|
||||
try {
|
||||
await preInitTasks();
|
||||
// Let iframe container know grafana has started loading
|
||||
parent.postMessage('GrafanaAppInit', '*');
|
||||
|
||||
@@ -268,6 +265,8 @@ export class GrafanaApp {
|
||||
app: this,
|
||||
})
|
||||
);
|
||||
|
||||
await postInitTasks();
|
||||
} catch (error) {
|
||||
console.error('Failed to start Grafana', error);
|
||||
window.__grafana_load_failed();
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useMemo, ReactElement } from 'react';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { getMessageFromError } from 'app/core/utils/errors';
|
||||
import { dispatch as storeDispatch } from 'app/store/store';
|
||||
import { AppNotification, AppNotificationSeverity, useDispatch } from 'app/types';
|
||||
|
||||
import { notifyApp } from '../actions';
|
||||
@@ -86,19 +87,50 @@ export function useAppNotification() {
|
||||
const dispatch = useDispatch();
|
||||
return useMemo(
|
||||
() => ({
|
||||
success: (title: string, text = '') => {
|
||||
dispatch(notifyApp(createSuccessNotification(title, text)));
|
||||
[AppNotificationSeverity.Success]: (title: string, text = '') => {
|
||||
dispatch(notifyApp(createNotification(title, text, AppNotificationSeverity.Success)));
|
||||
},
|
||||
warning: (title: string, text = '', traceId?: string) => {
|
||||
dispatch(notifyApp(createWarningNotification(title, text, traceId)));
|
||||
[AppNotificationSeverity.Warning]: (title: string, text = '', traceId?: string) => {
|
||||
dispatch(notifyApp(createNotification(title, text, AppNotificationSeverity.Warning, traceId)));
|
||||
},
|
||||
error: (title: string, text = '', traceId?: string) => {
|
||||
dispatch(notifyApp(createErrorNotification(title, text, traceId)));
|
||||
[AppNotificationSeverity.Error]: (title: string, text = '', traceId?: string) => {
|
||||
dispatch(notifyApp(createNotification(title, text, AppNotificationSeverity.Error, traceId)));
|
||||
},
|
||||
info: (title: string, text = '') => {
|
||||
dispatch(notifyApp(createInfoNotification(title, text)));
|
||||
[AppNotificationSeverity.Info]: (title: string, text = '') => {
|
||||
dispatch(notifyApp(createNotification(title, text, AppNotificationSeverity.Info)));
|
||||
},
|
||||
}),
|
||||
[dispatch]
|
||||
);
|
||||
}
|
||||
|
||||
function createNotification(
|
||||
title: string,
|
||||
text = '',
|
||||
severity: AppNotificationSeverity = AppNotificationSeverity.Success,
|
||||
traceId?: string
|
||||
) {
|
||||
const map = {
|
||||
[AppNotificationSeverity.Success]: (title: string, text = '') => {
|
||||
return createSuccessNotification(title, text);
|
||||
},
|
||||
[AppNotificationSeverity.Warning]: (title: string, text = '', traceId?: string) => {
|
||||
return createWarningNotification(title, text, traceId);
|
||||
},
|
||||
[AppNotificationSeverity.Error]: (title: string, text = '', traceId?: string) => {
|
||||
return createErrorNotification(title, text, traceId);
|
||||
},
|
||||
[AppNotificationSeverity.Info]: (title: string, text = '') => {
|
||||
return createInfoNotification(title, text);
|
||||
},
|
||||
};
|
||||
return map[severity](title, text, traceId);
|
||||
}
|
||||
|
||||
export function sendAppNotification(
|
||||
title: string,
|
||||
text = '',
|
||||
severity: AppNotificationSeverity = AppNotificationSeverity.Success
|
||||
) {
|
||||
storeDispatch(notifyApp(createNotification(title, text, severity)));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { initDevFeatures } from 'app/dev';
|
||||
import { notifyIfMockApiEnabled } from 'app/mock-api-utils';
|
||||
|
||||
/**
|
||||
* Lifecycle tasks that need to be run prior to app initialization,
|
||||
* such as setting up mock APIs or enabling dev-only features
|
||||
*/
|
||||
export async function preInitTasks() {
|
||||
await initDevFeatures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle tasks that need to be run once the app has fully initialized,
|
||||
* such as notifying if mock APIs are enabled
|
||||
*/
|
||||
export async function postInitTasks() {
|
||||
notifyIfMockApiEnabled();
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { getExploreUrl } from 'app/core/utils/explore';
|
||||
import { SaveDashboardDrawer } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer';
|
||||
import { ShareModal } from 'app/features/dashboard/components/ShareModal/ShareModal';
|
||||
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||
import { toggleMockApiAndReload } from 'app/mock-api-utils';
|
||||
|
||||
import { getTimeSrv } from '../../features/dashboard/services/TimeSrv';
|
||||
import {
|
||||
@@ -55,6 +56,10 @@ export class KeybindingSrv {
|
||||
|
||||
this.bind('c t', () => toggleTheme(false));
|
||||
this.bind('c r', () => toggleTheme(true));
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
this.bind('c m', () => toggleMockApiAndReload());
|
||||
}
|
||||
}
|
||||
|
||||
bindGlobalEsc() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { potentiallySetupMockApi } from './mock-api-utils';
|
||||
|
||||
export async function initDevFeatures() {
|
||||
// if why-render is in url enable why did you render react extension
|
||||
if (window.location.search.indexOf('why-render') !== -1) {
|
||||
@@ -8,4 +10,6 @@ export async function initDevFeatures() {
|
||||
trackAllPureComponents: true,
|
||||
});
|
||||
}
|
||||
|
||||
await potentiallySetupMockApi();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { enrichHelpItem } from 'app/core/components/AppChrome/MegaMenu/utils';
|
||||
import { performInviteUserClick, shouldRenderInviteUserButton } from 'app/core/components/InviteUserButton/utils';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { changeTheme } from 'app/core/services/theme';
|
||||
import { currentMockApiState, toggleMockApiAndReload } from 'app/mock-api-utils';
|
||||
|
||||
import { useSelector } from '../../../types';
|
||||
import { CommandPaletteAction } from '../types';
|
||||
@@ -75,7 +76,7 @@ function navTreeToActions(navTree: NavModelItem[], parents: NavModelItem[] = [])
|
||||
}
|
||||
|
||||
function getGlobalActions(): CommandPaletteAction[] {
|
||||
return [
|
||||
const actions: CommandPaletteAction[] = [
|
||||
{
|
||||
id: 'preferences/theme',
|
||||
name: t('command-palette.action.change-theme', 'Change theme'),
|
||||
@@ -100,6 +101,25 @@ function getGlobalActions(): CommandPaletteAction[] {
|
||||
priority: PREFERENCES_PRIORITY,
|
||||
},
|
||||
];
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// eslint-disable @grafana/no-untranslated-strings
|
||||
const section = 'Dev tooling';
|
||||
const currentState = currentMockApiState();
|
||||
const mockApiAction = currentState ? 'Disable' : 'Enable';
|
||||
actions.push({
|
||||
id: 'preferences/dev/toggle-mock-api',
|
||||
section,
|
||||
name: `${mockApiAction} Mock API worker and reload`,
|
||||
subtitle: 'Intercepts requests and returns mock data using MSW',
|
||||
keywords: 'mock api',
|
||||
priority: PREFERENCES_PRIORITY,
|
||||
perform: toggleMockApiAndReload,
|
||||
});
|
||||
// eslint-enable @grafana/no-untranslated-strings
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
export function useStaticActions(): CommandPaletteAction[] {
|
||||
|
||||
+1
-12
@@ -20,15 +20,4 @@ window.__grafana_app_bundle_loaded = true;
|
||||
|
||||
import app from './app';
|
||||
|
||||
const prepareInit = async () => {
|
||||
if (process.env.frontend_dev_mock_api) {
|
||||
return import('test/mock-api/worker').then((workerModule) => {
|
||||
workerModule.default.start({ onUnhandledRequest: 'bypass' });
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
prepareInit().then(() => {
|
||||
app.init();
|
||||
});
|
||||
app.init();
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import store from 'app/core/store';
|
||||
|
||||
import { sendAppNotification } from './core/copy/appNotification';
|
||||
import { AppNotificationSeverity } from './types';
|
||||
|
||||
export const STORAGE_MOCK_API_KEY = 'grafana.dev.mockApi';
|
||||
|
||||
export const currentMockApiState = () => {
|
||||
return store.getBool(STORAGE_MOCK_API_KEY, false);
|
||||
};
|
||||
|
||||
export const toggleMockApiAndReload = () => {
|
||||
const currentState = currentMockApiState();
|
||||
store.set(STORAGE_MOCK_API_KEY, String(!currentState));
|
||||
const action = currentState ? 'Disabling' : 'Enabling';
|
||||
sendAppNotification(`${action} Mock API`, 'Reloading...', AppNotificationSeverity.Info);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 200);
|
||||
};
|
||||
|
||||
export const potentiallySetupMockApi = async () => {
|
||||
const mockApiEnabled = currentMockApiState();
|
||||
if (process.env.NODE_ENV === 'development' && mockApiEnabled) {
|
||||
const { default: worker } = await import('test/mock-api/worker');
|
||||
|
||||
worker.start({ onUnhandledRequest: 'bypass' });
|
||||
}
|
||||
};
|
||||
|
||||
export const notifyIfMockApiEnabled = () => {
|
||||
if (process.env.NODE_ENV === 'development' && currentMockApiState()) {
|
||||
sendAppNotification(
|
||||
'Mock API currently enabled',
|
||||
'Some network requests will be intercepted',
|
||||
AppNotificationSeverity.Info
|
||||
);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user