mirror of
https://github.com/grafana/grafana.git
synced 2024-12-26 00:41:20 -06:00
e2e: adds e2e for panel edit (#23849)
* Explore: Create basic E2E test * Feature: adds e2e tests for panel inspector * Refactor: adds ts-ignore because of type checking errors * Refactor: changes after PR comments and updates snapshot * Refactor: adds typings back for IScope * e2e: adds e2e for panel edit Co-authored-by: Andreas Opferkuch <andreas.opferkuch@gmail.com>
This commit is contained in:
parent
cf77c3a50b
commit
80ab18f43d
143
e2e/suite1/specs/panel-edit.spec.ts
Normal file
143
e2e/suite1/specs/panel-edit.spec.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
const PANEL_UNDER_TEST = 'Random walk series';
|
||||
|
||||
e2e.scenario({
|
||||
describeName: 'Panel edit tests',
|
||||
itName: 'Testes various Panel edit scenarios',
|
||||
addScenarioDataSource: false,
|
||||
addScenarioDashBoard: false,
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
e2e.flows.openDashboard('5SdHCadmz');
|
||||
|
||||
e2e.flows.openPanelMenuItem(e2e.flows.PanelMenuItems.Edit, PANEL_UNDER_TEST);
|
||||
|
||||
// New panel editor opens when navigating from Panel menu
|
||||
e2e.components.PanelEditor.General.content().should('be.visible');
|
||||
|
||||
// Queries tab is rendered and open by default
|
||||
e2e.components.PanelEditor.DataPane.content()
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e.components.Tab.title('Query').should('be.visible');
|
||||
// data should be the active tab
|
||||
e2e.components.Tab.active().within((li: JQuery<HTMLLIElement>) => {
|
||||
expect(li.text()).equals('Query1'); // there's already a query so therefore Query + 1
|
||||
});
|
||||
e2e.components.QueryTab.content().should('be.visible');
|
||||
e2e.components.TransformTab.content().should('not.be.visible');
|
||||
e2e.components.AlertTab.content().should('not.be.visible');
|
||||
|
||||
// Bottom pane tabs
|
||||
// Can change to Transform tab
|
||||
e2e.components.Tab.title('Transform')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
e2e.components.Tab.active().within((li: JQuery<HTMLLIElement>) => {
|
||||
expect(li.text()).equals('Transform0'); // there's no transform so therefore Transform + 0
|
||||
});
|
||||
e2e.components.TransformTab.content().should('be.visible');
|
||||
e2e.components.QueryTab.content().should('not.be.visible');
|
||||
e2e.components.AlertTab.content().should('not.be.visible');
|
||||
|
||||
// Can change to Alerts tab (graph panel is the default vis so the alerts tab should be rendered)
|
||||
e2e.components.Tab.title('Alert')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
e2e.components.Tab.active().within((li: JQuery<HTMLLIElement>) => {
|
||||
expect(li.text()).equals('Alert0'); // there's no alert so therefore Alert + 0
|
||||
});
|
||||
e2e.components.AlertTab.content().should('be.visible');
|
||||
e2e.components.QueryTab.content().should('not.be.visible');
|
||||
e2e.components.TransformTab.content().should('not.be.visible');
|
||||
|
||||
e2e.components.Tab.title('Query')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
});
|
||||
|
||||
// Panel sidebar is rendered open by default
|
||||
e2e.components.PanelEditor.OptionsPane.content().should('be.visible');
|
||||
|
||||
// Can toggle on/off sidebar
|
||||
e2e.components.PanelEditor.OptionsPane.close().should('be.visible');
|
||||
e2e.components.PanelEditor.OptionsPane.open().should('not.be.visible');
|
||||
|
||||
// close options pane
|
||||
e2e.components.PanelEditor.OptionsPane.close().click();
|
||||
e2e.components.PanelEditor.OptionsPane.open().should('be.visible');
|
||||
e2e.components.PanelEditor.OptionsPane.close().should('not.be.visible');
|
||||
e2e.components.PanelEditor.OptionsPane.content().should('not.be.visible');
|
||||
|
||||
// open options pane
|
||||
e2e.components.PanelEditor.OptionsPane.open().click();
|
||||
e2e.components.PanelEditor.OptionsPane.close().should('be.visible');
|
||||
e2e.components.PanelEditor.OptionsPane.open().should('not.be.visible');
|
||||
e2e.components.PanelEditor.OptionsPane.content().should('be.visible');
|
||||
|
||||
// Can change visualisation type
|
||||
e2e.components.OptionsGroup.toggle('Panel type')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
|
||||
// Check that Graph is chosen
|
||||
e2e.components.PluginVisualization.item('Graph').should('be.visible');
|
||||
e2e.components.PluginVisualization.current().within((div: JQuery<HTMLDivElement>) => {
|
||||
expect(div.text()).equals('Graph');
|
||||
});
|
||||
|
||||
// Change to Text panel
|
||||
e2e.components.PluginVisualization.item('Text')
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
e2e.components.PluginVisualization.current().within((div: JQuery<HTMLDivElement>) => {
|
||||
expect(div.text()).equals('Text');
|
||||
});
|
||||
|
||||
// Data pane should not be rendered
|
||||
e2e.components.PanelEditor.DataPane.content().should('not.be.visible');
|
||||
|
||||
// Change to Table panel
|
||||
e2e.components.PluginVisualization.item('Table')
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
e2e.components.PluginVisualization.current().within((div: JQuery<HTMLDivElement>) => {
|
||||
expect(div.text()).equals('Table');
|
||||
});
|
||||
|
||||
// Data pane should be rendered
|
||||
e2e.components.PanelEditor.DataPane.content().should('be.visible');
|
||||
|
||||
// Field & Overrides tabs (need to switch to React based vis, i.e. Table)
|
||||
e2e.components.PanelEditor.OptionsPane.select()
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.within(() => {
|
||||
// Can change to Fields tab
|
||||
e2e.components.Select.option()
|
||||
.should('be.visible')
|
||||
.eq(1)
|
||||
.click();
|
||||
});
|
||||
|
||||
e2e.components.FieldConfigEditor.content().should('be.visible');
|
||||
e2e.components.OverridesConfigEditor.content().should('not.be.visible');
|
||||
|
||||
e2e.components.PanelEditor.OptionsPane.select()
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.within(() => {
|
||||
// Can change to Overrides tab
|
||||
e2e.components.Select.option()
|
||||
.should('be.visible')
|
||||
.eq(2)
|
||||
.click();
|
||||
});
|
||||
|
||||
e2e.components.OverridesConfigEditor.content().should('be.visible');
|
||||
e2e.components.FieldConfigEditor.content().should('not.be.visible');
|
||||
},
|
||||
});
|
@ -1,8 +1,8 @@
|
||||
import { TestData } from '../pages/testdata';
|
||||
import { Panel } from '../pages/panel';
|
||||
import { EditPanel } from '../pages/editPanel';
|
||||
import { Graph } from '../pages/graph';
|
||||
import { componentFactory } from '../support';
|
||||
import { Dashboard } from '../pages/dashboard';
|
||||
|
||||
export const Components = {
|
||||
DataSource: {
|
||||
@ -10,7 +10,6 @@ export const Components = {
|
||||
},
|
||||
Panels: {
|
||||
Panel,
|
||||
EditPanel,
|
||||
Visualization: {
|
||||
Graph,
|
||||
},
|
||||
@ -26,6 +25,27 @@ export const Components = {
|
||||
},
|
||||
}),
|
||||
},
|
||||
PanelEditor: {
|
||||
General: componentFactory({
|
||||
selectors: {
|
||||
content: 'Panel editor content',
|
||||
},
|
||||
}),
|
||||
OptionsPane: componentFactory({
|
||||
selectors: {
|
||||
content: 'Panel editor option pane content',
|
||||
close: Dashboard.selectors.toolbarItems('Close options pane'),
|
||||
open: Dashboard.selectors.toolbarItems('Open options pane'),
|
||||
select: 'Panel editor option pane select',
|
||||
},
|
||||
}),
|
||||
// not sure about the naming *DataPane*
|
||||
DataPane: componentFactory({
|
||||
selectors: {
|
||||
content: 'Panel editor data pane content',
|
||||
},
|
||||
}),
|
||||
},
|
||||
PanelInspector: {
|
||||
Data: componentFactory({
|
||||
selectors: {
|
||||
@ -54,6 +74,21 @@ export const Components = {
|
||||
active: () => '[class*="-activeTabStyle"]',
|
||||
},
|
||||
}),
|
||||
QueryTab: componentFactory({
|
||||
selectors: {
|
||||
content: 'Query editor tab content',
|
||||
},
|
||||
}),
|
||||
AlertTab: componentFactory({
|
||||
selectors: {
|
||||
content: 'Alert editor tab content',
|
||||
},
|
||||
}),
|
||||
TransformTab: componentFactory({
|
||||
selectors: {
|
||||
content: 'Transform editor tab content',
|
||||
},
|
||||
}),
|
||||
QueryEditorToolbarItem: componentFactory({
|
||||
selectors: {
|
||||
button: (title: string) => `QueryEditor toolbar item button ${title}`,
|
||||
@ -64,4 +99,30 @@ export const Components = {
|
||||
backArrow: 'Go Back button',
|
||||
},
|
||||
}),
|
||||
OptionsGroup: componentFactory({
|
||||
selectors: {
|
||||
toggle: (title: string) => `Options group ${title}`,
|
||||
},
|
||||
}),
|
||||
PluginVisualization: componentFactory({
|
||||
selectors: {
|
||||
item: (title: string) => `Plugin visualization item ${title}`,
|
||||
current: () => '[class*="-currentVisualizationItem"]',
|
||||
},
|
||||
}),
|
||||
Select: componentFactory({
|
||||
selectors: {
|
||||
option: 'Select option',
|
||||
},
|
||||
}),
|
||||
FieldConfigEditor: componentFactory({
|
||||
selectors: {
|
||||
content: 'Field config editor content',
|
||||
},
|
||||
}),
|
||||
OverridesConfigEditor: componentFactory({
|
||||
selectors: {
|
||||
content: 'Field overrides editor content',
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
@ -1,8 +0,0 @@
|
||||
import { pageFactory } from '../support';
|
||||
|
||||
export const EditPanel = pageFactory({
|
||||
url: '',
|
||||
selectors: {
|
||||
tabItems: (text: string) => `Edit panel tab item ${text}`,
|
||||
},
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import { css } from 'emotion';
|
||||
import { Alert, Button, IconName } from '@grafana/ui';
|
||||
|
||||
@ -15,10 +15,10 @@ import 'app/features/alerting/AlertTabCtrl';
|
||||
import { DashboardModel } from '../dashboard/state/DashboardModel';
|
||||
import { PanelModel } from '../dashboard/state/PanelModel';
|
||||
import { TestRuleResult } from './TestRuleResult';
|
||||
import { AppNotificationSeverity, StoreState } from 'app/types';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { AppNotificationSeverity, CoreEvents, StoreState } from 'app/types';
|
||||
import { updateLocation } from 'app/core/actions';
|
||||
import { PanelEditorTabId } from '../dashboard/components/PanelEditor/types';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface OwnProps {
|
||||
dashboard: DashboardModel;
|
||||
@ -206,7 +206,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
|
||||
|
||||
return (
|
||||
<EditorTabBody heading="Alert" toolbarItems={toolbarItems}>
|
||||
<>
|
||||
<div aria-label={e2e.components.AlertTab.selectors.content}>
|
||||
{alert && hasTransformations && (
|
||||
<Alert
|
||||
severity={AppNotificationSeverity.Error}
|
||||
@ -216,7 +216,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
|
||||
|
||||
<div ref={element => (this.element = element)} />
|
||||
{!alert && !validatonMessage && <EmptyListCTA {...model} />}
|
||||
</>
|
||||
</div>
|
||||
</EditorTabBody>
|
||||
);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import { getDataLinksVariableSuggestions } from '../../../panel/panellinks/link_
|
||||
import { OverrideEditor } from './OverrideEditor';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import { OptionsGroup } from './OptionsGroup';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface Props {
|
||||
plugin: PanelPlugin;
|
||||
@ -102,7 +103,7 @@ export const OverrideFieldConfigEditor: React.FC<Props> = props => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div aria-label={e2e.components.OverridesConfigEditor.selectors.content}>
|
||||
{renderOverrides()}
|
||||
{renderAddOverride()}
|
||||
</div>
|
||||
@ -182,7 +183,7 @@ export const DefaultFieldConfigEditor: React.FC<Props> = ({ data, onChange, conf
|
||||
const groupedConfigs = groupBy(plugin.fieldConfigRegistry.list(), i => i.category && i.category[0]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div aria-label={e2e.components.FieldConfigEditor.selectors.content}>
|
||||
{Object.keys(groupedConfigs).map((k, i) => {
|
||||
const groupItemsCounter = countGroupItems(groupedConfigs[k], config);
|
||||
|
||||
@ -204,7 +205,7 @@ export const DefaultFieldConfigEditor: React.FC<Props> = ({ data, onChange, conf
|
||||
</OptionsGroup>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { GrafanaTheme } from '@grafana/data';
|
||||
import { Icon, stylesFactory, useTheme } from '@grafana/ui';
|
||||
import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
export interface OptionsGroupProps {
|
||||
id: string;
|
||||
@ -46,6 +47,7 @@ export const OptionsGroup: FC<OptionsGroupProps> = ({
|
||||
|
||||
return (
|
||||
<CollapsibleSection
|
||||
id={id}
|
||||
defaultToClosed={defaultToClosed}
|
||||
className={className}
|
||||
nested={nested}
|
||||
@ -75,7 +77,8 @@ const CollapsibleSectionWithPersistence: FC<OptionsGroupProps> = memo(props => {
|
||||
return <CollapsibleSection {...props} defaultToClosed={value.defaultToClosed} onToggle={onToggle} />;
|
||||
});
|
||||
|
||||
const CollapsibleSection: FC<Omit<OptionsGroupProps, 'id' | 'persistMe'>> = ({
|
||||
const CollapsibleSection: FC<Omit<OptionsGroupProps, 'persistMe'>> = ({
|
||||
id,
|
||||
title,
|
||||
children,
|
||||
defaultToClosed,
|
||||
@ -95,7 +98,11 @@ const CollapsibleSection: FC<Omit<OptionsGroupProps, 'id' | 'persistMe'>> = ({
|
||||
|
||||
return (
|
||||
<div className={cx(styles.box, className, 'options-group')}>
|
||||
<div className={styles.header} onClick={() => toggleExpand(!isExpanded)}>
|
||||
<div
|
||||
className={styles.header}
|
||||
onClick={() => toggleExpand(!isExpanded)}
|
||||
aria-label={e2e.components.OptionsGroup.selectors.toggle(id)}
|
||||
>
|
||||
<div className={cx(styles.toggle, 'editor-options-group-toggle')}>
|
||||
<Icon name={isExpanded ? 'angle-down' : 'angle-right'} />
|
||||
</div>
|
||||
|
@ -1,13 +1,14 @@
|
||||
import React, { useCallback, useState, CSSProperties } from 'react';
|
||||
import React, { CSSProperties, useCallback, useState } from 'react';
|
||||
import Transition from 'react-transition-group/Transition';
|
||||
import { FieldConfigSource, GrafanaTheme, PanelPlugin, SelectableValue } from '@grafana/data';
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { CustomScrollbar, stylesFactory, Tab, TabContent, TabsBar, Select, useTheme, Icon, Input } from '@grafana/ui';
|
||||
import { CustomScrollbar, Icon, Input, Select, stylesFactory, Tab, TabContent, TabsBar, useTheme } from '@grafana/ui';
|
||||
import { DefaultFieldConfigEditor, OverrideFieldConfigEditor } from './FieldConfigEditor';
|
||||
import { css } from 'emotion';
|
||||
import { PanelOptionsTab } from './PanelOptionsTab';
|
||||
import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNavButton';
|
||||
import { usePanelLatestData } from './usePanelLatestData';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface Props {
|
||||
plugin: PanelPlugin;
|
||||
@ -80,7 +81,7 @@ export const OptionsPaneContent: React.FC<Props> = ({
|
||||
const showMainTab = activeTab === 'options' || plugin.meta.skipDataQuery;
|
||||
|
||||
return (
|
||||
<div className={styles.panelOptionsPane}>
|
||||
<div className={styles.panelOptionsPane} aria-label={e2e.components.PanelEditor.OptionsPane.selectors.content}>
|
||||
{plugin && (
|
||||
<div className={styles.wrapper}>
|
||||
<TabsBar className={styles.tabsBar}>
|
||||
@ -184,7 +185,7 @@ export const TabsBarContent: React.FC<{
|
||||
return (
|
||||
<>
|
||||
{width < 352 ? (
|
||||
<div className="flex-grow-1">
|
||||
<div className="flex-grow-1" aria-label={e2e.components.PanelEditor.OptionsPane.selectors.select}>
|
||||
<Select
|
||||
options={tabs}
|
||||
value={active}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { FieldConfigSource, GrafanaTheme, PanelData, PanelPlugin } from '@grafana/data';
|
||||
import { Button, stylesFactory, Icon, RadioButtonGroup } from '@grafana/ui';
|
||||
import { Button, Icon, RadioButtonGroup, stylesFactory } from '@grafana/ui';
|
||||
import { css, cx } from 'emotion';
|
||||
import config from 'app/core/config';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
@ -17,7 +17,7 @@ import { Unsubscribable } from 'rxjs';
|
||||
import { DisplayMode, displayModes, PanelEditorTab } from './types';
|
||||
import { PanelEditorTabs } from './PanelEditorTabs';
|
||||
import { DashNavTimeControls } from '../DashNav/DashNavTimeControls';
|
||||
import { LocationState, CoreEvents } from 'app/types';
|
||||
import { CoreEvents, LocationState } from 'app/types';
|
||||
import { calculatePanelSize } from './utils';
|
||||
import { initPanelEditor, panelEditorCleanUp, updatePanelEditorUIState } from './state/actions';
|
||||
import { PanelEditorUIState, setDiscardChanges } from './state/reducers';
|
||||
@ -31,6 +31,7 @@ import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuI
|
||||
import { BackButton } from 'app/core/components/BackButton/BackButton';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { SaveDashboardModalProxy } from '../SaveDashboard/SaveDashboardModalProxy';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface OwnProps {
|
||||
dashboard: DashboardModel;
|
||||
@ -196,7 +197,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
||||
onDragFinished={size => this.onDragFinished(Pane.Top, size)}
|
||||
>
|
||||
{this.renderPanel(styles)}
|
||||
<div className={styles.tabsWrapper}>
|
||||
<div className={styles.tabsWrapper} aria-label={e2e.components.PanelEditor.DataPane.selectors.content}>
|
||||
<PanelEditorTabs panel={panel} dashboard={dashboard} tabs={tabs} onChangeTab={this.onChangeTab} data={data} />
|
||||
</div>
|
||||
</SplitPane>
|
||||
@ -331,7 +332,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<div className={styles.wrapper} aria-label={e2e.components.PanelEditor.General.selectors.content}>
|
||||
{this.editorToolbar(styles)}
|
||||
<div className={styles.verticalSplitPanesWrapper}>
|
||||
{uiState.isPanelOptionsVisible ? this.renderWithOptionsPane(styles) : this.renderHorizontalSplit(styles)}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Container, CustomScrollbar, ValuePicker, Button, useTheme, VerticalGroup, stylesFactory } from '@grafana/ui';
|
||||
import { Button, Container, CustomScrollbar, stylesFactory, useTheme, ValuePicker, VerticalGroup } from '@grafana/ui';
|
||||
import {
|
||||
DataFrame,
|
||||
DataTransformerConfig,
|
||||
@ -11,6 +11,7 @@ import {
|
||||
import { TransformationOperationRow } from './TransformationOperationRow';
|
||||
import { Card, CardProps } from '../../../../core/components/Card/Card';
|
||||
import { css } from 'emotion';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface Props {
|
||||
onChange: (transformations: DataTransformerConfig[]) => void;
|
||||
@ -143,9 +144,11 @@ export class TransformationsEditor extends React.PureComponent<Props> {
|
||||
return (
|
||||
<CustomScrollbar autoHeightMin="100%">
|
||||
<Container padding="md">
|
||||
{!hasTransformationsConfigured && this.renderNoAddedTransformsState()}
|
||||
{hasTransformationsConfigured && this.renderTransformationEditors()}
|
||||
{hasTransformationsConfigured && this.renderTransformationSelector()}
|
||||
<div aria-label={e2e.components.TransformTab.selectors.content}>
|
||||
{!hasTransformationsConfigured && this.renderNoAddedTransformsState()}
|
||||
{hasTransformationsConfigured && this.renderTransformationEditors()}
|
||||
{hasTransformationsConfigured && this.renderTransformationSelector()}
|
||||
</div>
|
||||
</Container>
|
||||
</CustomScrollbar>
|
||||
);
|
||||
|
@ -1,6 +1,5 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
import _ from 'lodash';
|
||||
// Components
|
||||
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
||||
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
||||
@ -15,12 +14,13 @@ import config from 'app/core/config';
|
||||
// Types
|
||||
import { PanelModel } from '../state/PanelModel';
|
||||
import { DashboardModel } from '../state/DashboardModel';
|
||||
import { LoadingState, DefaultTimeRange, DataSourceSelectItem, DataQuery, PanelData } from '@grafana/data';
|
||||
import { DataQuery, DataSourceSelectItem, DefaultTimeRange, LoadingState, PanelData } from '@grafana/data';
|
||||
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
|
||||
import { addQuery } from 'app/core/utils/query';
|
||||
import { Unsubscribable } from 'rxjs';
|
||||
import { isSharedDashboardQuery, DashboardQueryEditor } from 'app/plugins/datasource/dashboard';
|
||||
import { DashboardQueryEditor, isSharedDashboardQuery } from 'app/plugins/datasource/dashboard';
|
||||
import { expressionDatasource, ExpressionDatasourceID } from 'app/features/expressions/ExpressionDatasource';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface Props {
|
||||
panel: PanelModel;
|
||||
@ -227,7 +227,7 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div aria-label={e2e.components.QueryTab.selectors.content}>
|
||||
<QueryEditorRows
|
||||
queries={panel.targets}
|
||||
datasource={currentDS}
|
||||
@ -240,7 +240,7 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
<PanelOptionsGroup>
|
||||
<QueryOptions panel={panel} datasource={currentDS} />
|
||||
</PanelOptionsGroup>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { GrafanaTheme, PanelPluginMeta } from '@grafana/data';
|
||||
import { stylesFactory, useTheme } from '@grafana/ui';
|
||||
import { css, cx } from 'emotion';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface Props {
|
||||
isCurrent: boolean;
|
||||
@ -20,7 +21,12 @@ const VizTypePickerPlugin: React.FC<Props> = ({ isCurrent, plugin, onClick, disa
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={cssClass} onClick={disabled ? () => {} : onClick} title={plugin.name}>
|
||||
<div
|
||||
className={cssClass}
|
||||
onClick={disabled ? () => {} : onClick}
|
||||
title={plugin.name}
|
||||
aria-label={e2e.components.PluginVisualization.selectors.item(plugin.name)}
|
||||
>
|
||||
<div className={styles.name}>{plugin.name}</div>
|
||||
<img className={styles.img} src={plugin.info.logos.small} />
|
||||
</div>
|
||||
@ -52,6 +58,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
}
|
||||
`,
|
||||
current: css`
|
||||
label: currentVisualizationItem;
|
||||
box-shadow: 0 0 6px ${theme.palette.orange} !important;
|
||||
border: 1px solid ${theme.palette.orange} !important;
|
||||
`,
|
||||
|
Loading…
Reference in New Issue
Block a user