= ({ dashboard, onNew, onEd
)}
| onEdit(idx)}>
- {annotation.datasource?.uid}
+ {dataSourceSrv.getInstanceSettings(annotation.datasource)?.name || annotation.datasource?.uid}
|
{idx !== 0 && (
diff --git a/public/app/features/dashboard/components/DashExportModal/DashboardExporter.test.ts b/public/app/features/dashboard/components/DashExportModal/DashboardExporter.test.ts
index 83482884b08..038812d89c6 100644
--- a/public/app/features/dashboard/components/DashExportModal/DashboardExporter.test.ts
+++ b/public/app/features/dashboard/components/DashExportModal/DashboardExporter.test.ts
@@ -1,13 +1,16 @@
import { find } from 'lodash';
-import config from 'app/core/config';
-import { DashboardExporter, LibraryElementExport } from './DashboardExporter';
-import { DashboardModel } from '../../state/DashboardModel';
+
import { DataSourceInstanceSettings, DataSourceRef, PanelPluginMeta } from '@grafana/data';
+import config from 'app/core/config';
+
+import { LibraryElementKind } from '../../../library-panels/types';
import { variableAdapters } from '../../../variables/adapters';
import { createConstantVariableAdapter } from '../../../variables/constant/adapter';
-import { createQueryVariableAdapter } from '../../../variables/query/adapter';
import { createDataSourceVariableAdapter } from '../../../variables/datasource/adapter';
-import { LibraryElementKind } from '../../../library-panels/types';
+import { createQueryVariableAdapter } from '../../../variables/query/adapter';
+import { DashboardModel } from '../../state/DashboardModel';
+
+import { DashboardExporter, LibraryElementExport } from './DashboardExporter';
jest.mock('app/core/store', () => {
return {
@@ -276,6 +279,10 @@ describe('given dashboard with repeated panels', () => {
},
],
},
+ {
+ id: 5,
+ targets: [{ scenarioId: 'random_walk', refId: 'A' }],
+ },
],
};
@@ -312,6 +319,23 @@ describe('given dashboard with repeated panels', () => {
expect(panel.datasource.uid).toBe('${DS_GFDB}');
});
+ it('should explicitly specify default datasources', () => {
+ const panel = exported.panels[7];
+ expect(exported.__inputs.some((ds: Record) => ds.name === 'DS_GFDB')).toBeTruthy();
+ expect(panel.datasource.uid).toBe('${DS_GFDB}');
+ expect(panel.targets[0].datasource).toBe('${DS_GFDB}');
+ });
+
+ it('should not include default datasource in __inputs unnecessarily', async () => {
+ const testJson: any = {
+ panels: [{ id: 1, datasource: { uid: 'other', type: 'other' }, type: 'graph' }],
+ };
+ const testDash = new DashboardModel(testJson);
+ const exporter = new DashboardExporter();
+ const exportedJson: any = await exporter.makeExportable(testDash);
+ expect(exportedJson.__inputs.some((ds: Record) => ds.name === 'DS_GFDB')).toBeFalsy();
+ });
+
it('should replace datasource refs in collapsed row', () => {
const panel = exported.panels[6].panels[0];
expect(panel.datasource.uid).toBe('${DS_GFDB}');
@@ -453,7 +477,7 @@ stubs['other2'] = {
meta: { id: 'other2', info: { version: '1.2.1' }, name: 'OtherDB_2' },
};
-stubs['-- Mixed --'] = {
+stubs['mixed'] = {
name: 'mixed',
meta: {
id: 'mixed',
@@ -463,7 +487,7 @@ stubs['-- Mixed --'] = {
},
};
-stubs['-- Grafana --'] = {
+stubs['grafana'] = {
name: '-- Grafana --',
meta: {
id: 'grafana',
diff --git a/public/app/features/dashboard/components/DashExportModal/DashboardExporter.ts b/public/app/features/dashboard/components/DashExportModal/DashboardExporter.ts
index 3e7886e4c1c..6fea11bd39f 100644
--- a/public/app/features/dashboard/components/DashExportModal/DashboardExporter.ts
+++ b/public/app/features/dashboard/components/DashExportModal/DashboardExporter.ts
@@ -1,14 +1,15 @@
import { defaults, each, sortBy } from 'lodash';
-import config from 'app/core/config';
-import { DashboardModel } from '../../state/DashboardModel';
-import { PanelModel } from 'app/features/dashboard/state';
import { PanelPluginMeta } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
-import { VariableOption, VariableRefresh } from '../../../variables/types';
-import { isConstant, isQuery } from '../../../variables/guard';
-import { LibraryElementKind } from '../../../library-panels/types';
+import config from 'app/core/config';
+import { PanelModel } from 'app/features/dashboard/state';
+
import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
+import { LibraryElementKind } from '../../../library-panels/types';
+import { isConstant, isQuery } from '../../../variables/guard';
+import { VariableOption, VariableRefresh } from '../../../variables/types';
+import { DashboardModel } from '../../state/DashboardModel';
interface Input {
name: string;
@@ -126,15 +127,18 @@ export class DashboardExporter {
};
const processPanel = (panel: PanelModel) => {
- if (panel.datasource !== undefined && panel.datasource !== null) {
+ const isRegularPanel =
+ (panel.repeatPanelId === undefined || panel.repeatPanelId === null) &&
+ !('collapsed' in panel) &&
+ !('panels' in panel);
+
+ if (isRegularPanel) {
templateizeDatasourceUsage(panel);
}
if (panel.targets) {
for (const target of panel.targets) {
- if (target.datasource !== undefined) {
- templateizeDatasourceUsage(target);
- }
+ templateizeDatasourceUsage(target);
}
}
diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx
index 084e52ed1b3..558f9dacd2a 100644
--- a/public/app/features/dashboard/components/DashNav/DashNav.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx
@@ -1,26 +1,24 @@
-// Libaries
import React, { FC, ReactNode } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { useLocation } from 'react-router-dom';
-// Utils & Services
+
+import { locationUtil, textUtil } from '@grafana/data';
+import { locationService } from '@grafana/runtime';
+import { ButtonGroup, ModalsController, ToolbarButton, PageToolbar, useForceUpdate } from '@grafana/ui';
+import config from 'app/core/config';
+import { toggleKioskMode } from 'app/core/navigation/kiosk';
+import { DashboardCommentsModal } from 'app/features/dashboard/components/DashboardComments/DashboardCommentsModal';
+import { SaveDashboardProxy } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardProxy';
+import { ShareModal } from 'app/features/dashboard/components/ShareModal';
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
-// Components
+import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
+import { KioskMode } from 'app/types';
+
+import { getDashboardSrv } from '../../services/DashboardSrv';
+import { DashboardModel } from '../../state';
+
import { DashNavButton } from './DashNavButton';
import { DashNavTimeControls } from './DashNavTimeControls';
-import { ButtonGroup, ModalsController, ToolbarButton, PageToolbar, useForceUpdate } from '@grafana/ui';
-import { locationUtil, textUtil } from '@grafana/data';
-// State
-import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
-// Types
-import { DashboardModel } from '../../state';
-import { KioskMode } from 'app/types';
-import { ShareModal } from 'app/features/dashboard/components/ShareModal';
-import { SaveDashboardProxy } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardProxy';
-import { DashboardCommentsModal } from 'app/features/dashboard/components/DashboardComments/DashboardCommentsModal';
-import { locationService } from '@grafana/runtime';
-import { toggleKioskMode } from 'app/core/navigation/kiosk';
-import { getDashboardSrv } from '../../services/DashboardSrv';
-import config from 'app/core/config';
const mapDispatchToProps = {
updateTimeZoneForSession,
diff --git a/public/app/features/dashboard/components/DashNav/DashNavButton.tsx b/public/app/features/dashboard/components/DashNav/DashNavButton.tsx
index 5f8e3e6a2d8..48db37402ca 100644
--- a/public/app/features/dashboard/components/DashNav/DashNavButton.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNavButton.tsx
@@ -1,9 +1,10 @@
// Libraries
-import React, { FunctionComponent, MouseEvent } from 'react';
import { css } from '@emotion/css';
+import React, { FunctionComponent, MouseEvent } from 'react';
+
// Components
-import { IconName, IconType, IconSize, IconButton, useTheme, stylesFactory } from '@grafana/ui';
import { GrafanaTheme } from '@grafana/data';
+import { IconName, IconType, IconSize, IconButton, useTheme, stylesFactory } from '@grafana/ui';
interface Props {
icon?: IconName;
diff --git a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx
index 29593cac102..b855f9633bb 100644
--- a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
import { render } from '@testing-library/react';
-import { DashNavTimeControls } from './DashNavTimeControls';
-import { DashboardModel } from '../../state/DashboardModel';
+import React from 'react';
+
import { getDashboardModel } from '../../../../../test/helpers/getDashboardModel';
+import { DashboardModel } from '../../state/DashboardModel';
+
+import { DashNavTimeControls } from './DashNavTimeControls';
describe('DashNavTimeControls', () => {
let dashboardModel: DashboardModel;
diff --git a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx
index 640efa92c3a..d3f3c29a3cb 100644
--- a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx
@@ -1,20 +1,15 @@
-// Libraries
import React, { Component } from 'react';
+import { Unsubscribable } from 'rxjs';
+
import { dateMath, TimeRange, TimeZone } from '@grafana/data';
import { TimeRangeUpdatedEvent } from '@grafana/runtime';
-
-// Types
-import { DashboardModel } from '../../state';
-
-// Components
import { defaultIntervals, RefreshPicker, ToolbarButtonRow } from '@grafana/ui';
import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePickerWithHistory';
-
-// Utils & Services
-import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { appEvents } from 'app/core/core';
+import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
+
import { ShiftTimeEvent, ShiftTimeEventDirection, ZoomOutEvent } from '../../../../types/events';
-import { Unsubscribable } from 'rxjs';
+import { DashboardModel } from '../../state';
export interface Props {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/DashboardComments/DashboardCommentsModal.tsx b/public/app/features/dashboard/components/DashboardComments/DashboardCommentsModal.tsx
index 5f77608749c..fff48e1b531 100644
--- a/public/app/features/dashboard/components/DashboardComments/DashboardCommentsModal.tsx
+++ b/public/app/features/dashboard/components/DashboardComments/DashboardCommentsModal.tsx
@@ -1,9 +1,10 @@
-import React from 'react';
import { css } from '@emotion/css';
-import { Modal, useStyles2 } from '@grafana/ui';
-import { GrafanaTheme2 } from '@grafana/data';
+import React from 'react';
+import { GrafanaTheme2 } from '@grafana/data';
+import { Modal, useStyles2 } from '@grafana/ui';
import { CommentManager } from 'app/features/comments/CommentManager';
+
import { DashboardModel } from '../../state/DashboardModel';
type Props = {
diff --git a/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx b/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx
index 4da79364423..ab6bb41f072 100644
--- a/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx
+++ b/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx
@@ -1,9 +1,10 @@
-import React from 'react';
import { css } from '@emotion/css';
-import { Alert, useStyles } from '@grafana/ui';
+import React from 'react';
+
import { GrafanaTheme } from '@grafana/data';
-import { DashboardInitError, AppNotificationSeverity } from 'app/types';
+import { Alert, useStyles } from '@grafana/ui';
import { getMessageFromError } from 'app/core/utils/errors';
+import { DashboardInitError, AppNotificationSeverity } from 'app/types';
export interface Props {
initError?: DashboardInitError;
diff --git a/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx b/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx
index 97ee5b5d417..0ab5f58f308 100644
--- a/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx
+++ b/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx
@@ -1,8 +1,9 @@
-import React from 'react';
import { css, keyframes } from '@emotion/css';
-import { Button, HorizontalGroup, Spinner, useStyles, VerticalGroup } from '@grafana/ui';
-import { locationService } from '@grafana/runtime';
+import React from 'react';
+
import { GrafanaTheme } from '@grafana/data';
+import { locationService } from '@grafana/runtime';
+import { Button, HorizontalGroup, Spinner, useStyles, VerticalGroup } from '@grafana/ui';
import { DashboardInitPhase } from 'app/types';
export interface Props {
diff --git a/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx b/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx
index b43fdf49642..989786dec44 100644
--- a/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx
+++ b/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx
@@ -1,8 +1,10 @@
import React from 'react';
-import { contextSrv } from 'app/core/core';
-import { DashboardModel } from '../../state';
-import { AccessControlAction } from 'app/types';
+
import { Permissions } from 'app/core/components/AccessControl';
+import { contextSrv } from 'app/core/core';
+import { AccessControlAction } from 'app/types';
+
+import { DashboardModel } from '../../state';
interface Props {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/DashboardPermissions/DashboardPermissions.tsx b/public/app/features/dashboard/components/DashboardPermissions/DashboardPermissions.tsx
index 9d9488f5758..b417791bbb4 100644
--- a/public/app/features/dashboard/components/DashboardPermissions/DashboardPermissions.tsx
+++ b/public/app/features/dashboard/components/DashboardPermissions/DashboardPermissions.tsx
@@ -1,20 +1,22 @@
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
+
import { Tooltip, Icon, Button } from '@grafana/ui';
import { SlideDown } from 'app/core/components/Animations/SlideDown';
+import AddPermission from 'app/core/components/PermissionList/AddPermission';
+import PermissionList from 'app/core/components/PermissionList/PermissionList';
+import PermissionsInfo from 'app/core/components/PermissionList/PermissionsInfo';
import { StoreState } from 'app/types';
import { DashboardAcl, PermissionLevel, NewDashboardAclItem } from 'app/types/acl';
+
+import { checkFolderPermissions } from '../../../folders/state/actions';
+import { DashboardModel } from '../../state/DashboardModel';
import {
getDashboardPermissions,
addDashboardPermission,
removeDashboardPermission,
updateDashboardPermission,
} from '../../state/actions';
-import { checkFolderPermissions } from '../../../folders/state/actions';
-import { DashboardModel } from '../../state/DashboardModel';
-import PermissionList from 'app/core/components/PermissionList/PermissionList';
-import AddPermission from 'app/core/components/PermissionList/AddPermission';
-import PermissionsInfo from 'app/core/components/PermissionList/PermissionsInfo';
const mapStateToProps = (state: StoreState) => ({
permissions: state.dashboard.permissions,
diff --git a/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.test.tsx b/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.test.tsx
index 6622d81152c..fc19f772d4f 100644
--- a/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.test.tsx
+++ b/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.test.tsx
@@ -1,6 +1,7 @@
+import { setContextSrv } from '../../../../core/services/context_srv';
import { DashboardModel } from '../../state/DashboardModel';
import { PanelModel } from '../../state/PanelModel';
-import { setContextSrv } from '../../../../core/services/context_srv';
+
import { hasChanges, ignoreChanges } from './DashboardPrompt';
function getDefaultDashboardModel(): DashboardModel {
diff --git a/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx b/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx
index b6823e765e3..f694e245afe 100644
--- a/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx
+++ b/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx
@@ -1,19 +1,21 @@
-import { locationService } from '@grafana/runtime';
-import { contextSrv } from 'app/core/services/context_srv';
-import React, { useContext, useEffect, useState } from 'react';
-import { Prompt } from 'react-router-dom';
-import { DashboardModel } from '../../state/DashboardModel';
-import { each, filter, find } from 'lodash';
-import { UnsavedChangesModal } from '../SaveDashboard/UnsavedChangesModal';
import * as H from 'history';
-import { SaveLibraryPanelModal } from 'app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal';
-import { PanelModelWithLibraryPanel } from 'app/features/library-panels/types';
+import { each, filter, find } from 'lodash';
+import React, { useContext, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
-import { discardPanelChanges, exitPanelEditor } from '../PanelEditor/state/actions';
+import { Prompt } from 'react-router-dom';
+
+import { locationService } from '@grafana/runtime';
import { ModalsContext } from '@grafana/ui';
import { appEvents } from 'app/core/app_events';
+import { contextSrv } from 'app/core/services/context_srv';
+import { SaveLibraryPanelModal } from 'app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal';
+import { PanelModelWithLibraryPanel } from 'app/features/library-panels/types';
import { DashboardSavedEvent } from 'app/types/events';
+import { DashboardModel } from '../../state/DashboardModel';
+import { discardPanelChanges, exitPanelEditor } from '../PanelEditor/state/actions';
+import { UnsavedChangesModal } from '../SaveDashboard/UnsavedChangesModal';
+
export interface Props {
dashboard: DashboardModel;
}
diff --git a/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx b/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
index 9da5aa3b5b7..e35d6d1487e 100644
--- a/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
+++ b/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
import { mount } from 'enzyme';
-import { DashboardRow } from './DashboardRow';
+import React from 'react';
+
import { PanelModel } from '../../state/PanelModel';
+import { DashboardRow } from './DashboardRow';
+
describe('DashboardRow', () => {
let wrapper: any, panel: PanelModel, dashboardMock: any;
diff --git a/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx b/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
index 6848ba1b13e..c2fbc41dbd1 100644
--- a/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
+++ b/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
@@ -1,14 +1,16 @@
-import React from 'react';
import classNames from 'classnames';
-import { Icon } from '@grafana/ui';
-import { PanelModel } from '../../state/PanelModel';
-import { DashboardModel } from '../../state/DashboardModel';
-import appEvents from 'app/core/app_events';
-import { RowOptionsButton } from '../RowOptions/RowOptionsButton';
-import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
-import { ShowConfirmModalEvent } from '../../../../types/events';
+import React from 'react';
import { Unsubscribable } from 'rxjs';
+
import { selectors } from '@grafana/e2e-selectors';
+import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
+import { Icon } from '@grafana/ui';
+import appEvents from 'app/core/app_events';
+
+import { ShowConfirmModalEvent } from '../../../../types/events';
+import { DashboardModel } from '../../state/DashboardModel';
+import { PanelModel } from '../../state/PanelModel';
+import { RowOptionsButton } from '../RowOptions/RowOptionsButton';
export interface DashboardRowProps {
panel: PanelModel;
diff --git a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
index 07c3d3d2b76..b838b8dd479 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
@@ -1,13 +1,14 @@
-import React from 'react';
-import '@testing-library/jest-dom';
-import { render, screen } from '@testing-library/react';
import { within } from '@testing-library/dom';
+import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import React from 'react';
+
import { selectors } from '@grafana/e2e-selectors';
import { setAngularLoader, setDataSourceSrv } from '@grafana/runtime';
-import { AnnotationsSettings } from './AnnotationsSettings';
import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified/mocks';
+import { AnnotationsSettings } from './AnnotationsSettings';
+
describe('AnnotationsSettings', () => {
let dashboard: any;
@@ -15,7 +16,7 @@ describe('AnnotationsSettings', () => {
grafana: mockDataSource(
{
name: 'Grafana',
- uid: 'Grafana',
+ uid: 'uid1',
type: 'grafana',
isDefault: true,
},
@@ -24,7 +25,7 @@ describe('AnnotationsSettings', () => {
Testdata: mockDataSource(
{
name: 'Testdata',
- uid: 'Testdata',
+ uid: 'uid2',
type: 'testdata',
isDefault: true,
},
@@ -33,7 +34,7 @@ describe('AnnotationsSettings', () => {
Prometheus: mockDataSource(
{
name: 'Prometheus',
- uid: 'Prometheus',
+ uid: 'uid3',
type: 'prometheus',
},
{ annotations: true }
@@ -63,7 +64,7 @@ describe('AnnotationsSettings', () => {
list: [
{
builtIn: 1,
- datasource: { uid: 'Grafana', type: 'grafana' },
+ datasource: { uid: 'uid1', type: 'grafana' },
enable: true,
hide: true,
iconColor: 'rgba(0, 211, 255, 1)',
@@ -76,7 +77,7 @@ describe('AnnotationsSettings', () => {
};
});
- test('it renders a header and cta if no annotations or only builtIn annotation', () => {
+ test('it renders a header and cta if no annotations or only builtIn annotation', async () => {
render();
expect(screen.getByRole('heading', { name: /annotations/i })).toBeInTheDocument();
@@ -87,7 +88,7 @@ describe('AnnotationsSettings', () => {
).toBeInTheDocument();
expect(screen.queryByRole('link', { name: /annotations documentation/i })).toBeInTheDocument();
- userEvent.click(screen.getByRole('cell', { name: /annotations & alerts \(built\-in\)/i }));
+ await userEvent.click(screen.getByRole('cell', { name: /annotations & alerts \(built\-in\)/i }));
const heading = screen.getByRole('heading', {
name: /annotations edit/i,
@@ -96,13 +97,13 @@ describe('AnnotationsSettings', () => {
expect(heading).toBeInTheDocument();
- userEvent.clear(nameInput);
- userEvent.type(nameInput, 'My Annotation');
+ await userEvent.clear(nameInput);
+ await userEvent.type(nameInput, 'My Annotation');
expect(screen.queryByText(/grafana/i)).toBeInTheDocument();
expect(screen.getByRole('checkbox', { name: /hidden/i })).toBeChecked();
- userEvent.click(within(heading).getByText(/annotations/i));
+ await userEvent.click(within(heading).getByText(/annotations/i));
expect(screen.getByRole('table')).toBeInTheDocument();
expect(screen.getByRole('row', { name: /my annotation \(built\-in\) grafana/i })).toBeInTheDocument();
@@ -111,8 +112,8 @@ describe('AnnotationsSettings', () => {
).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /new query/i })).not.toBeInTheDocument();
- userEvent.click(screen.getAllByLabelText(/Delete query with title/)[0]);
- userEvent.click(screen.getByRole('button', { name: 'Delete' }));
+ await userEvent.click(screen.getAllByLabelText(/Delete query with title/)[0]);
+ await userEvent.click(screen.getByRole('button', { name: 'Delete' }));
expect(screen.queryAllByRole('row').length).toBe(0);
expect(
@@ -120,12 +121,12 @@ describe('AnnotationsSettings', () => {
).toBeInTheDocument();
});
- test('it renders a sortable table of annotations', () => {
+ test('it renders the anotation names or uid if annotation doesnt exist', async () => {
const annotationsList = [
...dashboard.annotations.list,
{
builtIn: 0,
- datasource: { uid: 'Prometheus', type: 'prometheus' },
+ datasource: { uid: 'uid3', type: 'prometheus' },
enable: true,
hide: true,
iconColor: 'rgba(0, 211, 255, 1)',
@@ -134,7 +135,41 @@ describe('AnnotationsSettings', () => {
},
{
builtIn: 0,
- datasource: { uid: 'Prometheus', type: 'prometheus' },
+ datasource: { uid: 'deletedAnnotationId', type: 'prometheus' },
+ enable: true,
+ hide: true,
+ iconColor: 'rgba(0, 211, 255, 1)',
+ name: 'Annotation 2',
+ type: 'dashboard',
+ },
+ ];
+ const dashboardWithAnnotations = {
+ ...dashboard,
+ annotations: {
+ list: [...annotationsList],
+ },
+ };
+ render();
+ // Check that we have the correct annotations
+ expect(screen.queryByText(/prometheus/i)).toBeInTheDocument();
+ expect(screen.queryByText(/deletedAnnotationId/i)).toBeInTheDocument();
+ });
+
+ test('it renders a sortable table of annotations', async () => {
+ const annotationsList = [
+ ...dashboard.annotations.list,
+ {
+ builtIn: 0,
+ datasource: { uid: 'uid3', type: 'prometheus' },
+ enable: true,
+ hide: true,
+ iconColor: 'rgba(0, 211, 255, 1)',
+ name: 'Annotation 2',
+ type: 'dashboard',
+ },
+ {
+ builtIn: 0,
+ datasource: { uid: 'uid3', type: 'prometheus' },
enable: true,
hide: true,
iconColor: 'rgba(0, 211, 255, 1)',
@@ -164,9 +199,9 @@ describe('AnnotationsSettings', () => {
expect(within(getTableBodyRows()[1]).queryByText(/annotation 2/i)).toBeInTheDocument();
expect(within(getTableBodyRows()[2]).queryByText(/annotation 3/i)).toBeInTheDocument();
- userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[0]);
- userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[1]);
- userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-up' })[0]);
+ await userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[0]);
+ await userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[1]);
+ await userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-up' })[0]);
// Checking if it has changed the sorting accordingly
expect(within(getTableBodyRows()[0]).queryByText(/annotation 3/i)).toBeInTheDocument();
@@ -177,7 +212,7 @@ describe('AnnotationsSettings', () => {
test('it renders a form for adding/editing annotations', async () => {
render();
- userEvent.click(screen.getByTestId(selectors.components.CallToActionCard.buttonV2('Add annotation query')));
+ await userEvent.click(screen.getByTestId(selectors.components.CallToActionCard.buttonV2('Add annotation query')));
const heading = screen.getByRole('heading', {
name: /annotations edit/i,
@@ -186,19 +221,19 @@ describe('AnnotationsSettings', () => {
expect(heading).toBeInTheDocument();
- userEvent.clear(nameInput);
- userEvent.type(nameInput, 'My Prometheus Annotation');
+ await userEvent.clear(nameInput);
+ await userEvent.type(nameInput, 'My Prometheus Annotation');
- userEvent.click(screen.getByText(/testdata/i));
+ await userEvent.click(screen.getByText(/testdata/i));
expect(await screen.findByText(/Prometheus/i)).toBeVisible();
expect(screen.queryAllByText(/testdata/i)).toHaveLength(2);
- userEvent.click(screen.getByText(/prometheus/i));
+ await userEvent.click(screen.getByText(/prometheus/i));
expect(screen.getByRole('checkbox', { name: /hidden/i })).not.toBeChecked();
- userEvent.click(within(heading).getByText(/annotations/i));
+ await userEvent.click(within(heading).getByText(/annotations/i));
expect(within(screen.getAllByRole('rowgroup')[1]).getAllByRole('row').length).toBe(2);
expect(screen.queryByRole('row', { name: /my prometheus annotation prometheus/i })).toBeInTheDocument();
@@ -207,14 +242,14 @@ describe('AnnotationsSettings', () => {
screen.queryByTestId(selectors.components.CallToActionCard.buttonV2('Add annotation query'))
).not.toBeInTheDocument();
- userEvent.click(screen.getByRole('button', { name: /new query/i }));
+ await userEvent.click(screen.getByRole('button', { name: /new query/i }));
- userEvent.click(within(screen.getByRole('heading', { name: /annotations edit/i })).getByText(/annotations/i));
+ await userEvent.click(within(screen.getByRole('heading', { name: /annotations edit/i })).getByText(/annotations/i));
expect(within(screen.getAllByRole('rowgroup')[1]).getAllByRole('row').length).toBe(3);
- userEvent.click(screen.getAllByLabelText(/Delete query with title/)[0]);
- userEvent.click(screen.getByRole('button', { name: 'Delete' }));
+ await userEvent.click(screen.getAllByLabelText(/Delete query with title/)[0]);
+ await userEvent.click(screen.getByRole('button', { name: 'Delete' }));
expect(within(screen.getAllByRole('rowgroup')[1]).getAllByRole('row').length).toBe(2);
});
diff --git a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx
index 371b6c85422..0ce57e741af 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx
@@ -1,8 +1,11 @@
+import React, { useState } from 'react';
+
import { AnnotationQuery, getDataSourceRef } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
-import React, { useState } from 'react';
+
import { DashboardModel } from '../../state/DashboardModel';
import { AnnotationSettingsEdit, AnnotationSettingsList, newAnnotationName } from '../AnnotationSettings';
+
import { DashboardSettingsHeader } from './DashboardSettingsHeader';
interface Props {
diff --git a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx
index 948dfd93c15..5f6ffb16a33 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx
@@ -1,11 +1,13 @@
-import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import React from 'react';
+
import { defaultIntervals } from '@grafana/ui';
-import { AutoRefreshIntervals, getValidIntervals, Props, validateIntervals } from './AutoRefreshIntervals';
import { TimeSrv } from '../../services/TimeSrv';
+import { AutoRefreshIntervals, getValidIntervals, Props, validateIntervals } from './AutoRefreshIntervals';
+
const setupTestContext = (options: Partial) => {
const defaults: Props = {
refreshIntervals: ['1s', '5s', '10s'],
@@ -49,11 +51,11 @@ describe('AutoRefreshIntervals', () => {
});
describe('when input loses focus and intervals are valid', () => {
- it('then onRefreshIntervalChange should be called', () => {
+ it('then onRefreshIntervalChange should be called', async () => {
const { props } = setupTestContext({ validateIntervalsFunc: () => null });
- userEvent.type(screen.getByRole('textbox'), ',30s');
- userEvent.tab();
+ await userEvent.type(screen.getByRole('textbox'), ',30s');
+ await userEvent.tab();
expect(screen.getByRole('textbox')).toHaveValue('1s,5s,10s,30s');
expect(props.onRefreshIntervalChange).toHaveBeenCalledTimes(1);
@@ -62,11 +64,11 @@ describe('AutoRefreshIntervals', () => {
});
describe('when input loses focus and intervals are invalid', () => {
- it('then onRefreshIntervalChange should not be called', () => {
+ it('then onRefreshIntervalChange should not be called', async () => {
const { props } = setupTestContext({ validateIntervalsFunc: () => 'Not valid' });
- userEvent.type(screen.getByRole('textbox'), ',30q');
- userEvent.tab();
+ await userEvent.type(screen.getByRole('textbox'), ',30q');
+ await userEvent.tab();
expect(screen.getByRole('textbox')).toHaveValue('1s,5s,10s,30q');
expect(props.onRefreshIntervalChange).toHaveBeenCalledTimes(0);
@@ -74,14 +76,14 @@ describe('AutoRefreshIntervals', () => {
});
describe('when input loses focus and previous intervals were invalid', () => {
- it('then onRefreshIntervalChange should be called', () => {
+ it('then onRefreshIntervalChange should be called', async () => {
const validateIntervalsFunc = jest.fn().mockReturnValueOnce('Not valid').mockReturnValue(null);
const { props } = setupTestContext({ validateIntervalsFunc });
- userEvent.type(screen.getByRole('textbox'), ',30q');
- userEvent.tab();
- userEvent.type(screen.getByRole('textbox'), '{backspace}s');
- userEvent.tab();
+ await userEvent.type(screen.getByRole('textbox'), ',30q');
+ await userEvent.tab();
+ await userEvent.type(screen.getByRole('textbox'), '{backspace}s');
+ await userEvent.tab();
expect(screen.getByRole('textbox')).toHaveValue('1s,5s,10s,30s');
expect(props.onRefreshIntervalChange).toHaveBeenCalledTimes(1);
diff --git a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx
index 5554971c657..fa9ec12888b 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx
@@ -1,4 +1,5 @@
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
+
import { Input, defaultIntervals, Field } from '@grafana/ui';
import { getTimeSrv } from '../../services/TimeSrv';
diff --git a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx
index 1a0acb63656..886716a6af1 100644
--- a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx
@@ -1,25 +1,28 @@
+import { css, cx } from '@emotion/css';
+import { useDialog } from '@react-aria/dialog';
+import { FocusScope } from '@react-aria/focus';
+import { useOverlay } from '@react-aria/overlays';
import React, { useCallback, useMemo, useRef } from 'react';
import { Link } from 'react-router-dom';
-import { FocusScope } from '@react-aria/focus';
-import { useDialog } from '@react-aria/dialog';
-import { useOverlay } from '@react-aria/overlays';
-import { css, cx } from '@emotion/css';
+
+import { GrafanaTheme2, locationUtil } from '@grafana/data';
+import { locationService, reportInteraction } from '@grafana/runtime';
import { Button, CustomScrollbar, Icon, IconName, PageToolbar, stylesFactory, useForceUpdate } from '@grafana/ui';
import config from 'app/core/config';
import { contextSrv } from 'app/core/services/context_srv';
-import { DashboardModel } from '../../state/DashboardModel';
-import { SaveDashboardAsButton, SaveDashboardButton } from '../SaveDashboard/SaveDashboardButton';
+import { AccessControlAction } from 'app/types';
+
import { VariableEditorContainer } from '../../../variables/editor/VariableEditorContainer';
-import { DashboardPermissions } from '../DashboardPermissions/DashboardPermissions';
+import { DashboardModel } from '../../state/DashboardModel';
import { AccessControlDashboardPermissions } from '../DashboardPermissions/AccessControlDashboardPermissions';
-import { GeneralSettings } from './GeneralSettings';
+import { DashboardPermissions } from '../DashboardPermissions/DashboardPermissions';
+import { SaveDashboardAsButton, SaveDashboardButton } from '../SaveDashboard/SaveDashboardButton';
+
import { AnnotationsSettings } from './AnnotationsSettings';
+import { GeneralSettings } from './GeneralSettings';
+import { JsonEditorSettings } from './JsonEditorSettings';
import { LinksSettings } from './LinksSettings';
import { VersionsSettings } from './VersionsSettings';
-import { JsonEditorSettings } from './JsonEditorSettings';
-import { GrafanaTheme2, locationUtil } from '@grafana/data';
-import { locationService, reportInteraction } from '@grafana/runtime';
-import { AccessControlAction } from 'app/types';
export interface Props {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/DashboardSettings/DashboardSettingsHeader.tsx b/public/app/features/dashboard/components/DashboardSettings/DashboardSettingsHeader.tsx
index e17ee1daa3c..4e1485f9239 100644
--- a/public/app/features/dashboard/components/DashboardSettings/DashboardSettingsHeader.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/DashboardSettingsHeader.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+
import { Icon, HorizontalGroup } from '@grafana/ui';
type Props = {
diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
index dbec19a2961..c7f17b17dc0 100644
--- a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
@@ -1,12 +1,14 @@
-import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import React from 'react';
+import { byRole } from 'testing-library-selector';
+
+import { selectors } from '@grafana/e2e-selectors';
import { selectOptionInTest } from '@grafana/ui';
-import { byRole } from 'testing-library-selector';
-import { GeneralSettingsUnconnected as GeneralSettings, Props } from './GeneralSettings';
import { DashboardModel } from '../../state';
-import { selectors } from '@grafana/e2e-selectors';
+
+import { GeneralSettingsUnconnected as GeneralSettings, Props } from './GeneralSettings';
const setupTestContext = (options: Partial) => {
const defaults: Props = {
@@ -48,9 +50,9 @@ describe('General Settings', () => {
describe('when timezone is changed', () => {
it('should call update function', async () => {
const { props } = setupTestContext({});
- userEvent.click(screen.getByTestId(selectors.components.TimeZonePicker.containerV2));
+ await userEvent.click(screen.getByTestId(selectors.components.TimeZonePicker.containerV2));
const timeZonePicker = screen.getByTestId(selectors.components.TimeZonePicker.containerV2);
- userEvent.click(byRole('combobox').get(timeZonePicker));
+ await userEvent.click(byRole('combobox').get(timeZonePicker));
await selectOptionInTest(timeZonePicker, 'Browser Time');
expect(props.updateTimeZone).toHaveBeenCalledWith('browser');
expect(props.dashboard.timezone).toBe('browser');
diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx
index 9b2d3e77c8f..1ddfc1a4cef 100644
--- a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx
@@ -1,16 +1,18 @@
import React, { useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
+
import { TimeZone } from '@grafana/data';
-import { CollapsableSection, Field, Input, RadioButtonGroup, TagsInput } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors';
+import { config } from '@grafana/runtime';
+import { CollapsableSection, Field, Input, RadioButtonGroup, TagsInput } from '@grafana/ui';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
+import { updateTimeZoneDashboard, updateWeekStartDashboard } from 'app/features/dashboard/state/actions';
+
import { DashboardModel } from '../../state/DashboardModel';
import { DeleteDashboardButton } from '../DeleteDashboard/DeleteDashboardButton';
-import { TimePickerSettings } from './TimePickerSettings';
-import { updateTimeZoneDashboard, updateWeekStartDashboard } from 'app/features/dashboard/state/actions';
import { PreviewSettings } from './PreviewSettings';
-import { config } from '@grafana/runtime';
+import { TimePickerSettings } from './TimePickerSettings';
interface OwnProps {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx
index e5da865a634..55e9317942e 100644
--- a/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx
@@ -1,11 +1,13 @@
-import React, { useState } from 'react';
import { css } from '@emotion/css';
+import React, { useState } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
+
+import { GrafanaTheme2 } from '@grafana/data';
import { Button, CodeEditor, HorizontalGroup, useStyles2 } from '@grafana/ui';
import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
+
import { getDashboardSrv } from '../../services/DashboardSrv';
import { DashboardModel } from '../../state/DashboardModel';
-import { GrafanaTheme2 } from '@grafana/data';
interface Props {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
index a2646974940..f0156b67067 100644
--- a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
@@ -1,8 +1,8 @@
-import React from 'react';
-import '@testing-library/jest-dom';
-import { render, screen } from '@testing-library/react';
import { within } from '@testing-library/dom';
+import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import React from 'react';
+
import { selectors } from '@grafana/e2e-selectors';
import { LinksSettings } from './LinksSettings';
@@ -84,7 +84,7 @@ describe('LinksSettings', () => {
).not.toBeInTheDocument();
});
- test('it rearranges the order of dashboard links', () => {
+ test('it rearranges the order of dashboard links', async () => {
// @ts-ignore
render();
@@ -103,9 +103,9 @@ describe('LinksSettings', () => {
assertRowHasText(1, links[1].title);
assertRowHasText(2, links[2].url);
- userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[0]);
- userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[1]);
- userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-up' })[0]);
+ await userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[0]);
+ await userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-down' })[1]);
+ await userEvent.click(within(getTableBody()).getAllByRole('button', { name: 'arrow-up' })[0]);
// Checking if it has changed the sorting accordingly
assertRowHasText(0, links[2].url);
@@ -113,35 +113,35 @@ describe('LinksSettings', () => {
assertRowHasText(2, links[0].title);
});
- test('it duplicates dashboard links', () => {
+ test('it duplicates dashboard links', async () => {
// @ts-ignore
render();
expect(getTableBodyRows().length).toBe(links.length);
- userEvent.click(within(getTableBody()).getAllByRole('button', { name: /copy/i })[0]);
+ await userEvent.click(within(getTableBody()).getAllByRole('button', { name: /copy/i })[0]);
expect(getTableBodyRows().length).toBe(links.length + 1);
expect(within(getTableBody()).getAllByText(links[0].title).length).toBe(2);
});
- test('it deletes dashboard links', () => {
+ test('it deletes dashboard links', async () => {
// @ts-ignore
render();
expect(getTableBodyRows().length).toBe(links.length);
- userEvent.click(within(getTableBody()).getAllByLabelText(/Delete link with title/)[0]);
- userEvent.click(within(getTableBody()).getByRole('button', { name: 'Delete' }));
+ await userEvent.click(within(getTableBody()).getAllByLabelText(/Delete link with title/)[0]);
+ await userEvent.click(within(getTableBody()).getByRole('button', { name: 'Delete' }));
expect(getTableBodyRows().length).toBe(links.length - 1);
expect(within(getTableBody()).queryByText(links[0].title)).not.toBeInTheDocument();
});
- test('it renders a form which modifies dashboard links', () => {
+ test('it renders a form which modifies dashboard links', async () => {
// @ts-ignore
render();
- userEvent.click(screen.getByRole('button', { name: /new/i }));
+ await userEvent.click(screen.getByRole('button', { name: /new/i }));
expect(screen.queryByText('Type')).toBeInTheDocument();
expect(screen.queryByText('Title')).toBeInTheDocument();
@@ -151,29 +151,29 @@ describe('LinksSettings', () => {
expect(screen.queryByText('Tooltip')).not.toBeInTheDocument();
expect(screen.queryByText('Icon')).not.toBeInTheDocument();
- userEvent.click(screen.getByText('Dashboards'));
+ await userEvent.click(screen.getByText('Dashboards'));
expect(screen.queryAllByText('Dashboards')).toHaveLength(2);
expect(screen.queryByText('Link')).toBeVisible();
- userEvent.click(screen.getByText('Link'));
+ await userEvent.click(screen.getByText('Link'));
expect(screen.queryByText('URL')).toBeInTheDocument();
expect(screen.queryByText('Tooltip')).toBeInTheDocument();
expect(screen.queryByText('Icon')).toBeInTheDocument();
- userEvent.clear(screen.getByRole('textbox', { name: /title/i }));
- userEvent.type(screen.getByRole('textbox', { name: /title/i }), 'New Dashboard Link');
- userEvent.click(
+ await userEvent.clear(screen.getByRole('textbox', { name: /title/i }));
+ await userEvent.type(screen.getByRole('textbox', { name: /title/i }), 'New Dashboard Link');
+ await userEvent.click(
within(screen.getByRole('heading', { name: /dashboard links edit/i })).getByText(/dashboard links/i)
);
expect(getTableBodyRows().length).toBe(links.length + 1);
expect(within(getTableBody()).queryByText('New Dashboard Link')).toBeInTheDocument();
- userEvent.click(screen.getAllByText(links[0].type)[0]);
- userEvent.clear(screen.getByRole('textbox', { name: /title/i }));
- userEvent.type(screen.getByRole('textbox', { name: /title/i }), 'The first dashboard link');
- userEvent.click(
+ await userEvent.click(screen.getAllByText(links[0].type)[0]);
+ await userEvent.clear(screen.getByRole('textbox', { name: /title/i }));
+ await userEvent.type(screen.getByRole('textbox', { name: /title/i }), 'The first dashboard link');
+ await userEvent.click(
within(screen.getByRole('heading', { name: /dashboard links edit/i })).getByText(/dashboard links/i)
);
diff --git a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx
index 4b3eebac82e..b000a62e4ae 100644
--- a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx
@@ -1,7 +1,9 @@
import React, { useState } from 'react';
+
import { DashboardModel } from '../../state/DashboardModel';
import { LinkSettingsEdit, LinkSettingsList } from '../LinksSettings';
import { newLink } from '../LinksSettings/LinkSettingsEdit';
+
import { DashboardSettingsHeader } from './DashboardSettingsHeader';
interface Props {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx b/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx
index be40e1ddb7f..2f16558d0b0 100644
--- a/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx
@@ -1,7 +1,8 @@
-import React, { ButtonHTMLAttributes } from 'react';
-import { Button, useStyles } from '@grafana/ui';
-import { GrafanaTheme } from '@grafana/data';
import { css } from '@emotion/css';
+import React, { ButtonHTMLAttributes } from 'react';
+
+import { GrafanaTheme } from '@grafana/data';
+import { Button, useStyles } from '@grafana/ui';
export interface Props extends ButtonHTMLAttributes {}
diff --git a/public/app/features/dashboard/components/DashboardSettings/PreviewSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/PreviewSettings.tsx
index 0e7202b0a74..407c2f96783 100644
--- a/public/app/features/dashboard/components/DashboardSettings/PreviewSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/PreviewSettings.tsx
@@ -1,7 +1,8 @@
import React, { PureComponent } from 'react';
+
import { Button, CollapsableSection, FileUpload } from '@grafana/ui';
-import { getThumbnailURL } from 'app/features/search/components/SearchCard';
import { getBackendSrv } from 'app/core/services/backend_srv';
+import { getThumbnailURL } from 'app/features/search/components/SearchCard';
interface Props {
uid: string;
diff --git a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
index d4374ca35eb..e52c92cd2e3 100644
--- a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
@@ -1,8 +1,10 @@
-import React, { PureComponent } from 'react';
-import { CollapsableSection, Field, Input, Switch, TimeZonePicker, WeekStartPicker } from '@grafana/ui';
-import { rangeUtil, TimeZone } from '@grafana/data';
import { isEmpty } from 'lodash';
+import React, { PureComponent } from 'react';
+
+import { rangeUtil, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { CollapsableSection, Field, Input, Switch, TimeZonePicker, WeekStartPicker } from '@grafana/ui';
+
import { AutoRefreshIntervals } from './AutoRefreshIntervals';
interface Props {
diff --git a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
index 00788bbe65d..75baf12aa16 100644
--- a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
@@ -1,9 +1,11 @@
-import React from 'react';
-import '@testing-library/jest-dom';
-import { render, screen, waitFor } from '@testing-library/react';
import { within } from '@testing-library/dom';
+import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import { UserEvent } from '@testing-library/user-event/dist/types/setup';
+import React from 'react';
+
import { historySrv } from '../VersionHistory/HistorySrv';
+
import { VersionsSettings, VERSIONS_FETCH_LIMIT } from './VersionsSettings';
import { versions, diffs } from './__mocks__/versions';
@@ -28,8 +30,18 @@ describe('VersionSettings', () => {
getRelativeTime: jest.fn(() => 'time ago'),
};
+ let user: UserEvent;
+
beforeEach(() => {
+ // Need to use delay: null here to work with fakeTimers
+ // see https://github.com/testing-library/user-event/issues/833
+ user = userEvent.setup({ delay: null });
jest.resetAllMocks();
+ jest.useFakeTimers();
+ });
+
+ afterEach(() => {
+ jest.useRealTimers();
});
test('renders a header and a loading indicator followed by results in a table', async () => {
@@ -102,7 +114,9 @@ describe('VersionSettings', () => {
historySrv.getHistoryList
// @ts-ignore
.mockImplementationOnce(() => Promise.resolve(versions.slice(0, VERSIONS_FETCH_LIMIT)))
- .mockImplementationOnce(() => Promise.resolve(versions.slice(VERSIONS_FETCH_LIMIT, versions.length)));
+ .mockImplementationOnce(
+ () => new Promise((resolve) => setTimeout(() => resolve(versions.slice(VERSIONS_FETCH_LIMIT)), 1000))
+ );
render();
@@ -113,14 +127,16 @@ describe('VersionSettings', () => {
expect(within(screen.getAllByRole('rowgroup')[1]).getAllByRole('row').length).toBe(VERSIONS_FETCH_LIMIT);
const showMoreButton = screen.getByRole('button', { name: /show more versions/i });
- userEvent.click(showMoreButton);
+ await user.click(showMoreButton);
expect(historySrv.getHistoryList).toBeCalledTimes(2);
- expect(screen.queryByText(/Fetching more entries/i)).toBeInTheDocument();
+ expect(screen.getByText(/Fetching more entries/i)).toBeInTheDocument();
+ jest.advanceTimersByTime(1000);
- await waitFor(() =>
- expect(within(screen.getAllByRole('rowgroup')[1]).getAllByRole('row').length).toBe(versions.length)
- );
+ await waitFor(() => {
+ expect(screen.queryByText(/Fetching more entries/i)).not.toBeInTheDocument();
+ expect(within(screen.getAllByRole('rowgroup')[1]).getAllByRole('row').length).toBe(versions.length);
+ });
});
test('selecting two versions and clicking compare button should render compare view', async () => {
@@ -139,17 +155,17 @@ describe('VersionSettings', () => {
const compareButton = screen.getByRole('button', { name: /compare versions/i });
const tableBody = screen.getAllByRole('rowgroup')[1];
- userEvent.click(within(tableBody).getAllByRole('checkbox')[0]);
- userEvent.click(within(tableBody).getAllByRole('checkbox')[VERSIONS_FETCH_LIMIT - 1]);
+ await user.click(within(tableBody).getAllByRole('checkbox')[0]);
+ await user.click(within(tableBody).getAllByRole('checkbox')[VERSIONS_FETCH_LIMIT - 1]);
expect(compareButton).toBeEnabled();
- userEvent.click(within(tableBody).getAllByRole('checkbox')[1]);
+ await user.click(within(tableBody).getAllByRole('checkbox')[1]);
expect(compareButton).toBeDisabled();
- userEvent.click(within(tableBody).getAllByRole('checkbox')[1]);
- userEvent.click(compareButton);
+ await user.click(within(tableBody).getAllByRole('checkbox')[1]);
+ await user.click(compareButton);
await waitFor(() => expect(screen.getByRole('heading', { name: /versions comparing 2 11/i })).toBeInTheDocument());
@@ -170,7 +186,7 @@ describe('VersionSettings', () => {
expect(queryByFullText('version changed')).toBeInTheDocument();
expect(screen.queryByText(/view json diff/i)).toBeInTheDocument();
- userEvent.click(screen.getByText(/view json diff/i));
+ await user.click(screen.getByText(/view json diff/i));
await waitFor(() => expect(screen.getByRole('table')).toBeInTheDocument());
});
diff --git a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx
index f5702c2eb5a..448683461b9 100644
--- a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx
@@ -1,5 +1,7 @@
import React, { PureComponent } from 'react';
+
import { Spinner, HorizontalGroup } from '@grafana/ui';
+
import { DashboardModel } from '../../state/DashboardModel';
import {
historySrv,
diff --git a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx
index a32207fc831..8b8ec48e753 100644
--- a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx
+++ b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx
@@ -1,8 +1,11 @@
import React from 'react';
-import { DeleteDashboardModal } from './DeleteDashboardModal';
+
import { Button, ModalsController } from '@grafana/ui';
+
import { DashboardModel } from '../../state';
+import { DeleteDashboardModal } from './DeleteDashboardModal';
+
type Props = {
dashboard: DashboardModel;
};
diff --git a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx
index 97ea543fb3e..11a62a02e3d 100644
--- a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx
+++ b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx
@@ -1,12 +1,15 @@
-import React from 'react';
import { css } from '@emotion/css';
import { sumBy } from 'lodash';
-import { Modal, ConfirmModal, Button } from '@grafana/ui';
-import { DashboardModel, PanelModel } from '../../state';
-import { useDashboardDelete } from './useDashboardDelete';
+import React from 'react';
import useAsyncFn from 'react-use/lib/useAsyncFn';
+
+import { Modal, ConfirmModal, Button } from '@grafana/ui';
import { config } from 'app/core/config';
+import { DashboardModel, PanelModel } from '../../state';
+
+import { useDashboardDelete } from './useDashboardDelete';
+
type DeleteDashboardModalProps = {
hideModal(): void;
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/DeleteDashboard/useDashboardDelete.tsx b/public/app/features/dashboard/components/DeleteDashboard/useDashboardDelete.tsx
index 263c45f7c1e..ed9429909c5 100644
--- a/public/app/features/dashboard/components/DeleteDashboard/useDashboardDelete.tsx
+++ b/public/app/features/dashboard/components/DeleteDashboard/useDashboardDelete.tsx
@@ -1,8 +1,9 @@
import { useEffect } from 'react';
import { useAsyncFn } from 'react-use';
+
+import { locationService } from '@grafana/runtime';
import { useAppNotification } from 'app/core/copy/appNotification';
import { deleteDashboard } from 'app/features/manage-dashboards/state/actions';
-import { locationService } from '@grafana/runtime';
export const useDashboardDelete = (uid: string) => {
const [state, onDeleteDashboard] = useAsyncFn(() => deleteDashboard(uid, false), []);
diff --git a/public/app/features/dashboard/components/Inspector/InspectContent.tsx b/public/app/features/dashboard/components/Inspector/InspectContent.tsx
index b9852f42821..daa3608548d 100644
--- a/public/app/features/dashboard/components/Inspector/InspectContent.tsx
+++ b/public/app/features/dashboard/components/Inspector/InspectContent.tsx
@@ -1,16 +1,18 @@
import React, { useState } from 'react';
+
import { DataSourceApi, formattedValueToString, getValueFormat, PanelData, PanelPlugin } from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime';
import { Drawer, Tab, TabsBar } from '@grafana/ui';
-import { InspectMetadataTab } from 'app/features/inspector/InspectMetadataTab';
-import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab';
-import { QueryInspector } from 'app/features/inspector/QueryInspector';
-import { InspectStatsTab } from 'app/features/inspector/InspectStatsTab';
-import { InspectErrorTab } from 'app/features/inspector/InspectErrorTab';
import { InspectDataTab } from 'app/features/inspector/InspectDataTab';
+import { InspectErrorTab } from 'app/features/inspector/InspectErrorTab';
+import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab';
+import { InspectMetadataTab } from 'app/features/inspector/InspectMetadataTab';
+import { InspectStatsTab } from 'app/features/inspector/InspectStatsTab';
+import { QueryInspector } from 'app/features/inspector/QueryInspector';
import { InspectTab } from 'app/features/inspector/types';
-import { DashboardModel, PanelModel } from '../../state';
+
import { GetDataOptions } from '../../../query/state/PanelQueryRunner';
+import { DashboardModel, PanelModel } from '../../state';
interface Props {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/Inspector/PanelInspectActions.tsx b/public/app/features/dashboard/components/Inspector/PanelInspectActions.tsx
index 795f7a897d0..e66449ae3f4 100644
--- a/public/app/features/dashboard/components/Inspector/PanelInspectActions.tsx
+++ b/public/app/features/dashboard/components/Inspector/PanelInspectActions.tsx
@@ -1,3 +1,7 @@
+import React, { ComponentType } from 'react';
+
+import { PanelData } from '@grafana/data';
+
import { PanelModel } from '../../state';
export interface PanelInspectActionProps {
@@ -51,9 +55,6 @@ export interface PanelInspectActionSupplier {
// NOTE: This is an internal/experimental API/hack and will change!
// (window as any).grafanaPanelInspectActionSupplier = dummySupplier;
-import React, { ComponentType } from 'react';
-import { PanelData } from '@grafana/data';
-
interface InspectActionsTabProps {
panel: PanelModel;
data?: PanelData;
diff --git a/public/app/features/dashboard/components/Inspector/PanelInspector.tsx b/public/app/features/dashboard/components/Inspector/PanelInspector.tsx
index 568149226a1..f0b9cb05111 100644
--- a/public/app/features/dashboard/components/Inspector/PanelInspector.tsx
+++ b/public/app/features/dashboard/components/Inspector/PanelInspector.tsx
@@ -1,16 +1,19 @@
import React, { useState } from 'react';
import { connect, MapStateToProps } from 'react-redux';
-import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
+import { useLocation } from 'react-router-dom';
+
import { PanelPlugin } from '@grafana/data';
import { locationService } from '@grafana/runtime';
-import { StoreState } from 'app/types';
-import { GetDataOptions } from '../../../query/state/PanelQueryRunner';
-import { usePanelLatestData } from '../PanelEditor/usePanelLatestData';
-import { InspectContent } from './InspectContent';
-import { useDatasourceMetadata, useInspectTabs } from './hooks';
-import { useLocation } from 'react-router-dom';
+import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { InspectTab } from 'app/features/inspector/types';
import { getPanelStateForModel } from 'app/features/panel/state/selectors';
+import { StoreState } from 'app/types';
+
+import { GetDataOptions } from '../../../query/state/PanelQueryRunner';
+import { usePanelLatestData } from '../PanelEditor/usePanelLatestData';
+
+import { InspectContent } from './InspectContent';
+import { useDatasourceMetadata, useInspectTabs } from './hooks';
interface OwnProps {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/Inspector/hooks.ts b/public/app/features/dashboard/components/Inspector/hooks.ts
index c46fd8624a4..ca38e9ebcee 100644
--- a/public/app/features/dashboard/components/Inspector/hooks.ts
+++ b/public/app/features/dashboard/components/Inspector/hooks.ts
@@ -1,10 +1,13 @@
-import { DataQueryError, DataSourceApi, PanelData, PanelPlugin } from '@grafana/data';
+import { useMemo } from 'react';
import useAsync from 'react-use/lib/useAsync';
+
+import { DataQueryError, DataSourceApi, PanelData, PanelPlugin } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
-import { useMemo } from 'react';
-import { supportsDataQuery } from '../PanelEditor/utils';
import { InspectTab } from 'app/features/inspector/types';
+
+import { supportsDataQuery } from '../PanelEditor/utils';
+
import { PanelInspectActionSupplier } from './PanelInspectActions';
/**
diff --git a/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx b/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx
index ac99dca1faf..cd5b2d16236 100644
--- a/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx
+++ b/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx
@@ -1,6 +1,8 @@
import React, { useState } from 'react';
-import { CollapsableSection, TagsInput, Select, Field, Input, Checkbox } from '@grafana/ui';
+
import { SelectableValue } from '@grafana/data';
+import { CollapsableSection, TagsInput, Select, Field, Input, Checkbox } from '@grafana/ui';
+
import { DashboardLink, DashboardModel } from '../../state/DashboardModel';
export const newLink = {
diff --git a/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx b/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx
index f23cedc728b..4db46c6143f 100644
--- a/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx
+++ b/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx
@@ -1,9 +1,11 @@
import React, { useState } from 'react';
+
+import { arrayUtils } from '@grafana/data';
import { DeleteButton, HorizontalGroup, Icon, IconButton, TagList } from '@grafana/ui';
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
+
import { DashboardModel, DashboardLink } from '../../state/DashboardModel';
import { ListNewButton } from '../DashboardSettings/ListNewButton';
-import { arrayUtils } from '@grafana/data';
type LinkSettingsListProps = {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx b/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx
index 605b9573856..b625700c025 100644
--- a/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx
@@ -1,18 +1,16 @@
-// Libraries
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
-// Utils and services
-import { AngularComponent, getAngularLoader } from '@grafana/runtime';
-
-// Types
-import { PanelModel, DashboardModel } from '../../state';
import { PanelPlugin, PanelPluginMeta } from '@grafana/data';
-import { changePanelPlugin } from 'app/features/panel/state/actions';
-import { StoreState } from 'app/types';
-import { getSectionOpenState, saveSectionOpenState } from './state/utils';
+import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
+import { changePanelPlugin } from 'app/features/panel/state/actions';
import { getPanelStateForModel } from 'app/features/panel/state/selectors';
+import { StoreState } from 'app/types';
+
+import { PanelModel, DashboardModel } from '../../state';
+
+import { getSectionOpenState, saveSectionOpenState } from './state/utils';
interface OwnProps {
panel: PanelModel;
diff --git a/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx b/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx
index 1af676e798a..f23f470a786 100644
--- a/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx
@@ -1,3 +1,8 @@
+import { css, cx } from '@emotion/css';
+import React from 'react';
+// @ts-ignore
+import Highlighter from 'react-highlight-words';
+
import {
DynamicConfigValue,
FieldConfigOptionsRegistry,
@@ -5,11 +10,9 @@ import {
FieldOverrideContext,
GrafanaTheme,
} from '@grafana/data';
-import React from 'react';
import { Counter, Field, HorizontalGroup, IconButton, Label, stylesFactory, useTheme } from '@grafana/ui';
-import { css, cx } from '@emotion/css';
+
import { OptionsPaneCategory } from './OptionsPaneCategory';
-import Highlighter from 'react-highlight-words';
interface DynamicConfigValueEditorProps {
property: DynamicConfigValue;
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx
index 73e73e8ee24..2a025affce4 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx
@@ -1,15 +1,17 @@
-import React from 'react';
-import { GrafanaTheme } from '@grafana/data';
-import { useStyles } from '@grafana/ui';
import { css } from '@emotion/css';
-import { selectors } from '@grafana/e2e-selectors';
-import { VisualizationButton } from './VisualizationButton';
-import { OptionsPaneOptions } from './OptionsPaneOptions';
+import React from 'react';
import { useSelector } from 'react-redux';
+
+import { GrafanaTheme } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
+import { useStyles } from '@grafana/ui';
import { StoreState } from 'app/types';
+
+import { OptionsPaneOptions } from './OptionsPaneOptions';
+import { VisualizationButton } from './VisualizationButton';
import { VisualizationSelectPane } from './VisualizationSelectPane';
-import { usePanelLatestData } from './usePanelLatestData';
import { OptionPaneRenderProps } from './types';
+import { usePanelLatestData } from './usePanelLatestData';
export const OptionsPane: React.FC = ({
plugin,
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx
index 4c57d945ef4..8cfa6969013 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx
@@ -1,13 +1,15 @@
-import React, { FC, ReactNode, useCallback, useEffect, useState, useRef } from 'react';
import { css, cx } from '@emotion/css';
-import { GrafanaTheme2 } from '@grafana/data';
-import { Counter, useStyles2 } from '@grafana/ui';
-import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers';
+import React, { FC, ReactNode, useCallback, useEffect, useState, useRef } from 'react';
import { useLocalStorage } from 'react-use';
+
+import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { Counter, useStyles2 } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { CollapseToggle } from 'app/features/alerting/unified/components/CollapseToggle';
+import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers';
+
export interface OptionsPaneCategoryProps {
id: string;
title?: string;
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx
index 5715aec6c47..ef887c9256e 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+
import { OptionsPaneCategory } from './OptionsPaneCategory';
import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx
index a8f2ef53233..97906d5d2bb 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx
@@ -1,7 +1,10 @@
+import React, { ReactNode } from 'react';
+// @ts-ignore
+import Highlighter from 'react-highlight-words';
+
import { selectors } from '@grafana/e2e-selectors';
import { Field, Label } from '@grafana/ui';
-import React, { ReactNode } from 'react';
-import Highlighter from 'react-highlight-words';
+
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
import { OptionsPaneItemOverrides } from './OptionsPaneItemOverrides';
import { OptionPaneItemOverrideInfo } from './types';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx
index 7e086908788..769029e32f0 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
-import { Tooltip, useStyles2 } from '@grafana/ui';
-import { GrafanaTheme2 } from '@grafana/data';
import { css, CSSObject } from '@emotion/css';
+import React from 'react';
+
+import { GrafanaTheme2 } from '@grafana/data';
+import { Tooltip, useStyles2 } from '@grafana/ui';
+
import { OptionPaneItemOverrideInfo } from './types';
export interface Props {
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
index f7f3e910936..c539c11acc3 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
@@ -1,5 +1,8 @@
-import React from 'react';
import { fireEvent, render, screen, within } from '@testing-library/react';
+import React from 'react';
+import { Provider } from 'react-redux';
+import configureMockStore from 'redux-mock-store';
+
import {
FieldConfigSource,
FieldType,
@@ -9,15 +12,14 @@ import {
standardFieldConfigEditorRegistry,
toDataFrame,
} from '@grafana/data';
-
import { selectors } from '@grafana/e2e-selectors';
-import { OptionsPaneOptions } from './OptionsPaneOptions';
-import { DashboardModel, PanelModel } from '../../state';
-import { Provider } from 'react-redux';
-import configureMockStore from 'redux-mock-store';
-import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
-import { dataOverrideTooltipDescription, overrideRuleTooltipDescription } from './state/getOptionOverrides';
import { getAllOptionEditors, getAllStandardFieldConfigs } from 'app/core/components/editors/registry';
+import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
+
+import { DashboardModel, PanelModel } from '../../state';
+
+import { OptionsPaneOptions } from './OptionsPaneOptions';
+import { dataOverrideTooltipDescription, overrideRuleTooltipDescription } from './state/getOptionOverrides';
standardEditorsRegistry.setInit(getAllOptionEditors);
standardFieldConfigEditorRegistry.setInit(getAllStandardFieldConfigs);
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx
index 203c2095fc2..ac0bb0579fe 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx
@@ -1,17 +1,20 @@
+import { css } from '@emotion/css';
import React, { useMemo, useState } from 'react';
+
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { CustomScrollbar, FilterInput, RadioButtonGroup, useStyles2 } from '@grafana/ui';
+
+import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
+
+import { AngularPanelOptions } from './AngularPanelOptions';
+import { OptionsPaneCategory } from './OptionsPaneCategory';
+import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
+import { getFieldOverrideCategories } from './getFieldOverrideElements';
+import { getLibraryPanelOptionsCategory } from './getLibraryPanelOptions';
import { getPanelFrameCategory } from './getPanelFrameOptions';
import { getVisualizationOptions } from './getVisualizationOptions';
-import { css } from '@emotion/css';
-import { OptionsPaneCategory } from './OptionsPaneCategory';
-import { getFieldOverrideCategories } from './getFieldOverrideElements';
-import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
import { OptionSearchEngine } from './state/OptionSearchEngine';
-import { AngularPanelOptions } from './AngularPanelOptions';
import { getRecentOptions } from './state/getRecentOptions';
-import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
-import { getLibraryPanelOptionsCategory } from './getLibraryPanelOptions';
import { OptionPaneRenderProps } from './types';
export const OptionsPaneOptions: React.FC = (props) => {
diff --git a/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx b/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx
index 3fef9023966..961868cedf6 100644
--- a/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx
@@ -1,8 +1,9 @@
+import { css } from '@emotion/css';
import React, { FC } from 'react';
+
import { FieldConfigOptionsRegistry, GrafanaTheme, ConfigOverrideRule } from '@grafana/data';
import { HorizontalGroup, Icon, IconButton, useStyles } from '@grafana/ui';
import { FieldMatcherUIRegistryItem } from '@grafana/ui/src/components/MatchersUI/types';
-import { css } from '@emotion/css';
interface OverrideCategoryTitleProps {
isExpanded: boolean;
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
index 51d91021993..59c92814742 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
@@ -1,11 +1,12 @@
+import { css } from '@emotion/css';
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
-import { css } from '@emotion/css';
import { Subscription } from 'rxjs';
import { FieldConfigSource, GrafanaTheme } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { locationService } from '@grafana/runtime';
import {
HorizontalGroup,
InlineSwitch,
@@ -15,34 +16,19 @@ import {
stylesFactory,
ToolbarButton,
} from '@grafana/ui';
-
+import { SplitPaneWrapper } from 'app/core/components/SplitPaneWrapper/SplitPaneWrapper';
import config from 'app/core/config';
import { appEvents } from 'app/core/core';
-import { calculatePanelSize } from './utils';
-
-import { PanelEditorTabs } from './PanelEditorTabs';
-import { DashNavTimeControls } from '../DashNav/DashNavTimeControls';
-import { OptionsPane } from './OptionsPane';
import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuItems';
-import { SplitPaneWrapper } from 'app/core/components/SplitPaneWrapper/SplitPaneWrapper';
-import { SaveDashboardProxy } from '../SaveDashboard/SaveDashboardProxy';
-import { DashboardPanel } from '../../dashgrid/DashboardPanel';
-
-import { discardPanelChanges, initPanelEditor, updatePanelEditorUIState } from './state/actions';
-
-import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
-import { toggleTableView } from './state/reducers';
-
-import { getPanelEditorTabs } from './state/selectors';
-
-import { StoreState } from 'app/types';
-import { DisplayMode, displayModes, PanelEditorTab } from './types';
-import { DashboardModel, PanelModel } from '../../state';
-import { VisualizationButton } from './VisualizationButton';
-import { PanelOptionsChangedEvent, ShowModalReactEvent } from 'app/types/events';
-import { locationService } from '@grafana/runtime';
-import { UnlinkModal } from '../../../library-panels/components/UnlinkModal/UnlinkModal';
import { SaveLibraryPanelModal } from 'app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal';
+import { PanelModelWithLibraryPanel } from 'app/features/library-panels/types';
+import { getPanelStateForModel } from 'app/features/panel/state/selectors';
+import { updateTimeZoneForSession } from 'app/features/profile/state/reducers';
+import { StoreState } from 'app/types';
+import { PanelOptionsChangedEvent, ShowModalReactEvent } from 'app/types/events';
+
+import { notifyApp } from '../../../../core/actions';
+import { UnlinkModal } from '../../../library-panels/components/UnlinkModal/UnlinkModal';
import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
import { getLibraryPanelConnectedDashboards } from '../../../library-panels/state/api';
import {
@@ -50,11 +36,21 @@ import {
createPanelLibrarySuccessNotification,
saveAndRefreshLibraryPanel,
} from '../../../library-panels/utils';
-import { notifyApp } from '../../../../core/actions';
-import { PanelEditorTableView } from './PanelEditorTableView';
-import { PanelModelWithLibraryPanel } from 'app/features/library-panels/types';
-import { getPanelStateForModel } from 'app/features/panel/state/selectors';
import { getVariablesByKey } from '../../../variables/state/selectors';
+import { DashboardPanel } from '../../dashgrid/DashboardPanel';
+import { DashboardModel, PanelModel } from '../../state';
+import { DashNavTimeControls } from '../DashNav/DashNavTimeControls';
+import { SaveDashboardProxy } from '../SaveDashboard/SaveDashboardProxy';
+
+import { OptionsPane } from './OptionsPane';
+import { PanelEditorTableView } from './PanelEditorTableView';
+import { PanelEditorTabs } from './PanelEditorTabs';
+import { VisualizationButton } from './VisualizationButton';
+import { discardPanelChanges, initPanelEditor, updatePanelEditorUIState } from './state/actions';
+import { toggleTableView } from './state/reducers';
+import { getPanelEditorTabs } from './state/selectors';
+import { DisplayMode, displayModes, PanelEditorTab } from './types';
+import { calculatePanelSize } from './utils';
interface OwnProps {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx
index 36cc2d32b88..ca3ce045036 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx
@@ -1,10 +1,12 @@
import React, { PureComponent } from 'react';
-import { QueryGroup } from 'app/features/query/components/QueryGroup';
-import { PanelModel } from '../../state';
-import { locationService } from '@grafana/runtime';
-import { QueryGroupDataSource, QueryGroupOptions } from 'app/types';
+
import { DataQuery, getDataSourceRef } from '@grafana/data';
+import { locationService } from '@grafana/runtime';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
+import { QueryGroup } from 'app/features/query/components/QueryGroup';
+import { QueryGroupDataSource, QueryGroupOptions } from 'app/types';
+
+import { PanelModel } from '../../state';
interface Props {
/** Current panel */
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
index 826f419ac5c..fd4958d10b4 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
@@ -1,13 +1,16 @@
-import { PanelChrome } from '@grafana/ui';
-import { PanelRenderer } from 'app/features/panel/components/PanelRenderer';
import React, { useEffect, useState } from 'react';
-import { DashboardModel, PanelModel } from '../../state';
-import { usePanelLatestData } from './usePanelLatestData';
-import { PanelOptions } from 'app/plugins/panel/table/models.gen';
+
import { RefreshEvent } from '@grafana/runtime';
+import { PanelChrome } from '@grafana/ui';
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
-import { getTimeSrv } from '../../services/TimeSrv';
+import { PanelRenderer } from 'app/features/panel/components/PanelRenderer';
+import { PanelOptions } from 'app/plugins/panel/table/models.gen';
+
import PanelHeaderCorner from '../../dashgrid/PanelHeader/PanelHeaderCorner';
+import { getTimeSrv } from '../../services/TimeSrv';
+import { DashboardModel, PanelModel } from '../../state';
+
+import { usePanelLatestData } from './usePanelLatestData';
interface Props {
width: number;
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx
index 8c903e3fbfa..e9c4ed1a4dc 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx
@@ -1,16 +1,19 @@
-import React, { FC, useEffect } from 'react';
import { css } from '@emotion/css';
-import { IconName, Tab, TabContent, TabsBar, useForceUpdate, useStyles2 } from '@grafana/ui';
-import { TransformationsEditor } from '../TransformationsEditor/TransformationsEditor';
-import { DashboardModel, PanelModel } from '../../state';
-import { PanelEditorTab, PanelEditorTabId } from './types';
+import React, { FC, useEffect } from 'react';
import { Subscription } from 'rxjs';
-import { PanelQueriesChangedEvent, PanelTransformationsChangedEvent } from 'app/types/events';
-import { PanelEditorQueries } from './PanelEditorQueries';
+
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
+import { IconName, Tab, TabContent, TabsBar, useForceUpdate, useStyles2 } from '@grafana/ui';
import AlertTabIndex from 'app/features/alerting/AlertTabIndex';
import { PanelAlertTab } from 'app/features/alerting/unified/PanelAlertTab';
+import { PanelQueriesChangedEvent, PanelTransformationsChangedEvent } from 'app/types/events';
+
+import { DashboardModel, PanelModel } from '../../state';
+import { TransformationsEditor } from '../TransformationsEditor/TransformationsEditor';
+
+import { PanelEditorQueries } from './PanelEditorQueries';
+import { PanelEditorTab, PanelEditorTabId } from './types';
interface PanelEditorTabsProps {
panel: PanelModel;
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
index 3140999328a..b5e6f9ed926 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
@@ -1,7 +1,9 @@
-import { locationService } from '@grafana/runtime';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
+
+import { locationService } from '@grafana/runtime';
+
import { PanelNotSupported, Props } from './PanelNotSupported';
import { PanelEditorTabId } from './types';
@@ -28,9 +30,9 @@ describe('PanelNotSupported', () => {
});
describe('when the back to queries button is clicked', () => {
- it('then correct action should be dispatched', () => {
+ it('then correct action should be dispatched', async () => {
setupTestContext({});
- userEvent.click(screen.getByRole('button', { name: /go back to queries/i }));
+ await userEvent.click(screen.getByRole('button', { name: /go back to queries/i }));
expect(locationService.getSearchObject().tab).toBe(PanelEditorTabId.Query);
});
});
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
index 3c0bcdcc0a6..ea60c728c8f 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
@@ -1,9 +1,10 @@
import React, { useCallback } from 'react';
-import { Button, VerticalGroup } from '@grafana/ui';
-import { Layout } from '@grafana/ui/src/components/Layout/Layout';
-import { PanelEditorTabId } from './types';
import { locationService } from '@grafana/runtime';
+import { Button, VerticalGroup } from '@grafana/ui';
+import { Layout } from '@grafana/ui/src/components/Layout/Layout';
+
+import { PanelEditorTabId } from './types';
export interface Props {
message: string;
diff --git a/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx b/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx
index 8e705bbd8f2..476f77a3f3f 100644
--- a/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx
@@ -1,14 +1,17 @@
-import React, { FC } from 'react';
import { css } from '@emotion/css';
+import React, { FC } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+
import { GrafanaTheme } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
import { ToolbarButton, ButtonGroup, useStyles } from '@grafana/ui';
import { StoreState } from 'app/types';
-import { useDispatch, useSelector } from 'react-redux';
-import { setPanelEditorUIState, toggleVizPicker } from './state/reducers';
-import { selectors } from '@grafana/e2e-selectors';
+
import { PanelModel } from '../../state';
import { getPanelPluginWithFallback } from '../../state/selectors';
+import { setPanelEditorUIState, toggleVizPicker } from './state/reducers';
+
type Props = {
panel: PanelModel;
};
diff --git a/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx b/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx
index ca2e2e18f40..db9a56901c9 100644
--- a/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx
@@ -1,21 +1,24 @@
-import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
import { css } from '@emotion/css';
+import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { useLocalStorage } from 'react-use';
+
import { GrafanaTheme, PanelData, SelectableValue } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
import { Button, CustomScrollbar, FilterInput, RadioButtonGroup, useStyles } from '@grafana/ui';
+import { Field } from '@grafana/ui/src/components/Forms/Field';
+import { LS_VISUALIZATION_SELECT_TAB_KEY } from 'app/core/constants';
+import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup';
+import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
+import { VizTypeChangeDetails } from 'app/features/panel/components/VizTypePicker/types';
+
+import { VizTypePicker } from '../../../panel/components/VizTypePicker/VizTypePicker';
import { changePanelPlugin } from '../../../panel/state/actions';
import { PanelModel } from '../../state/PanelModel';
-import { useDispatch, useSelector } from 'react-redux';
-import { VizTypePicker } from '../../../panel/components/VizTypePicker/VizTypePicker';
-import { Field } from '@grafana/ui/src/components/Forms/Field';
-import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup';
-import { toggleVizPicker } from './state/reducers';
-import { selectors } from '@grafana/e2e-selectors';
import { getPanelPluginWithFallback } from '../../state/selectors';
-import { VizTypeChangeDetails } from 'app/features/panel/components/VizTypePicker/types';
-import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
-import { useLocalStorage } from 'react-use';
+
+import { toggleVizPicker } from './state/reducers';
import { VisualizationSelectPaneTab } from './types';
-import { LS_VISUALIZATION_SELECT_TAB_KEY } from 'app/core/constants';
interface Props {
panel: PanelModel;
diff --git a/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx b/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx
index 43af045b55e..9ca84fdf48a 100644
--- a/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx
@@ -1,5 +1,7 @@
-import React from 'react';
+import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
+import React from 'react';
+
import {
FieldConfigOptionsRegistry,
SelectableValue,
@@ -10,13 +12,13 @@ import {
GrafanaTheme2,
} from '@grafana/data';
import { fieldMatchersUI, useStyles2, ValuePicker } from '@grafana/ui';
-import { OptionPaneRenderProps } from './types';
-import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
-import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
-import { DynamicConfigValueEditor } from './DynamicConfigValueEditor';
import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
+
+import { DynamicConfigValueEditor } from './DynamicConfigValueEditor';
+import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
+import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
import { OverrideCategoryTitle } from './OverrideCategoryTitle';
-import { css } from '@emotion/css';
+import { OptionPaneRenderProps } from './types';
export function getFieldOverrideCategories(
props: OptionPaneRenderProps,
diff --git a/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx b/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx
index d92669f3f72..8f1036efcb4 100644
--- a/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx
@@ -1,11 +1,14 @@
-import { Input } from '@grafana/ui';
import React from 'react';
-import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
-import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
-import { OptionPaneRenderProps } from './types';
-import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
+
+import { Input } from '@grafana/ui';
import { LibraryPanelInformation } from 'app/features/library-panels/components/LibraryPanelInfo/LibraryPanelInfo';
+import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
+
+import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
+import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
+import { OptionPaneRenderProps } from './types';
+
export function getLibraryPanelOptionsCategory(props: OptionPaneRenderProps): OptionsPaneCategoryDescriptor {
const { panel, onPanelConfigChange, dashboard } = props;
const descriptor = new OptionsPaneCategoryDescriptor({
diff --git a/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx b/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx
index 5cd1e34348b..20e4a7a69b7 100644
--- a/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx
@@ -1,9 +1,12 @@
+import React from 'react';
+
import { DataLinksInlineEditor, Input, RadioButtonGroup, Select, Switch, TextArea } from '@grafana/ui';
import { getPanelLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
-import React from 'react';
+
import { RepeatRowSelect } from '../RepeatRowSelect/RepeatRowSelect';
-import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
+
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
+import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
import { OptionPaneRenderProps } from './types';
export function getPanelFrameCategory(props: OptionPaneRenderProps): OptionsPaneCategoryDescriptor {
diff --git a/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.test.ts b/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.test.ts
index 3d3c461f6f8..01f12b81f1c 100644
--- a/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.test.ts
+++ b/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.test.ts
@@ -1,4 +1,5 @@
import { EventBusSrv, FieldType, getDefaultTimeRange, LoadingState, toDataFrame } from '@grafana/data';
+
import { getStandardEditorContext } from './getVisualizationOptions';
describe('getStandardEditorContext', () => {
diff --git a/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx b/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx
index be266ae7e9b..a3fa3263e73 100644
--- a/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx
@@ -1,4 +1,6 @@
+import { get as lodashGet } from 'lodash';
import React from 'react';
+
import {
EventBus,
InterpolateFunction,
@@ -6,19 +8,19 @@ import {
StandardEditorContext,
VariableSuggestionsScope,
} from '@grafana/data';
-import { get as lodashGet } from 'lodash';
-import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
-import { OptionPaneRenderProps } from './types';
-import { setOptionImmutably, updateDefaultFieldConfigValue } from './utils';
-import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
-import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
+import { PanelOptionsSupplier } from '@grafana/data/src/panel/PanelPlugin';
import {
isNestedPanelOptions,
NestedValueAccess,
PanelOptionsEditorBuilder,
} from '@grafana/data/src/utils/OptionsUIBuilders';
-import { PanelOptionsSupplier } from '@grafana/data/src/panel/PanelPlugin';
+import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
+
+import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
+import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
import { getOptionOverrides } from './state/getOptionOverrides';
+import { OptionPaneRenderProps } from './types';
+import { setOptionImmutably, updateDefaultFieldConfigValue } from './utils';
type categoryGetter = (categoryNames?: string[]) => OptionsPaneCategoryDescriptor;
diff --git a/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.test.ts b/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.test.ts
index bb9d42bc0d7..43787af8f58 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.test.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.test.ts
@@ -1,5 +1,6 @@
import { OptionsPaneCategoryDescriptor } from '../OptionsPaneCategoryDescriptor';
import { OptionsPaneItemDescriptor } from '../OptionsPaneItemDescriptor';
+
import { OptionSearchEngine } from './OptionSearchEngine';
describe('OptionSearchEngine', () => {
diff --git a/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.ts b/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.ts
index c29f8399949..c861806702d 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/OptionSearchEngine.ts
@@ -1,5 +1,5 @@
-import { OptionsPaneItemDescriptor } from '../OptionsPaneItemDescriptor';
import { OptionsPaneCategoryDescriptor } from '../OptionsPaneCategoryDescriptor';
+import { OptionsPaneItemDescriptor } from '../OptionsPaneItemDescriptor';
export interface OptionSearchResults {
optionHits: OptionsPaneItemDescriptor[];
diff --git a/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts b/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts
index 1e864f160ac..b52df7d3ae9 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/actions.test.ts
@@ -1,10 +1,12 @@
-import { thunkTester } from '../../../../../../test/core/thunk/thunkTester';
-import { closeEditor, initialState, PanelEditorState } from './reducers';
-import { exitPanelEditor, initPanelEditor, skipPanelUpdate } from './actions';
import { panelModelAndPluginReady, removePanel } from 'app/features/panel/state/reducers';
-import { DashboardModel, PanelModel } from '../../../state';
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
+import { thunkTester } from '../../../../../../test/core/thunk/thunkTester';
+import { DashboardModel, PanelModel } from '../../../state';
+
+import { exitPanelEditor, initPanelEditor, skipPanelUpdate } from './actions';
+import { closeEditor, initialState, PanelEditorState } from './reducers';
+
describe('panelEditor actions', () => {
describe('initPanelEditor', () => {
it('initPanelEditor should create edit panel model as clone', async () => {
diff --git a/public/app/features/dashboard/components/PanelEditor/state/actions.ts b/public/app/features/dashboard/components/PanelEditor/state/actions.ts
index 7093dd47cdc..a2c037843eb 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/actions.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/actions.ts
@@ -1,8 +1,12 @@
import { pick } from 'lodash';
-import { ThunkResult } from 'app/types';
+
import store from 'app/core/store';
-import { panelModelAndPluginReady } from 'app/features/panel/state/reducers';
import { cleanUpPanelState, initPanelState } from 'app/features/panel/state/actions';
+import { panelModelAndPluginReady } from 'app/features/panel/state/reducers';
+import { ThunkResult } from 'app/types';
+
+import { DashboardModel, PanelModel } from '../../../state';
+
import {
closeEditor,
PANEL_EDITOR_UI_STATE_STORAGE_KEY,
@@ -11,7 +15,6 @@ import {
setPanelEditorUIState,
updateEditorInitState,
} from './reducers';
-import { DashboardModel, PanelModel } from '../../../state';
export function initPanelEditor(sourcePanel: PanelModel, dashboard: DashboardModel): ThunkResult {
return async (dispatch) => {
diff --git a/public/app/features/dashboard/components/PanelEditor/state/getOptionOverrides.ts b/public/app/features/dashboard/components/PanelEditor/state/getOptionOverrides.ts
index 7160401a861..0ce4e9ce71b 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/getOptionOverrides.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/getOptionOverrides.ts
@@ -1,5 +1,7 @@
-import { DataFrame, FieldConfigPropertyItem, FieldConfigSource } from '@grafana/data';
import { get as lodashGet } from 'lodash';
+
+import { DataFrame, FieldConfigPropertyItem, FieldConfigSource } from '@grafana/data';
+
import { OptionPaneItemOverrideInfo } from '../types';
export const dataOverrideTooltipDescription =
diff --git a/public/app/features/dashboard/components/PanelEditor/state/reducers.ts b/public/app/features/dashboard/components/PanelEditor/state/reducers.ts
index b8e77139e78..9a366235f2f 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/reducers.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/reducers.ts
@@ -1,8 +1,10 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { PanelModel } from '../../../state/PanelModel';
+
import { getDefaultTimeRange, LoadingState, PanelData } from '@grafana/data';
-import { DisplayMode } from '../types';
+
import store from '../../../../../core/store';
+import { PanelModel } from '../../../state/PanelModel';
+import { DisplayMode } from '../types';
export const PANEL_EDITOR_UI_STATE_STORAGE_KEY = 'grafana.dashboard.editor.ui';
diff --git a/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts b/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts
index 0bab17d32f9..86f37cb761a 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/selectors.test.ts
@@ -1,9 +1,11 @@
-import { getPanelEditorTabs } from './selectors';
import { PanelPlugin } from '@grafana/data';
-import { PanelEditorTabId } from '../types';
-import { updateConfig } from '../../../../../core/config';
import { contextSrv } from 'app/core/services/context_srv';
+import { updateConfig } from '../../../../../core/config';
+import { PanelEditorTabId } from '../types';
+
+import { getPanelEditorTabs } from './selectors';
+
jest.mock('app/core/services/context_srv');
const mocks = {
diff --git a/public/app/features/dashboard/components/PanelEditor/state/selectors.ts b/public/app/features/dashboard/components/PanelEditor/state/selectors.ts
index 007945700da..7627bcbcf07 100644
--- a/public/app/features/dashboard/components/PanelEditor/state/selectors.ts
+++ b/public/app/features/dashboard/components/PanelEditor/state/selectors.ts
@@ -1,11 +1,13 @@
import memoizeOne from 'memoize-one';
+
import { PanelPlugin } from '@grafana/data';
-import { PanelEditorTab, PanelEditorTabId } from '../types';
import { getConfig } from 'app/core/config';
-import { getRulesPermissions } from 'app/features/alerting/unified/utils/access-control';
import { contextSrv } from 'app/core/services/context_srv';
+import { getRulesPermissions } from 'app/features/alerting/unified/utils/access-control';
import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource';
+import { PanelEditorTab, PanelEditorTabId } from '../types';
+
export const getPanelEditorTabs = memoizeOne((tab?: string, plugin?: PanelPlugin) => {
const tabs: PanelEditorTab[] = [];
diff --git a/public/app/features/dashboard/components/PanelEditor/types.ts b/public/app/features/dashboard/components/PanelEditor/types.ts
index 6e4b2306637..39d8f6409bd 100644
--- a/public/app/features/dashboard/components/PanelEditor/types.ts
+++ b/public/app/features/dashboard/components/PanelEditor/types.ts
@@ -1,4 +1,5 @@
import { DataFrame, FieldConfigSource, PanelData, PanelPlugin } from '@grafana/data';
+
import { DashboardModel, PanelModel } from '../../state';
export interface PanelEditorTab {
diff --git a/public/app/features/dashboard/components/PanelEditor/usePanelLatestData.ts b/public/app/features/dashboard/components/PanelEditor/usePanelLatestData.ts
index 625642f43a5..f3e2aa5f2d2 100644
--- a/public/app/features/dashboard/components/PanelEditor/usePanelLatestData.ts
+++ b/public/app/features/dashboard/components/PanelEditor/usePanelLatestData.ts
@@ -1,8 +1,10 @@
-import { DataQueryError, LoadingState, PanelData } from '@grafana/data';
import { useEffect, useRef, useState } from 'react';
-import { PanelModel } from '../../state';
import { Unsubscribable } from 'rxjs';
+
+import { DataQueryError, LoadingState, PanelData } from '@grafana/data';
+
import { GetDataOptions } from '../../../query/state/PanelQueryRunner';
+import { PanelModel } from '../../state';
interface UsePanelLatestData {
data?: PanelData;
diff --git a/public/app/features/dashboard/components/PanelEditor/utils.test.ts b/public/app/features/dashboard/components/PanelEditor/utils.test.ts
index ba19f093308..b2efaa7aa7f 100644
--- a/public/app/features/dashboard/components/PanelEditor/utils.test.ts
+++ b/public/app/features/dashboard/components/PanelEditor/utils.test.ts
@@ -1,4 +1,5 @@
import { FieldConfig, FieldConfigSource, PanelPlugin, standardFieldConfigEditorRegistry } from '@grafana/data';
+
import { setOptionImmutably, supportsDataQuery, updateDefaultFieldConfigValue } from './utils';
describe('standardFieldConfigEditorRegistry', () => {
diff --git a/public/app/features/dashboard/components/PanelEditor/utils.ts b/public/app/features/dashboard/components/PanelEditor/utils.ts
index 868476b6241..d5a3342e668 100644
--- a/public/app/features/dashboard/components/PanelEditor/utils.ts
+++ b/public/app/features/dashboard/components/PanelEditor/utils.ts
@@ -1,9 +1,12 @@
import { omit } from 'lodash';
+
import { FieldConfigSource, PanelPlugin } from '@grafana/data';
-import { PanelModel } from '../../state/PanelModel';
-import { DisplayMode } from './types';
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
+import { PanelModel } from '../../state/PanelModel';
+
+import { DisplayMode } from './types';
+
export function calculatePanelSize(mode: DisplayMode, width: number, height: number, panel: PanelModel) {
if (mode === DisplayMode.Fill) {
return { width, height };
diff --git a/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx b/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx
index 0ad229d26df..596dd425654 100644
--- a/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx
+++ b/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx
@@ -1,10 +1,11 @@
import React, { FC, useCallback, useMemo } from 'react';
import { useSelector } from 'react-redux';
-import { Select } from '@grafana/ui';
-import { SelectableValue } from '@grafana/data';
-import { getLastKey, getVariablesByKey } from '../../../variables/state/selectors';
+import { SelectableValue } from '@grafana/data';
+import { Select } from '@grafana/ui';
+
import { StoreState } from '../../../../types';
+import { getLastKey, getVariablesByKey } from '../../../variables/state/selectors';
export interface Props {
id?: string;
diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx
index 417eeb3a795..fa49740bc0e 100644
--- a/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx
+++ b/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx
@@ -1,8 +1,9 @@
import React, { FC } from 'react';
+
import { Icon, ModalsController } from '@grafana/ui';
-import { RowOptionsModal } from './RowOptionsModal';
import { OnRowOptionsUpdate } from './RowOptionsForm';
+import { RowOptionsModal } from './RowOptionsModal';
export interface RowOptionsButtonProps {
title: string;
diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx
index 1f841528a90..40b9aafaabb 100644
--- a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx
+++ b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx
@@ -1,4 +1,5 @@
import React, { FC, useCallback, useState } from 'react';
+
import { Button, Field, Form, Modal, Input } from '@grafana/ui';
import { RepeatRowSelect } from '../RepeatRowSelect/RepeatRowSelect';
diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx
index 7e0555b3744..785d10f89f2 100644
--- a/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx
+++ b/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx
@@ -1,6 +1,7 @@
-import React, { FC } from 'react';
-import { Modal, stylesFactory } from '@grafana/ui';
import { css } from '@emotion/css';
+import React, { FC } from 'react';
+
+import { Modal, stylesFactory } from '@grafana/ui';
import { OnRowOptionsUpdate, RowOptionsForm } from './RowOptionsForm';
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardAsModal.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardAsModal.tsx
index ca9c0364b7c..785ee7b45ed 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardAsModal.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardAsModal.tsx
@@ -1,10 +1,12 @@
-import React, { useState } from 'react';
import { css } from '@emotion/css';
+import React, { useState } from 'react';
+
import { Modal } from '@grafana/ui';
-import { SaveDashboardAsForm } from './forms/SaveDashboardAsForm';
+
import { SaveDashboardErrorProxy } from './SaveDashboardErrorProxy';
-import { useDashboardSave } from './useDashboardSave';
+import { SaveDashboardAsForm } from './forms/SaveDashboardAsForm';
import { SaveDashboardModalProps } from './types';
+import { useDashboardSave } from './useDashboardSave';
export const SaveDashboardAsModal: React.FC<
SaveDashboardModalProps & {
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx
index d754fe352a4..75d09010f9a 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx
@@ -1,8 +1,10 @@
import React from 'react';
+
+import { selectors } from '@grafana/e2e-selectors';
import { Button, ButtonVariant, ModalsController, FullWidthButtonContainer } from '@grafana/ui';
import { DashboardModel } from 'app/features/dashboard/state';
+
import { SaveDashboardProxy } from './SaveDashboardProxy';
-import { selectors } from '@grafana/e2e-selectors';
interface SaveDashboardButtonProps {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx
index ba26e0ba1b2..6deb43117f4 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx
@@ -1,11 +1,13 @@
-import React from 'react';
import { css } from '@emotion/css';
+import React from 'react';
+import { useAsync } from 'react-use';
+
+import { GrafanaTheme2 } from '@grafana/data';
import { Spinner, useStyles2 } from '@grafana/ui';
-import { Diffs } from '../VersionHistory/utils';
+
import { DiffGroup } from '../VersionHistory/DiffGroup';
import { DiffViewer } from '../VersionHistory/DiffViewer';
-import { GrafanaTheme2 } from '@grafana/data';
-import { useAsync } from 'react-use';
+import { Diffs } from '../VersionHistory/utils';
interface SaveDashboardDiffProps {
oldValue?: any;
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx
index 798dd6a333e..5c37e6389d6 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx
@@ -1,15 +1,18 @@
import React, { useMemo, useState } from 'react';
-import { Drawer, Tab, TabsBar } from '@grafana/ui';
-import { SaveDashboardData, SaveDashboardModalProps, SaveDashboardOptions } from './types';
-import { jsonDiff } from '../VersionHistory/utils';
import { useAsync } from 'react-use';
+
+import { Drawer, Tab, TabsBar } from '@grafana/ui';
import { backendSrv } from 'app/core/services/backend_srv';
-import { useDashboardSave } from './useDashboardSave';
-import { SaveProvisionedDashboardForm } from './forms/SaveProvisionedDashboardForm';
+
+import { jsonDiff } from '../VersionHistory/utils';
+
+import { SaveDashboardDiff } from './SaveDashboardDiff';
import { SaveDashboardErrorProxy } from './SaveDashboardErrorProxy';
import { SaveDashboardAsForm } from './forms/SaveDashboardAsForm';
import { SaveDashboardForm } from './forms/SaveDashboardForm';
-import { SaveDashboardDiff } from './SaveDashboardDiff';
+import { SaveProvisionedDashboardForm } from './forms/SaveProvisionedDashboardForm';
+import { SaveDashboardData, SaveDashboardModalProps, SaveDashboardOptions } from './types';
+import { useDashboardSave } from './useDashboardSave';
export const SaveDashboardDrawer = ({ dashboard, onDismiss, onSaveSuccess, isCopy }: SaveDashboardModalProps) => {
const [options, setOptions] = useState({});
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx
index a1c1df7425f..cde2d55f1a1 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx
@@ -1,11 +1,13 @@
-import React, { useEffect } from 'react';
-import { Button, ConfirmModal, Modal, stylesFactory, useTheme } from '@grafana/ui';
-import { GrafanaTheme } from '@grafana/data';
import { css } from '@emotion/css';
+import React, { useEffect } from 'react';
+
+import { GrafanaTheme } from '@grafana/data';
+import { Button, ConfirmModal, Modal, stylesFactory, useTheme } from '@grafana/ui';
import { DashboardModel } from 'app/features/dashboard/state';
-import { useDashboardSave } from './useDashboardSave';
-import { SaveDashboardModalProps } from './types';
+
import { SaveDashboardAsButton } from './SaveDashboardButton';
+import { SaveDashboardModalProps } from './types';
+import { useDashboardSave } from './useDashboardSave';
interface SaveDashboardErrorProxyProps {
/** original dashboard */
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardModal.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardModal.tsx
index 42d4ac53a99..231d1d5021a 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardModal.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardModal.tsx
@@ -1,10 +1,12 @@
-import React, { useMemo, useState } from 'react';
-import { Modal } from '@grafana/ui';
import { css } from '@emotion/css';
-import { SaveDashboardForm } from './forms/SaveDashboardForm';
+import React, { useMemo, useState } from 'react';
+
+import { Modal } from '@grafana/ui';
+
import { SaveDashboardErrorProxy } from './SaveDashboardErrorProxy';
-import { useDashboardSave } from './useDashboardSave';
+import { SaveDashboardForm } from './forms/SaveDashboardForm';
import { SaveDashboardModalProps, SaveDashboardOptions, SaveDashboardData } from './types';
+import { useDashboardSave } from './useDashboardSave';
export const SaveDashboardModal: React.FC = ({ dashboard, onDismiss, onSaveSuccess }) => {
const { state, onDashboardSave } = useDashboardSave(dashboard);
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardProxy.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardProxy.tsx
index ba9288672b4..50d149bfce3 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardProxy.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardProxy.tsx
@@ -1,10 +1,12 @@
import React from 'react';
-import { SaveProvisionedDashboard } from './SaveProvisionedDashboard';
-import { SaveDashboardAsModal } from './SaveDashboardAsModal';
-import { SaveDashboardModalProps } from './types';
-import { SaveDashboardModal } from './SaveDashboardModal';
+
import { config } from '@grafana/runtime';
+
+import { SaveDashboardAsModal } from './SaveDashboardAsModal';
import { SaveDashboardDrawer } from './SaveDashboardDrawer';
+import { SaveDashboardModal } from './SaveDashboardModal';
+import { SaveProvisionedDashboard } from './SaveProvisionedDashboard';
+import { SaveDashboardModalProps } from './types';
export const SaveDashboardProxy: React.FC = ({
dashboard,
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveProvisionedDashboard.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveProvisionedDashboard.tsx
index 135825fe910..cedb83c9948 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveProvisionedDashboard.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveProvisionedDashboard.tsx
@@ -1,5 +1,7 @@
import React from 'react';
+
import { Modal } from '@grafana/ui';
+
import { SaveProvisionedDashboardForm } from './forms/SaveProvisionedDashboardForm';
import { SaveDashboardModalProps } from './types';
diff --git a/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx b/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx
index fa0eaa4cf19..e7b63939af9 100644
--- a/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx
@@ -1,8 +1,11 @@
-import React from 'react';
-import { Button, Modal } from '@grafana/ui';
-import { SaveDashboardButton } from './SaveDashboardButton';
-import { DashboardModel } from '../../state';
import { css } from '@emotion/css';
+import React from 'react';
+
+import { Button, Modal } from '@grafana/ui';
+
+import { DashboardModel } from '../../state';
+
+import { SaveDashboardButton } from './SaveDashboardButton';
interface UnsavedChangesModalProps {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx
index d58801a2c68..4a36443114c 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx
@@ -1,10 +1,12 @@
-import React from 'react';
import { mount } from 'enzyme';
-import { SaveDashboardAsForm, SaveDashboardAsFormProps } from './SaveDashboardAsForm';
-import { DashboardModel } from 'app/features/dashboard/state';
+import React from 'react';
import { act } from 'react-dom/test-utils';
+
+import { DashboardModel } from 'app/features/dashboard/state';
import * as api from 'app/features/manage-dashboards/state/actions';
+import { SaveDashboardAsForm, SaveDashboardAsFormProps } from './SaveDashboardAsForm';
+
jest.mock('app/features/plugins/datasource_srv', () => ({}));
jest.mock('app/features/expressions/ExpressionDatasource', () => ({}));
jest.mock('app/features/manage-dashboards/services/ValidationSrv', () => ({
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx
index a17b651089a..b1176a0808e 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx
@@ -1,10 +1,12 @@
import React from 'react';
+
import { Button, Input, Switch, Form, Field, InputControl, HorizontalGroup } from '@grafana/ui';
-import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
-import { SaveDashboardFormProps } from '../types';
+import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
+import { SaveDashboardFormProps } from '../types';
+
interface SaveDashboardAsFormDTO {
title: string;
$folder: { id?: number; title?: string };
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx
index ff7a020d637..8a5b60159d9 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx
@@ -1,10 +1,13 @@
-import React from 'react';
import { mount } from 'enzyme';
+import React from 'react';
import { act } from 'react-dom/test-utils';
+
import { DashboardModel } from 'app/features/dashboard/state';
-import { SaveDashboardForm } from './SaveDashboardForm';
+
import { SaveDashboardOptions } from '../types';
+import { SaveDashboardForm } from './SaveDashboardForm';
+
const prepareDashboardMock = (
timeChanged: boolean,
variableValuesChanged: boolean,
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx
index 37463b0c85e..1bae42d0dab 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx
@@ -1,11 +1,11 @@
import React, { useMemo, useState } from 'react';
-import { Button, Checkbox, Form, TextArea } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors';
-
-import { DashboardModel } from 'app/features/dashboard/state';
-import { SaveDashboardData, SaveDashboardOptions } from '../types';
import { Stack } from '@grafana/experimental';
+import { Button, Checkbox, Form, TextArea } from '@grafana/ui';
+import { DashboardModel } from 'app/features/dashboard/state';
+
+import { SaveDashboardData, SaveDashboardOptions } from '../types';
interface FormDTO {
message: string;
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx
index da03cbf3ce2..8fc0075998e 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx
@@ -1,11 +1,13 @@
-import React, { useCallback, useState } from 'react';
import { css } from '@emotion/css';
import { saveAs } from 'file-saver';
-import { Button, ClipboardButton, HorizontalGroup, stylesFactory, TextArea, useTheme } from '@grafana/ui';
-import { SaveDashboardFormProps } from '../types';
+import React, { useCallback, useState } from 'react';
+
import { GrafanaTheme } from '@grafana/data';
-import { useAppNotification } from 'app/core/copy/appNotification';
import { Stack } from '@grafana/experimental';
+import { Button, ClipboardButton, HorizontalGroup, stylesFactory, TextArea, useTheme } from '@grafana/ui';
+import { useAppNotification } from 'app/core/copy/appNotification';
+
+import { SaveDashboardFormProps } from '../types';
export const SaveProvisionedDashboardForm: React.FC = ({ dashboard, onCancel }) => {
const theme = useTheme();
diff --git a/public/app/features/dashboard/components/SaveDashboard/types.ts b/public/app/features/dashboard/components/SaveDashboard/types.ts
index a8783ff6b69..e0ab7e9c8c5 100644
--- a/public/app/features/dashboard/components/SaveDashboard/types.ts
+++ b/public/app/features/dashboard/components/SaveDashboard/types.ts
@@ -1,4 +1,5 @@
import { CloneOptions, DashboardModel } from 'app/features/dashboard/state/DashboardModel';
+
import { Diffs } from '../VersionHistory/utils';
export interface SaveDashboardData {
diff --git a/public/app/features/dashboard/components/SaveDashboard/useDashboardSave.tsx b/public/app/features/dashboard/components/SaveDashboard/useDashboardSave.tsx
index d6675c9dd97..6c4237f855f 100644
--- a/public/app/features/dashboard/components/SaveDashboard/useDashboardSave.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/useDashboardSave.tsx
@@ -1,15 +1,17 @@
import { useEffect } from 'react';
import useAsyncFn from 'react-use/lib/useAsyncFn';
+
import { locationUtil } from '@grafana/data';
-import { SaveDashboardOptions } from './types';
+import { locationService, reportInteraction } from '@grafana/runtime';
import appEvents from 'app/core/app_events';
-import { contextSrv } from 'app/core/core';
import { useAppNotification } from 'app/core/copy/appNotification';
+import { contextSrv } from 'app/core/core';
import { DashboardModel } from 'app/features/dashboard/state';
import { saveDashboard as saveDashboardApiCall } from 'app/features/manage-dashboards/state/actions';
-import { locationService, reportInteraction } from '@grafana/runtime';
import { DashboardSavedEvent } from 'app/types/events';
+import { SaveDashboardOptions } from './types';
+
const saveDashboard = async (saveModel: any, options: SaveDashboardOptions, dashboard: DashboardModel) => {
let folderId = options.folderId;
if (folderId === undefined) {
diff --git a/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx b/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx
index 22d9e22ad75..ac1293a487c 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx
@@ -1,9 +1,12 @@
-import React from 'react';
-import { ShareEmbed } from './ShareEmbed';
import { render, screen } from '@testing-library/react';
+import React from 'react';
+
import config from 'app/core/config';
+
import { DashboardModel, PanelModel } from '../../state';
+import { ShareEmbed } from './ShareEmbed';
+
jest.mock('app/features/dashboard/services/TimeSrv', () => ({
getTimeSrv: () => ({
timeRange: () => {
diff --git a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx
index f1c97a727a8..1262ee2dfde 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx
@@ -1,9 +1,11 @@
import React, { FormEvent, PureComponent } from 'react';
-import { ClipboardButton, Field, Modal, RadioButtonGroup, Switch, TextArea } from '@grafana/ui';
+
import { AppEvents, SelectableValue } from '@grafana/data';
+import { ClipboardButton, Field, Modal, RadioButtonGroup, Switch, TextArea } from '@grafana/ui';
import { appEvents } from 'app/core/core';
-import { buildIframeHtml } from './utils';
+
import { ShareModalTabProps } from './types';
+import { buildIframeHtml } from './utils';
const themeOptions: Array> = [
{ label: 'Current', value: 'current' },
diff --git a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx
index c687a86f89a..934b233eda1 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx
@@ -1,12 +1,14 @@
-import React, { PureComponent } from 'react';
import { saveAs } from 'file-saver';
-import { getBackendSrv } from 'app/core/services/backend_srv';
-import { Button, Field, Modal, Switch } from '@grafana/ui';
-import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal';
-import { appEvents } from 'app/core/core';
-import { ShowModalReactEvent } from 'app/types/events';
-import { ViewJsonModal } from './ViewJsonModal';
+import React, { PureComponent } from 'react';
+
import { config } from '@grafana/runtime';
+import { Button, Field, Modal, Switch } from '@grafana/ui';
+import { appEvents } from 'app/core/core';
+import { getBackendSrv } from 'app/core/services/backend_srv';
+import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal';
+import { ShowModalReactEvent } from 'app/types/events';
+
+import { ViewJsonModal } from './ViewJsonModal';
import { ShareModalTabProps } from './types';
interface Props extends ShareModalTabProps {}
diff --git a/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx b/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx
index a9b5ace06c9..db91c703b43 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx
@@ -1,5 +1,7 @@
import React from 'react';
+
import { AddLibraryPanelContents } from 'app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal';
+
import { ShareModalTabProps } from './types';
interface Props extends ShareModalTabProps {
diff --git a/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx b/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
index b8ec81aa3d3..a8c1ac5ea84 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
@@ -1,13 +1,16 @@
-import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
+import React from 'react';
+
+import { getDefaultTimeRange } from '@grafana/data';
import { setTemplateSrv } from '@grafana/runtime';
import config from 'app/core/config';
-import { Props, ShareLink, State } from './ShareLink';
+
import { initTemplateSrv } from '../../../../../test/helpers/initTemplateSrv';
import { variableAdapters } from '../../../variables/adapters';
import { createQueryVariableAdapter } from '../../../variables/query/adapter';
import { DashboardModel, PanelModel } from '../../state';
-import { getDefaultTimeRange } from '@grafana/data';
+
+import { Props, ShareLink, State } from './ShareLink';
jest.mock('app/features/dashboard/services/TimeSrv', () => ({
getTimeSrv: () => ({
diff --git a/public/app/features/dashboard/components/ShareModal/ShareLink.tsx b/public/app/features/dashboard/components/ShareModal/ShareLink.tsx
index b14b485a0cc..0b937f4cf6b 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareLink.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareLink.tsx
@@ -1,11 +1,13 @@
import React, { PureComponent } from 'react';
+
+import { AppEvents, SelectableValue } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { Alert, ClipboardButton, Field, FieldSet, Icon, Input, RadioButtonGroup, Switch } from '@grafana/ui';
-import { AppEvents, SelectableValue } from '@grafana/data';
-import { buildImageUrl, buildShareUrl } from './utils';
-import { appEvents } from 'app/core/core';
import config from 'app/core/config';
+import { appEvents } from 'app/core/core';
+
import { ShareModalTabProps } from './types';
+import { buildImageUrl, buildShareUrl } from './utils';
const themeOptions: Array> = [
{ label: 'Current', value: 'current' },
diff --git a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx
index 984d77ce8bf..bc4945f416a 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx
@@ -1,14 +1,16 @@
import React from 'react';
+
import { Modal, ModalTabsHeader, TabContent } from '@grafana/ui';
+import { contextSrv } from 'app/core/core';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard';
+
+import { ShareEmbed } from './ShareEmbed';
+import { ShareExport } from './ShareExport';
+import { ShareLibraryPanel } from './ShareLibraryPanel';
import { ShareLink } from './ShareLink';
import { ShareSnapshot } from './ShareSnapshot';
-import { ShareExport } from './ShareExport';
-import { ShareEmbed } from './ShareEmbed';
import { ShareModalTabModel } from './types';
-import { contextSrv } from 'app/core/core';
-import { ShareLibraryPanel } from './ShareLibraryPanel';
const customDashboardTabs: ShareModalTabModel[] = [];
const customPanelTabs: ShareModalTabModel[] = [];
diff --git a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx
index 1ac5b0d4d19..91d552a0195 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx
@@ -1,11 +1,14 @@
import React, { PureComponent } from 'react';
-import { Button, ClipboardButton, Field, Icon, Input, LinkButton, Modal, Select, Spinner } from '@grafana/ui';
+
import { AppEvents, SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
-import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
-import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
+import { Button, ClipboardButton, Field, Icon, Input, LinkButton, Modal, Select, Spinner } from '@grafana/ui';
import { appEvents } from 'app/core/core';
+import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
+import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
+
import { VariableRefresh } from '../../../variables/types';
+
import { ShareModalTabProps } from './types';
const snapshotApiUrl = '/api/snapshots';
diff --git a/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx b/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx
index 272d60057e1..fc5f35cb7fe 100644
--- a/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx
@@ -1,10 +1,11 @@
import React, { useCallback } from 'react';
+import AutoSizer from 'react-virtualized-auto-sizer';
+
import { ClipboardButton, CodeEditor, Modal } from '@grafana/ui';
-import AutoSizer from 'react-virtualized-auto-sizer';
import { notifyApp } from '../../../../core/actions';
-import { dispatch } from '../../../../store/store';
import { createSuccessNotification } from '../../../../core/copy/appNotification';
+import { dispatch } from '../../../../store/store';
export interface ViewJsonModalProps {
json: string;
diff --git a/public/app/features/dashboard/components/ShareModal/types.ts b/public/app/features/dashboard/components/ShareModal/types.ts
index 42d45c9ea89..558bd0fa8a9 100644
--- a/public/app/features/dashboard/components/ShareModal/types.ts
+++ b/public/app/features/dashboard/components/ShareModal/types.ts
@@ -1,4 +1,5 @@
import React from 'react';
+
import { NavModelItem } from '@grafana/data';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
diff --git a/public/app/features/dashboard/components/ShareModal/utils.test.ts b/public/app/features/dashboard/components/ShareModal/utils.test.ts
index 5b359e1ea2a..8e2a42d553a 100644
--- a/public/app/features/dashboard/components/ShareModal/utils.test.ts
+++ b/public/app/features/dashboard/components/ShareModal/utils.test.ts
@@ -1,6 +1,7 @@
-import { buildParams } from './utils';
import { TimeRange } from '@grafana/data';
+import { buildParams } from './utils';
+
describe('buildParams', () => {
it.each`
search | useCurrentTimeRange | selectedTheme | panel | expected
diff --git a/public/app/features/dashboard/components/ShareModal/utils.ts b/public/app/features/dashboard/components/ShareModal/utils.ts
index 4667ec23ae1..fb350ce464a 100644
--- a/public/app/features/dashboard/components/ShareModal/utils.ts
+++ b/public/app/features/dashboard/components/ShareModal/utils.ts
@@ -1,7 +1,7 @@
-import { config } from '@grafana/runtime';
-import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
-import { createShortLink } from 'app/core/utils/shortLinks';
import { dateTime, locationUtil, PanelModel, TimeRange, urlUtil } from '@grafana/data';
+import { config } from '@grafana/runtime';
+import { createShortLink } from 'app/core/utils/shortLinks';
+import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
export interface BuildParamsArgs {
useCurrentTimeRange: boolean;
diff --git a/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx b/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx
index dda2461e908..ed9a0b3f38c 100644
--- a/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx
+++ b/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx
@@ -1,10 +1,12 @@
-import { AnnotationQuery, EventBus, GrafanaTheme2 } from '@grafana/data';
+import { css } from '@emotion/css';
import React, { useEffect, useState } from 'react';
-import { getDashboardQueryRunner } from '../../../query/state/DashboardQueryRunner/DashboardQueryRunner';
-import { AnnotationQueryFinished, AnnotationQueryStarted } from '../../../../types/events';
+
+import { AnnotationQuery, EventBus, GrafanaTheme2 } from '@grafana/data';
import { InlineField, InlineFieldRow, InlineSwitch, useStyles2 } from '@grafana/ui';
import { LoadingIndicator } from '@grafana/ui/src/components/PanelChrome/LoadingIndicator';
-import { css } from '@emotion/css';
+
+import { AnnotationQueryFinished, AnnotationQueryStarted } from '../../../../types/events';
+import { getDashboardQueryRunner } from '../../../query/state/DashboardQueryRunner/DashboardQueryRunner';
export interface AnnotationPickerProps {
events: EventBus;
diff --git a/public/app/features/dashboard/components/SubMenu/Annotations.tsx b/public/app/features/dashboard/components/SubMenu/Annotations.tsx
index 8f0d30afe5d..a08f235341a 100644
--- a/public/app/features/dashboard/components/SubMenu/Annotations.tsx
+++ b/public/app/features/dashboard/components/SubMenu/Annotations.tsx
@@ -1,5 +1,7 @@
import React, { FunctionComponent, useEffect, useState } from 'react';
+
import { AnnotationQuery, EventBus } from '@grafana/data';
+
import { AnnotationPicker } from './AnnotationPicker';
interface Props {
diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx
index 2cc9bd5b752..b86b66651c8 100644
--- a/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx
+++ b/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx
@@ -1,15 +1,17 @@
import React, { FC } from 'react';
-import { Icon, IconName, Tooltip, useForceUpdate } from '@grafana/ui';
-import { sanitizeUrl } from '@grafana/data/src/text/sanitize';
-import { DashboardLinksDashboard } from './DashboardLinksDashboard';
-import { getLinkSrv } from '../../../panel/panellinks/link_srv';
+import { useEffectOnce } from 'react-use';
+import { sanitizeUrl } from '@grafana/data/src/text/sanitize';
+import { selectors } from '@grafana/e2e-selectors';
+import { TimeRangeUpdatedEvent } from '@grafana/runtime';
+import { Icon, IconName, Tooltip, useForceUpdate } from '@grafana/ui';
+
+import { getLinkSrv } from '../../../panel/panellinks/link_srv';
import { DashboardModel } from '../../state';
import { DashboardLink } from '../../state/DashboardModel';
import { linkIconMap } from '../LinksSettings/LinkSettingsEdit';
-import { useEffectOnce } from 'react-use';
-import { selectors } from '@grafana/e2e-selectors';
-import { TimeRangeUpdatedEvent } from '@grafana/runtime';
+
+import { DashboardLinksDashboard } from './DashboardLinksDashboard';
export interface Props {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.test.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.test.tsx
index 23d17ef61da..8586b726640 100644
--- a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.test.tsx
+++ b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.test.tsx
@@ -1,7 +1,8 @@
-import { DashboardLink } from '../../state/DashboardModel';
-import { DashboardSearchHit, DashboardSearchItemType } from '../../../search/types';
-import { resolveLinks, searchForTags } from './DashboardLinksDashboard';
import { describe, expect } from '../../../../../test/lib/common';
+import { DashboardSearchHit, DashboardSearchItemType } from '../../../search/types';
+import { DashboardLink } from '../../state/DashboardModel';
+
+import { resolveLinks, searchForTags } from './DashboardLinksDashboard';
describe('searchForTags', () => {
const setupTestContext = () => {
diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx
index 203af35cf60..53ccd630a0b 100644
--- a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx
+++ b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx
@@ -1,13 +1,15 @@
+import { css, cx } from '@emotion/css';
import React, { useRef, useState, useLayoutEffect } from 'react';
-import { Icon, ToolbarButton, Tooltip, useStyles2 } from '@grafana/ui';
+import { useAsync } from 'react-use';
+
import { sanitize, sanitizeUrl } from '@grafana/data/src/text/sanitize';
+import { selectors } from '@grafana/e2e-selectors';
+import { Icon, ToolbarButton, Tooltip, useStyles2 } from '@grafana/ui';
import { getBackendSrv } from 'app/core/services/backend_srv';
+import { DashboardSearchHit } from 'app/features/search/types';
+
import { getLinkSrv } from '../../../panel/panellinks/link_srv';
import { DashboardLink } from '../../state/DashboardModel';
-import { DashboardSearchHit } from 'app/features/search/types';
-import { selectors } from '@grafana/e2e-selectors';
-import { useAsync } from 'react-use';
-import { css, cx } from '@emotion/css';
interface Props {
link: DashboardLink;
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
index 14839796da0..a22a3e4a280 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
@@ -1,15 +1,18 @@
+import { css } from '@emotion/css';
import React, { PureComponent } from 'react';
import { connect, MapStateToProps } from 'react-redux';
+
+import { AnnotationQuery } from '@grafana/data';
+
import { StoreState } from '../../../../types';
import { getSubMenuVariables, getVariablesState } from '../../../variables/state/selectors';
import { VariableModel } from '../../../variables/types';
import { DashboardModel } from '../../state';
-import { DashboardLinks } from './DashboardLinks';
-import { Annotations } from './Annotations';
-import { SubMenuItems } from './SubMenuItems';
import { DashboardLink } from '../../state/DashboardModel';
-import { AnnotationQuery } from '@grafana/data';
-import { css } from '@emotion/css';
+
+import { Annotations } from './Annotations';
+import { DashboardLinks } from './DashboardLinks';
+import { SubMenuItems } from './SubMenuItems';
interface OwnProps {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
index 72f15ba4db8..7bc29f1721a 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
@@ -1,7 +1,9 @@
import React, { FunctionComponent, useEffect, useState } from 'react';
-import { VariableHide, VariableModel } from '../../../variables/types';
+
import { selectors } from '@grafana/e2e-selectors';
+
import { PickerRenderer } from '../../../variables/pickers/PickerRenderer';
+import { VariableHide, VariableModel } from '../../../variables/types';
interface Props {
variables: VariableModel[];
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx
index 64b626a5a1b..f1d99bd708c 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx
@@ -1,7 +1,7 @@
+import { css } from '@emotion/css';
import React, { useEffect, useMemo, useState } from 'react';
import { mergeMap } from 'rxjs/operators';
-import { css } from '@emotion/css';
-import { Icon, JSONFormatter, useStyles } from '@grafana/ui';
+
import {
DataFrame,
DataTransformerConfig,
@@ -10,6 +10,7 @@ import {
TransformerRegistryItem,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { Icon, JSONFormatter, useStyles } from '@grafana/ui';
import { TransformationsEditorTransformation } from './types';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
index c2d82b330d7..71eeb0200e1 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
@@ -1,17 +1,18 @@
import React, { useCallback } from 'react';
+import { useToggle } from 'react-use';
+
import { DataFrame, DataTransformerConfig, TransformerRegistryItem } from '@grafana/data';
import { HorizontalGroup } from '@grafana/ui';
-
-import { TransformationEditor } from './TransformationEditor';
+import { OperationRowHelp } from 'app/core/components/QueryOperationRow/OperationRowHelp';
+import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction';
import {
QueryOperationRow,
QueryOperationRowRenderProps,
} from 'app/core/components/QueryOperationRow/QueryOperationRow';
-import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction';
-import { TransformationsEditorTransformation } from './types';
import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
-import { useToggle } from 'react-use';
-import { OperationRowHelp } from 'app/core/components/QueryOperationRow/OperationRowHelp';
+
+import { TransformationEditor } from './TransformationEditor';
+import { TransformationsEditorTransformation } from './types';
interface TransformationOperationRowProps {
id: string;
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx
index 6477e0ee920..c9849c755d5 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+
import { DataFrame, DataTransformerConfig, standardTransformersRegistry } from '@grafana/data';
import { TransformationOperationRow } from './TransformationOperationRow';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx
index da6ff1462fd..83586953eb1 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx
@@ -1,11 +1,14 @@
-import React from 'react';
-import { DataTransformerConfig, standardTransformersRegistry } from '@grafana/data';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { TransformationsEditor } from './TransformationsEditor';
-import { PanelModel } from '../../state';
-import { getStandardTransformers } from 'app/features/transformers/standardTransformers';
+import React from 'react';
+
+import { DataTransformerConfig, standardTransformersRegistry } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { getStandardTransformers } from 'app/features/transformers/standardTransformers';
+
+import { PanelModel } from '../../state';
+
+import { TransformationsEditor } from './TransformationsEditor';
const setup = (transformations: DataTransformerConfig[] = []) => {
const panel = new PanelModel({});
@@ -33,13 +36,13 @@ describe('TransformationsEditor', () => {
options: {},
},
]);
- const editors = screen.getAllByLabelText(/^Transformation editor/g);
+ const editors = screen.getAllByLabelText(/^Transformation editor/);
expect(editors).toHaveLength(1);
});
});
describe('when Add transformation clicked', () => {
- it('renders transformations picker', () => {
+ it('renders transformations picker', async () => {
const buttonLabel = 'Add transformation';
setup([
{
@@ -49,7 +52,7 @@ describe('TransformationsEditor', () => {
]);
const addTransformationButton = screen.getByText(buttonLabel);
- userEvent.click(addTransformationButton);
+ await userEvent.click(addTransformationButton);
const search = screen.getByLabelText(selectors.components.Transforms.searchInput);
expect(search).toBeDefined();
@@ -58,7 +61,7 @@ describe('TransformationsEditor', () => {
describe('actions', () => {
describe('debug', () => {
- it('should show/hide debugger', () => {
+ it('should show/hide debugger', async () => {
setup([
{
id: 'reduce',
@@ -70,7 +73,7 @@ describe('TransformationsEditor', () => {
expect(screen.queryByLabelText(debuggerSelector)).toBeNull();
const debugButton = screen.getByLabelText(selectors.components.QueryEditorRow.actionButton('Debug'));
- userEvent.click(debugButton);
+ await userEvent.click(debugButton);
expect(screen.getByLabelText(debuggerSelector)).toBeInTheDocument();
});
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
index 5450522ce61..8e9c99230ed 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
@@ -1,4 +1,19 @@
+import { css } from '@emotion/css';
import React, { ChangeEvent } from 'react';
+import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
+import { Unsubscribable } from 'rxjs';
+
+import {
+ DataFrame,
+ DataTransformerConfig,
+ DocsId,
+ GrafanaTheme2,
+ PanelData,
+ SelectableValue,
+ standardTransformersRegistry,
+ TransformerRegistryItem,
+} from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
import {
Alert,
Button,
@@ -12,28 +27,16 @@ import {
useStyles2,
Card,
} from '@grafana/ui';
-import {
- DataFrame,
- DataTransformerConfig,
- DocsId,
- GrafanaTheme2,
- PanelData,
- SelectableValue,
- standardTransformersRegistry,
- TransformerRegistryItem,
-} from '@grafana/data';
-import { css } from '@emotion/css';
-import { selectors } from '@grafana/e2e-selectors';
-import { Unsubscribable } from 'rxjs';
-import { PanelModel } from '../../state';
+import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
import { getDocsLink } from 'app/core/utils/docsLinks';
-import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
+import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
+
+import { AppNotificationSeverity } from '../../../../types';
+import { PanelModel } from '../../state';
+import { PanelNotSupported } from '../PanelEditor/PanelNotSupported';
+
import { TransformationOperationRows } from './TransformationOperationRows';
import { TransformationsEditorTransformation } from './types';
-import { PanelNotSupported } from '../PanelEditor/PanelNotSupported';
-import { AppNotificationSeverity } from '../../../../types';
-import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
-import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
const LOCAL_STORAGE_KEY = 'dashboard.components.TransformationEditor.featureInfoBox.isDismissed';
diff --git a/public/app/features/dashboard/components/VersionHistory/DiffGroup.tsx b/public/app/features/dashboard/components/VersionHistory/DiffGroup.tsx
index cfe61de8e7f..487d43c8d37 100644
--- a/public/app/features/dashboard/components/VersionHistory/DiffGroup.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/DiffGroup.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
-import { last } from 'lodash';
-import { useStyles } from '@grafana/ui';
-import { GrafanaTheme } from '@grafana/data';
import { css } from '@emotion/css';
+import { last } from 'lodash';
+import React from 'react';
+
+import { GrafanaTheme } from '@grafana/data';
+import { useStyles } from '@grafana/ui';
+
import { DiffTitle } from './DiffTitle';
import { DiffValues } from './DiffValues';
import { Diff, getDiffText } from './utils';
diff --git a/public/app/features/dashboard/components/VersionHistory/DiffTitle.tsx b/public/app/features/dashboard/components/VersionHistory/DiffTitle.tsx
index 1637b4b76b0..e62157343d9 100644
--- a/public/app/features/dashboard/components/VersionHistory/DiffTitle.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/DiffTitle.tsx
@@ -1,9 +1,11 @@
-import React from 'react';
-import { useStyles, Icon } from '@grafana/ui';
-import { GrafanaTheme } from '@grafana/data';
import { css } from '@emotion/css';
-import { Diff, getDiffText } from './utils';
+import React from 'react';
+
+import { GrafanaTheme } from '@grafana/data';
+import { useStyles, Icon } from '@grafana/ui';
+
import { DiffValues } from './DiffValues';
+import { Diff, getDiffText } from './utils';
type DiffTitleProps = {
diff?: Diff;
diff --git a/public/app/features/dashboard/components/VersionHistory/DiffValues.tsx b/public/app/features/dashboard/components/VersionHistory/DiffValues.tsx
index f7e901213f9..c59207bf466 100644
--- a/public/app/features/dashboard/components/VersionHistory/DiffValues.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/DiffValues.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
-import { isArray, isObject, isUndefined } from 'lodash';
-import { useStyles2, Icon } from '@grafana/ui';
-import { GrafanaTheme2 } from '@grafana/data';
import { css } from '@emotion/css';
+import { isArray, isObject, isUndefined } from 'lodash';
+import React from 'react';
+
+import { GrafanaTheme2 } from '@grafana/data';
+import { useStyles2, Icon } from '@grafana/ui';
+
import { Diff } from './utils';
type DiffProps = {
diff --git a/public/app/features/dashboard/components/VersionHistory/DiffViewer.tsx b/public/app/features/dashboard/components/VersionHistory/DiffViewer.tsx
index fcf0cfc7ca4..52490961500 100644
--- a/public/app/features/dashboard/components/VersionHistory/DiffViewer.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/DiffViewer.tsx
@@ -1,9 +1,10 @@
-import React from 'react';
import { css } from '@emotion/css';
+import React from 'react';
import ReactDiffViewer, { ReactDiffViewerProps, DiffMethod } from 'react-diff-viewer';
-import { useTheme } from '@grafana/ui';
import tinycolor from 'tinycolor2';
+import { useTheme } from '@grafana/ui';
+
export const DiffViewer: React.FC = ({ oldValue, newValue }) => {
const theme = useTheme();
diff --git a/public/app/features/dashboard/components/VersionHistory/HistorySrv.test.ts b/public/app/features/dashboard/components/VersionHistory/HistorySrv.test.ts
index fd36f7b2a37..8502085fad7 100644
--- a/public/app/features/dashboard/components/VersionHistory/HistorySrv.test.ts
+++ b/public/app/features/dashboard/components/VersionHistory/HistorySrv.test.ts
@@ -1,7 +1,8 @@
-import { restore, versions } from './__mocks__/dashboardHistoryMocks';
-import { HistorySrv } from './HistorySrv';
import { DashboardModel } from '../../state/DashboardModel';
+import { HistorySrv } from './HistorySrv';
+import { restore, versions } from './__mocks__/dashboardHistoryMocks';
+
const getMock = jest.fn().mockResolvedValue({});
const postMock = jest.fn().mockResolvedValue({});
diff --git a/public/app/features/dashboard/components/VersionHistory/HistorySrv.ts b/public/app/features/dashboard/components/VersionHistory/HistorySrv.ts
index 5bcd302ffac..0c9db504b01 100644
--- a/public/app/features/dashboard/components/VersionHistory/HistorySrv.ts
+++ b/public/app/features/dashboard/components/VersionHistory/HistorySrv.ts
@@ -1,7 +1,9 @@
import { isNumber } from 'lodash';
-import { DashboardModel } from '../../state/DashboardModel';
+
import { getBackendSrv } from '@grafana/runtime';
+import { DashboardModel } from '../../state/DashboardModel';
+
export interface HistoryListOpts {
limit: number;
start: number;
diff --git a/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx b/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx
index f4f2641d5e0..0420131e03a 100644
--- a/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx
@@ -1,5 +1,7 @@
import React, { useEffect } from 'react';
+
import { ConfirmModal } from '@grafana/ui';
+
import { useDashboardRestore } from './useDashboardRestore';
export interface RevertDashboardModalProps {
hideModal: () => void;
diff --git a/public/app/features/dashboard/components/VersionHistory/VersionHistoryButtons.tsx b/public/app/features/dashboard/components/VersionHistory/VersionHistoryButtons.tsx
index b720d72822b..c8d0d1ad083 100644
--- a/public/app/features/dashboard/components/VersionHistory/VersionHistoryButtons.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/VersionHistoryButtons.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+
import { HorizontalGroup, Tooltip, Button } from '@grafana/ui';
type VersionsButtonsType = {
diff --git a/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx b/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx
index e132b20a647..8af4e929f90 100644
--- a/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx
@@ -1,13 +1,15 @@
-import React from 'react';
import { css, cx } from '@emotion/css';
+import React from 'react';
+import { GrafanaTheme } from '@grafana/data';
import { Button, ModalsController, CollapsableSection, HorizontalGroup, useStyles } from '@grafana/ui';
+
import { DecoratedRevisionModel } from '../DashboardSettings/VersionsSettings';
-import { RevertDashboardModal } from './RevertDashboardModal';
+
import { DiffGroup } from './DiffGroup';
import { DiffViewer } from './DiffViewer';
+import { RevertDashboardModal } from './RevertDashboardModal';
import { jsonDiff } from './utils';
-import { GrafanaTheme } from '@grafana/data';
type DiffViewProps = {
isNewLatest: boolean;
diff --git a/public/app/features/dashboard/components/VersionHistory/VersionHistoryHeader.tsx b/public/app/features/dashboard/components/VersionHistory/VersionHistoryHeader.tsx
index 8ad1cd2ccee..c1109172d62 100644
--- a/public/app/features/dashboard/components/VersionHistory/VersionHistoryHeader.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/VersionHistoryHeader.tsx
@@ -1,6 +1,7 @@
-import React from 'react';
import { css } from '@emotion/css';
import { noop } from 'lodash';
+import React from 'react';
+
import { GrafanaTheme } from '@grafana/data';
import { Icon, useStyles } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx b/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx
index c0b12528f3c..b1809b4502e 100644
--- a/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx
@@ -1,7 +1,10 @@
-import React from 'react';
import { css } from '@emotion/css';
+import React from 'react';
+
import { Checkbox, Button, Tag, ModalsController } from '@grafana/ui';
+
import { DecoratedRevisionModel } from '../DashboardSettings/VersionsSettings';
+
import { RevertDashboardModal } from './RevertDashboardModal';
type VersionsTableProps = {
diff --git a/public/app/features/dashboard/components/VersionHistory/useDashboardRestore.tsx b/public/app/features/dashboard/components/VersionHistory/useDashboardRestore.tsx
index f2422cc850d..b54c2d017fb 100644
--- a/public/app/features/dashboard/components/VersionHistory/useDashboardRestore.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/useDashboardRestore.tsx
@@ -1,12 +1,15 @@
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
import { useAsyncFn } from 'react-use';
+
import { locationUtil } from '@grafana/data';
-import { StoreState } from 'app/types';
-import { useAppNotification } from 'app/core/copy/appNotification';
-import { historySrv } from './HistorySrv';
-import { DashboardModel } from '../../state';
import { locationService } from '@grafana/runtime';
+import { useAppNotification } from 'app/core/copy/appNotification';
+import { StoreState } from 'app/types';
+
+import { DashboardModel } from '../../state';
+
+import { historySrv } from './HistorySrv';
const restoreDashboard = async (version: number, dashboard: DashboardModel) => {
return await historySrv.restoreDashboard(dashboard, version);
diff --git a/public/app/features/dashboard/containers/DashboardPage.test.tsx b/public/app/features/dashboard/containers/DashboardPage.test.tsx
index 4c68581de51..c81a9980224 100644
--- a/public/app/features/dashboard/containers/DashboardPage.test.tsx
+++ b/public/app/features/dashboard/containers/DashboardPage.test.tsx
@@ -1,23 +1,30 @@
+import { render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
-import { render, screen } from '@testing-library/react';
-import { Props, UnthemedDashboardPage } from './DashboardPage';
-import { Props as LazyLoaderProps } from '../dashgrid/LazyLoader';
import { Router } from 'react-router-dom';
-import { locationService, setDataSourceSrv } from '@grafana/runtime';
-import { DashboardModel } from '../state';
-import { configureStore } from '../../../store/configureStore';
-import { mockToolkitActionCreator } from 'test/core/redux/mocks';
-import { DashboardInitPhase, DashboardRoutes } from 'app/types';
-import { notifyApp } from 'app/core/actions';
-import { selectors } from '@grafana/e2e-selectors';
-import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
-import { createTheme } from '@grafana/data';
+import { useEffectOnce } from 'react-use';
import { AutoSizerProps } from 'react-virtualized-auto-sizer';
+import { mockToolkitActionCreator } from 'test/core/redux/mocks';
+
+import { createTheme } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
+import { locationService, setDataSourceSrv } from '@grafana/runtime';
+import { notifyApp } from 'app/core/actions';
+import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
+import { DashboardInitPhase, DashboardRoutes } from 'app/types';
+
+import { configureStore } from '../../../store/configureStore';
+import { Props as LazyLoaderProps } from '../dashgrid/LazyLoader';
import { setDashboardSrv } from '../services/DashboardSrv';
+import { DashboardModel } from '../state';
+
+import { Props, UnthemedDashboardPage } from './DashboardPage';
jest.mock('app/features/dashboard/dashgrid/LazyLoader', () => {
- const LazyLoader = ({ children }: Pick) => {
+ const LazyLoader = ({ children, onLoad }: Pick) => {
+ useEffectOnce(() => {
+ onLoad?.();
+ });
return <>{typeof children === 'function' ? children({ isInView: true }) : children}>;
};
return { LazyLoader };
diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx
index c73c0c6fb16..32904dd6042 100644
--- a/public/app/features/dashboard/containers/DashboardPage.tsx
+++ b/public/app/features/dashboard/containers/DashboardPage.tsx
@@ -1,35 +1,37 @@
-import React, { PureComponent } from 'react';
import { css } from '@emotion/css';
+import classnames from 'classnames';
+import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
-import { locationService } from '@grafana/runtime';
+
+import { GrafanaTheme2, TimeRange } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { locationService } from '@grafana/runtime';
import { CustomScrollbar, stylesFactory, Themeable2, withTheme2 } from '@grafana/ui';
-import { createErrorNotification } from 'app/core/copy/appNotification';
-import { Branding } from 'app/core/components/Branding/Branding';
-import { DashboardGrid } from '../dashgrid/DashboardGrid';
-import { DashNav } from '../components/DashNav';
-import { DashboardSettings } from '../components/DashboardSettings';
-import { PanelEditor } from '../components/PanelEditor/PanelEditor';
-import { initDashboard } from '../state/initDashboard';
import { notifyApp } from 'app/core/actions';
-import { KioskMode, StoreState } from 'app/types';
+import { Branding } from 'app/core/components/Branding/Branding';
+import { createErrorNotification } from 'app/core/copy/appNotification';
+import { getKioskMode } from 'app/core/navigation/kiosk';
+import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { PanelModel } from 'app/features/dashboard/state';
-import { PanelInspector } from '../components/Inspector/PanelInspector';
-import { SubMenu } from '../components/SubMenu/SubMenu';
-import { cleanUpDashboardAndVariables } from '../state/actions';
+import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
+import { KioskMode, StoreState } from 'app/types';
+import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events';
+
import { cancelVariables, templateVarsChangedInUrl } from '../../variables/state/actions';
import { findTemplateVarChanges } from '../../variables/utils';
-import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
-import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
-import { getTimeSrv } from '../services/TimeSrv';
-import { getKioskMode } from 'app/core/navigation/kiosk';
-import { GrafanaTheme2, TimeRange } from '@grafana/data';
-import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
+import { DashNav } from '../components/DashNav';
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
+import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
import { DashboardPrompt } from '../components/DashboardPrompt/DashboardPrompt';
-import classnames from 'classnames';
-import { PanelEditEnteredEvent, PanelEditExitedEvent } from 'app/types/events';
+import { DashboardSettings } from '../components/DashboardSettings';
+import { PanelInspector } from '../components/Inspector/PanelInspector';
+import { PanelEditor } from '../components/PanelEditor/PanelEditor';
+import { SubMenu } from '../components/SubMenu/SubMenu';
+import { DashboardGrid } from '../dashgrid/DashboardGrid';
import { liveTimer } from '../dashgrid/liveTimer';
+import { getTimeSrv } from '../services/TimeSrv';
+import { cleanUpDashboardAndVariables } from '../state/actions';
+import { initDashboard } from '../state/initDashboard';
export interface DashboardPageRouteParams {
uid?: string;
diff --git a/public/app/features/dashboard/containers/SoloPanelPage.test.tsx b/public/app/features/dashboard/containers/SoloPanelPage.test.tsx
index 9ae03c233cb..c292c978f37 100644
--- a/public/app/features/dashboard/containers/SoloPanelPage.test.tsx
+++ b/public/app/features/dashboard/containers/SoloPanelPage.test.tsx
@@ -1,10 +1,13 @@
-import React from 'react';
import { render, screen } from '@testing-library/react';
-import { Props, SoloPanelPage } from './SoloPanelPage';
+import React from 'react';
+
+import { DashboardRoutes } from 'app/types';
+
+import { getRouteComponentProps } from '../../../core/navigation/__mocks__/routeProps';
import { Props as DashboardPanelProps } from '../dashgrid/DashboardPanel';
import { DashboardModel } from '../state';
-import { DashboardRoutes } from 'app/types';
-import { getRouteComponentProps } from '../../../core/navigation/__mocks__/routeProps';
+
+import { Props, SoloPanelPage } from './SoloPanelPage';
jest.mock('app/features/dashboard/components/DashboardSettings/GeneralSettings', () => ({}));
jest.mock('app/features/dashboard/dashgrid/DashboardPanel', () => {
diff --git a/public/app/features/dashboard/containers/SoloPanelPage.tsx b/public/app/features/dashboard/containers/SoloPanelPage.tsx
index b03acf813bd..2d7360f2cdb 100644
--- a/public/app/features/dashboard/containers/SoloPanelPage.tsx
+++ b/public/app/features/dashboard/containers/SoloPanelPage.tsx
@@ -1,11 +1,13 @@
import React, { Component } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
+
+import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
+import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
+import { StoreState } from 'app/types';
+
import { DashboardPanel } from '../dashgrid/DashboardPanel';
import { initDashboard } from '../state/initDashboard';
-import { StoreState } from 'app/types';
-import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
-import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
export interface DashboardPageRouteParams {
uid?: string;
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
index e12caba291c..95963ad97d5 100644
--- a/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
import { shallow, ShallowWrapper } from 'enzyme';
-import { DashboardGridUnconnected as DashboardGrid, Props } from './DashboardGrid';
+import React from 'react';
+
import { DashboardModel } from '../state';
+import { DashboardGridUnconnected as DashboardGrid, Props } from './DashboardGrid';
+
jest.mock('app/features/dashboard/dashgrid/LazyLoader', () => {
const LazyLoader: React.FC = ({ children }) => {
return <>{children}>;
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
index 29d6578dc9a..e5d8e613f20 100644
--- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
@@ -1,23 +1,21 @@
-// Libraries
+import classNames from 'classnames';
import React, { PureComponent, CSSProperties } from 'react';
import ReactGridLayout, { ItemCallback } from 'react-grid-layout';
-import classNames from 'classnames';
+import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
+import { Subscription } from 'rxjs';
+
+import { config } from '@grafana/runtime';
+import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
+import { cleanAndRemoveMany } from 'app/features/panel/state/actions';
+import { DashboardPanelsChangedEvent } from 'app/types/events';
-// Components
import { AddPanelWidget } from '../components/AddPanelWidget';
import { DashboardRow } from '../components/DashboardRow';
-
-// Types
-import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
-import { DashboardPanel } from './DashboardPanel';
import { DashboardModel, PanelModel } from '../state';
-import { Subscription } from 'rxjs';
-import { connect, ConnectedProps } from 'react-redux';
-import { DashboardPanelsChangedEvent } from 'app/types/events';
-import { cleanAndRemoveMany } from 'app/features/panel/state/actions';
import { GridPos } from '../state/PanelModel';
-import { config } from '@grafana/runtime';
+
+import { DashboardPanel } from './DashboardPanel';
export interface OwnProps {
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
index 0401ecf9397..773e6de1709 100644
--- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
@@ -1,13 +1,15 @@
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
+
+import { StoreState } from 'app/types';
+
+import { initPanelState } from '../../panel/state/actions';
+import { setPanelInstanceState } from '../../panel/state/reducers';
+import { DashboardModel, PanelModel } from '../state';
+
+import { LazyLoader } from './LazyLoader';
import { PanelChrome } from './PanelChrome';
import { PanelChromeAngular } from './PanelChromeAngular';
-import { DashboardModel, PanelModel } from '../state';
-import { StoreState } from 'app/types';
-import { PanelPlugin } from '@grafana/data';
-import { setPanelInstanceState } from '../../panel/state/reducers';
-import { initPanelState } from '../../panel/state/actions';
-import { LazyLoader } from './LazyLoader';
export interface OwnProps {
panel: PanelModel;
@@ -48,8 +50,8 @@ export class DashboardPanelUnconnected extends PureComponent {
componentDidMount() {
this.props.panel.isInView = !this.props.lazy;
- if (!this.props.plugin) {
- this.props.initPanelState(this.props.panel);
+ if (!this.props.lazy) {
+ this.onPanelLoad();
}
}
@@ -61,11 +63,18 @@ export class DashboardPanelUnconnected extends PureComponent {
this.props.panel.isInView = v;
};
- renderPanel(plugin: PanelPlugin) {
- const { dashboard, panel, isViewing, isEditing, width, height, lazy } = this.props;
+ onPanelLoad = () => {
+ if (!this.props.plugin) {
+ this.props.initPanelState(this.props.panel);
+ }
+ };
+
+ render() {
+ const { dashboard, panel, isViewing, isEditing, width, height, lazy, plugin } = this.props;
const renderPanelChrome = (isInView: boolean) =>
- plugin.angularPanelCtrl ? (
+ plugin &&
+ (plugin.angularPanelCtrl ? (
{
height={height}
onInstanceStateChange={this.onInstanceStateChange}
/>
- );
+ ));
return lazy ? (
-
+
{({ isInView }) => renderPanelChrome(isInView)}
) : (
renderPanelChrome(true)
);
}
-
- render() {
- const { plugin } = this.props;
-
- // If we have not loaded plugin exports yet, wait
- if (!plugin) {
- return null;
- }
-
- return this.renderPanel(plugin);
- }
}
export const DashboardPanel = connector(DashboardPanelUnconnected);
diff --git a/public/app/features/dashboard/dashgrid/LazyLoader.tsx b/public/app/features/dashboard/dashgrid/LazyLoader.tsx
index 30f9034a125..da9339e5459 100644
--- a/public/app/features/dashboard/dashgrid/LazyLoader.tsx
+++ b/public/app/features/dashboard/dashgrid/LazyLoader.tsx
@@ -1,7 +1,8 @@
import React, { useRef, useState } from 'react';
-import { useUniqueId } from 'app/plugins/datasource/influxdb/components/useUniqueId';
import { useEffectOnce } from 'react-use';
+import { useUniqueId } from 'app/plugins/datasource/influxdb/components/useUniqueId';
+
export interface Props {
children: React.ReactNode | (({ isInView }: { isInView: boolean }) => React.ReactNode);
width?: number;
diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx
index 148c3628c8a..a883596bac4 100644
--- a/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx
@@ -1,14 +1,16 @@
+import { act, render, screen } from '@testing-library/react';
import React, { FC } from 'react';
-import { ReplaySubject } from 'rxjs';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
-import { act, render, screen } from '@testing-library/react';
+import { ReplaySubject } from 'rxjs';
+
import { EventBusSrv, getDefaultTimeRange, LoadingState, PanelData, PanelPlugin, PanelProps } from '@grafana/data';
-import { PanelChrome, Props } from './PanelChrome';
-import { DashboardModel, PanelModel } from '../state';
import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
import { setTimeSrv, TimeSrv } from '../services/TimeSrv';
+import { DashboardModel, PanelModel } from '../state';
+
+import { PanelChrome, Props } from './PanelChrome';
jest.mock('app/core/profiler', () => ({
profiler: {
diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx
index 890c6c86075..7ace1ab35fa 100644
--- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx
@@ -1,7 +1,7 @@
-import React, { PureComponent } from 'react';
import classNames from 'classnames';
+import React, { PureComponent } from 'react';
import { Subscription } from 'rxjs';
-import { locationService, RefreshEvent } from '@grafana/runtime';
+
import {
AbsoluteTimeRange,
AnnotationChangeEvent,
@@ -19,26 +19,28 @@ import {
toDataFrameDTO,
toUtc,
} from '@grafana/data';
-import { ErrorBoundary, PanelContext, PanelContextProvider, SeriesVisibilityChangeMode } from '@grafana/ui';
-import { VizLegendOptions } from '@grafana/schema';
import { selectors } from '@grafana/e2e-selectors';
-
-import { PanelHeader } from './PanelHeader/PanelHeader';
-import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
-import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
-import { profiler } from 'app/core/profiler';
+import { locationService, RefreshEvent } from '@grafana/runtime';
+import { VizLegendOptions } from '@grafana/schema';
+import { ErrorBoundary, PanelContext, PanelContextProvider, SeriesVisibilityChangeMode } from '@grafana/ui';
import config from 'app/core/config';
-import { DashboardModel, PanelModel } from '../state';
import { PANEL_BORDER } from 'app/core/constants';
-import { loadSnapshotData } from '../utils/loadSnapshotData';
-import { RenderEvent } from 'app/types/events';
+import { profiler } from 'app/core/profiler';
+import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
import { changeSeriesColorConfigFactory } from 'app/plugins/panel/timeseries/overrides/colorSeriesConfigFactory';
-import { seriesVisibilityConfigFactory } from './SeriesVisibilityConfigFactory';
+import { RenderEvent } from 'app/types/events';
+
+import { contextSrv } from '../../../core/services/context_srv';
+import { isSoloRoute } from '../../../routes/utils';
import { deleteAnnotation, saveAnnotation, updateAnnotation } from '../../annotations/api';
import { getDashboardQueryRunner } from '../../query/state/DashboardQueryRunner/DashboardQueryRunner';
+import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
+import { DashboardModel, PanelModel } from '../state';
+import { loadSnapshotData } from '../utils/loadSnapshotData';
+
+import { PanelHeader } from './PanelHeader/PanelHeader';
+import { seriesVisibilityConfigFactory } from './SeriesVisibilityConfigFactory';
import { liveTimer } from './liveTimer';
-import { isSoloRoute } from '../../../routes/utils';
-import { contextSrv } from '../../../core/services/context_srv';
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
diff --git a/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx b/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
index 3d82607222b..7f967d603b1 100644
--- a/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
@@ -1,20 +1,22 @@
-import React, { PureComponent } from 'react';
import classNames from 'classnames';
-import { Subscription } from 'rxjs';
+import React, { PureComponent } from 'react';
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
-import { AngularComponent, getAngularLoader, locationService } from '@grafana/runtime';
+import { Subscription } from 'rxjs';
+
import { getDefaultTimeRange, LoadingState, PanelData, PanelPlugin } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { AngularComponent, getAngularLoader, locationService } from '@grafana/runtime';
+import config from 'app/core/config';
+import { PANEL_BORDER } from 'app/core/constants';
+import { setPanelAngularComponent } from 'app/features/panel/state/reducers';
+import { getPanelStateForModel } from 'app/features/panel/state/selectors';
+import { StoreState } from 'app/types';
+
+import { isSoloRoute } from '../../../routes/utils';
+import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
+import { DashboardModel, PanelModel } from '../state';
import { PanelHeader } from './PanelHeader/PanelHeader';
-import { getTimeSrv, TimeSrv } from '../services/TimeSrv';
-import { setPanelAngularComponent } from 'app/features/panel/state/reducers';
-import config from 'app/core/config';
-import { DashboardModel, PanelModel } from '../state';
-import { StoreState } from 'app/types';
-import { PANEL_BORDER } from 'app/core/constants';
-import { isSoloRoute } from '../../../routes/utils';
-import { getPanelStateForModel } from 'app/features/panel/state/selectors';
interface OwnProps {
panel: PanelModel;
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx
index a5f020a89a6..36c377f0d37 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx
@@ -1,17 +1,18 @@
-import React, { FC } from 'react';
import { css, cx } from '@emotion/css';
-import { DataLink, GrafanaTheme2, PanelData } from '@grafana/data';
-import { Icon, useStyles2 } from '@grafana/ui';
-import { selectors } from '@grafana/e2e-selectors';
+import React, { FC } from 'react';
-import PanelHeaderCorner from './PanelHeaderCorner';
+import { DataLink, GrafanaTheme2, PanelData } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
+import { Icon, useStyles2 } from '@grafana/ui';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { getPanelLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers';
-import { PanelHeaderNotices } from './PanelHeaderNotices';
-import { PanelHeaderMenuTrigger } from './PanelHeaderMenuTrigger';
+
+import PanelHeaderCorner from './PanelHeaderCorner';
import { PanelHeaderLoadingIndicator } from './PanelHeaderLoadingIndicator';
+import { PanelHeaderMenuTrigger } from './PanelHeaderMenuTrigger';
import { PanelHeaderMenuWrapper } from './PanelHeaderMenuWrapper';
+import { PanelHeaderNotices } from './PanelHeaderNotices';
export interface Props {
panel: PanelModel;
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.test.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.test.tsx
index 9d2095e2572..20a88cff82d 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.test.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.test.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
import { shallow } from 'enzyme';
-import { PanelHeaderCorner } from './PanelHeaderCorner';
+import React from 'react';
+
import { PanelModel } from '../../state';
+import { PanelHeaderCorner } from './PanelHeaderCorner';
+
describe('Render', () => {
it('should render component', () => {
const panel = new PanelModel({});
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx
index 0448a550a08..09b5b83cfd1 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx
@@ -1,13 +1,12 @@
import React, { Component } from 'react';
import { renderMarkdown, LinkModelSupplier, ScopedVars } from '@grafana/data';
-import { Tooltip, PopoverContent } from '@grafana/ui';
-import { locationService, getTemplateSrv } from '@grafana/runtime';
-
-import { PanelModel } from 'app/features/dashboard/state/PanelModel';
-import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
-import { InspectTab } from 'app/features/inspector/types';
import { selectors } from '@grafana/e2e-selectors';
+import { locationService, getTemplateSrv } from '@grafana/runtime';
+import { Tooltip, PopoverContent } from '@grafana/ui';
+import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
+import { PanelModel } from 'app/features/dashboard/state/PanelModel';
+import { InspectTab } from 'app/features/inspector/types';
enum InfoMode {
Error = 'Error',
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderLoadingIndicator.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderLoadingIndicator.tsx
index fb1d42a596a..14151ba1417 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderLoadingIndicator.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderLoadingIndicator.tsx
@@ -1,5 +1,6 @@
-import React, { FC } from 'react';
import { css } from '@emotion/css';
+import React, { FC } from 'react';
+
import { GrafanaTheme, LoadingState } from '@grafana/data';
import { Icon, Tooltip, useStyles } from '@grafana/ui';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx
index c180359922a..af37c1b6dbc 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx
@@ -1,7 +1,9 @@
import React, { PureComponent } from 'react';
-import { PanelHeaderMenuItem } from './PanelHeaderMenuItem';
+
import { PanelMenuItem } from '@grafana/data';
+import { PanelHeaderMenuItem } from './PanelHeaderMenuItem';
+
export interface Props {
items: PanelMenuItem[];
}
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx
index ab1a5395583..2e25ccab6e9 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuItem.tsx
@@ -1,8 +1,9 @@
-import React, { FC, useState } from 'react';
import { css } from '@emotion/css';
+import React, { FC, useState } from 'react';
+
import { PanelMenuItem } from '@grafana/data';
-import { Icon, IconName, useTheme } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors';
+import { Icon, IconName, useTheme } from '@grafana/ui';
interface Props {
children?: any;
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuProvider.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuProvider.tsx
index b3b2afe1ab2..54088922bf1 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuProvider.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuProvider.tsx
@@ -1,12 +1,13 @@
import { FC, ReactElement, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
-import { PanelMenuItem } from '@grafana/data';
-import { DashboardModel, PanelModel } from '../../state';
-import { StoreState } from '../../../../types';
-import { getPanelMenu } from '../../utils/getPanelMenu';
+import { PanelMenuItem } from '@grafana/data';
import { getPanelStateForModel } from 'app/features/panel/state/selectors';
+import { StoreState } from '../../../../types';
+import { DashboardModel, PanelModel } from '../../state';
+import { getPanelMenu } from '../../utils/getPanelMenu';
+
interface PanelHeaderMenuProviderApi {
items: PanelMenuItem[];
}
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuTrigger.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuTrigger.tsx
index 509dd0e0c1e..174c07a2d49 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuTrigger.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuTrigger.tsx
@@ -1,4 +1,5 @@
import React, { FC, HTMLAttributes, MouseEvent, ReactElement, useCallback, useState } from 'react';
+
import { CartesianCoords2D } from '@grafana/data';
interface PanelHeaderMenuTriggerApi {
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx
index 596dc96fa65..40d69a5efe7 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx
@@ -1,9 +1,12 @@
import React, { FC } from 'react';
+
import { ClickOutsideWrapper } from '@grafana/ui';
-import { PanelHeaderMenuProvider } from './PanelHeaderMenuProvider';
-import { PanelHeaderMenu } from './PanelHeaderMenu';
+
import { DashboardModel, PanelModel } from '../../state';
+import { PanelHeaderMenu } from './PanelHeaderMenu';
+import { PanelHeaderMenuProvider } from './PanelHeaderMenuProvider';
+
interface Props {
panel: PanelModel;
dashboard: DashboardModel;
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx
index 16e9670523a..18e13ca1ccc 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx
@@ -1,4 +1,5 @@
import React, { FC } from 'react';
+
import { QueryResultMetaNotice } from '@grafana/data';
import { Icon, Tooltip } from '@grafana/ui';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx
index 4e70fdad7e9..76b98043de7 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx
@@ -1,8 +1,10 @@
import React, { FC, useCallback } from 'react';
+
import { DataFrame, QueryResultMetaNotice } from '@grafana/data';
-import { PanelHeaderNotice } from './PanelHeaderNotice';
import { locationService } from '@grafana/runtime';
+import { PanelHeaderNotice } from './PanelHeaderNotice';
+
interface Props {
panelId: number;
frames: DataFrame[];
diff --git a/public/app/features/dashboard/dashgrid/PanelResizer.tsx b/public/app/features/dashboard/dashgrid/PanelResizer.tsx
index 3bd191300ff..f7dd6757dac 100644
--- a/public/app/features/dashboard/dashgrid/PanelResizer.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelResizer.tsx
@@ -1,5 +1,5 @@
-import React, { PureComponent } from 'react';
import { throttle } from 'lodash';
+import React, { PureComponent } from 'react';
import Draggable, { DraggableEventHandler } from 'react-draggable';
import { PanelModel } from '../state/PanelModel';
diff --git a/public/app/features/dashboard/dashgrid/liveTimer.ts b/public/app/features/dashboard/dashgrid/liveTimer.ts
index 0631c3ca4db..65b37811ea3 100644
--- a/public/app/features/dashboard/dashgrid/liveTimer.ts
+++ b/public/app/features/dashboard/dashgrid/liveTimer.ts
@@ -1,5 +1,7 @@
-import { dateMath, dateTime, TimeRange } from '@grafana/data';
import { BehaviorSubject } from 'rxjs';
+
+import { dateMath, dateTime, TimeRange } from '@grafana/data';
+
import { PanelChrome } from './PanelChrome';
// target is 20hz (50ms), but we poll at 100ms to smooth out jitter
diff --git a/public/app/features/dashboard/services/DashboardLoaderSrv.ts b/public/app/features/dashboard/services/DashboardLoaderSrv.ts
index dc06ab6e1d2..68a4ec18e6f 100644
--- a/public/app/features/dashboard/services/DashboardLoaderSrv.ts
+++ b/public/app/features/dashboard/services/DashboardLoaderSrv.ts
@@ -1,16 +1,18 @@
-import moment from 'moment'; // eslint-disable-line no-restricted-imports
-// eslint-disable-next-line lodash/import-scope
-import _, { isFunction } from 'lodash';
import $ from 'jquery';
-import kbn from 'app/core/utils/kbn';
+import _, { isFunction } from 'lodash'; // eslint-disable-line lodash/import-scope
+import moment from 'moment'; // eslint-disable-line no-restricted-imports
+
import { AppEvents, dateMath, UrlQueryValue } from '@grafana/data';
-import impressionSrv from 'app/core/services/impression_srv';
-import { backendSrv } from 'app/core/services/backend_srv';
-import { getDashboardSrv } from './DashboardSrv';
-import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { getBackendSrv, locationService } from '@grafana/runtime';
+import { backendSrv } from 'app/core/services/backend_srv';
+import impressionSrv from 'app/core/services/impression_srv';
+import kbn from 'app/core/utils/kbn';
+import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
+
import { appEvents } from '../../../core/core';
+import { getDashboardSrv } from './DashboardSrv';
+
export class DashboardLoaderSrv {
constructor() {}
_dashboardLoadFailed(title: string, snapshot?: boolean) {
diff --git a/public/app/features/dashboard/services/DashboardSrv.ts b/public/app/features/dashboard/services/DashboardSrv.ts
index 7fa5084d850..0a0ae013172 100644
--- a/public/app/features/dashboard/services/DashboardSrv.ts
+++ b/public/app/features/dashboard/services/DashboardSrv.ts
@@ -1,12 +1,14 @@
+import { lastValueFrom } from 'rxjs';
+
+import { BackendSrvRequest } from '@grafana/runtime';
import { appEvents } from 'app/core/app_events';
-import { DashboardModel } from '../state/DashboardModel';
-import { removePanel } from '../utils/panel';
-import { DashboardMeta } from 'app/types';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { saveDashboard } from 'app/features/manage-dashboards/state/actions';
+import { DashboardMeta } from 'app/types';
+
import { RemovePanelEvent } from '../../../types/events';
-import { BackendSrvRequest } from '@grafana/runtime';
-import { lastValueFrom } from 'rxjs';
+import { DashboardModel } from '../state/DashboardModel';
+import { removePanel } from '../utils/panel';
export interface SaveDashboardOptions {
/** The complete dashboard model. If `dashboard.id` is not set a new dashboard will be created. */
diff --git a/public/app/features/dashboard/services/TimeSrv.test.ts b/public/app/features/dashboard/services/TimeSrv.test.ts
index 90220dd63c1..26124b7b299 100644
--- a/public/app/features/dashboard/services/TimeSrv.test.ts
+++ b/public/app/features/dashboard/services/TimeSrv.test.ts
@@ -1,10 +1,13 @@
-import { TimeSrv } from './TimeSrv';
-import { ContextSrvStub } from 'test/specs/helpers';
-import { dateTime, isDateTime } from '@grafana/data';
import * as H from 'history';
+import { ContextSrvStub } from 'test/specs/helpers';
+
+import { dateTime, isDateTime } from '@grafana/data';
import { HistoryWrapper, locationService, setLocationService } from '@grafana/runtime';
+
import { beforeEach } from '../../../../test/lib/common';
+import { TimeSrv } from './TimeSrv';
+
jest.mock('app/core/core', () => ({
appEvents: {
subscribe: () => {},
diff --git a/public/app/features/dashboard/services/TimeSrv.ts b/public/app/features/dashboard/services/TimeSrv.ts
index 490f480ce55..7966a83387b 100644
--- a/public/app/features/dashboard/services/TimeSrv.ts
+++ b/public/app/features/dashboard/services/TimeSrv.ts
@@ -1,4 +1,5 @@
import { cloneDeep, extend, isString } from 'lodash';
+
import {
dateMath,
dateTime,
@@ -9,14 +10,15 @@ import {
TimeRange,
toUtc,
} from '@grafana/data';
-import { getShiftedTimeRange, getZoomedTimeRange } from 'app/core/utils/timePicker';
-import { config } from 'app/core/config';
-import { getRefreshFromUrl } from '../utils/getRefreshFromUrl';
import { locationService } from '@grafana/runtime';
-import { AbsoluteTimeEvent, ShiftTimeEvent, ShiftTimeEventDirection, ZoomOutEvent } from '../../../types/events';
-import { contextSrv, ContextSrv } from 'app/core/services/context_srv';
import appEvents from 'app/core/app_events';
+import { config } from 'app/core/config';
+import { contextSrv, ContextSrv } from 'app/core/services/context_srv';
+import { getShiftedTimeRange, getZoomedTimeRange } from 'app/core/utils/timePicker';
+
+import { AbsoluteTimeEvent, ShiftTimeEvent, ShiftTimeEventDirection, ZoomOutEvent } from '../../../types/events';
import { TimeModel } from '../state/TimeModel';
+import { getRefreshFromUrl } from '../utils/getRefreshFromUrl';
export class TimeSrv {
time: any;
diff --git a/public/app/features/dashboard/state/DashboardMigrator.test.ts b/public/app/features/dashboard/state/DashboardMigrator.test.ts
index 201ba1ce202..b53a4088208 100644
--- a/public/app/features/dashboard/state/DashboardMigrator.test.ts
+++ b/public/app/features/dashboard/state/DashboardMigrator.test.ts
@@ -1,15 +1,17 @@
import { each, map } from 'lodash';
+import { expect } from 'test/lib/common';
+
+import { DataLinkBuiltInVars, MappingType } from '@grafana/data';
+import { setDataSourceSrv } from '@grafana/runtime';
+import { config } from 'app/core/config';
+import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants';
+import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified/mocks';
+import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
+import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
+
+import { VariableHide } from '../../variables/types';
import { DashboardModel } from '../state/DashboardModel';
import { PanelModel } from '../state/PanelModel';
-import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants';
-import { expect } from 'test/lib/common';
-import { DataLinkBuiltInVars, MappingType } from '@grafana/data';
-import { VariableHide } from '../../variables/types';
-import { config } from 'app/core/config';
-import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
-import { setDataSourceSrv } from '@grafana/runtime';
-import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified/mocks';
-import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
jest.mock('app/core/services/context_srv', () => ({}));
diff --git a/public/app/features/dashboard/state/DashboardMigrator.ts b/public/app/features/dashboard/state/DashboardMigrator.ts
index 7ee735ff5d4..f9e5be516c0 100644
--- a/public/app/features/dashboard/state/DashboardMigrator.ts
+++ b/public/app/features/dashboard/state/DashboardMigrator.ts
@@ -1,11 +1,5 @@
-// Libraries
import { each, find, findIndex, flattenDeep, isArray, isBoolean, isNumber, isString, map, max, some } from 'lodash';
-// Utils
-import getFactors from 'app/core/utils/factors';
-import kbn from 'app/core/utils/kbn';
-// Types
-import { PanelModel } from './PanelModel';
-import { DashboardModel } from './DashboardModel';
+
import {
AnnotationQuery,
DataLink,
@@ -29,7 +23,10 @@ import {
ValueMap,
ValueMapping,
} from '@grafana/data';
-// Constants
+import { getDataSourceSrv, setDataSourceSrv } from '@grafana/runtime';
+import { AxisPlacement, GraphFieldConfig } from '@grafana/ui';
+import { getAllOptionEditors, getAllStandardFieldConfigs } from 'app/core/components/editors/registry';
+import { config } from 'app/core/config';
import {
DEFAULT_PANEL_SPAN,
DEFAULT_ROW_HEIGHT,
@@ -38,24 +35,26 @@ import {
GRID_COLUMN_COUNT,
MIN_PANEL_HEIGHT,
} from 'app/core/constants';
+import getFactors from 'app/core/utils/factors';
+import kbn from 'app/core/utils/kbn';
+import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
import { isConstant, isMulti } from 'app/features/variables/guard';
import { alignCurrentWithMulti } from 'app/features/variables/shared/multiOptions';
-import { VariableHide } from '../../variables/types';
-import { config } from 'app/core/config';
-import { plugin as statPanelPlugin } from 'app/plugins/panel/stat/module';
-import { plugin as gaugePanelPlugin } from 'app/plugins/panel/gauge/module';
-import { AxisPlacement, GraphFieldConfig } from '@grafana/ui';
-import { getDataSourceSrv, setDataSourceSrv } from '@grafana/runtime';
-import { labelsToFieldsTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/labelsToFields';
-import { mergeTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/merge';
import {
migrateCloudWatchQuery,
migrateMultipleStatsAnnotationQuery,
migrateMultipleStatsMetricsQuery,
} from 'app/plugins/datasource/cloudwatch/migrations';
import { CloudWatchAnnotationQuery, CloudWatchMetricsQuery } from 'app/plugins/datasource/cloudwatch/types';
-import { getAllOptionEditors, getAllStandardFieldConfigs } from 'app/core/components/editors/registry';
-import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
+import { plugin as gaugePanelPlugin } from 'app/plugins/panel/gauge/module';
+import { plugin as statPanelPlugin } from 'app/plugins/panel/stat/module';
+
+import { labelsToFieldsTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/labelsToFields';
+import { mergeTransformer } from '../../../../../packages/grafana-data/src/transformations/transformers/merge';
+import { VariableHide } from '../../variables/types';
+
+import { DashboardModel } from './DashboardModel';
+import { PanelModel } from './PanelModel';
standardEditorsRegistry.setInit(getAllOptionEditors);
standardFieldConfigEditorRegistry.setInit(getAllStandardFieldConfigs);
diff --git a/public/app/features/dashboard/state/DashboardModel.refresh.test.ts b/public/app/features/dashboard/state/DashboardModel.refresh.test.ts
index 338540becdc..8eed7928506 100644
--- a/public/app/features/dashboard/state/DashboardModel.refresh.test.ts
+++ b/public/app/features/dashboard/state/DashboardModel.refresh.test.ts
@@ -1,9 +1,10 @@
-import { DashboardModel } from './DashboardModel';
+import { afterEach, beforeEach } from '../../../../test/lib/common';
import { appEvents } from '../../../core/core';
import { VariablesChanged } from '../../variables/types';
-import { PanelModel } from './PanelModel';
import { getTimeSrv, setTimeSrv } from '../services/TimeSrv';
-import { afterEach, beforeEach } from '../../../../test/lib/common';
+
+import { DashboardModel } from './DashboardModel';
+import { PanelModel } from './PanelModel';
function getTestContext({
usePanelInEdit,
diff --git a/public/app/features/dashboard/state/DashboardModel.repeat.test.ts b/public/app/features/dashboard/state/DashboardModel.repeat.test.ts
index e393b98d8eb..b333eb878a4 100644
--- a/public/app/features/dashboard/state/DashboardModel.repeat.test.ts
+++ b/public/app/features/dashboard/state/DashboardModel.repeat.test.ts
@@ -1,10 +1,13 @@
import { compact, flattenDeep, map, uniq } from 'lodash';
-import { DashboardModel } from '../state/DashboardModel';
import { expect } from 'test/lib/common';
-import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
-import { PanelModel } from './PanelModel';
+
import { DashboardPanelsChangedEvent } from 'app/types/events';
+import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
+import { DashboardModel } from '../state/DashboardModel';
+
+import { PanelModel } from './PanelModel';
+
jest.mock('app/core/services/context_srv', () => ({}));
describe('given dashboard with panel repeat', () => {
diff --git a/public/app/features/dashboard/state/DashboardModel.test.ts b/public/app/features/dashboard/state/DashboardModel.test.ts
index 764cccd8fcd..f5d494a780c 100644
--- a/public/app/features/dashboard/state/DashboardModel.test.ts
+++ b/public/app/features/dashboard/state/DashboardModel.test.ts
@@ -1,13 +1,14 @@
import { keys as _keys } from 'lodash';
-import { DashboardModel } from '../state/DashboardModel';
-import { PanelModel } from '../state/PanelModel';
+
import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
+import { expect } from '../../../../test/lib/common';
import { variableAdapters } from '../../variables/adapters';
import { createAdHocVariableAdapter } from '../../variables/adhoc/adapter';
-import { createQueryVariableAdapter } from '../../variables/query/adapter';
import { createCustomVariableAdapter } from '../../variables/custom/adapter';
-import { expect } from '../../../../test/lib/common';
+import { createQueryVariableAdapter } from '../../variables/query/adapter';
import { setTimeSrv, TimeSrv } from '../services/TimeSrv';
+import { DashboardModel } from '../state/DashboardModel';
+import { PanelModel } from '../state/PanelModel';
jest.mock('app/core/services/context_srv', () => ({}));
diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts
index 874127c04d0..1c99bb5a33a 100644
--- a/public/app/features/dashboard/state/DashboardModel.ts
+++ b/public/app/features/dashboard/state/DashboardModel.ts
@@ -1,4 +1,3 @@
-// Libaries
import {
cloneDeep,
defaults as _defaults,
@@ -13,15 +12,8 @@ import {
pull,
some,
} from 'lodash';
-// Constants
-import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui';
-import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, REPEAT_DIR_VERTICAL } from 'app/core/constants';
-// Utils & Services
-import { contextSrv } from 'app/core/services/context_srv';
-// Types
-import { GridPos, PanelModel } from './PanelModel';
-import { TimeModel } from './TimeModel';
-import { DashboardMigrator } from './DashboardMigrator';
+import { Subscription } from 'rxjs';
+
import {
AnnotationQuery,
AppEvent,
@@ -37,26 +29,33 @@ import {
TimeZone,
UrlQueryValue,
} from '@grafana/data';
-import { CoreEvents, DashboardMeta, KioskMode } from 'app/types';
-import { GetVariables, getVariablesByKey } from 'app/features/variables/state/selectors';
+import { RefreshEvent, TimeRangeUpdatedEvent } from '@grafana/runtime';
+import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui';
+import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, REPEAT_DIR_VERTICAL } from 'app/core/constants';
+import { contextSrv } from 'app/core/services/context_srv';
+import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object';
import { variableAdapters } from 'app/features/variables/adapters';
import { onTimeRangeUpdated } from 'app/features/variables/state/actions';
-import { dispatch } from '../../../store/store';
-import { isAllVariable } from '../../variables/utils';
+import { GetVariables, getVariablesByKey } from 'app/features/variables/state/selectors';
+import { CoreEvents, DashboardMeta, KioskMode } from 'app/types';
import { DashboardPanelsChangedEvent, RenderEvent } from 'app/types/events';
-import { getTimeSrv } from '../services/TimeSrv';
-import { mergePanels, PanelMergeInfo } from '../utils/panelMerge';
-import { deleteScopeVars, isOnTheSameGridRow } from './utils';
-import { RefreshEvent, TimeRangeUpdatedEvent } from '@grafana/runtime';
-import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object';
-import { Subscription } from 'rxjs';
+
import { appEvents } from '../../../core/core';
+import { dispatch } from '../../../store/store';
import {
VariablesChanged,
VariablesChangedEvent,
VariablesChangedInUrl,
VariablesTimeRangeProcessDone,
} from '../../variables/types';
+import { isAllVariable } from '../../variables/utils';
+import { getTimeSrv } from '../services/TimeSrv';
+import { mergePanels, PanelMergeInfo } from '../utils/panelMerge';
+
+import { DashboardMigrator } from './DashboardMigrator';
+import { GridPos, PanelModel } from './PanelModel';
+import { TimeModel } from './TimeModel';
+import { deleteScopeVars, isOnTheSameGridRow } from './utils';
export interface CloneOptions {
saveVariables?: boolean;
@@ -1198,7 +1197,7 @@ export class DashboardModel implements TimeModel {
canEditAnnotations(dashboardId: number) {
let canEdit = true;
- // if FGAC is enabled there are additional conditions to check
+ // if RBAC is enabled there are additional conditions to check
if (contextSrv.accessControlEnabled()) {
if (dashboardId === 0) {
canEdit = !!this.meta.annotationsPermissions?.organization.canEdit;
@@ -1212,7 +1211,7 @@ export class DashboardModel implements TimeModel {
canAddAnnotations() {
let canAdd = true;
- // if FGAC is enabled there are additional conditions to check
+ // if RBAC is enabled there are additional conditions to check
if (contextSrv.accessControlEnabled()) {
canAdd = !!this.meta.annotationsPermissions?.dashboard.canAdd;
}
diff --git a/public/app/features/dashboard/state/PanelModel.test.ts b/public/app/features/dashboard/state/PanelModel.test.ts
index 1af302c5538..df5459411aa 100644
--- a/public/app/features/dashboard/state/PanelModel.test.ts
+++ b/public/app/features/dashboard/state/PanelModel.test.ts
@@ -1,5 +1,5 @@
-import { PanelModel } from './PanelModel';
-import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
+import { ComponentClass } from 'react';
+
import {
DataLinkBuiltInVars,
FieldConfigProperty,
@@ -10,17 +10,20 @@ import {
dateTime,
TimeRange,
} from '@grafana/data';
-import { ComponentClass } from 'react';
-import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
-import { setTimeSrv } from '../services/TimeSrv';
-import { TemplateSrv } from '../../templating/template_srv';
import { setTemplateSrv } from '@grafana/runtime';
+import { queryBuilder } from 'app/features/variables/shared/testing/builders';
+
+import { mockStandardFieldConfigOptions } from '../../../../test/helpers/fieldConfig';
+import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
+import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
+import { TemplateSrv } from '../../templating/template_srv';
import { variableAdapters } from '../../variables/adapters';
import { createQueryVariableAdapter } from '../../variables/query/adapter';
-import { mockStandardFieldConfigOptions } from '../../../../test/helpers/fieldConfig';
-import { queryBuilder } from 'app/features/variables/shared/testing/builders';
+import { setTimeSrv } from '../services/TimeSrv';
import { TimeOverrideResult } from '../utils/panel';
+import { PanelModel } from './PanelModel';
+
standardFieldConfigEditorRegistry.setInit(() => mockStandardFieldConfigOptions());
standardEditorsRegistry.setInit(() => mockStandardFieldConfigOptions());
diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts
index 115c7ed8502..81723a24d62 100644
--- a/public/app/features/dashboard/state/PanelModel.ts
+++ b/public/app/features/dashboard/state/PanelModel.ts
@@ -1,10 +1,6 @@
-// Libraries
import { cloneDeep, defaultsDeep, isArray, isEqual, keys } from 'lodash';
import { v4 as uuidv4 } from 'uuid';
-// Utils
-import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
-import { getNextRefIdChar } from 'app/core/utils/query';
-// Types
+
import {
DataConfigSource,
DataFrameDTO,
@@ -21,24 +17,29 @@ import {
PanelModel as IPanelModel,
DataSourceRef,
} from '@grafana/data';
+import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
import config from 'app/core/config';
-import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
+import { getNextRefIdChar } from 'app/core/utils/query';
+import { QueryGroupOptions } from 'app/types';
import {
PanelOptionsChangedEvent,
PanelQueriesChangedEvent,
PanelTransformationsChangedEvent,
RenderEvent,
} from 'app/types/events';
-import { getTimeSrv } from '../services/TimeSrv';
+
+import { PanelModelLibraryPanel } from '../../library-panels/types';
+import { PanelQueryRunner } from '../../query/state/PanelQueryRunner';
import { getVariablesUrlParams } from '../../variables/getAllVariableValuesForUrl';
+import { getTimeSrv } from '../services/TimeSrv';
+import { TimeOverrideResult } from '../utils/panel';
+
import {
filterFieldConfigOverrides,
getPanelOptionsWithDefaults,
isStandardFieldProp,
restoreCustomOverrideRules,
} from './getPanelOptionsWithDefaults';
-import { QueryGroupOptions } from 'app/types';
-import { PanelModelLibraryPanel } from '../../library-panels/types';
export interface GridPos {
x: number;
@@ -48,8 +49,6 @@ export interface GridPos {
static?: boolean;
}
-import { TimeOverrideResult } from '../utils/panel';
-
const notPersistedProperties: { [str: string]: boolean } = {
events: true,
isViewing: true,
diff --git a/public/app/features/dashboard/state/actions.ts b/public/app/features/dashboard/state/actions.ts
index e6c070c2c1b..d31b6e168cc 100644
--- a/public/app/features/dashboard/state/actions.ts
+++ b/public/app/features/dashboard/state/actions.ts
@@ -1,16 +1,15 @@
-// Services & Utils
+import { TimeZone } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
-import { createSuccessNotification } from 'app/core/copy/appNotification';
-// Actions
-import { loadPluginDashboards } from '../../plugins/admin/state/actions';
-import { cleanUpDashboard, loadDashboardPermissions } from './reducers';
import { notifyApp } from 'app/core/actions';
+import { createSuccessNotification } from 'app/core/copy/appNotification';
import { updateTimeZoneForSession, updateWeekStartForSession } from 'app/features/profile/state/reducers';
-// Types
import { DashboardAcl, DashboardAclUpdateDTO, NewDashboardAclItem, PermissionLevel, ThunkResult } from 'app/types';
+
+import { loadPluginDashboards } from '../../plugins/admin/state/actions';
import { cancelVariables } from '../../variables/state/actions';
import { getTimeSrv } from '../services/TimeSrv';
-import { TimeZone } from '@grafana/data';
+
+import { cleanUpDashboard, loadDashboardPermissions } from './reducers';
export function getDashboardPermissions(id: number): ThunkResult {
return async (dispatch) => {
diff --git a/public/app/features/dashboard/state/analyticsProcessor.ts b/public/app/features/dashboard/state/analyticsProcessor.ts
index 9834d86f149..258cf71ee45 100644
--- a/public/app/features/dashboard/state/analyticsProcessor.ts
+++ b/public/app/features/dashboard/state/analyticsProcessor.ts
@@ -1,6 +1,7 @@
-import { DashboardModel } from './DashboardModel';
import { reportMetaAnalytics, MetaAnalyticsEventName, DashboardViewEventPayload } from '@grafana/runtime';
+import { DashboardModel } from './DashboardModel';
+
export function emitDashboardViewEvent(dashboard: DashboardModel) {
const eventData: DashboardViewEventPayload = {
dashboardId: dashboard.id,
diff --git a/public/app/features/dashboard/state/getPanelOptionsWithDefaults.test.ts b/public/app/features/dashboard/state/getPanelOptionsWithDefaults.test.ts
index 6b61bdcaf60..a56c2669238 100644
--- a/public/app/features/dashboard/state/getPanelOptionsWithDefaults.test.ts
+++ b/public/app/features/dashboard/state/getPanelOptionsWithDefaults.test.ts
@@ -1,3 +1,5 @@
+import { mockStandardFieldConfigOptions } from 'test/helpers/fieldConfig';
+
import {
ConfigOverrideRule,
FieldColorModeId,
@@ -11,7 +13,7 @@ import {
ThresholdsMode,
} from '@grafana/data';
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
-import { mockStandardFieldConfigOptions } from 'test/helpers/fieldConfig';
+
import { getPanelOptionsWithDefaults, restoreCustomOverrideRules } from './getPanelOptionsWithDefaults';
standardFieldConfigEditorRegistry.setInit(() => mockStandardFieldConfigOptions());
diff --git a/public/app/features/dashboard/state/getPanelOptionsWithDefaults.ts b/public/app/features/dashboard/state/getPanelOptionsWithDefaults.ts
index 2eb30b6d951..fadb6071164 100644
--- a/public/app/features/dashboard/state/getPanelOptionsWithDefaults.ts
+++ b/public/app/features/dashboard/state/getPanelOptionsWithDefaults.ts
@@ -1,3 +1,5 @@
+import { mergeWith, isArray, isObject, unset, isEqual } from 'lodash';
+
import {
ConfigOverrideRule,
DynamicConfigValue,
@@ -11,7 +13,6 @@ import {
ThresholdsConfig,
ThresholdsMode,
} from '@grafana/data';
-import { mergeWith, isArray, isObject, unset, isEqual } from 'lodash';
export interface Props {
plugin: PanelPlugin;
diff --git a/public/app/features/dashboard/state/initDashboard.test.ts b/public/app/features/dashboard/state/initDashboard.test.ts
index 0bcb74ef8d2..eae72482c81 100644
--- a/public/app/features/dashboard/state/initDashboard.test.ts
+++ b/public/app/features/dashboard/state/initDashboard.test.ts
@@ -1,28 +1,30 @@
-import { Subject } from 'rxjs';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
-import { locationService, setEchoSrv } from '@grafana/runtime';
+import { Subject } from 'rxjs';
-import { initDashboard, InitDashboardArgs } from './initDashboard';
-import { DashboardInitPhase, DashboardRoutes } from 'app/types';
+import { locationService, setEchoSrv } from '@grafana/runtime';
import { getBackendSrv } from 'app/core/services/backend_srv';
-import { dashboardInitCompleted, dashboardInitFetching, dashboardInitServices } from './reducers';
-import { Echo } from '../../../core/services/echo/Echo';
+import { keybindingSrv } from 'app/core/services/keybindingSrv';
import { variableAdapters } from 'app/features/variables/adapters';
import { createConstantVariableAdapter } from 'app/features/variables/constant/adapter';
import { constantBuilder } from 'app/features/variables/shared/testing/builders';
-import { initialTransactionState, variablesInitTransaction } from '../../variables/state/transactionReducer';
-import { keybindingSrv } from 'app/core/services/keybindingSrv';
-import { getTimeSrv, setTimeSrv } from '../services/TimeSrv';
-import { DashboardLoaderSrv, setDashboardLoaderSrv } from '../services/DashboardLoaderSrv';
-import { getDashboardSrv, setDashboardSrv } from '../services/DashboardSrv';
+import { DashboardInitPhase, DashboardRoutes } from 'app/types';
+
+import { Echo } from '../../../core/services/echo/Echo';
import {
getDashboardQueryRunner,
setDashboardQueryRunnerFactory,
} from '../../query/state/DashboardQueryRunner/DashboardQueryRunner';
import { emptyResult } from '../../query/state/DashboardQueryRunner/utils';
-import { TransactionStatus } from '../../variables/types';
import { getPreloadedState } from '../../variables/state/helpers';
+import { initialTransactionState, variablesInitTransaction } from '../../variables/state/transactionReducer';
+import { TransactionStatus } from '../../variables/types';
+import { DashboardLoaderSrv, setDashboardLoaderSrv } from '../services/DashboardLoaderSrv';
+import { getDashboardSrv, setDashboardSrv } from '../services/DashboardSrv';
+import { getTimeSrv, setTimeSrv } from '../services/TimeSrv';
+
+import { initDashboard, InitDashboardArgs } from './initDashboard';
+import { dashboardInitCompleted, dashboardInitFetching, dashboardInitServices } from './reducers';
jest.mock('app/core/services/backend_srv');
jest.mock('app/features/dashboard/services/TimeSrv', () => {
diff --git a/public/app/features/dashboard/state/initDashboard.ts b/public/app/features/dashboard/state/initDashboard.ts
index 654bf8cdab1..c49b5f95628 100644
--- a/public/app/features/dashboard/state/initDashboard.ts
+++ b/public/app/features/dashboard/state/initDashboard.ts
@@ -1,25 +1,24 @@
-// Services & Utils
+import { locationUtil, setWeekStart } from '@grafana/data';
+import { config, locationService } from '@grafana/runtime';
+import { notifyApp } from 'app/core/actions';
import { createErrorNotification } from 'app/core/copy/appNotification';
import { backendSrv } from 'app/core/services/backend_srv';
-import { DashboardSrv, getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
-import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
-import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { keybindingSrv } from 'app/core/services/keybindingSrv';
-// Actions
-import { notifyApp } from 'app/core/actions';
-import { dashboardInitCompleted, dashboardInitFailed, dashboardInitFetching, dashboardInitServices } from './reducers';
-// Types
-import { DashboardDTO, DashboardInitPhase, DashboardRoutes, StoreState, ThunkDispatch, ThunkResult } from 'app/types';
-import { DashboardModel } from './DashboardModel';
-import { locationUtil, setWeekStart } from '@grafana/data';
-import { initVariablesTransaction } from '../../variables/state/actions';
-import { emitDashboardViewEvent } from './analyticsProcessor';
-import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
-import { config, locationService } from '@grafana/runtime';
-import { createDashboardQueryRunner } from '../../query/state/DashboardQueryRunner/DashboardQueryRunner';
-import { getIfExistsLastKey } from '../../variables/state/selectors';
-import { toStateKey } from 'app/features/variables/utils';
import store from 'app/core/store';
+import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
+import { DashboardSrv, getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
+import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
+import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
+import { toStateKey } from 'app/features/variables/utils';
+import { DashboardDTO, DashboardInitPhase, DashboardRoutes, StoreState, ThunkDispatch, ThunkResult } from 'app/types';
+
+import { createDashboardQueryRunner } from '../../query/state/DashboardQueryRunner/DashboardQueryRunner';
+import { initVariablesTransaction } from '../../variables/state/actions';
+import { getIfExistsLastKey } from '../../variables/state/selectors';
+
+import { DashboardModel } from './DashboardModel';
+import { emitDashboardViewEvent } from './analyticsProcessor';
+import { dashboardInitCompleted, dashboardInitFailed, dashboardInitFetching, dashboardInitServices } from './reducers';
export interface InitDashboardArgs {
urlUid?: string;
diff --git a/public/app/features/dashboard/state/reducers.test.ts b/public/app/features/dashboard/state/reducers.test.ts
index f98a4fa6dec..ab2fa4a8c9e 100644
--- a/public/app/features/dashboard/state/reducers.test.ts
+++ b/public/app/features/dashboard/state/reducers.test.ts
@@ -1,3 +1,6 @@
+import { DashboardInitPhase, DashboardState, OrgRole, PermissionLevel } from 'app/types';
+
+import { DashboardModel } from './DashboardModel';
import {
dashboardInitCompleted,
dashboardInitFailed,
@@ -6,8 +9,6 @@ import {
dashboardReducer,
initialState,
} from './reducers';
-import { DashboardInitPhase, DashboardState, OrgRole, PermissionLevel } from 'app/types';
-import { DashboardModel } from './DashboardModel';
describe('dashboard reducer', () => {
describe('loadDashboardPermissions', () => {
diff --git a/public/app/features/dashboard/state/reducers.ts b/public/app/features/dashboard/state/reducers.ts
index 59cc5eadad2..4e57923e7c4 100644
--- a/public/app/features/dashboard/state/reducers.ts
+++ b/public/app/features/dashboard/state/reducers.ts
@@ -1,10 +1,12 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { DashboardAclDTO, DashboardInitError, DashboardInitPhase, DashboardState } from 'app/types';
+
+import { PanelPlugin } from '@grafana/data';
import { AngularComponent } from '@grafana/runtime';
import { processAclItems } from 'app/core/utils/acl';
+import { DashboardAclDTO, DashboardInitError, DashboardInitPhase, DashboardState } from 'app/types';
+
import { DashboardModel } from './DashboardModel';
import { PanelModel } from './PanelModel';
-import { PanelPlugin } from '@grafana/data';
export const initialState: DashboardState = {
initPhase: DashboardInitPhase.NotStarted,
diff --git a/public/app/features/dashboard/state/selectors.ts b/public/app/features/dashboard/state/selectors.ts
index b0bf7529bbe..59d486d3a73 100644
--- a/public/app/features/dashboard/state/selectors.ts
+++ b/public/app/features/dashboard/state/selectors.ts
@@ -1,5 +1,6 @@
-import { StoreState } from 'app/types';
import { PanelPlugin } from '@grafana/data';
+import { StoreState } from 'app/types';
+
import { getPanelPluginNotFound } from '../../panel/components/PanelPluginError';
export const getPanelPluginWithFallback =
diff --git a/public/app/features/dashboard/state/utils.test.ts b/public/app/features/dashboard/state/utils.test.ts
index fcaee378186..5c63afdf2ee 100644
--- a/public/app/features/dashboard/state/utils.test.ts
+++ b/public/app/features/dashboard/state/utils.test.ts
@@ -1,6 +1,7 @@
+import { REPEAT_DIR_HORIZONTAL } from '../../../core/constants';
+
import { PanelModel } from './PanelModel';
import { deleteScopeVars, isOnTheSameGridRow } from './utils';
-import { REPEAT_DIR_HORIZONTAL } from '../../../core/constants';
describe('isOnTheSameGridRow', () => {
describe('when source panel is next to a panel', () => {
diff --git a/public/app/features/dashboard/state/utils.ts b/public/app/features/dashboard/state/utils.ts
index 7a726900aeb..13ca54d302c 100644
--- a/public/app/features/dashboard/state/utils.ts
+++ b/public/app/features/dashboard/state/utils.ts
@@ -1,6 +1,7 @@
-import { PanelModel } from './PanelModel';
import { REPEAT_DIR_HORIZONTAL } from '../../../core/constants';
+import { PanelModel } from './PanelModel';
+
export function isOnTheSameGridRow(sourcePanel: PanelModel, otherPanel: PanelModel): boolean {
if (sourcePanel.repeatDirection === REPEAT_DIR_HORIZONTAL) {
return false;
diff --git a/public/app/features/dashboard/utils/getPanelMenu.test.ts b/public/app/features/dashboard/utils/getPanelMenu.test.ts
index 9b2746f5141..6ca07eb7998 100644
--- a/public/app/features/dashboard/utils/getPanelMenu.test.ts
+++ b/public/app/features/dashboard/utils/getPanelMenu.test.ts
@@ -1,10 +1,12 @@
import { PanelMenuItem } from '@grafana/data';
-import { DashboardModel, PanelModel } from '../state';
-import { getPanelMenu } from './getPanelMenu';
-import { describe } from '../../../../test/lib/common';
-import { setStore } from 'app/store/store';
import config from 'app/core/config';
import * as actions from 'app/features/explore/state/main';
+import { setStore } from 'app/store/store';
+
+import { describe } from '../../../../test/lib/common';
+import { DashboardModel, PanelModel } from '../state';
+
+import { getPanelMenu } from './getPanelMenu';
jest.mock('app/core/services/context_srv', () => ({
contextSrv: {
diff --git a/public/app/features/dashboard/utils/getPanelMenu.ts b/public/app/features/dashboard/utils/getPanelMenu.ts
index 16c18b8501e..f5921d734b3 100644
--- a/public/app/features/dashboard/utils/getPanelMenu.ts
+++ b/public/app/features/dashboard/utils/getPanelMenu.ts
@@ -1,6 +1,9 @@
-import { store } from 'app/store/store';
-import { AngularComponent, getDataSourceSrv, locationService } from '@grafana/runtime';
import { PanelMenuItem } from '@grafana/data';
+import { AngularComponent, getDataSourceSrv, locationService } from '@grafana/runtime';
+import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
+import config from 'app/core/config';
+import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
+import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import {
addLibraryPanel,
copyPanel,
@@ -10,14 +13,12 @@ import {
unlinkLibraryPanel,
} from 'app/features/dashboard/utils/panel';
import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard';
-import { PanelModel } from 'app/features/dashboard/state/PanelModel';
-import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
+import { store } from 'app/store/store';
+
import { contextSrv } from '../../../core/services/context_srv';
-import { navigateToExplore } from '../../explore/state/main';
import { getExploreUrl } from '../../../core/utils/explore';
+import { navigateToExplore } from '../../explore/state/main';
import { getTimeSrv } from '../services/TimeSrv';
-import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
-import config from 'app/core/config';
export function getPanelMenu(
dashboard: DashboardModel,
diff --git a/public/app/features/dashboard/utils/loadSnapshotData.ts b/public/app/features/dashboard/utils/loadSnapshotData.ts
index 2a451cef341..40ae85cc49a 100644
--- a/public/app/features/dashboard/utils/loadSnapshotData.ts
+++ b/public/app/features/dashboard/utils/loadSnapshotData.ts
@@ -1,10 +1,12 @@
import { applyFieldOverrides, ArrayDataFrame, getDefaultTimeRange, LoadingState, PanelData } from '@grafana/data';
import { config } from 'app/core/config';
-import { DashboardModel, PanelModel } from '../state';
-import { getProcessedDataFrames } from '../../query/state/runRequest';
+
import { SnapshotWorker } from '../../query/state/DashboardQueryRunner/SnapshotWorker';
-import { applyPanelTimeOverrides } from './panel';
+import { getProcessedDataFrames } from '../../query/state/runRequest';
import { getTimeSrv } from '../services/TimeSrv';
+import { DashboardModel, PanelModel } from '../state';
+
+import { applyPanelTimeOverrides } from './panel';
export function loadSnapshotData(panel: PanelModel, dashboard: DashboardModel): PanelData {
const data = getProcessedDataFrames(panel.snapshotData);
diff --git a/public/app/features/dashboard/utils/panel.test.ts b/public/app/features/dashboard/utils/panel.test.ts
index f1431af92a1..a979c7ab1cc 100644
--- a/public/app/features/dashboard/utils/panel.test.ts
+++ b/public/app/features/dashboard/utils/panel.test.ts
@@ -1,9 +1,11 @@
+import { advanceTo, clear } from 'jest-date-mock';
+import { ComponentClass } from 'react';
+
import { dateTime, DateTime, PanelProps, TimeRange } from '@grafana/data';
import { applyPanelTimeOverrides, calculateInnerPanelHeight } from 'app/features/dashboard/utils/panel';
-import { advanceTo, clear } from 'jest-date-mock';
-import { PanelModel } from '../state';
+
import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
-import { ComponentClass } from 'react';
+import { PanelModel } from '../state';
const dashboardTimeRange: TimeRange = {
from: dateTime([2019, 1, 11, 12, 0]),
diff --git a/public/app/features/dashboard/utils/panel.ts b/public/app/features/dashboard/utils/panel.ts
index d92497a43f0..202de4be4f4 100644
--- a/public/app/features/dashboard/utils/panel.ts
+++ b/public/app/features/dashboard/utils/panel.ts
@@ -1,28 +1,20 @@
-// Store
-import store from 'app/core/store';
-import { dispatch } from 'app/store/store';
-
-// Models
-import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
-import { PanelModel } from 'app/features/dashboard/state/PanelModel';
-import { TimeRange, AppEvents, rangeUtil, dateMath, PanelModel as IPanelModel } from '@grafana/data';
-
-// Utils
import { isString as _isString } from 'lodash';
+
+import { TimeRange, AppEvents, rangeUtil, dateMath, PanelModel as IPanelModel } from '@grafana/data';
+import { getTemplateSrv } from '@grafana/runtime';
import appEvents from 'app/core/app_events';
import config from 'app/core/config';
-
-// Services
-import { getTemplateSrv } from '@grafana/runtime';
-
-// Constants
import { LS_PANEL_COPY_KEY, PANEL_BORDER } from 'app/core/constants';
-
+import store from 'app/core/store';
import { ShareModal } from 'app/features/dashboard/components/ShareModal';
-import { ShowConfirmModalEvent, ShowModalReactEvent } from '../../../types/events';
+import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
+import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { AddLibraryPanelModal } from 'app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal';
import { UnlinkModal } from 'app/features/library-panels/components/UnlinkModal/UnlinkModal';
import { cleanUpPanelState } from 'app/features/panel/state/actions';
+import { dispatch } from 'app/store/store';
+
+import { ShowConfirmModalEvent, ShowModalReactEvent } from '../../../types/events';
export const removePanel = (dashboard: DashboardModel, panel: PanelModel, ask: boolean) => {
// confirm deletion
diff --git a/public/app/features/dashboard/utils/panelMerge.test.ts b/public/app/features/dashboard/utils/panelMerge.test.ts
index d0117f532ad..9882379d3a2 100644
--- a/public/app/features/dashboard/utils/panelMerge.test.ts
+++ b/public/app/features/dashboard/utils/panelMerge.test.ts
@@ -1,4 +1,5 @@
import { PanelModel } from '@grafana/data';
+
import { DashboardModel } from '../state/DashboardModel';
describe('Merge dashbaord panels', () => {
diff --git a/public/app/features/dashboard/utils/panelMerge.ts b/public/app/features/dashboard/utils/panelMerge.ts
index a0de905acbd..946d3177cf0 100644
--- a/public/app/features/dashboard/utils/panelMerge.ts
+++ b/public/app/features/dashboard/utils/panelMerge.ts
@@ -1,5 +1,7 @@
-import { PanelModel as IPanelModel } from '@grafana/data';
import { isEqualWith } from 'lodash';
+
+import { PanelModel as IPanelModel } from '@grafana/data';
+
import { PanelModel } from '../state';
export interface PanelMergeInfo {
diff --git a/public/app/features/datasources/DashboardsTable.test.tsx b/public/app/features/datasources/DashboardsTable.test.tsx
index 10a14f464e4..4e6fafe722f 100644
--- a/public/app/features/datasources/DashboardsTable.test.tsx
+++ b/public/app/features/datasources/DashboardsTable.test.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
import { shallow } from 'enzyme';
-import DashboardsTable, { Props } from './DashboardsTable';
+import React from 'react';
+
import { PluginDashboard } from '../../types';
+import DashboardsTable, { Props } from './DashboardsTable';
+
const setup = (propOverrides?: object) => {
const props: Props = {
dashboards: [] as PluginDashboard[],
diff --git a/public/app/features/datasources/DashboardsTable.tsx b/public/app/features/datasources/DashboardsTable.tsx
index da71c9de227..3e45624871c 100644
--- a/public/app/features/datasources/DashboardsTable.tsx
+++ b/public/app/features/datasources/DashboardsTable.tsx
@@ -1,7 +1,9 @@
import React, { FC } from 'react';
-import { PluginDashboard } from '../../types';
+
import { Button, Icon } from '@grafana/ui';
+import { PluginDashboard } from '../../types';
+
export interface Props {
dashboards: PluginDashboard[];
onImport: (dashboard: PluginDashboard, overwrite: boolean) => void;
diff --git a/public/app/features/datasources/DataSourceDashboards.test.tsx b/public/app/features/datasources/DataSourceDashboards.test.tsx
index b90133586fa..516b90f6570 100644
--- a/public/app/features/datasources/DataSourceDashboards.test.tsx
+++ b/public/app/features/datasources/DataSourceDashboards.test.tsx
@@ -1,9 +1,11 @@
-import React from 'react';
import { shallow } from 'enzyme';
-import { DataSourceDashboards, Props } from './DataSourceDashboards';
+import React from 'react';
+
import { DataSourceSettings, NavModel } from '@grafana/data';
-import { PluginDashboard } from 'app/types';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
+import { PluginDashboard } from 'app/types';
+
+import { DataSourceDashboards, Props } from './DataSourceDashboards';
const setup = (propOverrides?: object) => {
const props: Props = {
diff --git a/public/app/features/datasources/DataSourceDashboards.tsx b/public/app/features/datasources/DataSourceDashboards.tsx
index f035776ddae..9673716ddc3 100644
--- a/public/app/features/datasources/DataSourceDashboards.tsx
+++ b/public/app/features/datasources/DataSourceDashboards.tsx
@@ -1,21 +1,17 @@
-// Libraries
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
-// Components
import Page from 'app/core/components/Page/Page';
-import DashboardTable from './DashboardsTable';
-
-// Actions & Selectors
-import { getNavModel } from 'app/core/selectors/navModel';
-import { loadDataSource } from './state/actions';
-import { loadPluginDashboards } from '../plugins/admin/state/actions';
-import { importDashboard, removeDashboard } from '../dashboard/state/actions';
-import { getDataSource } from './state/selectors';
-
-// Types
-import { PluginDashboard, StoreState } from 'app/types';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
+import { getNavModel } from 'app/core/selectors/navModel';
+import { PluginDashboard, StoreState } from 'app/types';
+
+import { importDashboard, removeDashboard } from '../dashboard/state/actions';
+import { loadPluginDashboards } from '../plugins/admin/state/actions';
+
+import DashboardTable from './DashboardsTable';
+import { loadDataSource } from './state/actions';
+import { getDataSource } from './state/selectors';
export interface OwnProps extends GrafanaRouteComponentProps<{ uid: string }> {}
diff --git a/public/app/features/datasources/DataSourceList.test.tsx b/public/app/features/datasources/DataSourceList.test.tsx
index 55c24291bce..3110b35a6e8 100644
--- a/public/app/features/datasources/DataSourceList.test.tsx
+++ b/public/app/features/datasources/DataSourceList.test.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
import { render, screen } from '@testing-library/react';
+import React from 'react';
+
+import { LayoutModes } from '@grafana/data';
+
import DataSourcesList from './DataSourcesList';
import { getMockDataSources } from './__mocks__/dataSourcesMocks';
-import { LayoutModes } from '@grafana/data';
const setup = () => {
const props = {
diff --git a/public/app/features/datasources/DataSourcesList.tsx b/public/app/features/datasources/DataSourcesList.tsx
index 3566177d7c0..9bcca5d543c 100644
--- a/public/app/features/datasources/DataSourcesList.tsx
+++ b/public/app/features/datasources/DataSourcesList.tsx
@@ -1,10 +1,10 @@
// Libraries
+import { css } from '@emotion/css';
import React, { FC } from 'react';
// Types
import { DataSourceSettings, LayoutMode } from '@grafana/data';
import { Card, Tag, useStyles } from '@grafana/ui';
-import { css } from '@emotion/css';
export interface Props {
dataSources: DataSourceSettings[];
diff --git a/public/app/features/datasources/DataSourcesListPage.test.tsx b/public/app/features/datasources/DataSourcesListPage.test.tsx
index 975f925c8b3..c26bd1af413 100644
--- a/public/app/features/datasources/DataSourcesListPage.test.tsx
+++ b/public/app/features/datasources/DataSourcesListPage.test.tsx
@@ -1,5 +1,6 @@
-import React from 'react';
import { shallow } from 'enzyme';
+import React from 'react';
+
import { DataSourceSettings, NavModel, LayoutModes } from '@grafana/data';
import { DataSourcesListPage, Props } from './DataSourcesListPage';
diff --git a/public/app/features/datasources/DataSourcesListPage.tsx b/public/app/features/datasources/DataSourcesListPage.tsx
index 4b1a5101f96..ca8c5d3ec20 100644
--- a/public/app/features/datasources/DataSourcesListPage.tsx
+++ b/public/app/features/datasources/DataSourcesListPage.tsx
@@ -1,27 +1,23 @@
-// Libraries
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
-// Services & Utils
-import { contextSrv } from 'app/core/core';
-// Components
+
+import { IconName } from '@grafana/ui';
+import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
import Page from 'app/core/components/Page/Page';
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
-import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
-import DataSourcesList from './DataSourcesList';
-// Types
-import { IconName } from '@grafana/ui';
-import { StoreState, AccessControlAction } from 'app/types';
-// Actions
-import { loadDataSources } from './state/actions';
+import { contextSrv } from 'app/core/core';
import { getNavModel } from 'app/core/selectors/navModel';
+import { StoreState, AccessControlAction } from 'app/types';
+import DataSourcesList from './DataSourcesList';
+import { loadDataSources } from './state/actions';
+import { setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/reducers';
import {
getDataSources,
getDataSourcesCount,
getDataSourcesLayoutMode,
getDataSourcesSearchQuery,
} from './state/selectors';
-import { setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/reducers';
function mapStateToProps(state: StoreState) {
return {
diff --git a/public/app/features/datasources/NewDataSourcePage.tsx b/public/app/features/datasources/NewDataSourcePage.tsx
index 21b68754131..b7943e8af90 100644
--- a/public/app/features/datasources/NewDataSourcePage.tsx
+++ b/public/app/features/datasources/NewDataSourcePage.tsx
@@ -1,17 +1,19 @@
+import { css, cx } from '@emotion/css';
import React, { FC, PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
-import { DataSourcePluginMeta, GrafanaTheme2, NavModel } from '@grafana/data';
-import { Card, LinkButton, List, PluginSignatureBadge, FilterInput, useStyles2 } from '@grafana/ui';
-import { css, cx } from '@emotion/css';
-import { selectors } from '@grafana/e2e-selectors';
+import { DataSourcePluginMeta, GrafanaTheme2, NavModel } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
+import { Card, LinkButton, List, PluginSignatureBadge, FilterInput, useStyles2 } from '@grafana/ui';
import Page from 'app/core/components/Page/Page';
import { StoreState } from 'app/types';
-import { addDataSource, loadDataSourcePlugins } from './state/actions';
-import { getDataSourcePlugins } from './state/selectors';
-import { setDataSourceTypeSearchQuery } from './state/reducers';
+
import { PluginsErrorsInfo } from '../plugins/components/PluginsErrorsInfo';
+import { addDataSource, loadDataSourcePlugins } from './state/actions';
+import { setDataSourceTypeSearchQuery } from './state/reducers';
+import { getDataSourcePlugins } from './state/selectors';
+
function mapStateToProps(state: StoreState) {
return {
navModel: getNavModel(),
diff --git a/public/app/features/datasources/settings/BasicSettings.test.tsx b/public/app/features/datasources/settings/BasicSettings.test.tsx
index 0194adc9007..389c6618fcc 100644
--- a/public/app/features/datasources/settings/BasicSettings.test.tsx
+++ b/public/app/features/datasources/settings/BasicSettings.test.tsx
@@ -1,5 +1,6 @@
-import React from 'react';
import { shallow } from 'enzyme';
+import React from 'react';
+
import BasicSettings, { Props } from './BasicSettings';
const setup = () => {
diff --git a/public/app/features/datasources/settings/BasicSettings.tsx b/public/app/features/datasources/settings/BasicSettings.tsx
index 1271672e6e6..ad9d7d49f72 100644
--- a/public/app/features/datasources/settings/BasicSettings.tsx
+++ b/public/app/features/datasources/settings/BasicSettings.tsx
@@ -1,6 +1,7 @@
import React, { FC } from 'react';
-import { InlineFormLabel, LegacyForms } from '@grafana/ui';
+
import { selectors } from '@grafana/e2e-selectors';
+import { InlineFormLabel, LegacyForms } from '@grafana/ui';
const { Input, Switch } = LegacyForms;
diff --git a/public/app/features/datasources/settings/ButtonRow.test.tsx b/public/app/features/datasources/settings/ButtonRow.test.tsx
index aa713dd557d..9508cfd8e97 100644
--- a/public/app/features/datasources/settings/ButtonRow.test.tsx
+++ b/public/app/features/datasources/settings/ButtonRow.test.tsx
@@ -1,5 +1,6 @@
-import React from 'react';
import { shallow } from 'enzyme';
+import React from 'react';
+
import ButtonRow, { Props } from './ButtonRow';
jest.mock('app/core/core', () => {
diff --git a/public/app/features/datasources/settings/ButtonRow.tsx b/public/app/features/datasources/settings/ButtonRow.tsx
index e2907d72889..473043ac451 100644
--- a/public/app/features/datasources/settings/ButtonRow.tsx
+++ b/public/app/features/datasources/settings/ButtonRow.tsx
@@ -1,10 +1,9 @@
import React, { FC } from 'react';
+
import { selectors } from '@grafana/e2e-selectors';
-
import { Button, LinkButton } from '@grafana/ui';
-
-import { AccessControlAction } from 'app/types/';
import { contextSrv } from 'app/core/core';
+import { AccessControlAction } from 'app/types/';
export interface Props {
exploreUrl: string;
diff --git a/public/app/features/datasources/settings/CloudInfoBox.tsx b/public/app/features/datasources/settings/CloudInfoBox.tsx
index 96990bf434f..ce087cd6148 100644
--- a/public/app/features/datasources/settings/CloudInfoBox.tsx
+++ b/public/app/features/datasources/settings/CloudInfoBox.tsx
@@ -1,9 +1,10 @@
-import { DataSourceSettings } from '@grafana/data';
-import { Alert } from '@grafana/ui';
import React, { FC } from 'react';
-import { config } from 'app/core/config';
+
+import { DataSourceSettings } from '@grafana/data';
import { GrafanaEdition } from '@grafana/data/src/types/config';
+import { Alert } from '@grafana/ui';
import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
+import { config } from 'app/core/config';
const LOCAL_STORAGE_KEY = 'datasources.settings.cloudInfoBox.isDismissed';
diff --git a/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx b/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
index 12f7226151b..57e0d50c8a6 100644
--- a/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
+++ b/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
@@ -1,13 +1,16 @@
-import React from 'react';
-import { DataSourceSettingsPage, Props } from './DataSourceSettingsPage';
-import { getMockDataSource } from '../__mocks__/dataSourcesMocks';
-import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
-import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers';
-import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
-import { cleanUpAction } from 'app/core/actions/cleanUp';
import { screen, render } from '@testing-library/react';
-import { selectors } from '@grafana/e2e-selectors';
+import React from 'react';
+
import { PluginState } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
+import { cleanUpAction } from 'app/core/actions/cleanUp';
+import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
+
+import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
+import { getMockDataSource } from '../__mocks__/dataSourcesMocks';
+import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers';
+
+import { DataSourceSettingsPage, Props } from './DataSourceSettingsPage';
jest.mock('app/core/core', () => {
return {
diff --git a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx b/public/app/features/datasources/settings/DataSourceSettingsPage.tsx
index f4d12900901..68e2a4f2384 100644
--- a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx
+++ b/public/app/features/datasources/settings/DataSourceSettingsPage.tsx
@@ -1,15 +1,19 @@
import React, { PureComponent } from 'react';
-// Components
-import Page from 'app/core/components/Page/Page';
-import { PluginSettings } from './PluginSettings';
-import BasicSettings from './BasicSettings';
-import ButtonRow from './ButtonRow';
-// Services & Utils
-import appEvents from 'app/core/app_events';
-import { contextSrv } from 'app/core/core';
+import { connect, ConnectedProps } from 'react-redux';
-// Actions & selectors
-import { getDataSource, getDataSourceMeta } from '../state/selectors';
+import { DataSourceSettings, urlUtil } from '@grafana/data';
+import { selectors } from '@grafana/e2e-selectors';
+import { Alert, Button } from '@grafana/ui';
+import { cleanUpAction } from 'app/core/actions/cleanUp';
+import appEvents from 'app/core/app_events';
+import Page from 'app/core/components/Page/Page';
+import { contextSrv } from 'app/core/core';
+import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
+import { getNavModel } from 'app/core/selectors/navModel';
+import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
+import { StoreState, AccessControlAction } from 'app/types/';
+
+import { ShowConfirmModalEvent } from '../../../types/events';
import {
deleteDataSource,
initDataSourceSettings,
@@ -17,21 +21,14 @@ import {
testDataSource,
updateDataSource,
} from '../state/actions';
-import { getNavModel } from 'app/core/selectors/navModel';
-
-// Types
-import { StoreState, AccessControlAction } from 'app/types/';
-import { DataSourceSettings, urlUtil } from '@grafana/data';
-import { Alert, Button } from '@grafana/ui';
import { getDataSourceLoadingNav, buildNavModel, getDataSourceNav } from '../state/navModel';
-import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers';
-import { selectors } from '@grafana/e2e-selectors';
+import { getDataSource, getDataSourceMeta } from '../state/selectors';
+
+import BasicSettings from './BasicSettings';
+import ButtonRow from './ButtonRow';
import { CloudInfoBox } from './CloudInfoBox';
-import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
-import { connect, ConnectedProps } from 'react-redux';
-import { cleanUpAction } from 'app/core/actions/cleanUp';
-import { ShowConfirmModalEvent } from '../../../types/events';
+import { PluginSettings } from './PluginSettings';
export interface OwnProps extends GrafanaRouteComponentProps<{ uid: string }> {}
diff --git a/public/app/features/datasources/settings/PluginSettings.tsx b/public/app/features/datasources/settings/PluginSettings.tsx
index 429f3de6e98..ca322ff2cc5 100644
--- a/public/app/features/datasources/settings/PluginSettings.tsx
+++ b/public/app/features/datasources/settings/PluginSettings.tsx
@@ -1,5 +1,6 @@
-import React, { PureComponent } from 'react';
import { cloneDeep } from 'lodash';
+import React, { PureComponent } from 'react';
+
import {
DataQuery,
DataSourceApi,
diff --git a/public/app/features/datasources/state/actions.test.ts b/public/app/features/datasources/state/actions.test.ts
index 8d652cdcd72..84e6ca9c108 100644
--- a/public/app/features/datasources/state/actions.test.ts
+++ b/public/app/features/datasources/state/actions.test.ts
@@ -1,3 +1,14 @@
+import { of } from 'rxjs';
+import { thunkTester } from 'test/core/thunk/thunkTester';
+
+import { BackendSrvRequest, FetchResponse } from '@grafana/runtime';
+import { getBackendSrv } from 'app/core/services/backend_srv';
+import { ThunkResult, ThunkDispatch } from 'app/types';
+
+import { getMockPlugin, getMockPlugins } from '../../plugins/__mocks__/pluginMocks';
+import { GenericDataSourcePlugin } from '../settings/PluginSettings';
+import { initDataSourceSettings } from '../state/actions';
+
import {
findNewName,
nameExits,
@@ -6,8 +17,6 @@ import {
TestDataSourceDependencies,
getDataSourceUsingUidOrId,
} from './actions';
-import { getMockPlugin, getMockPlugins } from '../../plugins/__mocks__/pluginMocks';
-import { thunkTester } from 'test/core/thunk/thunkTester';
import {
initDataSourceSettingsSucceeded,
initDataSourceSettingsFailed,
@@ -15,12 +24,6 @@ import {
testDataSourceSucceeded,
testDataSourceFailed,
} from './reducers';
-import { initDataSourceSettings } from '../state/actions';
-import { ThunkResult, ThunkDispatch } from 'app/types';
-import { GenericDataSourcePlugin } from '../settings/PluginSettings';
-import { getBackendSrv } from 'app/core/services/backend_srv';
-import { BackendSrvRequest, FetchResponse } from '@grafana/runtime';
-import { of } from 'rxjs';
jest.mock('app/core/services/backend_srv');
jest.mock('@grafana/runtime', () => ({
diff --git a/public/app/features/datasources/state/actions.ts b/public/app/features/datasources/state/actions.ts
index 54fa40cc03d..9dd8d5d26e9 100644
--- a/public/app/features/datasources/state/actions.ts
+++ b/public/app/features/datasources/state/actions.ts
@@ -1,13 +1,17 @@
import { lastValueFrom } from 'rxjs';
+
import { DataSourcePluginMeta, DataSourceSettings, locationUtil } from '@grafana/data';
import { DataSourceWithBackend, getDataSourceSrv, locationService } from '@grafana/runtime';
import { updateNavIndex } from 'app/core/actions';
import { getBackendSrv } from 'app/core/services/backend_srv';
+import { accessControlQueryParam } from 'app/core/utils/accessControl';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
-import { importDataSourcePlugin } from 'app/features/plugins/plugin_loader';
import { getPluginSettings } from 'app/features/plugins/pluginSettings';
+import { importDataSourcePlugin } from 'app/features/plugins/plugin_loader';
import { DataSourcePluginCategory, ThunkDispatch, ThunkResult } from 'app/types';
+import { contextSrv } from '../../../core/services/context_srv';
+
import { buildCategories } from './buildCategories';
import { buildNavModel } from './navModel';
import {
@@ -23,8 +27,6 @@ import {
testDataSourceSucceeded,
} from './reducers';
import { getDataSource, getDataSourceMeta } from './selectors';
-import { accessControlQueryParam } from 'app/core/utils/accessControl';
-import { contextSrv } from '../../../core/services/context_srv';
export interface DataSourceTypesLoadedPayload {
plugins: DataSourcePluginMeta[];
diff --git a/public/app/features/datasources/state/buildCategories.test.ts b/public/app/features/datasources/state/buildCategories.test.ts
index 04076b74e13..5bea2aa63d1 100644
--- a/public/app/features/datasources/state/buildCategories.test.ts
+++ b/public/app/features/datasources/state/buildCategories.test.ts
@@ -1,7 +1,9 @@
-import { buildCategories } from './buildCategories';
-import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
import { DataSourcePluginMeta } from '@grafana/data';
+import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
+
+import { buildCategories } from './buildCategories';
+
const plugins: DataSourcePluginMeta[] = [
{
...getMockPlugin({ id: 'graphite' }),
diff --git a/public/app/features/datasources/state/navModel.ts b/public/app/features/datasources/state/navModel.ts
index 24c82d75074..4e0b1ed593d 100644
--- a/public/app/features/datasources/state/navModel.ts
+++ b/public/app/features/datasources/state/navModel.ts
@@ -1,9 +1,11 @@
import { DataSourceSettings, PluginType, PluginInclude, NavModel, NavModelItem } from '@grafana/data';
import { featureEnabled } from '@grafana/runtime';
+import { ProBadge } from 'app/core/components/Upgrade/ProBadge';
import config from 'app/core/config';
import { contextSrv } from 'app/core/core';
import { AccessControlAction } from 'app/types';
-import { ProBadge } from 'app/core/components/Upgrade/ProBadge';
+
+import { highlightTrial } from '../../admin/utils';
import { GenericDataSourcePlugin } from '../settings/PluginSettings';
const loadingDSType = 'Loading';
@@ -53,7 +55,8 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
const isLoadingNav = dataSource.type === loadingDSType;
- const dsPermissions = {
+ const permissionsExperimentId = 'feature-highlights-data-source-permissions-badge';
+ const dsPermissions: NavModelItem = {
active: false,
icon: 'lock',
id: `datasource-permissions-${dataSource.uid}`,
@@ -61,6 +64,10 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
url: `datasources/edit/${dataSource.uid}/permissions`,
};
+ if (highlightTrial() && !isLoadingNav) {
+ dsPermissions.tabSuffix = () => ProBadge({ experimentId: permissionsExperimentId, eventVariant: 'trial' });
+ }
+
if (featureEnabled('dspermissions')) {
if (contextSrv.hasPermission(AccessControlAction.DataSourcesPermissionsRead)) {
navModel.children!.push(dsPermissions);
@@ -69,11 +76,12 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
navModel.children!.push({
...dsPermissions,
url: dsPermissions.url + '/upgrade',
- tabSuffix: () => ProBadge({ experimentId: 'feature-highlights-data-source-permissions-badge' }),
+ tabSuffix: () => ProBadge({ experimentId: permissionsExperimentId }),
});
}
- const analytics = {
+ const analyticsExperimentId = 'feature-highlights-data-source-insights-badge';
+ const analytics: NavModelItem = {
active: false,
icon: 'info-circle',
id: `datasource-insights-${dataSource.uid}`,
@@ -81,17 +89,23 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
url: `datasources/edit/${dataSource.uid}/insights`,
};
+ if (highlightTrial() && !isLoadingNav) {
+ analytics.tabSuffix = () => ProBadge({ experimentId: analyticsExperimentId, eventVariant: 'trial' });
+ }
+
if (featureEnabled('analytics')) {
navModel.children!.push(analytics);
} else if (highlightsEnabled && !isLoadingNav) {
navModel.children!.push({
...analytics,
url: analytics.url + '/upgrade',
- tabSuffix: () => ProBadge({ experimentId: 'feature-highlights-data-source-insights-badge' }),
+ tabSuffix: () => ProBadge({ experimentId: analyticsExperimentId }),
});
}
- const caching = {
+ const cachingExperimentId = 'feature-highlights-query-caching-badge';
+
+ const caching: NavModelItem = {
active: false,
icon: 'database',
id: `datasource-cache-${dataSource.uid}`,
@@ -100,13 +114,17 @@ export function buildNavModel(dataSource: DataSourceSettings, plugin: GenericDat
hideFromTabs: !pluginMeta.isBackend || !config.caching.enabled,
};
+ if (highlightTrial() && !isLoadingNav) {
+ caching.tabSuffix = () => ProBadge({ experimentId: cachingExperimentId, eventVariant: 'trial' });
+ }
+
if (featureEnabled('caching')) {
navModel.children!.push(caching);
} else if (highlightsEnabled && !isLoadingNav) {
navModel.children!.push({
...caching,
url: caching.url + '/upgrade',
- tabSuffix: () => ProBadge({ experimentId: 'feature-highlights-query-caching-badge' }),
+ tabSuffix: () => ProBadge({ experimentId: cachingExperimentId }),
});
}
diff --git a/public/app/features/datasources/state/reducers.test.ts b/public/app/features/datasources/state/reducers.test.ts
index cb5e6afed54..f6d409fd5a6 100644
--- a/public/app/features/datasources/state/reducers.test.ts
+++ b/public/app/features/datasources/state/reducers.test.ts
@@ -1,4 +1,11 @@
import { reducerTester } from 'test/core/redux/reducerTester';
+
+import { PluginMeta, PluginMetaInfo, PluginType, LayoutModes } from '@grafana/data';
+import { DataSourceSettingsState, DataSourcesState } from 'app/types';
+
+import { getMockDataSource, getMockDataSources } from '../__mocks__/dataSourcesMocks';
+import { GenericDataSourcePlugin } from '../settings/PluginSettings';
+
import {
dataSourceLoaded,
dataSourceMetaLoaded,
@@ -17,10 +24,6 @@ import {
setDataSourceTypeSearchQuery,
setIsDefault,
} from './reducers';
-import { getMockDataSource, getMockDataSources } from '../__mocks__/dataSourcesMocks';
-import { DataSourceSettingsState, DataSourcesState } from 'app/types';
-import { PluginMeta, PluginMetaInfo, PluginType, LayoutModes } from '@grafana/data';
-import { GenericDataSourcePlugin } from '../settings/PluginSettings';
const mockPlugin = () =>
({
diff --git a/public/app/features/datasources/state/reducers.ts b/public/app/features/datasources/state/reducers.ts
index 1af1f762d6b..8410ec5aab6 100644
--- a/public/app/features/datasources/state/reducers.ts
+++ b/public/app/features/datasources/state/reducers.ts
@@ -1,10 +1,12 @@
import { AnyAction, createAction } from '@reduxjs/toolkit';
-import { DataSourcePluginMeta, DataSourceSettings, LayoutMode, LayoutModes } from '@grafana/data';
+import { DataSourcePluginMeta, DataSourceSettings, LayoutMode, LayoutModes } from '@grafana/data';
import { DataSourcesState, DataSourceSettingsState, TestingStatus } from 'app/types';
-import { DataSourceTypesLoadedPayload } from './actions';
+
import { GenericDataSourcePlugin } from '../settings/PluginSettings';
+import { DataSourceTypesLoadedPayload } from './actions';
+
export const initialState: DataSourcesState = {
dataSources: [],
plugins: [],
diff --git a/public/app/features/datasources/state/selectors.ts b/public/app/features/datasources/state/selectors.ts
index b09e79698f4..558dfa88a4e 100644
--- a/public/app/features/datasources/state/selectors.ts
+++ b/public/app/features/datasources/state/selectors.ts
@@ -1,4 +1,5 @@
import { DataSourcePluginMeta, DataSourceSettings, UrlQueryValue } from '@grafana/data';
+
import { DataSourcesState } from '../../../types/datasources';
export const getDataSources = (state: DataSourcesState) => {
diff --git a/public/app/features/dimensions/color.ts b/public/app/features/dimensions/color.ts
index d38a3fc34be..5e6646db95c 100644
--- a/public/app/features/dimensions/color.ts
+++ b/public/app/features/dimensions/color.ts
@@ -1,4 +1,5 @@
import { DataFrame, Field, getDisplayProcessor, getFieldColorModeForField, GrafanaTheme2 } from '@grafana/data';
+
import { ColorDimensionConfig, DimensionSupplier } from './types';
import { findField, getLastNotNullFieldValue } from './utils';
diff --git a/public/app/features/dimensions/editors/ColorDimensionEditor.tsx b/public/app/features/dimensions/editors/ColorDimensionEditor.tsx
index 823fa1989c5..1b18ddedc60 100644
--- a/public/app/features/dimensions/editors/ColorDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ColorDimensionEditor.tsx
@@ -1,12 +1,14 @@
+import { css } from '@emotion/css';
import React, { FC, useCallback } from 'react';
+
import { GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data';
-import { ColorDimensionConfig } from '../types';
import { Select, ColorPicker, useStyles2 } from '@grafana/ui';
+
import {
useFieldDisplayNames,
useSelectOptions,
} from '../../../../../packages/grafana-ui/src/components/MatchersUI/utils';
-import { css } from '@emotion/css';
+import { ColorDimensionConfig } from '../types';
const fixedColorOption: SelectableValue = {
label: 'Fixed color',
diff --git a/public/app/features/dimensions/editors/FolderPickerTab.tsx b/public/app/features/dimensions/editors/FolderPickerTab.tsx
index 13fa478d577..005566852c6 100644
--- a/public/app/features/dimensions/editors/FolderPickerTab.tsx
+++ b/public/app/features/dimensions/editors/FolderPickerTab.tsx
@@ -1,11 +1,13 @@
-import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { css } from '@emotion/css';
-import { Field, FilterInput, Select, useStyles2 } from '@grafana/ui';
+import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
+
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
+import { Field, FilterInput, Select, useStyles2 } from '@grafana/ui';
+import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
+import { FileElement, GrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
import { MediaType, ResourceFolderName } from '../types';
-import { FileElement, GrafanaDatasource } from 'app/plugins/datasource/grafana/datasource';
-import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
+
import { ResourceCards } from './ResourceCards';
const getFolders = (mediaType: MediaType) => {
diff --git a/public/app/features/dimensions/editors/IconSelector.tsx b/public/app/features/dimensions/editors/IconSelector.tsx
index 3a2d977c9a7..58188cc383e 100644
--- a/public/app/features/dimensions/editors/IconSelector.tsx
+++ b/public/app/features/dimensions/editors/IconSelector.tsx
@@ -1,7 +1,8 @@
import React, { useState, useEffect } from 'react';
-import { Select } from '@grafana/ui';
+
import { SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
+import { Select } from '@grafana/ui';
interface Props {
value: string;
diff --git a/public/app/features/dimensions/editors/NumberInput.tsx b/public/app/features/dimensions/editors/NumberInput.tsx
index da21132a776..24e8b281c13 100644
--- a/public/app/features/dimensions/editors/NumberInput.tsx
+++ b/public/app/features/dimensions/editors/NumberInput.tsx
@@ -1,4 +1,5 @@
import React, { PureComponent } from 'react';
+
import { Field, Input } from '@grafana/ui';
interface Props {
diff --git a/public/app/features/dimensions/editors/ResourceCards.tsx b/public/app/features/dimensions/editors/ResourceCards.tsx
index aeaa1fc6758..afd7e0d6bd1 100644
--- a/public/app/features/dimensions/editors/ResourceCards.tsx
+++ b/public/app/features/dimensions/editors/ResourceCards.tsx
@@ -1,10 +1,12 @@
+import { css, cx } from '@emotion/css';
import React, { memo, CSSProperties } from 'react';
-import { areEqual, FixedSizeGrid as Grid } from 'react-window';
+import SVG from 'react-inlinesvg';
import AutoSizer from 'react-virtualized-auto-sizer';
+import { areEqual, FixedSizeGrid as Grid } from 'react-window';
+
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2, stylesFactory } from '@grafana/ui';
-import SVG from 'react-inlinesvg';
-import { css, cx } from '@emotion/css';
+
import { ResourceItem } from './FolderPickerTab';
interface CellProps {
diff --git a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx
index 6818ab6ee37..a9020f991c2 100644
--- a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx
@@ -1,8 +1,10 @@
import React, { FC, useCallback } from 'react';
+
import { FieldNamePickerConfigSettings, StandardEditorProps, StandardEditorsRegistryItem } from '@grafana/data';
import { InlineField, InlineFieldRow, RadioButtonGroup } from '@grafana/ui';
import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldNamePicker';
+import { getPublicOrAbsoluteUrl, ResourceFolderName } from '..';
import {
MediaType,
ResourceDimensionConfig,
@@ -10,7 +12,7 @@ import {
ResourceDimensionOptions,
ResourcePickerSize,
} from '../types';
-import { getPublicOrAbsoluteUrl, ResourceFolderName } from '..';
+
import { ResourcePicker } from './ResourcePicker';
const resourceOptions = [
diff --git a/public/app/features/dimensions/editors/ResourcePicker.tsx b/public/app/features/dimensions/editors/ResourcePicker.tsx
index 938792bc14d..7bc55df26b7 100644
--- a/public/app/features/dimensions/editors/ResourcePicker.tsx
+++ b/public/app/features/dimensions/editors/ResourcePicker.tsx
@@ -1,5 +1,8 @@
-import React, { createRef } from 'react';
import { css } from '@emotion/css';
+import React, { createRef } from 'react';
+import SVG from 'react-inlinesvg';
+
+import { GrafanaTheme2 } from '@grafana/data';
import {
Button,
InlineField,
@@ -11,13 +14,12 @@ import {
useStyles2,
useTheme2,
} from '@grafana/ui';
-import { GrafanaTheme2 } from '@grafana/data';
-import SVG from 'react-inlinesvg';
-
-import { MediaType, ResourceFolderName, ResourcePickerSize } from '../types';
import { closePopover } from '@grafana/ui/src/utils/closePopover';
-import { ResourcePickerPopover } from './ResourcePickerPopover';
+
import { getPublicOrAbsoluteUrl } from '../resource';
+import { MediaType, ResourceFolderName, ResourcePickerSize } from '../types';
+
+import { ResourcePickerPopover } from './ResourcePickerPopover';
interface Props {
onChange: (value?: string) => void;
diff --git a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx
index c38df5788f3..66baddbbcbd 100644
--- a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx
+++ b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx
@@ -1,12 +1,14 @@
-import React, { createRef, useState } from 'react';
import { css } from '@emotion/css';
-import { Button, ButtonGroup, useStyles2 } from '@grafana/ui';
-import { GrafanaTheme2 } from '@grafana/data';
-import { FocusScope } from '@react-aria/focus';
import { useDialog } from '@react-aria/dialog';
+import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
+import React, { createRef, useState } from 'react';
+
+import { GrafanaTheme2 } from '@grafana/data';
+import { Button, ButtonGroup, useStyles2 } from '@grafana/ui';
import { MediaType, PickerTabType, ResourceFolderName } from '../types';
+
import { FolderPickerTab } from './FolderPickerTab';
import { URLPickerTab } from './URLPickerTab';
diff --git a/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx b/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx
index 4efef4cb0ec..dc6bc6c4de7 100644
--- a/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx
@@ -1,10 +1,13 @@
+import { css } from '@emotion/css';
import React, { FC, useCallback } from 'react';
+
import { FieldType, GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data';
-import { ScalarDimensionConfig, ScalarDimensionMode, ScalarDimensionOptions } from '../types';
import { InlineField, InlineFieldRow, RadioButtonGroup, Select, useStyles2 } from '@grafana/ui';
import { useFieldDisplayNames, useSelectOptions } from '@grafana/ui/src/components/MatchersUI/utils';
+
+import { ScalarDimensionConfig, ScalarDimensionMode, ScalarDimensionOptions } from '../types';
+
import { NumberInput } from './NumberInput';
-import { css } from '@emotion/css';
const fixedValueOption: SelectableValue = {
label: 'Fixed value',
diff --git a/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx b/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx
index 7162a82e86e..f57bd2f0fbe 100644
--- a/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx
@@ -1,14 +1,17 @@
+import { css } from '@emotion/css';
import React, { FC, useCallback, useMemo } from 'react';
+
import { GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data';
-import { ScaleDimensionConfig, ScaleDimensionOptions } from '../types';
import { InlineField, InlineFieldRow, Select, useStyles2 } from '@grafana/ui';
+
import {
useFieldDisplayNames,
useSelectOptions,
} from '../../../../../packages/grafana-ui/src/components/MatchersUI/utils';
-import { NumberInput } from './NumberInput';
-import { css } from '@emotion/css';
import { validateScaleOptions, validateScaleConfig } from '../scale';
+import { ScaleDimensionConfig, ScaleDimensionOptions } from '../types';
+
+import { NumberInput } from './NumberInput';
const fixedValueOption: SelectableValue = {
label: 'Fixed value',
diff --git a/public/app/features/dimensions/editors/TextDimensionEditor.tsx b/public/app/features/dimensions/editors/TextDimensionEditor.tsx
index 0c452fd58b8..6688bbf23ee 100644
--- a/public/app/features/dimensions/editors/TextDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/TextDimensionEditor.tsx
@@ -1,4 +1,5 @@
import React, { FC, useCallback } from 'react';
+
import {
FieldNamePickerConfigSettings,
StandardEditorProps,
@@ -7,8 +8,8 @@ import {
} from '@grafana/data';
import { Button, InlineField, InlineFieldRow, RadioButtonGroup, StringValueEditor } from '@grafana/ui';
-import { TextDimensionConfig, TextDimensionMode, TextDimensionOptions } from '../types';
import { FieldNamePicker } from '../../../../../packages/grafana-ui/src/components/MatchersUI/FieldNamePicker';
+import { TextDimensionConfig, TextDimensionMode, TextDimensionOptions } from '../types';
const textOptions = [
{ label: 'Fixed', value: TextDimensionMode.Fixed, description: 'Fixed value' },
diff --git a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx
index f7213e925fa..c680e51c66f 100644
--- a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx
+++ b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx
@@ -1,9 +1,11 @@
-import React, { ChangeEvent } from 'react';
import { mount } from 'enzyme';
+import React, { ChangeEvent } from 'react';
+
import { createTheme, ThresholdsMode } from '@grafana/data';
-import { ThresholdsEditor, Props, thresholdsWithoutKey } from './ThresholdsEditor';
import { mockThemeContext, colors } from '@grafana/ui';
+import { ThresholdsEditor, Props, thresholdsWithoutKey } from './ThresholdsEditor';
+
const setup = (propOverrides?: Partial) => {
const props: Props = {
onChange: jest.fn(),
diff --git a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx
index e79c84a0084..2e1c44a78eb 100644
--- a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx
+++ b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx
@@ -1,5 +1,7 @@
-import React, { PureComponent, ChangeEvent } from 'react';
import { css } from '@emotion/css';
+import { isNumber } from 'lodash';
+import React, { PureComponent, ChangeEvent } from 'react';
+
import {
Threshold,
sortThresholds,
@@ -8,7 +10,6 @@ import {
SelectableValue,
GrafanaTheme,
} from '@grafana/data';
-import { isNumber } from 'lodash';
import {
Input,
colors,
diff --git a/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx b/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx
index 9900698a6f9..1642c083fe1 100644
--- a/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx
+++ b/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx
@@ -1,5 +1,7 @@
import React from 'react';
+
import { FieldConfigEditorProps, ThresholdsConfig, ThresholdsMode, ThresholdsFieldConfigSettings } from '@grafana/data';
+
import { ThresholdsEditor } from './ThresholdsEditor';
export class ThresholdsValueEditor extends React.PureComponent<
diff --git a/public/app/features/dimensions/editors/URLPickerTab.tsx b/public/app/features/dimensions/editors/URLPickerTab.tsx
index ff2638fbd9e..5402d2e6112 100644
--- a/public/app/features/dimensions/editors/URLPickerTab.tsx
+++ b/public/app/features/dimensions/editors/URLPickerTab.tsx
@@ -1,11 +1,12 @@
-import React, { Dispatch, SetStateAction } from 'react';
-import { Field, Input, Label, useStyles2 } from '@grafana/ui';
-import { GrafanaTheme2 } from '@grafana/data';
import { css } from '@emotion/css';
+import React, { Dispatch, SetStateAction } from 'react';
import SVG from 'react-inlinesvg';
-import { MediaType } from '../types';
+import { GrafanaTheme2 } from '@grafana/data';
+import { Field, Input, Label, useStyles2 } from '@grafana/ui';
+
import { getPublicOrAbsoluteUrl } from '../resource';
+import { MediaType } from '../types';
interface Props {
newValue: string;
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx
index f30c5364cfd..4298ee0d84d 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx
@@ -1,10 +1,12 @@
-import React, { useCallback, useEffect, useRef } from 'react';
-import { GrafanaTheme2, MappingType, SpecialValueMatch, SelectableValue, ValueMappingResult } from '@grafana/data';
-import { Draggable } from 'react-beautiful-dnd';
import { css } from '@emotion/css';
+import React, { useCallback, useEffect, useRef } from 'react';
+import { Draggable } from 'react-beautiful-dnd';
+
+import { GrafanaTheme2, MappingType, SpecialValueMatch, SelectableValue, ValueMappingResult } from '@grafana/data';
import { useStyles2, Icon, Select, HorizontalGroup, ColorPicker, IconButton, Input, Button } from '@grafana/ui';
-import { ResourcePicker } from '../ResourcePicker';
+
import { ResourcePickerSize, ResourceFolderName, MediaType } from '../../types';
+import { ResourcePicker } from '../ResourcePicker';
export interface ValueMappingEditRowModel {
type: MappingType;
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx
index 74426b5b5a4..af45eee4069 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx
@@ -1,8 +1,10 @@
-import React from 'react';
import { render, screen } from '@testing-library/react';
-import { ValueMappingsEditor, Props } from './ValueMappingsEditor';
+import React from 'react';
+
import { MappingType } from '@grafana/data';
+import { ValueMappingsEditor, Props } from './ValueMappingsEditor';
+
const setup = (spy?: any, propOverrides?: object) => {
const props: Props = {
onChange: (mappings: any) => {
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx
index 0081440dfc6..46020d3f21d 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx
@@ -1,11 +1,14 @@
-import React, { useCallback, useMemo, useState } from 'react';
-import { GrafanaTheme2, MappingType, StandardEditorProps, ValueMapping } from '@grafana/data';
import { css } from '@emotion/css';
-import { buildEditRowModels, editModelToSaveModel, ValueMappingsEditorModal } from './ValueMappingsEditorModal';
+import React, { useCallback, useMemo, useState } from 'react';
+
+import { GrafanaTheme2, MappingType, StandardEditorProps, ValueMapping } from '@grafana/data';
import { useStyles2, VerticalGroup, Icon, ColorPicker, Button, Modal } from '@grafana/ui';
+
import { MediaType, ResourceFolderName, ResourcePickerSize } from '../../types';
import { ResourcePicker } from '../ResourcePicker';
+import { buildEditRowModels, editModelToSaveModel, ValueMappingsEditorModal } from './ValueMappingsEditorModal';
+
export interface Props extends StandardEditorProps {
showIcon?: boolean;
}
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx
index e5185c4da07..370e24f7f6b 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx
@@ -1,10 +1,12 @@
-import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
-import { ValueMappingsEditorModal, Props } from './ValueMappingsEditorModal';
+import React from 'react';
+
import { MappingType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { selectOptionInTest } from '@grafana/ui';
+import { ValueMappingsEditorModal, Props } from './ValueMappingsEditorModal';
+
const setup = (spy?: any, propOverrides?: object) => {
const props: Props = {
onClose: jest.fn(),
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx
index a8ff61d7c30..aacb26e065a 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx
@@ -1,10 +1,12 @@
-import React, { useEffect, useState } from 'react';
-import { GrafanaTheme2, MappingType, SelectableValue, SpecialValueMatch, ValueMapping } from '@grafana/data';
-import { ValueMappingEditRow, ValueMappingEditRowModel } from './ValueMappingEditRow';
-import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { css } from '@emotion/css';
+import React, { useEffect, useState } from 'react';
+import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
+
+import { GrafanaTheme2, MappingType, SelectableValue, SpecialValueMatch, ValueMapping } from '@grafana/data';
import { useStyles2, Modal, ValuePicker, Button } from '@grafana/ui';
+import { ValueMappingEditRow, ValueMappingEditRowModel } from './ValueMappingEditRow';
+
export interface Props {
value: ValueMapping[];
onChange: (valueMappings: ValueMapping[]) => void;
diff --git a/public/app/features/dimensions/resource.ts b/public/app/features/dimensions/resource.ts
index f7e0d87a1ea..d48873a5740 100644
--- a/public/app/features/dimensions/resource.ts
+++ b/public/app/features/dimensions/resource.ts
@@ -1,4 +1,5 @@
import { DataFrame } from '@grafana/data';
+
import { DimensionSupplier, ResourceDimensionConfig, ResourceDimensionMode } from './types';
import { findField, getLastNotNullFieldValue } from './utils';
diff --git a/public/app/features/dimensions/scalar.test.ts b/public/app/features/dimensions/scalar.test.ts
index 3055b2cbc59..7643d090f1f 100644
--- a/public/app/features/dimensions/scalar.test.ts
+++ b/public/app/features/dimensions/scalar.test.ts
@@ -1,7 +1,9 @@
import { ArrayVector, DataFrame, FieldType } from '@grafana/data';
-import { ScalarDimensionMode } from '.';
+
import { getScalarDimension } from './scalar';
+import { ScalarDimensionMode } from '.';
+
describe('scalar dimensions', () => {
it('handles string field', () => {
const values = ['-720', '10', '540', '90', '-210'];
diff --git a/public/app/features/dimensions/scalar.ts b/public/app/features/dimensions/scalar.ts
index f5388b61c5e..377b412e5a1 100644
--- a/public/app/features/dimensions/scalar.ts
+++ b/public/app/features/dimensions/scalar.ts
@@ -1,4 +1,5 @@
import { DataFrame, Field } from '@grafana/data';
+
import { DimensionSupplier, ScalarDimensionConfig, ScalarDimensionMode } from './types';
import { findField, getLastNotNullFieldValue } from './utils';
diff --git a/public/app/features/dimensions/scale.test.ts b/public/app/features/dimensions/scale.test.ts
index 096171babee..d10d65e5875 100644
--- a/public/app/features/dimensions/scale.test.ts
+++ b/public/app/features/dimensions/scale.test.ts
@@ -1,4 +1,5 @@
import { ArrayVector, DataFrame, FieldType } from '@grafana/data';
+
import { getScaledDimension, validateScaleConfig } from './scale';
describe('scale dimensions', () => {
diff --git a/public/app/features/dimensions/scale.ts b/public/app/features/dimensions/scale.ts
index 45c82c027a1..d3b06fec454 100644
--- a/public/app/features/dimensions/scale.ts
+++ b/public/app/features/dimensions/scale.ts
@@ -1,9 +1,12 @@
import { DataFrame, Field } from '@grafana/data';
-import { ScaleDimensionMode } from '.';
+
import { getMinMaxAndDelta } from '../../../../packages/grafana-data/src/field/scale';
+
import { ScaleDimensionConfig, DimensionSupplier, ScaleDimensionOptions } from './types';
import { findField, getLastNotNullFieldValue } from './utils';
+import { ScaleDimensionMode } from '.';
+
//---------------------------------------------------------
// Scale dimension
//---------------------------------------------------------
diff --git a/public/app/features/dimensions/text.ts b/public/app/features/dimensions/text.ts
index c77d0c3e21e..5a7db09529d 100644
--- a/public/app/features/dimensions/text.ts
+++ b/public/app/features/dimensions/text.ts
@@ -1,4 +1,5 @@
import { DataFrame, Field, FieldType, formattedValueToString } from '@grafana/data';
+
import { DimensionSupplier, TextDimensionConfig, TextDimensionMode } from './types';
import { findField, getLastNotNullFieldValue } from './utils';
diff --git a/public/app/features/dimensions/utils.ts b/public/app/features/dimensions/utils.ts
index 19bc7342d64..983356ab430 100644
--- a/public/app/features/dimensions/utils.ts
+++ b/public/app/features/dimensions/utils.ts
@@ -1,4 +1,5 @@
import { DataFrame, PanelData, Field, getFieldDisplayName, ReducerID } from '@grafana/data';
+import { config } from '@grafana/runtime';
import {
getColorDimension,
getScaledDimension,
@@ -11,7 +12,7 @@ import {
TextDimensionConfig,
ScalarDimensionConfig,
} from 'app/features/dimensions';
-import { config } from '@grafana/runtime';
+
import { getScalarDimension } from './scalar';
export function getColorDimensionFromData(
diff --git a/public/app/features/explore/AddToDashboard/AddToDashboardModal.tsx b/public/app/features/explore/AddToDashboard/AddToDashboardModal.tsx
index 161f6b57443..4d2366ce2b2 100644
--- a/public/app/features/explore/AddToDashboard/AddToDashboardModal.tsx
+++ b/public/app/features/explore/AddToDashboard/AddToDashboardModal.tsx
@@ -1,15 +1,18 @@
-import React, { useEffect, useState } from 'react';
-import { Alert, Button, Field, InputControl, Modal, RadioButtonGroup } from '@grafana/ui';
-import { locationUtil, SelectableValue } from '@grafana/data';
-import { setDashboardInLocalStorage, AddToDashboardError } from './addToDashboard';
-import { useSelector } from 'react-redux';
-import { ExploreId } from 'app/types';
-import { DashboardPicker } from 'app/core/components/Select/DashboardPicker';
-import { DeepMap, FieldError, useForm } from 'react-hook-form';
-import { config, locationService, reportInteraction } from '@grafana/runtime';
-import { getExploreItemSelector } from '../state/selectors';
import { partial } from 'lodash';
+import React, { useEffect, useState } from 'react';
+import { DeepMap, FieldError, useForm } from 'react-hook-form';
+import { useSelector } from 'react-redux';
+
+import { locationUtil, SelectableValue } from '@grafana/data';
+import { config, locationService, reportInteraction } from '@grafana/runtime';
+import { Alert, Button, Field, InputControl, Modal, RadioButtonGroup } from '@grafana/ui';
+import { DashboardPicker } from 'app/core/components/Select/DashboardPicker';
import { removeDashboardToFetchFromLocalStorage } from 'app/features/dashboard/state/initDashboard';
+import { ExploreId } from 'app/types';
+
+import { getExploreItemSelector } from '../state/selectors';
+
+import { setDashboardInLocalStorage, AddToDashboardError } from './addToDashboard';
enum SaveTarget {
NewDashboard = 'new-dashboard',
@@ -18,11 +21,11 @@ enum SaveTarget {
const SAVE_TARGETS: Array> = [
{
- label: 'New Dashboard',
+ label: 'New dashboard',
value: SaveTarget.NewDashboard,
},
{
- label: 'Existing Dashboard',
+ label: 'Existing dashboard',
value: SaveTarget.ExistingDashboard,
},
];
@@ -141,7 +144,7 @@ export const AddToDashboardModal = ({ onClose, exploreId }: Props) => {
(
-
+
)}
@@ -195,7 +198,7 @@ export const AddToDashboardModal = ({ onClose, exploreId }: Props) => {
Open in new tab
diff --git a/public/app/features/explore/AddToDashboard/addToDashboard.test.ts b/public/app/features/explore/AddToDashboard/addToDashboard.test.ts
index b81c7c9ca48..cc6f3c054b2 100644
--- a/public/app/features/explore/AddToDashboard/addToDashboard.test.ts
+++ b/public/app/features/explore/AddToDashboard/addToDashboard.test.ts
@@ -1,9 +1,11 @@
import { DataQuery, MutableDataFrame } from '@grafana/data';
-import { ExplorePanelData } from 'app/types';
-import { createEmptyQueryResponse } from '../state/utils';
-import { setDashboardInLocalStorage } from './addToDashboard';
-import * as api from 'app/features/dashboard/state/initDashboard';
import { backendSrv } from 'app/core/services/backend_srv';
+import * as api from 'app/features/dashboard/state/initDashboard';
+import { ExplorePanelData } from 'app/types';
+
+import { createEmptyQueryResponse } from '../state/utils';
+
+import { setDashboardInLocalStorage } from './addToDashboard';
describe('addPanelToDashboard', () => {
let spy: jest.SpyInstance;
diff --git a/public/app/features/explore/AddToDashboard/index.test.tsx b/public/app/features/explore/AddToDashboard/index.test.tsx
index 62db02ba6b4..a4f4275ceb3 100644
--- a/public/app/features/explore/AddToDashboard/index.test.tsx
+++ b/public/app/features/explore/AddToDashboard/index.test.tsx
@@ -1,18 +1,22 @@
-import React, { ReactNode } from 'react';
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
+import React, { ReactNode } from 'react';
+import { Provider } from 'react-redux';
+
+import { DataQuery } from '@grafana/data';
+import { locationService, setEchoSrv } from '@grafana/runtime';
+import { backendSrv } from 'app/core/services/backend_srv';
+import { Echo } from 'app/core/services/echo/Echo';
+import * as initDashboard from 'app/features/dashboard/state/initDashboard';
+import { DashboardSearchItemType } from 'app/features/search/types';
import { configureStore } from 'app/store/configureStore';
import { ExploreId, ExploreState } from 'app/types';
-import { Provider } from 'react-redux';
-import { AddToDashboard } from '.';
-import * as api from './addToDashboard';
-import { locationService, setEchoSrv } from '@grafana/runtime';
-import * as initDashboard from 'app/features/dashboard/state/initDashboard';
-import { DataQuery } from '@grafana/data';
+
import { createEmptyQueryResponse } from '../state/utils';
-import { backendSrv } from 'app/core/services/backend_srv';
-import { DashboardSearchItemType } from 'app/features/search/types';
-import { Echo } from 'app/core/services/echo/Echo';
+
+import * as api from './addToDashboard';
+
+import { AddToDashboard } from '.';
const setup = (children: ReactNode, queries: DataQuery[] = [{ refId: 'A' }]) => {
const store = configureStore({
@@ -28,7 +32,7 @@ const setup = (children: ReactNode, queries: DataQuery[] = [{ refId: 'A' }]) =>
};
const openModal = async () => {
- userEvent.click(screen.getByRole('button', { name: /add to dashboard/i }));
+ await userEvent.click(screen.getByRole('button', { name: /add to dashboard/i }));
expect(await screen.findByRole('dialog', { name: 'Add panel to dashboard' })).toBeInTheDocument();
};
@@ -44,7 +48,7 @@ describe('AddToDashboardButton', () => {
const button = await screen.findByRole('button', { name: /add to dashboard/i });
expect(button).toBeDisabled();
- userEvent.click(button);
+ await userEvent.click(button);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
@@ -71,7 +75,7 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('button', { name: /cancel/i }));
+ await userEvent.click(screen.getByRole('button', { name: /cancel/i }));
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
@@ -86,7 +90,7 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('button', { name: /open$/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open dashboard$/i }));
await waitForAddToDashboardResponse();
@@ -105,7 +109,7 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
await waitForAddToDashboardResponse();
@@ -124,7 +128,7 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
await waitForAddToDashboardResponse();
@@ -138,7 +142,7 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('button', { name: /open$/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open dashboard$/i }));
await waitForAddToDashboardResponse();
@@ -157,7 +161,7 @@ describe('AddToDashboardButton', () => {
expect(screen.queryByRole('combobox', { name: /dashboard/ })).not.toBeInTheDocument();
- userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
+ await userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
expect(screen.getByRole('combobox', { name: /dashboard/ })).toBeInTheDocument();
});
@@ -168,9 +172,9 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
+ await userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
- userEvent.click(screen.getByRole('button', { name: /open$/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open dashboard$/i }));
await waitForAddToDashboardResponse();
expect(locationService.push).not.toHaveBeenCalled();
@@ -203,16 +207,16 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
+ await userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
- userEvent.click(screen.getByRole('combobox', { name: /dashboard/i }));
+ await userEvent.click(screen.getByRole('combobox', { name: /dashboard/i }));
await waitFor(async () => {
await screen.findByLabelText('Select option');
});
- userEvent.click(screen.getByLabelText('Select option'));
+ await userEvent.click(screen.getByLabelText('Select option'));
- userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
await waitFor(async () => {
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
@@ -246,16 +250,16 @@ describe('AddToDashboardButton', () => {
await openModal();
- userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
+ await userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
- userEvent.click(screen.getByRole('combobox', { name: /dashboard/i }));
+ await userEvent.click(screen.getByRole('combobox', { name: /dashboard/i }));
await waitFor(async () => {
await screen.findByLabelText('Select option');
});
- userEvent.click(screen.getByLabelText('Select option'));
+ await userEvent.click(screen.getByLabelText('Select option'));
- userEvent.click(screen.getByRole('button', { name: /open$/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open dashboard$/i }));
await waitFor(async () => {
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
@@ -281,7 +285,7 @@ describe('AddToDashboardButton', () => {
await openModal();
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
await waitFor(async () => {
expect(await screen.findByRole('alert')).toBeInTheDocument();
@@ -300,7 +304,7 @@ describe('AddToDashboardButton', () => {
await openModal();
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
await waitFor(async () => {
expect(await screen.findByRole('alert')).toBeInTheDocument();
@@ -328,16 +332,16 @@ describe('AddToDashboardButton', () => {
await openModal();
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
+ await userEvent.click(screen.getByRole('radio', { name: /existing dashboard/i }));
- userEvent.click(screen.getByRole('combobox', { name: /dashboard/i }));
+ await userEvent.click(screen.getByRole('combobox', { name: /dashboard/i }));
await waitFor(async () => {
await screen.findByLabelText('Select option');
});
- userEvent.click(screen.getByLabelText('Select option'));
+ await userEvent.click(screen.getByLabelText('Select option'));
- userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
await waitFor(async () => {
expect(await screen.findByRole('alert')).toBeInTheDocument();
@@ -352,7 +356,7 @@ describe('AddToDashboardButton', () => {
await openModal();
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
- userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
+ await userEvent.click(screen.getByRole('button', { name: /open in new tab/i }));
await waitFor(async () => {
expect(await screen.findByRole('alert')).toBeInTheDocument();
diff --git a/public/app/features/explore/AddToDashboard/index.tsx b/public/app/features/explore/AddToDashboard/index.tsx
index 50d19c3e643..37cbd9a8697 100644
--- a/public/app/features/explore/AddToDashboard/index.tsx
+++ b/public/app/features/explore/AddToDashboard/index.tsx
@@ -1,10 +1,13 @@
import React, { useState } from 'react';
-import { ExploreId } from 'app/types';
-import { AddToDashboardModal } from './AddToDashboardModal';
-import { ToolbarButton } from '@grafana/ui';
import { useSelector } from 'react-redux';
+
+import { ToolbarButton } from '@grafana/ui';
+import { ExploreId } from 'app/types';
+
import { getExploreItemSelector } from '../state/selectors';
+import { AddToDashboardModal } from './AddToDashboardModal';
+
interface Props {
exploreId: ExploreId;
}
diff --git a/public/app/features/explore/ElapsedTime.tsx b/public/app/features/explore/ElapsedTime.tsx
index c358a0048bf..f0eea87e29a 100644
--- a/public/app/features/explore/ElapsedTime.tsx
+++ b/public/app/features/explore/ElapsedTime.tsx
@@ -1,5 +1,6 @@
import React, { FC, useState, useEffect } from 'react';
import { useInterval } from 'react-use';
+
import { Time, TimeProps } from './Time';
const INTERVAL = 150;
diff --git a/public/app/features/explore/ErrorContainer.test.tsx b/public/app/features/explore/ErrorContainer.test.tsx
index accc19c1877..a3699acc9d4 100644
--- a/public/app/features/explore/ErrorContainer.test.tsx
+++ b/public/app/features/explore/ErrorContainer.test.tsx
@@ -1,5 +1,6 @@
-import React from 'react';
import { render, screen } from '@testing-library/react';
+import React from 'react';
+
import { ErrorContainer, ErrorContainerProps } from './ErrorContainer';
describe('ErrorContainer', () => {
diff --git a/public/app/features/explore/ErrorContainer.tsx b/public/app/features/explore/ErrorContainer.tsx
index fffa9c10313..9f6d6a4a320 100644
--- a/public/app/features/explore/ErrorContainer.tsx
+++ b/public/app/features/explore/ErrorContainer.tsx
@@ -1,4 +1,5 @@
import React, { FunctionComponent } from 'react';
+
import { DataQueryError } from '@grafana/data';
import { Alert } from '@grafana/ui';
import { FadeIn } from 'app/core/components/Animations/FadeIn';
diff --git a/public/app/features/explore/Explore.test.tsx b/public/app/features/explore/Explore.test.tsx
index b9ce6c9f5f7..d1c30e4d722 100644
--- a/public/app/features/explore/Explore.test.tsx
+++ b/public/app/features/explore/Explore.test.tsx
@@ -1,12 +1,14 @@
-import React from 'react';
-import { DataSourceApi, LoadingState, CoreApp, createTheme } from '@grafana/data';
import { render, screen } from '@testing-library/react';
+import React from 'react';
+import { Provider } from 'react-redux';
+import { AutoSizerProps } from 'react-virtualized-auto-sizer';
+
+import { DataSourceApi, LoadingState, CoreApp, createTheme } from '@grafana/data';
+import { configureStore } from 'app/store/configureStore';
import { ExploreId } from 'app/types/explore';
+
import { Explore, Props } from './Explore';
import { scanStopAction } from './state/query';
-import { Provider } from 'react-redux';
-import { configureStore } from 'app/store/configureStore';
-import { AutoSizerProps } from 'react-virtualized-auto-sizer';
import { createEmptyQueryResponse } from './state/utils';
const makeEmptyQueryResponse = (loadingState: LoadingState) => {
diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx
index 38ec9457441..319d3801189 100644
--- a/public/app/features/explore/Explore.tsx
+++ b/public/app/features/explore/Explore.tsx
@@ -1,40 +1,42 @@
-import React, { createRef } from 'react';
import { css, cx } from '@emotion/css';
-import { compose } from 'redux';
+import memoizeOne from 'memoize-one';
+import React, { createRef } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
-import memoizeOne from 'memoize-one';
+import { compose } from 'redux';
+import { Unsubscribable } from 'rxjs';
+
+import { AbsoluteTimeRange, DataQuery, GrafanaTheme2, LoadingState, RawTimeRange } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Collapse, CustomScrollbar, ErrorBoundaryAlert, Themeable2, withTheme2 } from '@grafana/ui';
-import { AbsoluteTimeRange, DataQuery, GrafanaTheme2, LoadingState, RawTimeRange } from '@grafana/data';
-
-import LogsContainer from './LogsContainer';
-import { QueryRows } from './QueryRows';
-import TableContainer from './TableContainer';
-import RichHistoryContainer from './RichHistory/RichHistoryContainer';
-import ExploreQueryInspector from './ExploreQueryInspector';
-import { splitOpen } from './state/main';
-import { changeSize, changeGraphStyle } from './state/explorePane';
-import { makeAbsoluteTime, updateTimeRange } from './state/time';
-import { addQueryRow, loadLogsVolumeData, modifyQueries, scanStart, scanStopAction, setQueries } from './state/query';
-import { ExploreGraphStyle, ExploreId, ExploreItemState } from 'app/types/explore';
-import { StoreState } from 'app/types';
-import { ExploreToolbar } from './ExploreToolbar';
-import { NoDataSourceCallToAction } from './NoDataSourceCallToAction';
-import { getTimeZone } from '../profile/state/selectors';
-import { SecondaryActions } from './SecondaryActions';
import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR, FilterItem } from '@grafana/ui/src/components/Table/types';
-import { NodeGraphContainer } from './NodeGraphContainer';
-import { ResponseErrorContainer } from './ResponseErrorContainer';
-import { TraceViewContainer } from './TraceView/TraceViewContainer';
-import { ExploreGraph } from './ExploreGraph';
-import { LogsVolumePanel } from './LogsVolumePanel';
-import { ExploreGraphLabel } from './ExploreGraphLabel';
import appEvents from 'app/core/app_events';
-import { AbsoluteTimeEvent } from 'app/types/events';
-import { Unsubscribable } from 'rxjs';
import { getNodeGraphDataFrames } from 'app/plugins/panel/nodeGraph/utils';
+import { StoreState } from 'app/types';
+import { AbsoluteTimeEvent } from 'app/types/events';
+import { ExploreGraphStyle, ExploreId, ExploreItemState } from 'app/types/explore';
+
+import { getTimeZone } from '../profile/state/selectors';
+
+import { ExploreGraph } from './ExploreGraph';
+import { ExploreGraphLabel } from './ExploreGraphLabel';
+import ExploreQueryInspector from './ExploreQueryInspector';
+import { ExploreToolbar } from './ExploreToolbar';
+import LogsContainer from './LogsContainer';
+import { LogsVolumePanel } from './LogsVolumePanel';
import { NoData } from './NoData';
+import { NoDataSourceCallToAction } from './NoDataSourceCallToAction';
+import { NodeGraphContainer } from './NodeGraphContainer';
+import { QueryRows } from './QueryRows';
+import { ResponseErrorContainer } from './ResponseErrorContainer';
+import RichHistoryContainer from './RichHistory/RichHistoryContainer';
+import { SecondaryActions } from './SecondaryActions';
+import TableContainer from './TableContainer';
+import { TraceViewContainer } from './TraceView/TraceViewContainer';
+import { changeSize, changeGraphStyle } from './state/explorePane';
+import { splitOpen } from './state/main';
+import { addQueryRow, loadLogsVolumeData, modifyQueries, scanStart, scanStopAction, setQueries } from './state/query';
+import { makeAbsoluteTime, updateTimeRange } from './state/time';
const getStyles = (theme: GrafanaTheme2) => {
return {
diff --git a/public/app/features/explore/ExploreActions.tsx b/public/app/features/explore/ExploreActions.tsx
new file mode 100644
index 00000000000..95b038d4f0e
--- /dev/null
+++ b/public/app/features/explore/ExploreActions.tsx
@@ -0,0 +1,96 @@
+import { useRegisterActions, useKBar, Action, Priority } from 'kbar';
+import { FC, useEffect, useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+
+import { ExploreId } from 'app/types';
+
+import { splitOpen, splitClose } from './state/main';
+import { runQueries } from './state/query';
+import { isSplit } from './state/selectors';
+
+interface Props {
+ exploreIdLeft: ExploreId;
+ exploreIdRight?: ExploreId;
+}
+
+export const ExploreActions: FC = ({ exploreIdLeft, exploreIdRight }: Props) => {
+ const [actions, setActions] = useState([]);
+ const { query } = useKBar();
+ const dispatch = useDispatch();
+ const splitted = useSelector(isSplit);
+
+ useEffect(() => {
+ const exploreSection = {
+ name: 'Explore',
+ priority: Priority.HIGH + 1,
+ };
+
+ const actionsArr: Action[] = [];
+
+ if (splitted) {
+ actionsArr.push({
+ id: 'explore/run-query-left',
+ name: 'Run Query (Left)',
+ keywords: 'query left',
+ perform: () => {
+ dispatch(runQueries(exploreIdLeft));
+ },
+ section: exploreSection,
+ });
+ if (exploreIdRight) {
+ // we should always have the right exploreId if split
+ actionsArr.push({
+ id: 'explore/run-query-right',
+ name: 'Run Query (Right)',
+ keywords: 'query right',
+ perform: () => {
+ dispatch(runQueries(exploreIdRight));
+ },
+ section: exploreSection,
+ });
+ actionsArr.push({
+ id: 'explore/split-view-close-left',
+ name: 'Close split view left',
+ keywords: 'split',
+ perform: () => {
+ dispatch(splitClose(exploreIdLeft));
+ },
+ section: exploreSection,
+ });
+ actionsArr.push({
+ id: 'explore/split-view-close-right',
+ name: 'Close split view right',
+ keywords: 'split',
+ perform: () => {
+ dispatch(splitClose(exploreIdRight));
+ },
+ section: exploreSection,
+ });
+ }
+ } else {
+ actionsArr.push({
+ id: 'explore/run-query',
+ name: 'Run Query',
+ keywords: 'query',
+ perform: () => {
+ dispatch(runQueries(exploreIdLeft));
+ },
+ section: exploreSection,
+ });
+ actionsArr.push({
+ id: 'explore/split-view-open',
+ name: 'Open split view',
+ keywords: 'split',
+ perform: () => {
+ dispatch(splitOpen());
+ },
+ section: exploreSection,
+ });
+ }
+ setActions(actionsArr);
+ }, [exploreIdLeft, exploreIdRight, splitted, query, dispatch]);
+
+ useRegisterActions(!query ? [] : actions, [actions, query]);
+
+ return null;
+};
diff --git a/public/app/features/explore/ExploreDrawer.tsx b/public/app/features/explore/ExploreDrawer.tsx
index 222feef2dac..10fa3489d5e 100644
--- a/public/app/features/explore/ExploreDrawer.tsx
+++ b/public/app/features/explore/ExploreDrawer.tsx
@@ -1,17 +1,17 @@
// Libraries
-import React from 'react';
-import { Resizable, ResizeCallback } from 're-resizable';
import { css, cx, keyframes } from '@emotion/css';
+import { Resizable, ResizeCallback } from 're-resizable';
+import React from 'react';
// Services & Utils
+import { GrafanaTheme2 } from '@grafana/data';
import { stylesFactory, useTheme2 } from '@grafana/ui';
// Types
-import { GrafanaTheme2 } from '@grafana/data';
-const drawerSlide = keyframes`
+const drawerSlide = (theme: GrafanaTheme2) => keyframes`
0% {
- transform: translateY(400px);
+ transform: translateY(${theme.components.horizontalDrawer.defaultHeight}px);
}
100% {
@@ -32,7 +32,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => {
`,
drawerActive: css`
opacity: 1;
- animation: 0.5s ease-out ${drawerSlide};
+ animation: 0.5s ease-out ${drawerSlide(theme)};
`,
rzHandle: css`
background: ${theme.colors.secondary.main};
@@ -66,7 +66,7 @@ export function ExploreDrawer(props: Props) {
return (
|