mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
e2e: Migrates query variable CRUD tests to new framework (#21146)
* Refactor: Adds params to visit * Refactor: Restructures exported Pages somewhat * Refactor: Moves more into new framework but holdup because of bugs in digest * Refactor: Finish migrating templating e2e tests to new framework * Refactor: Changes after merge with master * Refactor: Removes weird change * Refactor: Adds duplication test * Refactor: Adds move down and move up variable asserts * Refactor: Adds some test to value select dropdown
This commit is contained in:
parent
331bc173cc
commit
841cffbe9a
@ -1,7 +1,7 @@
|
|||||||
import { e2e } from '../index';
|
import { e2e } from '../index';
|
||||||
|
|
||||||
export const saveDashboard = () => {
|
export const saveDashboard = () => {
|
||||||
e2e.pages.Dashboard.toolbarItems('Save dashboard').click();
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click();
|
||||||
|
|
||||||
e2e.pages.SaveDashboardModal.save().click();
|
e2e.pages.SaveDashboardModal.save().click();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { e2e } from '../index';
|
import { e2e } from '../index';
|
||||||
|
|
||||||
export const saveNewDashboard = () => {
|
export const saveNewDashboard = () => {
|
||||||
e2e.pages.Dashboard.toolbarItems('Save dashboard').click();
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click();
|
||||||
|
|
||||||
const dashboardTitle = `e2e-${new Date().getTime()}`;
|
const dashboardTitle = `e2e-${new Date().getTime()}`;
|
||||||
e2e.pages.SaveDashboardAsModal.newName().clear();
|
e2e.pages.SaveDashboardAsModal.newName().clear();
|
||||||
|
@ -8,9 +8,9 @@ import { Pages } from './pages';
|
|||||||
import { Flows } from './flows';
|
import { Flows } from './flows';
|
||||||
import { scenarioContext } from './support/scenarioContext';
|
import { scenarioContext } from './support/scenarioContext';
|
||||||
|
|
||||||
export type SelectorFunction = (text?: string) => Cypress.Chainable<any>;
|
export type SelectorFunction = (text?: string) => Cypress.Chainable<JQuery<HTMLElement>>;
|
||||||
export type SelectorObject<S> = {
|
export type SelectorObject<S> = {
|
||||||
visit: (args?: string) => Cypress.Chainable<any>;
|
visit: (args?: string) => Cypress.Chainable<Window>;
|
||||||
selectors: S;
|
selectors: S;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,5 +5,6 @@ export const Dashboard = pageFactory({
|
|||||||
selectors: {
|
selectors: {
|
||||||
toolbarItems: (button: string) => `Dashboard navigation bar button ${button}`,
|
toolbarItems: (button: string) => `Dashboard navigation bar button ${button}`,
|
||||||
backArrow: 'Dashboard settings Go Back button',
|
backArrow: 'Dashboard settings Go Back button',
|
||||||
|
navBar: () => '.navbar',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,7 @@ export const DashboardSettings = pageFactory({
|
|||||||
url: '',
|
url: '',
|
||||||
selectors: {
|
selectors: {
|
||||||
deleteDashBoard: 'Dashboard settings page delete dashboard button',
|
deleteDashBoard: 'Dashboard settings page delete dashboard button',
|
||||||
sectionItems: 'Dashboard settings section item',
|
sectionItems: (item: string) => `Dashboard settings section item ${item}`,
|
||||||
saveDashBoard: 'Dashboard settings aside actions Save button',
|
saveDashBoard: 'Dashboard settings aside actions Save button',
|
||||||
saveAsDashBoard: 'Dashboard settings aside actions Save As button',
|
saveAsDashBoard: 'Dashboard settings aside actions Save As button',
|
||||||
},
|
},
|
||||||
|
@ -14,6 +14,7 @@ import { Graph } from './graph';
|
|||||||
import { SaveDashboardModal } from './saveDashboardModal';
|
import { SaveDashboardModal } from './saveDashboardModal';
|
||||||
import { Panel } from './panel';
|
import { Panel } from './panel';
|
||||||
import { SharePanelModal } from './sharePanelModal';
|
import { SharePanelModal } from './sharePanelModal';
|
||||||
|
import { ConstantVariable, QueryVariable, VariableGeneral, Variables, VariablesSubMenu } from './variables';
|
||||||
|
|
||||||
export const Pages = {
|
export const Pages = {
|
||||||
Login,
|
Login,
|
||||||
@ -22,20 +23,34 @@ export const Pages = {
|
|||||||
AddDataSource,
|
AddDataSource,
|
||||||
ConfirmModal,
|
ConfirmModal,
|
||||||
AddDashboard,
|
AddDashboard,
|
||||||
Dashboard,
|
Dashboard: {
|
||||||
|
visit: (uid: string) => Dashboard.visit(uid),
|
||||||
|
Toolbar: Dashboard,
|
||||||
|
SubMenu: VariablesSubMenu,
|
||||||
|
Settings: {
|
||||||
|
General: DashboardSettings,
|
||||||
|
Variables: {
|
||||||
|
List: Variables,
|
||||||
|
Edit: {
|
||||||
|
General: VariableGeneral,
|
||||||
|
QueryVariable: QueryVariable,
|
||||||
|
ConstantVariable: ConstantVariable,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Panels: {
|
||||||
|
Panel,
|
||||||
|
EditPanel,
|
||||||
|
DataSource: {
|
||||||
|
TestData,
|
||||||
|
},
|
||||||
|
Visualization: {
|
||||||
|
Graph,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
Dashboards,
|
Dashboards,
|
||||||
SaveDashboardAsModal,
|
SaveDashboardAsModal,
|
||||||
SaveDashboardModal,
|
SaveDashboardModal,
|
||||||
DashboardSettings,
|
|
||||||
SharePanelModal,
|
SharePanelModal,
|
||||||
Panels: {
|
|
||||||
Panel,
|
|
||||||
EditPanel,
|
|
||||||
DataSource: {
|
|
||||||
TestData,
|
|
||||||
},
|
|
||||||
Visualization: {
|
|
||||||
Graph,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
69
packages/grafana-e2e/src/pages/variables.ts
Normal file
69
packages/grafana-e2e/src/pages/variables.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { pageFactory } from '../support';
|
||||||
|
|
||||||
|
export const Variables = pageFactory({
|
||||||
|
url: '',
|
||||||
|
selectors: {
|
||||||
|
addVariableCTA: 'Call to action button Add variable',
|
||||||
|
newButton: 'Variable editor New variable button',
|
||||||
|
table: 'Variable editor Table',
|
||||||
|
tableRowNameFields: (variableName: string) => `Variable editor Table Name field ${variableName}`,
|
||||||
|
tableRowDefinitionFields: (variableName: string) => `Variable editor Table Definition field ${variableName}`,
|
||||||
|
tableRowArrowUpButtons: (variableName: string) => `Variable editor Table ArrowUp button ${variableName}`,
|
||||||
|
tableRowArrowDownButtons: (variableName: string) => `Variable editor Table ArrowDown button ${variableName}`,
|
||||||
|
tableRowDuplicateButtons: (variableName: string) => `Variable editor Table Duplicate button ${variableName}`,
|
||||||
|
tableRowRemoveButtons: (variableName: string) => `Variable editor Table Remove button ${variableName}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const VariablesSubMenu = pageFactory({
|
||||||
|
url: '',
|
||||||
|
selectors: {
|
||||||
|
submenuItem: 'Dashboard template variables submenu item',
|
||||||
|
submenuItemLabels: (item: string) => `Dashboard template variables submenu Label ${item}`,
|
||||||
|
submenuItemValueDropDownValueLinkTexts: (item: string) =>
|
||||||
|
`Dashboard template variables Variable Value DropDown value link text ${item}`,
|
||||||
|
submenuItemValueDropDownDropDown: 'Dashboard template variables Variable Value DropDown DropDown',
|
||||||
|
submenuItemValueDropDownOptionTexts: (item: string) =>
|
||||||
|
`Dashboard template variables Variable Value DropDown option text ${item}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const VariableGeneral = pageFactory({
|
||||||
|
url: '',
|
||||||
|
selectors: {
|
||||||
|
headerLink: 'Variable editor Header link',
|
||||||
|
modeLabelNew: 'Variable editor Header mode New',
|
||||||
|
modeLabelEdit: 'Variable editor Header mode Edit',
|
||||||
|
generalNameInput: 'Variable editor Form Name field',
|
||||||
|
generalTypeSelect: 'Variable editor Form Type select',
|
||||||
|
generalLabelInput: 'Variable editor Form Label field',
|
||||||
|
generalHideSelect: 'Variable editor Form Hide select',
|
||||||
|
selectionOptionsMultiSwitch: 'Variable editor Form Multi switch',
|
||||||
|
selectionOptionsIncludeAllSwitch: 'Variable editor Form IncludeAll switch',
|
||||||
|
selectionOptionsCustomAllInput: 'Variable editor Form IncludeAll field',
|
||||||
|
previewOfValuesOption: 'Variable editor Preview of Values option',
|
||||||
|
addButton: 'Variable editor Add button',
|
||||||
|
updateButton: 'Variable editor Update button',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const QueryVariable = pageFactory({
|
||||||
|
url: '',
|
||||||
|
selectors: {
|
||||||
|
queryOptionsDataSourceSelect: 'Variable editor Form Query DataSource select',
|
||||||
|
queryOptionsRefreshSelect: 'Variable editor Form Query Refresh select',
|
||||||
|
queryOptionsRegExInput: 'Variable editor Form Query RegEx field',
|
||||||
|
queryOptionsSortSelect: 'Variable editor Form Query Sort select',
|
||||||
|
queryOptionsQueryInput: 'Variable editor Form Default Variable Query Editor textarea',
|
||||||
|
valueGroupsTagsEnabledSwitch: 'Variable editor Form Query UseTags switch',
|
||||||
|
valueGroupsTagsTagsQueryInput: 'Variable editor Form Query TagsQuery field',
|
||||||
|
valueGroupsTagsTagsValuesQueryInput: 'Variable editor Form Query TagsValuesQuery field',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ConstantVariable = pageFactory({
|
||||||
|
url: '',
|
||||||
|
selectors: {
|
||||||
|
constantOptionsQueryInput: 'Variable editor Form Constant Query field',
|
||||||
|
},
|
||||||
|
});
|
@ -5,6 +5,7 @@ import filter from 'lodash/filter';
|
|||||||
import find from 'lodash/find';
|
import find from 'lodash/find';
|
||||||
import indexOf from 'lodash/indexOf';
|
import indexOf from 'lodash/indexOf';
|
||||||
import map from 'lodash/map';
|
import map from 'lodash/map';
|
||||||
|
import { e2e } from '@grafana/e2e';
|
||||||
|
|
||||||
import coreModule from '../core_module';
|
import coreModule from '../core_module';
|
||||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||||
@ -26,11 +27,13 @@ export class ValueSelectDropdownCtrl {
|
|||||||
onUpdated: any;
|
onUpdated: any;
|
||||||
queryHasSearchFilter: boolean;
|
queryHasSearchFilter: boolean;
|
||||||
debouncedQueryChanged: Function;
|
debouncedQueryChanged: Function;
|
||||||
|
selectors: typeof e2e.pages.Dashboard.SubMenu.selectors;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private $scope: IScope) {
|
constructor(private $scope: IScope) {
|
||||||
this.queryHasSearchFilter = this.variable ? containsSearchFilter(this.variable.query) : false;
|
this.queryHasSearchFilter = this.variable ? containsSearchFilter(this.variable.query) : false;
|
||||||
this.debouncedQueryChanged = debounce(this.queryChanged.bind(this), 200);
|
this.debouncedQueryChanged = debounce(this.queryChanged.bind(this), 200);
|
||||||
|
this.selectors = e2e.pages.Dashboard.SubMenu.selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
|
@ -160,7 +160,7 @@ export class DashNav extends PureComponent<Props> {
|
|||||||
<button
|
<button
|
||||||
className="navbar-edit__back-btn"
|
className="navbar-edit__back-btn"
|
||||||
onClick={this.onClose}
|
onClick={this.onClose}
|
||||||
aria-label={e2e.pages.Dashboard.selectors.backArrow}
|
aria-label={e2e.pages.Dashboard.Toolbar.selectors.backArrow}
|
||||||
>
|
>
|
||||||
<i className="fa fa-arrow-left" />
|
<i className="fa fa-arrow-left" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -19,7 +19,7 @@ export const DashNavButton: FunctionComponent<Props> = ({ icon, tooltip, classSu
|
|||||||
<button
|
<button
|
||||||
className={`btn navbar-button navbar-button--${classSuffix}`}
|
className={`btn navbar-button navbar-button--${classSuffix}`}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
aria-label={e2e.pages.Dashboard.selectors.toolbarItems(tooltip)}
|
aria-label={e2e.pages.Dashboard.Toolbar.selectors.toolbarItems(tooltip)}
|
||||||
>
|
>
|
||||||
<i className={icon} />
|
<i className={icon} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -22,7 +22,7 @@ export class SettingsCtrl {
|
|||||||
canDelete: boolean;
|
canDelete: boolean;
|
||||||
sections: any[];
|
sections: any[];
|
||||||
hasUnsavedFolderChange: boolean;
|
hasUnsavedFolderChange: boolean;
|
||||||
selectors: typeof e2e.pages.DashboardSettings.selectors;
|
selectors: typeof e2e.pages.Dashboard.Settings.General.selectors;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(
|
constructor(
|
||||||
@ -55,7 +55,7 @@ export class SettingsCtrl {
|
|||||||
this.$rootScope.onAppEvent(CoreEvents.routeUpdated, this.onRouteUpdated.bind(this), $scope);
|
this.$rootScope.onAppEvent(CoreEvents.routeUpdated, this.onRouteUpdated.bind(this), $scope);
|
||||||
this.$rootScope.appEvent(CoreEvents.dashScroll, { animate: false, pos: 0 });
|
this.$rootScope.appEvent(CoreEvents.dashScroll, { animate: false, pos: 0 });
|
||||||
this.$rootScope.onAppEvent(CoreEvents.dashboardSaved, this.onPostSave.bind(this), $scope);
|
this.$rootScope.onAppEvent(CoreEvents.dashboardSaved, this.onPostSave.bind(this), $scope);
|
||||||
this.selectors = e2e.pages.DashboardSettings.selectors;
|
this.selectors = e2e.pages.Dashboard.Settings.General.selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSectionList() {
|
buildSectionList() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<aside class="dashboard-settings__aside">
|
<aside class="dashboard-settings__aside">
|
||||||
<a href="{{::section.url}}" class="dashboard-settings__nav-item" ng-class="{active: ctrl.viewId === section.id}" ng-repeat="section in ctrl.sections" aria-label={{ctrl.selectors.sectionItems}}>
|
<a href="{{::section.url}}" class="dashboard-settings__nav-item" ng-class="{active: ctrl.viewId === section.id}" ng-repeat="section in ctrl.sections" aria-label={{ctrl.selectors.sectionItems(section.title)}}>
|
||||||
<i class="{{::section.icon}}"></i>
|
<i class="{{::section.icon}}"></i>
|
||||||
{{::section.title}}
|
{{::section.title}}
|
||||||
</a>
|
</a>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import angular, { ILocationService } from 'angular';
|
import angular, { ILocationService } from 'angular';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { e2e } from '@grafana/e2e';
|
||||||
import { VariableSrv } from 'app/features/templating/all';
|
import { VariableSrv } from 'app/features/templating/all';
|
||||||
import { CoreEvents } from '../../../../types';
|
import { CoreEvents } from '../../../../types';
|
||||||
|
|
||||||
@ -8,6 +9,7 @@ export class SubMenuCtrl {
|
|||||||
variables: any;
|
variables: any;
|
||||||
dashboard: any;
|
dashboard: any;
|
||||||
submenuEnabled: boolean;
|
submenuEnabled: boolean;
|
||||||
|
selectors: typeof e2e.pages.Dashboard.SubMenu.selectors;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private variableSrv: VariableSrv, private $location: ILocationService) {
|
constructor(private variableSrv: VariableSrv, private $location: ILocationService) {
|
||||||
@ -17,6 +19,7 @@ export class SubMenuCtrl {
|
|||||||
this.dashboard.events.on(CoreEvents.submenuVisibilityChanged, (enabled: boolean) => {
|
this.dashboard.events.on(CoreEvents.submenuVisibilityChanged, (enabled: boolean) => {
|
||||||
this.submenuEnabled = enabled;
|
this.submenuEnabled = enabled;
|
||||||
});
|
});
|
||||||
|
this.selectors = e2e.pages.Dashboard.SubMenu.selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
annotationStateChanged() {
|
annotationStateChanged() {
|
||||||
|
@ -1,28 +1,59 @@
|
|||||||
<div class="submenu-controls" ng-hide="ctrl.submenuEnabled === false">
|
<div class="submenu-controls" ng-hide="ctrl.submenuEnabled === false">
|
||||||
<div ng-repeat="variable in ctrl.variables" ng-hide="variable.hide === 2" class="submenu-item gf-form-inline">
|
<div
|
||||||
|
ng-repeat="variable in ctrl.variables"
|
||||||
|
ng-hide="variable.hide === 2"
|
||||||
|
class="submenu-item gf-form-inline"
|
||||||
|
aria-label="{{::ctrl.selectors.submenuItem}}"
|
||||||
|
>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label
|
<label
|
||||||
class="gf-form-label template-variable"
|
class="gf-form-label template-variable"
|
||||||
ng-hide="variable.hide === 1"
|
ng-hide="variable.hide === 1"
|
||||||
aria-label="Dashboard template variables submenu LabelName label"
|
aria-label="{{ctrl.selectors.submenuItemLabels(variable.label || variable.name)}}"
|
||||||
>{{variable.label || variable.name}}</label>
|
>{{variable.label || variable.name}}</label
|
||||||
<value-select-dropdown ng-if="variable.type !== 'adhoc' && variable.type !== 'textbox'" dashboard="ctrl.dashboard" variable="variable" on-updated="ctrl.variableUpdated(variable)"></value-select-dropdown>
|
>
|
||||||
<input type="text" ng-if="variable.type === 'textbox'" ng-model="variable.query" class="gf-form-input width-12" ng-blur="variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);" ng-keydown="$event.keyCode === 13 && variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);" ></input>
|
<value-select-dropdown
|
||||||
|
ng-if="variable.type !== 'adhoc' && variable.type !== 'textbox'"
|
||||||
|
dashboard="ctrl.dashboard"
|
||||||
|
variable="variable"
|
||||||
|
on-updated="ctrl.variableUpdated(variable)"
|
||||||
|
></value-select-dropdown>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
ng-if="variable.type === 'textbox'"
|
||||||
|
ng-model="variable.query"
|
||||||
|
class="gf-form-input width-12"
|
||||||
|
ng-blur="variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);"
|
||||||
|
ng-keydown="$event.keyCode === 13 && variable.current.value != variable.query && variable.updateOptions() && ctrl.variableUpdated(variable);"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ad-hoc-filters ng-if="variable.type === 'adhoc'" variable="variable" dashboard="ctrl.dashboard"></ad-hoc-filters>
|
<ad-hoc-filters ng-if="variable.type === 'adhoc'" variable="variable" dashboard="ctrl.dashboard"></ad-hoc-filters>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="ctrl.dashboard.annotations.list.length > 0">
|
<div ng-if="ctrl.dashboard.annotations.list.length > 0">
|
||||||
<div ng-repeat="annotation in ctrl.dashboard.annotations.list" ng-hide="annotation.hide" class="submenu-item" ng-class="{'annotation-disabled': !annotation.enable}">
|
<div
|
||||||
<gf-form-switch class="gf-form" label="{{annotation.name}}" checked="annotation.enable" on-change="ctrl.annotationStateChanged()"></gf-form-switch>
|
ng-repeat="annotation in ctrl.dashboard.annotations.list"
|
||||||
|
ng-hide="annotation.hide"
|
||||||
|
class="submenu-item"
|
||||||
|
ng-class="{'annotation-disabled': !annotation.enable}"
|
||||||
|
>
|
||||||
|
<gf-form-switch
|
||||||
|
class="gf-form"
|
||||||
|
label="{{annotation.name}}"
|
||||||
|
checked="annotation.enable"
|
||||||
|
on-change="ctrl.annotationStateChanged()"
|
||||||
|
></gf-form-switch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form gf-form--grow">
|
<div class="gf-form gf-form--grow"></div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div ng-if="ctrl.dashboard.links.length > 0" >
|
<div ng-if="ctrl.dashboard.links.length > 0">
|
||||||
<dash-links-container links="ctrl.dashboard.links" dashboard="ctrl.dashboard" class="gf-form-inline"></dash-links-container>
|
<dash-links-container
|
||||||
|
links="ctrl.dashboard.links"
|
||||||
|
dashboard="ctrl.dashboard"
|
||||||
|
class="gf-form-inline"
|
||||||
|
></dash-links-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
@ -96,7 +96,7 @@ export class PanelHeader extends Component<Props, State> {
|
|||||||
className="panel-title-container"
|
className="panel-title-container"
|
||||||
onClick={this.onMenuToggle}
|
onClick={this.onMenuToggle}
|
||||||
onMouseDown={this.onMouseDown}
|
onMouseDown={this.onMouseDown}
|
||||||
aria-label={e2e.pages.Panels.Panel.selectors.title(title)}
|
aria-label={e2e.pages.Dashboard.Panels.Panel.selectors.title(title)}
|
||||||
>
|
>
|
||||||
<div className="panel-title">
|
<div className="panel-title">
|
||||||
<span className="icon-gf panel-alert-icon" />
|
<span className="icon-gf panel-alert-icon" />
|
||||||
|
@ -15,7 +15,10 @@ export const PanelHeaderMenuItem: FC<Props & PanelMenuItem> = props => {
|
|||||||
<li className={isSubMenu ? 'dropdown-submenu' : null}>
|
<li className={isSubMenu ? 'dropdown-submenu' : null}>
|
||||||
<a onClick={props.onClick}>
|
<a onClick={props.onClick}>
|
||||||
{props.iconClassName && <i className={props.iconClassName} />}
|
{props.iconClassName && <i className={props.iconClassName} />}
|
||||||
<span className="dropdown-item-text" aria-label={e2e.pages.Panels.Panel.selectors.headerItems(props.text)}>
|
<span
|
||||||
|
className="dropdown-item-text"
|
||||||
|
aria-label={e2e.pages.Dashboard.Panels.Panel.selectors.headerItems(props.text)}
|
||||||
|
>
|
||||||
{props.text}
|
{props.text}
|
||||||
</span>
|
</span>
|
||||||
{props.shortcut && <span className="dropdown-menu-item-shortcut">{props.shortcut}</span>}
|
{props.shortcut && <span className="dropdown-menu-item-shortcut">{props.shortcut}</span>}
|
||||||
|
@ -131,7 +131,7 @@ function TabItem({ tab, activeTab, onClick }: TabItemParams) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="panel-editor-tabs__item" onClick={() => onClick(tab)}>
|
<div className="panel-editor-tabs__item" onClick={() => onClick(tab)}>
|
||||||
<a className={tabClasses} aria-label={e2e.pages.Panels.EditPanel.selectors.tabItems(tab.text)}>
|
<a className={tabClasses} aria-label={e2e.pages.Dashboard.Panels.EditPanel.selectors.tabItems(tab.text)}>
|
||||||
<Tooltip content={`${tab.text}`} placement="auto">
|
<Tooltip content={`${tab.text}`} placement="auto">
|
||||||
<i className={`gicon gicon-${tab.id}${activeTab === tab.id ? '-active' : ''}`} />
|
<i className={`gicon gicon-${tab.id}${activeTab === tab.id ? '-active' : ''}`} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -43,7 +43,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => {
|
|||||||
const panelContent = elem.find('.panel-content');
|
const panelContent = elem.find('.panel-content');
|
||||||
const cornerInfoElem = elem.find('.panel-info-corner');
|
const cornerInfoElem = elem.find('.panel-info-corner');
|
||||||
const ctrl = scope.ctrl;
|
const ctrl = scope.ctrl;
|
||||||
ctrl.selectors = e2e.pages.Panels.Panel.selectors;
|
ctrl.selectors = e2e.pages.Dashboard.Panels.Panel.selectors;
|
||||||
let infoDrop: any;
|
let infoDrop: any;
|
||||||
let panelScrollbar: any;
|
let panelScrollbar: any;
|
||||||
|
|
||||||
|
@ -36,9 +36,9 @@ function renderMenuItem(item: AngularPanelMenuItem, ctrl: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
html += `><i class="${item.icon}"></i>`;
|
html += `><i class="${item.icon}"></i>`;
|
||||||
html += `<span class="dropdown-item-text" aria-label="${e2e.pages.Panels.Panel.selectors.headerItems(item.text)}">${
|
html += `<span class="dropdown-item-text" aria-label="${e2e.pages.Dashboard.Panels.Panel.selectors.headerItems(
|
||||||
item.text
|
item.text
|
||||||
}</span>`;
|
)}">${item.text}</span>`;
|
||||||
|
|
||||||
if (item.shortcut) {
|
if (item.shortcut) {
|
||||||
html += `<span class="dropdown-menu-item-shortcut">${item.shortcut}</span>`;
|
html += `<span class="dropdown-menu-item-shortcut">${item.shortcut}</span>`;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { VariableQueryProps } from 'app/types/plugins';
|
import { VariableQueryProps } from 'app/types/plugins';
|
||||||
|
import { e2e } from '@grafana/e2e';
|
||||||
|
|
||||||
export default class DefaultVariableQueryEditor extends PureComponent<VariableQueryProps, any> {
|
export default class DefaultVariableQueryEditor extends PureComponent<VariableQueryProps, any> {
|
||||||
constructor(props: VariableQueryProps) {
|
constructor(props: VariableQueryProps) {
|
||||||
@ -37,7 +38,7 @@ export default class DefaultVariableQueryEditor extends PureComponent<VariableQu
|
|||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
placeholder="metric name or tags query"
|
placeholder="metric name or tags query"
|
||||||
required
|
required
|
||||||
aria-label="Variable editor Form Default Variable Query Editor textarea"
|
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.queryOptionsQueryInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { AppEvents } from '@grafana/data';
|
||||||
|
import { e2e } from '@grafana/e2e';
|
||||||
|
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
import { variableTypes } from './variable';
|
import { variableTypes } from './variable';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
import DatasourceSrv from '../plugins/datasource_srv';
|
import DatasourceSrv from '../plugins/datasource_srv';
|
||||||
import { VariableSrv } from './all';
|
import { VariableSrv } from './all';
|
||||||
import { TemplateSrv } from './template_srv';
|
import { TemplateSrv } from './template_srv';
|
||||||
import { AppEvents } from '@grafana/data';
|
|
||||||
import { promiseToDigest } from '../../core/utils/promiseToDigest';
|
import { promiseToDigest } from '../../core/utils/promiseToDigest';
|
||||||
|
|
||||||
export class VariableEditorCtrl {
|
export class VariableEditorCtrl {
|
||||||
@ -57,6 +59,13 @@ export class VariableEditorCtrl {
|
|||||||
{ value: 2, text: 'Variable' },
|
{ value: 2, text: 'Variable' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$scope.selectors = {
|
||||||
|
...e2e.pages.Dashboard.Settings.Variables.List.selectors,
|
||||||
|
...e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors,
|
||||||
|
...e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors,
|
||||||
|
...e2e.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.selectors,
|
||||||
|
};
|
||||||
|
|
||||||
$scope.init = () => {
|
$scope.init = () => {
|
||||||
$scope.mode = 'list';
|
$scope.mode = 'list';
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<div ng-controller="VariableEditorCtrl" ng-init="init()">
|
<div ng-controller="VariableEditorCtrl" ng-init="init()">
|
||||||
<div class="page-action-bar">
|
<div class="page-action-bar">
|
||||||
<h3 class="dashboard-settings__header">
|
<h3 class="dashboard-settings__header">
|
||||||
<a ng-click="setMode('list')" aria-label="Variable editor Header link">Variables</a>
|
<a ng-click="setMode('list')" aria-label="{{::selectors.headerLink}}">Variables</a>
|
||||||
<span ng-show="mode === 'new'"
|
<span ng-show="mode === 'new'"
|
||||||
><i class="fa fa-fw fa-chevron-right" aria-label="Variable editor Header mode New"></i> New</span
|
><i class="fa fa-fw fa-chevron-right" aria-label="{{::selectors.modeLabelNew}}"></i> New</span
|
||||||
>
|
>
|
||||||
<span ng-show="mode === 'edit'"
|
<span ng-show="mode === 'edit'"
|
||||||
><i class="fa fa-fw fa-chevron-right" aria-label="Variable editor Header mode Edit"></i> Edit</span
|
><i class="fa fa-fw fa-chevron-right" aria-label="{{::selectors.modeLabelEdit}}"></i> Edit</span
|
||||||
>
|
>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
@ -17,7 +17,7 @@
|
|||||||
ng-click="setMode('new');"
|
ng-click="setMode('new');"
|
||||||
ng-if="variables.length > 0"
|
ng-if="variables.length > 0"
|
||||||
ng-hide="mode === 'edit' || mode === 'new'"
|
ng-hide="mode === 'edit' || mode === 'new'"
|
||||||
aria-label="Variable editor New variable button"
|
aria-label="{{::selectors.newButton}}"
|
||||||
>
|
>
|
||||||
New
|
New
|
||||||
</a>
|
</a>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="variables.length">
|
<div ng-if="variables.length">
|
||||||
<table class="filter-table filter-table--hover" aria-label="Variable editor Table">
|
<table class="filter-table filter-table--hover" aria-label="{{::selectors.table}}">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Variable</th>
|
<th>Variable</th>
|
||||||
@ -50,7 +50,7 @@
|
|||||||
<span
|
<span
|
||||||
ng-click="edit(variable)"
|
ng-click="edit(variable)"
|
||||||
class="pointer template-variable"
|
class="pointer template-variable"
|
||||||
aria-label="Variable editor Table Name field"
|
aria-label="{{::selectors.tableRowNameFields(variable.name)}}"
|
||||||
>
|
>
|
||||||
${{ variable.name }}
|
${{ variable.name }}
|
||||||
</span>
|
</span>
|
||||||
@ -59,7 +59,7 @@
|
|||||||
style="max-width: 200px;"
|
style="max-width: 200px;"
|
||||||
ng-click="edit(variable)"
|
ng-click="edit(variable)"
|
||||||
class="pointer max-width"
|
class="pointer max-width"
|
||||||
aria-label="Variable editor Table Definition field"
|
aria-label="{{::selectors.tableRowDefinitionFields(variable.name)}}"
|
||||||
>
|
>
|
||||||
{{ variable.definition ? variable.definition : variable.query }}
|
{{ variable.definition ? variable.definition : variable.query }}
|
||||||
</td>
|
</td>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
ng-click="_.move(variables,$index,$index-1)"
|
ng-click="_.move(variables,$index,$index-1)"
|
||||||
ng-hide="$first"
|
ng-hide="$first"
|
||||||
class="pointer fa fa-arrow-up"
|
class="pointer fa fa-arrow-up"
|
||||||
aria-label="Variable editor Table ArrowUp button"
|
aria-label="{{::selectors.tableRowArrowUpButtons(variable.name)}}"
|
||||||
></i>
|
></i>
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 1%">
|
<td style="width: 1%">
|
||||||
@ -76,14 +76,14 @@
|
|||||||
ng-click="_.move(variables,$index,$index+1)"
|
ng-click="_.move(variables,$index,$index+1)"
|
||||||
ng-hide="$last"
|
ng-hide="$last"
|
||||||
class="pointer fa fa-arrow-down"
|
class="pointer fa fa-arrow-down"
|
||||||
aria-label="Variable editor Table ArrowDown button"
|
aria-label="{{::selectors.tableRowArrowDownButtons(variable.name)}}"
|
||||||
></i>
|
></i>
|
||||||
</td>
|
</td>
|
||||||
<td style="width: 1%">
|
<td style="width: 1%">
|
||||||
<a
|
<a
|
||||||
ng-click="duplicate(variable)"
|
ng-click="duplicate(variable)"
|
||||||
class="btn btn-inverse btn-small"
|
class="btn btn-inverse btn-small"
|
||||||
aria-label="Variable editor Table Duplicate button"
|
aria-label="{{::selectors.tableRowDuplicateButtons(variable.name)}}"
|
||||||
>
|
>
|
||||||
Duplicate
|
Duplicate
|
||||||
</a>
|
</a>
|
||||||
@ -92,7 +92,7 @@
|
|||||||
<a
|
<a
|
||||||
ng-click="removeVariable(variable)"
|
ng-click="removeVariable(variable)"
|
||||||
class="btn btn-danger btn-small"
|
class="btn btn-danger btn-small"
|
||||||
aria-label="Variable editor Table Remove button"
|
aria-label="{{::selectors.tableRowRemoveButtons(variable.name)}}"
|
||||||
>
|
>
|
||||||
<i class="fa fa-remove"></i>
|
<i class="fa fa-remove"></i>
|
||||||
</a>
|
</a>
|
||||||
@ -117,7 +117,7 @@
|
|||||||
ng-model="current.name"
|
ng-model="current.name"
|
||||||
required
|
required
|
||||||
ng-pattern="namePattern"
|
ng-pattern="namePattern"
|
||||||
aria-label="Variable editor Form Name field"
|
aria-label="{{::selectors.generalNameInput}}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form max-width-19">
|
<div class="gf-form max-width-19">
|
||||||
@ -133,7 +133,7 @@
|
|||||||
ng-model="current.type"
|
ng-model="current.type"
|
||||||
ng-options="k as v.name for (k, v) in variableTypes"
|
ng-options="k as v.name for (k, v) in variableTypes"
|
||||||
ng-change="typeChanged()"
|
ng-change="typeChanged()"
|
||||||
aria-label="Variable editor Form Type select"
|
aria-label="{{::selectors.generalTypeSelect}}"
|
||||||
></select>
|
></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -153,7 +153,7 @@
|
|||||||
class="gf-form-input"
|
class="gf-form-input"
|
||||||
ng-model="current.label"
|
ng-model="current.label"
|
||||||
placeholder="optional display name"
|
placeholder="optional display name"
|
||||||
aria-label="Variable editor Form Label field"
|
aria-label="{{::selectors.generalLabelInput}}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form max-width-19">
|
<div class="gf-form max-width-19">
|
||||||
@ -163,7 +163,7 @@
|
|||||||
class="gf-form-input"
|
class="gf-form-input"
|
||||||
ng-model="current.hide"
|
ng-model="current.hide"
|
||||||
ng-options="f.value as f.text for f in hideOptions"
|
ng-options="f.value as f.text for f in hideOptions"
|
||||||
aria-label="Variable editor Form Hide select"
|
aria-label="{{::selectors.generalHideSelect}}"
|
||||||
></select>
|
></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -255,7 +255,7 @@
|
|||||||
ng-model="current.query"
|
ng-model="current.query"
|
||||||
ng-blur="runQuery()"
|
ng-blur="runQuery()"
|
||||||
placeholder="your metric prefix"
|
placeholder="your metric prefix"
|
||||||
aria-label="Variable editor Form Constant Query field"
|
aria-label="{{::selectors.constantOptionsQueryInput}}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -288,7 +288,7 @@
|
|||||||
ng-options="f.value as f.name for f in datasources"
|
ng-options="f.value as f.name for f in datasources"
|
||||||
ng-change="datasourceChanged()"
|
ng-change="datasourceChanged()"
|
||||||
required
|
required
|
||||||
aria-label="Variable editor Form Query DataSource select"
|
aria-label="{{::selectors.queryOptionsDataSourceSelect}}"
|
||||||
>
|
>
|
||||||
<option value="" ng-if="false"></option>
|
<option value="" ng-if="false"></option>
|
||||||
</select>
|
</select>
|
||||||
@ -307,7 +307,7 @@
|
|||||||
class="gf-form-input"
|
class="gf-form-input"
|
||||||
ng-model="current.refresh"
|
ng-model="current.refresh"
|
||||||
ng-options="f.value as f.text for f in refreshOptions"
|
ng-options="f.value as f.text for f in refreshOptions"
|
||||||
aria-label="Variable editor Form Query Refresh select"
|
aria-label="{{::selectors.queryOptionsRefreshSelect}}"
|
||||||
></select>
|
></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -331,7 +331,7 @@
|
|||||||
placeholder="/.*-(.*)-.*/"
|
placeholder="/.*-(.*)-.*/"
|
||||||
ng-model-onblur
|
ng-model-onblur
|
||||||
ng-change="runQuery()"
|
ng-change="runQuery()"
|
||||||
aria-label="Variable editor Form Query RegEx field"
|
aria-label="{{::selectors.queryOptionsRegExInput}}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form max-width-21">
|
<div class="gf-form max-width-21">
|
||||||
@ -347,7 +347,7 @@
|
|||||||
ng-model="current.sort"
|
ng-model="current.sort"
|
||||||
ng-options="f.value as f.text for f in sortOptions"
|
ng-options="f.value as f.text for f in sortOptions"
|
||||||
ng-change="runQuery()"
|
ng-change="runQuery()"
|
||||||
aria-label="Variable editor Form Query Sort select"
|
aria-label="{{::selectors.queryOptionsSortSelect}}"
|
||||||
></select>
|
></select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -420,7 +420,7 @@
|
|||||||
tooltip="Enables multiple values to be selected at the same time"
|
tooltip="Enables multiple values to be selected at the same time"
|
||||||
checked="current.multi"
|
checked="current.multi"
|
||||||
on-change="runQuery()"
|
on-change="runQuery()"
|
||||||
aria-label="Variable editor Form Multi switch"
|
aria-label="{{::selectors.selectionOptionsMultiSwitch}}"
|
||||||
>
|
>
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
<gf-form-switch
|
<gf-form-switch
|
||||||
@ -429,7 +429,7 @@
|
|||||||
label-class="width-10"
|
label-class="width-10"
|
||||||
checked="current.includeAll"
|
checked="current.includeAll"
|
||||||
on-change="runQuery()"
|
on-change="runQuery()"
|
||||||
aria-label="Variable editor Form IncludeAll switch"
|
aria-label="{{::selectors.selectionOptionsIncludeAllSwitch}}"
|
||||||
>
|
>
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
</div>
|
</div>
|
||||||
@ -440,7 +440,7 @@
|
|||||||
class="gf-form-input max-width-15"
|
class="gf-form-input max-width-15"
|
||||||
ng-model="current.allValue"
|
ng-model="current.allValue"
|
||||||
placeholder="blank = auto"
|
placeholder="blank = auto"
|
||||||
aria-label="Variable editor Form IncludeAll field"
|
aria-label="{{::selectors.selectionOptionsCustomAllInput}}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -453,7 +453,7 @@
|
|||||||
label-class="width-10"
|
label-class="width-10"
|
||||||
checked="current.useTags"
|
checked="current.useTags"
|
||||||
on-change="runQuery()"
|
on-change="runQuery()"
|
||||||
aria-label="Variable editor Form Query UseTags switch"
|
aria-label="{{::selectors.valueGroupsTagsEnabledSwitch}}"
|
||||||
>
|
>
|
||||||
</gf-form-switch>
|
</gf-form-switch>
|
||||||
<div class="gf-form last" ng-if="current.useTags">
|
<div class="gf-form last" ng-if="current.useTags">
|
||||||
@ -464,7 +464,7 @@
|
|||||||
ng-model="current.tagsQuery"
|
ng-model="current.tagsQuery"
|
||||||
placeholder="metric name or tags query"
|
placeholder="metric name or tags query"
|
||||||
ng-model-onblur
|
ng-model-onblur
|
||||||
aria-label="Variable editor Form Query TagsQuery field"
|
aria-label="{{::selectors.valueGroupsTagsTagsQueryInput}}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form" ng-if="current.useTags">
|
<div class="gf-form" ng-if="current.useTags">
|
||||||
@ -475,7 +475,7 @@
|
|||||||
ng-model="current.tagValuesQuery"
|
ng-model="current.tagValuesQuery"
|
||||||
placeholder="apps.$tag.*"
|
placeholder="apps.$tag.*"
|
||||||
ng-model-onblur
|
ng-model-onblur
|
||||||
aria-label="Variable editor Form Query TagsValuesQuery field"
|
aria-label="{{::selectors.valueGroupsTagsTagsValuesQueryInput}}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -484,7 +484,7 @@
|
|||||||
<h5>Preview of values</h5>
|
<h5>Preview of values</h5>
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form" ng-repeat="option in current.options | limitTo: optionsLimit">
|
<div class="gf-form" ng-repeat="option in current.options | limitTo: optionsLimit">
|
||||||
<span class="gf-form-label" aria-label="Variable editor Preview of Values option">{{ option.text }}</span>
|
<span class="gf-form-label" aria-label="{{::selectors.previewOfValuesOption}}">{{ option.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form" ng-if="current.options.length > optionsLimit">
|
<div class="gf-form" ng-if="current.options.length > optionsLimit">
|
||||||
<a
|
<a
|
||||||
@ -508,7 +508,7 @@
|
|||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
ng-show="mode === 'edit'"
|
ng-show="mode === 'edit'"
|
||||||
ng-click="update();"
|
ng-click="update();"
|
||||||
aria-label="Variable editor Update button"
|
aria-label="{{::selectors.updateButton}}"
|
||||||
>
|
>
|
||||||
Update
|
Update
|
||||||
</button>
|
</button>
|
||||||
@ -517,7 +517,7 @@
|
|||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
ng-show="mode === 'new'"
|
ng-show="mode === 'new'"
|
||||||
ng-click="add();"
|
ng-click="add();"
|
||||||
aria-label="Variable editor Add button"
|
aria-label="{{::selectors.addButton}}"
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,60 +1,72 @@
|
|||||||
<div class="variable-link-wrapper">
|
<div class="variable-link-wrapper">
|
||||||
<a
|
<a
|
||||||
ng-click="vm.show()"
|
ng-click="vm.show()"
|
||||||
class="variable-value-link"
|
class="variable-value-link"
|
||||||
aria-label="Dashboard template variables Variable Value DropDown value link"
|
aria-label="{{vm.selectors.submenuItemValueDropDownValueLinkTexts(vm.linkText)}}"
|
||||||
>
|
>
|
||||||
{{vm.linkText}}
|
{{vm.linkText}}
|
||||||
<span ng-repeat="tag in vm.selectedTags" bs-tooltip='tag.valuesText' data-placement="bottom">
|
<span ng-repeat="tag in vm.selectedTags" bs-tooltip="tag.valuesText" data-placement="bottom">
|
||||||
<span class="label-tag"tag-color-from-name="tag.text">
|
<span class="label-tag" tag-color-from-name="tag.text">
|
||||||
<i class="fa fa-tag"></i>
|
<i class="fa fa-tag"></i> {{tag.text}}
|
||||||
{{tag.text}}
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
<i class="fa fa-caret-down" style="font-size:12px"></i>
|
||||||
<i class="fa fa-caret-down" style="font-size:12px"></i>
|
</a>
|
||||||
</a>
|
|
||||||
|
|
||||||
<input type="text" class="gf-form-input" style="display: none" ng-keydown="vm.keyDown($event)" ng-model="vm.search.query" ng-change="vm.debouncedQueryChanged()" ></input>
|
<input
|
||||||
|
type="text"
|
||||||
|
class="gf-form-input"
|
||||||
|
style="display: none"
|
||||||
|
ng-keydown="vm.keyDown($event)"
|
||||||
|
ng-model="vm.search.query"
|
||||||
|
ng-change="vm.debouncedQueryChanged()"
|
||||||
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="variable-value-dropdown"
|
class="variable-value-dropdown"
|
||||||
ng-if="vm.dropdownVisible"
|
ng-if="vm.dropdownVisible"
|
||||||
ng-class="{'multi': vm.variable.multi, 'single': !vm.variable.multi}"
|
ng-class="{'multi': vm.variable.multi, 'single': !vm.variable.multi}"
|
||||||
aria-label="Dashboard template variables Variable Value DropDown DropDown"
|
aria-label="{{::vm.selectors.submenuItemValueDropDownDropDown}}"
|
||||||
>
|
>
|
||||||
<div class="variable-options-wrapper">
|
<div class="variable-options-wrapper">
|
||||||
<div class="variable-options-column">
|
<div class="variable-options-column">
|
||||||
<a
|
<a
|
||||||
class="variable-options-column-header"
|
class="variable-options-column-header"
|
||||||
ng-if="vm.variable.multi"
|
ng-if="vm.variable.multi"
|
||||||
ng-class="{'many-selected': vm.selectedValues.length > 1}"
|
ng-class="{'many-selected': vm.selectedValues.length > 1}"
|
||||||
bs-tooltip="'Clear selections'"
|
bs-tooltip="'Clear selections'"
|
||||||
data-placement="top"
|
data-placement="top"
|
||||||
ng-click="vm.clearSelections()"
|
ng-click="vm.clearSelections()"
|
||||||
aria-label="Dashboard template variables Variable Value DropDown Selected link"
|
|
||||||
>
|
>
|
||||||
<span class="variable-option-icon"></span>
|
<span class="variable-option-icon"></span>
|
||||||
Selected ({{vm.selectedValues.length}})
|
Selected ({{vm.selectedValues.length}})
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="variable-option pointer"
|
class="variable-option pointer"
|
||||||
ng-repeat="option in vm.search.options"
|
ng-repeat="option in vm.search.options"
|
||||||
ng-class="{'selected': option.selected, 'highlighted': $index === vm.highlightIndex}"
|
ng-class="{'selected': option.selected, 'highlighted': $index === vm.highlightIndex}"
|
||||||
ng-click="vm.selectValue(option, $event)"
|
ng-click="vm.selectValue(option, $event)"
|
||||||
>
|
>
|
||||||
<span class="variable-option-icon"></span>
|
<span class="variable-option-icon"></span>
|
||||||
<span aria-label="Dashboard template variables Variable Value DropDown option text">{{option.text}}</span>
|
<span aria-label="{{vm.selectors.submenuItemValueDropDownOptionTexts(option.text)}}">{{option.text}}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="variable-options-column" ng-if="vm.tags.length">
|
<div class="variable-options-column" ng-if="vm.tags.length">
|
||||||
<div class="variable-options-column-header text-center">
|
<div class="variable-options-column-header text-center">
|
||||||
Tags
|
Tags
|
||||||
</div>
|
</div>
|
||||||
<a class="variable-option-tag pointer" ng-repeat="tag in vm.tags" ng-click="vm.selectTag(tag, $event)" ng-class="{'selected': tag.selected}">
|
<a
|
||||||
<span class="fa fa-fw variable-option-icon"></span>
|
class="variable-option-tag pointer"
|
||||||
<span class="label-tag" tag-color-from-name="tag.text">{{tag.text}} <i class="fa fa-tag"></i> </span>
|
ng-repeat="tag in vm.tags"
|
||||||
</a>
|
ng-click="vm.selectTag(tag, $event)"
|
||||||
</div>
|
ng-class="{'selected': tag.selected}"
|
||||||
</div>
|
>
|
||||||
</div>
|
<span class="fa fa-fw variable-option-icon"></span>
|
||||||
|
<span class="label-tag" tag-color-from-name="tag.text"
|
||||||
|
>{{tag.text}} <i class="fa fa-tag"></i> </span
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,7 +31,7 @@ export class TestDataQueryCtrl extends QueryCtrl {
|
|||||||
selectedPoint: any;
|
selectedPoint: any;
|
||||||
|
|
||||||
showLabels = false;
|
showLabels = false;
|
||||||
selectors: typeof e2e.pages.Panels.DataSource.TestData.QueryTab.selectors;
|
selectors: typeof e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.selectors;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor($scope: any, $injector: any) {
|
constructor($scope: any, $injector: any) {
|
||||||
@ -42,7 +42,7 @@ export class TestDataQueryCtrl extends QueryCtrl {
|
|||||||
this.newPointTime = dateTime();
|
this.newPointTime = dateTime();
|
||||||
this.selectedPoint = { text: 'Select point', value: null };
|
this.selectedPoint = { text: 'Select point', value: null };
|
||||||
this.showLabels = showLabelsFor.includes(this.target.scenarioId);
|
this.showLabels = showLabelsFor.includes(this.target.scenarioId);
|
||||||
this.selectors = e2e.pages.Panels.DataSource.TestData.QueryTab.selectors;
|
this.selectors = e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPoints() {
|
getPoints() {
|
||||||
|
@ -8,7 +8,7 @@ export class AxesEditorCtrl {
|
|||||||
xAxisModes: any;
|
xAxisModes: any;
|
||||||
xAxisStatOptions: any;
|
xAxisStatOptions: any;
|
||||||
xNameSegment: any;
|
xNameSegment: any;
|
||||||
selectors: typeof e2e.pages.Panels.Visualization.Graph.VisualizationTab.selectors;
|
selectors: typeof e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.selectors;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private $scope: any) {
|
constructor(private $scope: any) {
|
||||||
@ -45,7 +45,7 @@ export class AxesEditorCtrl {
|
|||||||
this.panel.xaxis.name = 'specify field';
|
this.panel.xaxis.name = 'specify field';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.selectors = e2e.pages.Panels.Visualization.Graph.VisualizationTab.selectors;
|
this.selectors = e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.selectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
setUnitFormat(axis: { format: any }) {
|
setUnitFormat(axis: { format: any }) {
|
||||||
|
587
public/e2e-tests/integration/queryVariableCrud.spec.ts
Normal file
587
public/e2e-tests/integration/queryVariableCrud.spec.ts
Normal file
@ -0,0 +1,587 @@
|
|||||||
|
import { e2e } from '@grafana/e2e';
|
||||||
|
|
||||||
|
const assertDefaultsForNewVariable = () => {
|
||||||
|
logSection('Asserting defaults for new variable');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput().within(input => {
|
||||||
|
expect(input.attr('placeholder')).equals('name');
|
||||||
|
expect(input.val()).equals('');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelect().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('option:selected')
|
||||||
|
.should('have.text', 'Query');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInput().within(input => {
|
||||||
|
expect(input.attr('placeholder')).equals('optional display name');
|
||||||
|
expect(input.val()).equals('');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('option:selected')
|
||||||
|
.should('have.text', '');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsDataSourceSelect().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('option:selected')
|
||||||
|
.should('not.exist');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput().should('not.exist');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRefreshSelect().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('option:selected')
|
||||||
|
.should('have.text', 'Never');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRegExInput().within(input => {
|
||||||
|
expect(input.attr('placeholder')).equals('/.*-(.*)-.*/');
|
||||||
|
expect(input.val()).equals('');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsSortSelect().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('option:selected')
|
||||||
|
.should('have.text', 'Disabled');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('input')
|
||||||
|
.should('not.be.checked');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('input')
|
||||||
|
.should('not.be.checked');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.valueGroupsTagsEnabledSwitch().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('input')
|
||||||
|
.should('not.be.checked');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().should('not.exist');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput().should('not.exist');
|
||||||
|
logSection('Asserting defaults for new variable, OK!');
|
||||||
|
};
|
||||||
|
|
||||||
|
interface CreateQueryVariableArguments extends QueryVariableData {
|
||||||
|
dataSourceName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createQueryVariable = ({ name, label, dataSourceName, query }: CreateQueryVariableArguments) => {
|
||||||
|
logSection('Creating a Query Variable with', { name, label, dataSourceName, query });
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput().should('be.visible');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput().type(name);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInput().type(label);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsDataSourceSelect()
|
||||||
|
.select(`string:${dataSourceName}`)
|
||||||
|
.blur();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput()
|
||||||
|
.within(input => {
|
||||||
|
expect(input.attr('placeholder')).equals('metric name or tags query');
|
||||||
|
expect(input.val()).equals('');
|
||||||
|
})
|
||||||
|
.type(query)
|
||||||
|
.blur();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().should('exist');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch()
|
||||||
|
.click()
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('input')
|
||||||
|
.should('be.checked');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch()
|
||||||
|
.click()
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('input')
|
||||||
|
.should('be.checked');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput().within(input => {
|
||||||
|
expect(input.attr('placeholder')).equals('blank = auto');
|
||||||
|
expect(input.val()).equals('');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.addButton().click();
|
||||||
|
logSection('Creating a Query Variable with required, OK!');
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertVariableTableRow = ({ name, query }: QueryVariableData) => {
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowNameFields(name)
|
||||||
|
.should('exist')
|
||||||
|
.contains(name);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowDefinitionFields(name)
|
||||||
|
.should('exist')
|
||||||
|
.contains(query);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowArrowUpButtons(name).should('exist');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowArrowDownButtons(name).should('exist');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowDuplicateButtons(name).should('exist');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowRemoveButtons(name).should('exist');
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertVariableTable = (args: QueryVariableData[]) => {
|
||||||
|
logSection('Asserting variable table with', args);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.table()
|
||||||
|
.should('be.visible')
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('tbody > tr')
|
||||||
|
.should('have.length', args.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let index = 0; index < args.length; index++) {
|
||||||
|
assertVariableTableRow(args[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
logSection('Asserting variable table, Ok');
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertVariableLabelAndComponent = ({ label, options, selectedOption }: QueryVariableData) => {
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemLabels(label).should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(selectedOption)
|
||||||
|
.should('be.visible')
|
||||||
|
.click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownDropDown().should('be.visible');
|
||||||
|
for (let optionIndex = 0; optionIndex < options.length; optionIndex++) {
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(options[optionIndex]).should('be.visible');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertVariableLabelsAndComponents = (args: QueryVariableData[]) => {
|
||||||
|
logSection('Asserting variable components and labels');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItem().should('have.length', args.length);
|
||||||
|
for (let index = 0; index < args.length; index++) {
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItem()
|
||||||
|
.eq(index)
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('label')
|
||||||
|
.contains(args[index].name);
|
||||||
|
});
|
||||||
|
assertVariableLabelAndComponent(args[index]);
|
||||||
|
}
|
||||||
|
logSection('Asserting variable components and labels, Ok');
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertAdding3dependantQueryVariablesScenario = (queryVariables: QueryVariableData[]) => {
|
||||||
|
// This creates 3 variables where 2 depends on 1 and 3 depends on 2 and for each added variable
|
||||||
|
// we assert that the variable looks ok in the variable list and that it looks ok in the submenu in dashboard
|
||||||
|
for (let queryVariableIndex = 0; queryVariableIndex < queryVariables.length; queryVariableIndex++) {
|
||||||
|
const { name, label, query, options, selectedOption } = queryVariables[queryVariableIndex];
|
||||||
|
const asserts = queryVariables.slice(0, queryVariableIndex + 1);
|
||||||
|
createQueryVariable({
|
||||||
|
dataSourceName: e2e.context().get('lastAddedDataSource'),
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
query,
|
||||||
|
options,
|
||||||
|
selectedOption,
|
||||||
|
});
|
||||||
|
|
||||||
|
assertVariableTable(asserts);
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Settings.General.saveDashBoard().click();
|
||||||
|
e2e.pages.SaveDashboardModal.save().click();
|
||||||
|
e2e.flows.assertSuccessNotification();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.backArrow().click();
|
||||||
|
|
||||||
|
assertVariableLabelsAndComponents(asserts);
|
||||||
|
|
||||||
|
if (queryVariableIndex < queryVariables.length - 1) {
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.newButton().click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
interface QueryVariableData {
|
||||||
|
name: string;
|
||||||
|
query: string;
|
||||||
|
label: string;
|
||||||
|
options: string[];
|
||||||
|
selectedOption: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const logSection = (message: string, args?: any) => {
|
||||||
|
e2e().logToConsole('');
|
||||||
|
e2e().logToConsole(message, args);
|
||||||
|
e2e().logToConsole('===============================================================================');
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertDuplicateItem = (queryVariables: QueryVariableData[]) => {
|
||||||
|
logSection('Asserting variable duplicate');
|
||||||
|
|
||||||
|
const itemToDuplicate = queryVariables[1];
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowDuplicateButtons(itemToDuplicate.name)
|
||||||
|
.should('exist')
|
||||||
|
.click();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.table()
|
||||||
|
.should('be.visible')
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('tbody > tr')
|
||||||
|
.should('have.length', queryVariables.length + 1);
|
||||||
|
});
|
||||||
|
const newItem = { ...itemToDuplicate, name: `copy_of_${itemToDuplicate.name}` };
|
||||||
|
assertVariableTableRow(newItem);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowNameFields(newItem.name).click();
|
||||||
|
|
||||||
|
newItem.label = `copy_of_${itemToDuplicate.label}`;
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInput()
|
||||||
|
.clear()
|
||||||
|
.type(newItem.label);
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Settings.General.saveDashBoard().click();
|
||||||
|
e2e.pages.SaveDashboardModal.save().click();
|
||||||
|
e2e.flows.assertSuccessNotification();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.backArrow().click();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemLabels(newItem.label).should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(newItem.selectedOption)
|
||||||
|
.should('be.visible')
|
||||||
|
.eq(1)
|
||||||
|
.click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownDropDown().should('be.visible');
|
||||||
|
for (let optionIndex = 0; optionIndex < newItem.options.length; optionIndex++) {
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(newItem.options[optionIndex]).should('be.visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
logSection('Asserting variable duplicate, OK!');
|
||||||
|
return [...queryVariables, newItem];
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertDeleteItem = (queryVariables: QueryVariableData[]) => {
|
||||||
|
logSection('Asserting variable delete');
|
||||||
|
|
||||||
|
const itemToDelete = queryVariables[1];
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowRemoveButtons(itemToDelete.name).click();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.table()
|
||||||
|
.should('be.visible')
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('tbody > tr')
|
||||||
|
.should('have.length', queryVariables.length - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Settings.General.saveDashBoard().click();
|
||||||
|
e2e.pages.SaveDashboardModal.save().click();
|
||||||
|
e2e.flows.assertSuccessNotification();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.backArrow().click();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemLabels(itemToDelete.label).should('not.exist');
|
||||||
|
|
||||||
|
logSection('Asserting variable delete, OK!');
|
||||||
|
|
||||||
|
return queryVariables.filter(item => item.name !== itemToDelete.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertUpdateItem = (data: QueryVariableData[]) => {
|
||||||
|
logSection('Asserting variable update');
|
||||||
|
const queryVariables = [...data];
|
||||||
|
// updates an item to a constant variable instead
|
||||||
|
const itemToUpdate = queryVariables[1];
|
||||||
|
const updatedItem = {
|
||||||
|
...itemToUpdate,
|
||||||
|
name: `update_of_${itemToUpdate.name}`,
|
||||||
|
label: `update_of_${itemToUpdate.label}`,
|
||||||
|
query: 'A constant',
|
||||||
|
options: ['A constant'],
|
||||||
|
selectedOption: 'undefined',
|
||||||
|
};
|
||||||
|
queryVariables[1] = updatedItem;
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowNameFields(itemToUpdate.name).click();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput().should('be.visible');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput()
|
||||||
|
.should('have.value', itemToUpdate.name)
|
||||||
|
.clear()
|
||||||
|
.type(updatedItem.name);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInput()
|
||||||
|
.should('have.value', itemToUpdate.label)
|
||||||
|
.clear()
|
||||||
|
.type(updatedItem.label);
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelect().select('Constant');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect().within(select => {
|
||||||
|
e2e()
|
||||||
|
.get('option:selected')
|
||||||
|
.should('have.text', 'Variable');
|
||||||
|
});
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect().select('');
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.constantOptionsQueryInput().type(updatedItem.query);
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.backArrow().click();
|
||||||
|
|
||||||
|
assertVariableLabelAndComponent(queryVariables[1]);
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
|
||||||
|
assertVariableTableRow(queryVariables[1]);
|
||||||
|
queryVariables[1].selectedOption = 'A constant';
|
||||||
|
|
||||||
|
logSection('Asserting variable update, OK!');
|
||||||
|
return queryVariables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertMoveDownItem = (data: QueryVariableData[]) => {
|
||||||
|
logSection('Asserting variable move down');
|
||||||
|
const queryVariables = [...data];
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowArrowDownButtons(queryVariables[0].name).click();
|
||||||
|
const temp = { ...queryVariables[0] };
|
||||||
|
queryVariables[0] = { ...queryVariables[1] };
|
||||||
|
queryVariables[1] = temp;
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.table().within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('tbody > tr')
|
||||||
|
.eq(0)
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(0)
|
||||||
|
.contains(queryVariables[0].name);
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(1)
|
||||||
|
.contains(queryVariables[0].query);
|
||||||
|
});
|
||||||
|
e2e()
|
||||||
|
.get('tbody > tr')
|
||||||
|
.eq(1)
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(0)
|
||||||
|
.contains(queryVariables[1].name);
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(1)
|
||||||
|
.contains(queryVariables[1].query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.backArrow().click();
|
||||||
|
|
||||||
|
assertVariableLabelsAndComponents(queryVariables);
|
||||||
|
|
||||||
|
logSection('Asserting variable move down, OK!');
|
||||||
|
|
||||||
|
return queryVariables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertSelects = (queryVariables: QueryVariableData[]) => {
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [A] query2: [AA] query3: [AAA]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('A').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('A').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('B').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [B] query2: [All] query3: [All]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All').should('have.length', 2);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All')
|
||||||
|
.eq(0)
|
||||||
|
.click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BA').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BB').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BC').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BB').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [B] query2: [BB] query3: [All]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All')
|
||||||
|
.eq(0)
|
||||||
|
.click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BBA').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BBB').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BBC').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BBB').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All').should('have.length', 0);
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [B] query2: [BB] query3: [BBB]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('BB').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BA').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BB').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BC').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BC').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('BB + BC').should('have.length', 1);
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [B] query2: [BB + BC] query3: [BBB]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('BBB').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BBA').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BBB').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BBC').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BCA').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BCB').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BCC').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BCC').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('BBB + BCC').should('have.length', 1);
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [B] query2: [BB + BC] query3: [BBB + BCC]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('BB + BC').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BA').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BB').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BC').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BA').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BB').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('BC').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('BA').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All').should('have.length', 1);
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [B] query2: [BA] query3: [All]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('B').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('A').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('B').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('C').should('be.visible');
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('A').click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('B').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('A').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All').should('have.length', 2);
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [A] query2: [All] query3: [All]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All')
|
||||||
|
.eq(0)
|
||||||
|
.click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('AA').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('A').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('AA').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All').should('have.length', 1);
|
||||||
|
// Values in submenus should be
|
||||||
|
// query1: [A] query2: [AA] query3: [All]
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All')
|
||||||
|
.eq(0)
|
||||||
|
.click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('AAA').click();
|
||||||
|
e2e.pages.Dashboard.Toolbar.navBar().click();
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('A').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('AA').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('AAA').should('have.length', 1);
|
||||||
|
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All').should('have.length', 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertMoveUpItem = (data: QueryVariableData[]) => {
|
||||||
|
logSection('Asserting variable move up');
|
||||||
|
const queryVariables = [...data];
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.tableRowArrowUpButtons(queryVariables[1].name).click();
|
||||||
|
const temp = { ...queryVariables[0] };
|
||||||
|
queryVariables[0] = { ...queryVariables[1] };
|
||||||
|
queryVariables[1] = temp;
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.table().within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('tbody > tr')
|
||||||
|
.eq(0)
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(0)
|
||||||
|
.contains(queryVariables[0].name);
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(1)
|
||||||
|
.contains(queryVariables[0].query);
|
||||||
|
});
|
||||||
|
e2e()
|
||||||
|
.get('tbody > tr')
|
||||||
|
.eq(1)
|
||||||
|
.within(() => {
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(0)
|
||||||
|
.contains(queryVariables[1].name);
|
||||||
|
e2e()
|
||||||
|
.get('td')
|
||||||
|
.eq(1)
|
||||||
|
.contains(queryVariables[1].query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Toolbar.backArrow().click();
|
||||||
|
|
||||||
|
assertVariableLabelsAndComponents(queryVariables);
|
||||||
|
|
||||||
|
logSection('Asserting variable move up, OK!');
|
||||||
|
|
||||||
|
return queryVariables;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This test should really be broken into several smaller tests
|
||||||
|
e2e.scenario({
|
||||||
|
describeName: 'Variables',
|
||||||
|
itName: 'Query Variables CRUD',
|
||||||
|
addScenarioDataSource: true,
|
||||||
|
addScenarioDashBoard: true,
|
||||||
|
skipScenario: false,
|
||||||
|
scenario: () => {
|
||||||
|
e2e.flows.openDashboard(e2e.context().get('lastAddedDashboardUid'));
|
||||||
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.addVariableCTA().click();
|
||||||
|
|
||||||
|
assertDefaultsForNewVariable();
|
||||||
|
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('General').click();
|
||||||
|
e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click();
|
||||||
|
e2e.pages.Dashboard.Settings.Variables.List.addVariableCTA().click();
|
||||||
|
|
||||||
|
let queryVariables: QueryVariableData[] = [
|
||||||
|
{
|
||||||
|
name: 'query1',
|
||||||
|
query: '*',
|
||||||
|
label: 'query1-label',
|
||||||
|
options: ['All', 'A', 'B', 'C'],
|
||||||
|
selectedOption: 'A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'query2',
|
||||||
|
query: '$query1.*',
|
||||||
|
label: 'query2-label',
|
||||||
|
options: ['All', 'AA', 'AB', 'AC'],
|
||||||
|
selectedOption: 'AA',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'query3',
|
||||||
|
query: '$query1.$query2.*',
|
||||||
|
label: 'query3-label',
|
||||||
|
options: ['All', 'AAA', 'AAB', 'AAC'],
|
||||||
|
selectedOption: 'AAA',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
assertAdding3dependantQueryVariablesScenario(queryVariables);
|
||||||
|
|
||||||
|
// assert select updates
|
||||||
|
assertSelects(queryVariables);
|
||||||
|
|
||||||
|
// assert that duplicate works
|
||||||
|
queryVariables = assertDuplicateItem(queryVariables);
|
||||||
|
|
||||||
|
// assert that delete works
|
||||||
|
queryVariables = assertDeleteItem(queryVariables);
|
||||||
|
|
||||||
|
// assert that update works
|
||||||
|
queryVariables = assertUpdateItem(queryVariables);
|
||||||
|
|
||||||
|
// assert that move down works
|
||||||
|
queryVariables = assertMoveDownItem(queryVariables);
|
||||||
|
|
||||||
|
// assert that move up works
|
||||||
|
assertMoveUpItem(queryVariables);
|
||||||
|
},
|
||||||
|
});
|
@ -8,27 +8,25 @@ e2e.scenario({
|
|||||||
skipScenario: false,
|
skipScenario: false,
|
||||||
scenario: () => {
|
scenario: () => {
|
||||||
e2e.flows.openDashboard(e2e.context().get('lastAddedDashboardUid'));
|
e2e.flows.openDashboard(e2e.context().get('lastAddedDashboardUid'));
|
||||||
e2e.pages.Dashboard.toolbarItems('Add panel')
|
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
|
||||||
.should('be.visible') // prevents flakiness
|
|
||||||
.click();
|
|
||||||
e2e.pages.AddDashboard.ctaButtons('Add Query').click();
|
e2e.pages.AddDashboard.ctaButtons('Add Query').click();
|
||||||
|
|
||||||
e2e.pages.Panels.EditPanel.tabItems('Queries').click();
|
e2e.pages.Dashboard.Panels.EditPanel.tabItems('Queries').click();
|
||||||
e2e.pages.Panels.DataSource.TestData.QueryTab.scenarioSelect().select('CSV Metric Values');
|
e2e.pages.Dashboard.Panels.DataSource.TestData.QueryTab.scenarioSelect().select('CSV Metric Values');
|
||||||
|
|
||||||
e2e.pages.Panels.EditPanel.tabItems('Visualization').click();
|
e2e.pages.Dashboard.Panels.EditPanel.tabItems('Visualization').click();
|
||||||
|
|
||||||
e2e.pages.Panels.Visualization.Graph.VisualizationTab.xAxisSection()
|
e2e.pages.Dashboard.Panels.Visualization.Graph.VisualizationTab.xAxisSection()
|
||||||
.contains('Show')
|
.contains('Show')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
e2e.flows.saveDashboard();
|
e2e.flows.saveDashboard();
|
||||||
|
|
||||||
e2e.pages.Dashboard.backArrow().click();
|
e2e.pages.Dashboard.Toolbar.backArrow().click();
|
||||||
|
|
||||||
e2e.pages.Panels.Panel.title('Panel Title').click();
|
e2e.pages.Dashboard.Panels.Panel.title('Panel Title').click();
|
||||||
|
|
||||||
e2e.pages.Panels.Panel.headerItems('Share').click();
|
e2e.pages.Dashboard.Panels.Panel.headerItems('Share').click();
|
||||||
|
|
||||||
e2e.pages.SharePanelModal.linkToRenderedImage().then(($a: any) => {
|
e2e.pages.SharePanelModal.linkToRenderedImage().then(($a: any) => {
|
||||||
// extract the fully qualified href property
|
// extract the fully qualified href property
|
||||||
|
Loading…
Reference in New Issue
Block a user