mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Controls] Re-add filtering settings (#172857)
Closes https://github.com/elastic/kibana/issues/162985 ## Summary This PR re-adds UI for the filtering settings that allow authors to determine whether or not they want the unified search bar / time picker to sync with the control group. To provide some context, we **used** to have these settings, but they were deemed over complicated and the UI to control them was removed back in `v8.3`. Here's a screenshot of what they used to look like: <p align="center"><img width="700" src="c84c4be0
-a12e-46fa-b7b5-2e94682d8bbf"/></p> > [!NOTE] > These settings still existed in the code, even after `v8.3` - all we did was remove the UI to control them. After customer feedback, we decided to re-add the UI to control these settings, with **some** simplification - specifically, after investigating how other apps (Maps, Lens, etc.) handle unified search bar settings, I noticed that the control group was the **only** place that considered the query bar to be different than / seperate from filter pills. Therefore, rather than having **three** toggles like we did previously (filter pills, query bar, and time picker), I combined the filter pills + query bar settings into a single "Apply global filters" toggle. So now, our unified search bar settings have only **two** toggles, like so: <p align="center"><img width="500" src="ba8d3a8f
-ee0c-48c6-8d35-6068571013b3"/></p> This is not only simpler than it was in versions less than `v8.3.0`, it is also more consistent with how other apps do it. > [!IMPORTANT] > After some design feedback, I moved the old descriptions for the "Validate user selections" and "Chain controls" settings into tooltips + switched to a compressed `EuiSwitch` for all the settings. > > All of the screenshots in this PR description have been updated to reflect this change, but some screenshots in the comments below may be out of date. ### Summary of Control Group Settings by Version | Version | Screenshot | |--------|--------| | Version <= `v8.2.0` | <img width="535" src="c84c4be0
-a12e-46fa-b7b5-2e94682d8bbf"/> | | `v8.3.0` <= version <= `v8.12.0` | <img width="535" src="cb49f33e
-ce7a-4a29-9830-2c3feafdcb23"/> | | This branch (`v8.13.0`) | <img width="535" src="a76fc1f9
-5b2d-4dc5-855a-6a284256e8c5"/> | ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed ([Link](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4638))  - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
parent
ea580e69f1
commit
2486ed5bd1
9 changed files with 264 additions and 193 deletions
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
export const ControlSettingTooltipLabel = ({
|
||||
label,
|
||||
tooltip,
|
||||
}: {
|
||||
label: string;
|
||||
tooltip: string;
|
||||
}) => (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs" responsive={false}>
|
||||
<EuiFlexItem grow={false}>{label}</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
css={css`
|
||||
margin-top: 0px !important;
|
||||
`}
|
||||
>
|
||||
<EuiIconTip content={tooltip} position="right" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
|
@ -246,54 +246,46 @@ export const ControlGroupStrings = {
|
|||
defaultMessage: 'Cancel',
|
||||
}),
|
||||
},
|
||||
validateSelections: {
|
||||
getValidateSelectionsTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.validate.title', {
|
||||
defaultMessage: 'Validate user selections',
|
||||
}),
|
||||
getValidateSelectionsSubTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.validate.subtitle', {
|
||||
defaultMessage:
|
||||
'Automatically ignore any control selection that would result in no data.',
|
||||
selectionSettings: {
|
||||
getSelectionSettingsTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.selectionSettings', {
|
||||
defaultMessage: 'Selections',
|
||||
}),
|
||||
validateSelections: {
|
||||
getValidateSelectionsTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.validate.title', {
|
||||
defaultMessage: 'Validate user selections',
|
||||
}),
|
||||
getValidateSelectionsSubTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.validate.subtitle', {
|
||||
defaultMessage:
|
||||
'Automatically ignore any control selection that would result in no data.',
|
||||
}),
|
||||
},
|
||||
controlChaining: {
|
||||
getHierarchyTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.hierarchy.title', {
|
||||
defaultMessage: 'Chain controls',
|
||||
}),
|
||||
getHierarchySubTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.hierarchy.subtitle', {
|
||||
defaultMessage:
|
||||
'Selections in one control narrow down available options in the next. Controls are chained from left to right.',
|
||||
}),
|
||||
},
|
||||
},
|
||||
controlChaining: {
|
||||
getHierarchyTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.hierarchy.title', {
|
||||
defaultMessage: 'Chain controls',
|
||||
filteringSettings: {
|
||||
getFilteringSettingsTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.filteringSettings', {
|
||||
defaultMessage: 'Filtering',
|
||||
}),
|
||||
getHierarchySubTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.hierarchy.subtitle', {
|
||||
defaultMessage:
|
||||
'Selections in one control narrow down available options in the next. Controls are chained from left to right.',
|
||||
getUseGlobalFiltersTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.filtering.useGlobalFilters', {
|
||||
defaultMessage: 'Apply global filters to controls',
|
||||
}),
|
||||
},
|
||||
/** TODO: These translations aren't used but they will be once https://github.com/elastic/kibana/issues/162985 is resolved */
|
||||
querySync: {
|
||||
getQuerySettingsTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.query.searchSettingsTitle', {
|
||||
defaultMessage: 'Sync with query bar',
|
||||
}),
|
||||
getQuerySettingsSubtitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.query.useAllSearchSettingsTitle', {
|
||||
defaultMessage:
|
||||
'Keeps the control group in sync with the query bar by applying time range, filter pills, and queries from the query bar',
|
||||
}),
|
||||
getAdvancedSettingsTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.query.advancedSettings', {
|
||||
defaultMessage: 'Advanced',
|
||||
}),
|
||||
getIgnoreTimerangeTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.query.ignoreTimerange', {
|
||||
defaultMessage: 'Ignore timerange',
|
||||
}),
|
||||
getIgnoreQueryTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.query.ignoreQuery', {
|
||||
defaultMessage: 'Ignore query bar',
|
||||
}),
|
||||
getIgnoreFilterPillsTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.query.ignoreFilterPills', {
|
||||
defaultMessage: 'Ignore filter pills',
|
||||
getUseGlobalTimeRangeTitle: () =>
|
||||
i18n.translate('controls.controlGroup.management.filtering.useGlobalTimeRange', {
|
||||
defaultMessage: 'Apply global time range to controls',
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
|
|
@ -16,30 +16,31 @@
|
|||
|
||||
import fastIsEqual from 'fast-deep-equal';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
|
||||
import {
|
||||
EuiFlyoutHeader,
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiButtonGroup,
|
||||
EuiFlyoutBody,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiTitle,
|
||||
EuiFlyoutBody,
|
||||
EuiFlyoutFooter,
|
||||
EuiButton,
|
||||
EuiFormRow,
|
||||
EuiButtonEmpty,
|
||||
EuiSpacer,
|
||||
EuiFlyoutHeader,
|
||||
EuiForm,
|
||||
EuiSwitch,
|
||||
EuiText,
|
||||
EuiFormRow,
|
||||
EuiHorizontalRule,
|
||||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { CONTROL_LAYOUT_OPTIONS } from './editor_constants';
|
||||
import { ControlGroupStrings } from '../control_group_strings';
|
||||
import { ControlStyle } from '../../types';
|
||||
import { ParentIgnoreSettings } from '../..';
|
||||
import { ControlGroupInput } from '..';
|
||||
import { ParentIgnoreSettings } from '../..';
|
||||
import { getDefaultControlGroupInput } from '../../../common';
|
||||
import { ControlSettingTooltipLabel } from '../../components/control_setting_tooltip_label';
|
||||
import { ControlStyle } from '../../types';
|
||||
import { ControlGroupStrings } from '../control_group_strings';
|
||||
import { CONTROL_LAYOUT_OPTIONS } from './editor_constants';
|
||||
|
||||
interface EditControlGroupProps {
|
||||
initialInput: ControlGroupInput;
|
||||
|
@ -102,7 +103,7 @@ export const ControlGroupEditor = ({
|
|||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
<EuiFlyoutBody data-test-subj="control-group-settings-flyout">
|
||||
<EuiForm>
|
||||
<EuiForm component="form" fullWidth>
|
||||
<EuiFormRow label={ControlGroupStrings.management.labelPosition.getLabelPositionTitle()}>
|
||||
<EuiButtonGroup
|
||||
color="primary"
|
||||
|
@ -112,43 +113,69 @@ export const ControlGroupEditor = ({
|
|||
legend={ControlGroupStrings.management.labelPosition.getLabelPositionLegend()}
|
||||
onChange={(newControlStyle: string) => {
|
||||
// The UI copy calls this setting labelPosition, but to avoid an unnecessary migration it will be left as controlStyle in the state.
|
||||
updateControlGroupEditorSetting({ controlStyle: newControlStyle as ControlStyle });
|
||||
updateControlGroupEditorSetting({
|
||||
controlStyle: newControlStyle as ControlStyle,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
<EuiHorizontalRule margin="m" />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<EuiFormRow
|
||||
label={ControlGroupStrings.management.filteringSettings.getFilteringSettingsTitle()}
|
||||
>
|
||||
<div>
|
||||
<EuiSwitch
|
||||
compressed
|
||||
data-test-subj="control-group-filter-sync"
|
||||
label={ControlGroupStrings.management.filteringSettings.getUseGlobalFiltersTitle()}
|
||||
onChange={(e) =>
|
||||
updateIgnoreSetting({
|
||||
ignoreFilters: !e.target.checked,
|
||||
ignoreQuery: !e.target.checked,
|
||||
})
|
||||
}
|
||||
checked={
|
||||
!Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreFilters) ||
|
||||
!Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreQuery)
|
||||
}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSwitch
|
||||
compressed
|
||||
data-test-subj="control-group-query-sync-time-range"
|
||||
label={ControlGroupStrings.management.filteringSettings.getUseGlobalTimeRangeTitle()}
|
||||
onChange={(e) => updateIgnoreSetting({ ignoreTimerange: !e.target.checked })}
|
||||
checked={!Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreTimerange)}
|
||||
/>
|
||||
</div>
|
||||
</EuiFormRow>
|
||||
|
||||
<EuiFormRow
|
||||
label={ControlGroupStrings.management.selectionSettings.getSelectionSettingsTitle()}
|
||||
>
|
||||
<div>
|
||||
<EuiSwitch
|
||||
compressed
|
||||
data-test-subj="control-group-validate-selections"
|
||||
label={ControlGroupStrings.management.validateSelections.getValidateSelectionsTitle()}
|
||||
showLabel={false}
|
||||
label={
|
||||
<ControlSettingTooltipLabel
|
||||
label={ControlGroupStrings.management.selectionSettings.validateSelections.getValidateSelectionsTitle()}
|
||||
tooltip={ControlGroupStrings.management.selectionSettings.validateSelections.getValidateSelectionsSubTitle()}
|
||||
/>
|
||||
}
|
||||
checked={!Boolean(controlGroupEditorState.ignoreParentSettings?.ignoreValidations)}
|
||||
onChange={(e) => updateIgnoreSetting({ ignoreValidations: !e.target.checked })}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxs">
|
||||
<h3>
|
||||
{ControlGroupStrings.management.validateSelections.getValidateSelectionsTitle()}
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiText size="s">
|
||||
<p>
|
||||
{ControlGroupStrings.management.validateSelections.getValidateSelectionsSubTitle()}
|
||||
</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiHorizontalRule margin="m" />
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSwitch
|
||||
compressed
|
||||
data-test-subj="control-group-chaining"
|
||||
label={ControlGroupStrings.management.controlChaining.getHierarchyTitle()}
|
||||
showLabel={false}
|
||||
label={
|
||||
<ControlSettingTooltipLabel
|
||||
label={ControlGroupStrings.management.selectionSettings.controlChaining.getHierarchyTitle()}
|
||||
tooltip={ControlGroupStrings.management.selectionSettings.controlChaining.getHierarchySubTitle()}
|
||||
/>
|
||||
}
|
||||
checked={controlGroupEditorState.chainingSystem === 'HIERARCHICAL'}
|
||||
onChange={(e) =>
|
||||
updateControlGroupEditorSetting({
|
||||
|
@ -156,31 +183,25 @@ export const ControlGroupEditor = ({
|
|||
})
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="xxs">
|
||||
<h3>{ControlGroupStrings.management.controlChaining.getHierarchyTitle()}</h3>
|
||||
</EuiTitle>
|
||||
<EuiText size="s">
|
||||
<p>{ControlGroupStrings.management.controlChaining.getHierarchySubTitle()}</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</div>
|
||||
</EuiFormRow>
|
||||
|
||||
{controlCount > 0 && (
|
||||
<>
|
||||
<EuiHorizontalRule margin="m" />
|
||||
<EuiSpacer size="m" />
|
||||
<EuiButtonEmpty
|
||||
onClick={onDeleteAll}
|
||||
data-test-subj="delete-all-controls-button"
|
||||
aria-label={'delete-all'}
|
||||
iconType="trash"
|
||||
color="danger"
|
||||
flush="left"
|
||||
size="s"
|
||||
>
|
||||
{ControlGroupStrings.management.getDeleteAllButtonTitle()}
|
||||
</EuiButtonEmpty>
|
||||
<EuiFormRow>
|
||||
<EuiButtonEmpty
|
||||
onClick={onDeleteAll}
|
||||
data-test-subj="delete-all-controls-button"
|
||||
aria-label={'delete-all'}
|
||||
iconType="trash"
|
||||
color="danger"
|
||||
flush="left"
|
||||
size="s"
|
||||
>
|
||||
{ControlGroupStrings.management.getDeleteAllButtonTitle()}
|
||||
</EuiButtonEmpty>
|
||||
</EuiFormRow>
|
||||
</>
|
||||
)}
|
||||
</EuiForm>
|
||||
|
|
|
@ -9,17 +9,7 @@
|
|||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
import {
|
||||
Direction,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFormRow,
|
||||
EuiIconTip,
|
||||
EuiLoadingSpinner,
|
||||
EuiRadioGroup,
|
||||
EuiSwitch,
|
||||
} from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { Direction, EuiFormRow, EuiLoadingSpinner, EuiRadioGroup, EuiSwitch } from '@elastic/eui';
|
||||
|
||||
import { ControlEditorProps, OptionsListEmbeddableInput } from '../..';
|
||||
import {
|
||||
|
@ -33,20 +23,7 @@ import {
|
|||
} from '../../../common/options_list/suggestions_sorting';
|
||||
import { pluginServices } from '../../services';
|
||||
import { OptionsListStrings } from './options_list_strings';
|
||||
|
||||
const TooltipText = ({ label, tooltip }: { label: string; tooltip: string }) => (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs" responsive={false}>
|
||||
<EuiFlexItem grow={false}>{label}</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
css={css`
|
||||
margin-top: 0px !important;
|
||||
`}
|
||||
>
|
||||
<EuiIconTip content={tooltip} position="right" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
import { ControlSettingTooltipLabel } from '../../components/control_setting_tooltip_label';
|
||||
|
||||
const selectionOptions = [
|
||||
{
|
||||
|
@ -65,7 +42,7 @@ const allSearchOptions = [
|
|||
{
|
||||
id: 'prefix',
|
||||
label: (
|
||||
<TooltipText
|
||||
<ControlSettingTooltipLabel
|
||||
label={OptionsListStrings.editor.searchTypes.prefix.getLabel()}
|
||||
tooltip={OptionsListStrings.editor.searchTypes.prefix.getTooltip()}
|
||||
/>
|
||||
|
@ -75,7 +52,7 @@ const allSearchOptions = [
|
|||
{
|
||||
id: 'wildcard',
|
||||
label: (
|
||||
<TooltipText
|
||||
<ControlSettingTooltipLabel
|
||||
label={OptionsListStrings.editor.searchTypes.wildcard.getLabel()}
|
||||
tooltip={OptionsListStrings.editor.searchTypes.wildcard.getTooltip()}
|
||||
/>
|
||||
|
@ -85,7 +62,7 @@ const allSearchOptions = [
|
|||
{
|
||||
id: 'exact',
|
||||
label: (
|
||||
<TooltipText
|
||||
<ControlSettingTooltipLabel
|
||||
label={OptionsListStrings.editor.searchTypes.exact.getLabel()}
|
||||
tooltip={OptionsListStrings.editor.searchTypes.exact.getTooltip()}
|
||||
/>
|
||||
|
@ -207,7 +184,7 @@ export const OptionsListEditorOptions = ({
|
|||
<EuiFormRow label={OptionsListStrings.editor.getAdditionalSettingsTitle()}>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<TooltipText
|
||||
<ControlSettingTooltipLabel
|
||||
label={OptionsListStrings.editor.getRunPastTimeoutTitle()}
|
||||
tooltip={OptionsListStrings.editor.getRunPastTimeoutTooltip()}
|
||||
/>
|
||||
|
|
|
@ -6,21 +6,28 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { OPTIONS_LIST_CONTROL } from '@kbn/controls-plugin/common';
|
||||
import { OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL } from '@kbn/controls-plugin/common';
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const find = getService('find');
|
||||
const { dashboardControls, dashboard } = getPageObjects(['dashboardControls', 'dashboard']);
|
||||
const queryBar = getService('queryBar');
|
||||
const filterBar = getService('filterBar');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const { dashboardControls, dashboard, timePicker } = getPageObjects([
|
||||
'dashboardControls',
|
||||
'dashboard',
|
||||
'timePicker',
|
||||
]);
|
||||
|
||||
describe('Dashboard control group settings', () => {
|
||||
before(async () => {
|
||||
await dashboard.navigateToApp();
|
||||
await dashboard.gotoDashboardLandingPage();
|
||||
await dashboard.clickNewDashboard();
|
||||
await timePicker.setDefaultDataRange();
|
||||
await dashboard.saveDashboard('Test Control Group Settings');
|
||||
});
|
||||
|
||||
|
@ -76,6 +83,93 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('filtering settings', async () => {
|
||||
let firstOptionsListId: string;
|
||||
let beforeCount: number;
|
||||
|
||||
let rangeSliderId: string;
|
||||
let beforeRange: number;
|
||||
|
||||
const getRange = async () => {
|
||||
await dashboardControls.rangeSliderWaitForLoading(rangeSliderId);
|
||||
const lower = await dashboardControls.rangeSliderGetLowerBoundAttribute(
|
||||
rangeSliderId,
|
||||
'placeholder'
|
||||
);
|
||||
const upper = await dashboardControls.rangeSliderGetUpperBoundAttribute(
|
||||
rangeSliderId,
|
||||
'placeholder'
|
||||
);
|
||||
return parseInt(upper, 10) - parseInt(lower, 10);
|
||||
};
|
||||
|
||||
before(async () => {
|
||||
await dashboardControls.createControl({
|
||||
controlType: RANGE_SLIDER_CONTROL,
|
||||
dataViewTitle: 'animals-*',
|
||||
fieldName: 'weightLbs',
|
||||
});
|
||||
await dashboard.clickQuickSave();
|
||||
|
||||
firstOptionsListId = (await dashboardControls.getAllControlIds())[0];
|
||||
await dashboardControls.optionsListWaitForLoading(firstOptionsListId);
|
||||
await dashboardControls.optionsListOpenPopover(firstOptionsListId);
|
||||
beforeCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
|
||||
|
||||
rangeSliderId = (await dashboardControls.getAllControlIds())[2];
|
||||
beforeRange = await getRange();
|
||||
});
|
||||
|
||||
describe('do not apply global filters', async () => {
|
||||
it('- filter pills', async () => {
|
||||
await filterBar.addFilter({ field: 'animal.keyword', operation: 'is', value: 'cat' });
|
||||
await dashboardControls.optionsListOpenPopover(firstOptionsListId);
|
||||
let afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
|
||||
expect(afterCount).to.be.lessThan(beforeCount);
|
||||
await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
|
||||
|
||||
await dashboardControls.updateFilterSyncSetting(false);
|
||||
await dashboardControls.optionsListOpenPopover(firstOptionsListId);
|
||||
afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
|
||||
expect(afterCount).to.be.equal(beforeCount);
|
||||
|
||||
await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
|
||||
await filterBar.removeAllFilters();
|
||||
});
|
||||
|
||||
it('- query', async () => {
|
||||
await queryBar.setQuery('weightLbs < 40');
|
||||
await queryBar.submitQuery();
|
||||
let afterRange = await getRange();
|
||||
expect(afterRange).to.be.equal(beforeRange);
|
||||
await dashboardControls.rangeSliderEnsurePopoverIsClosed(rangeSliderId);
|
||||
|
||||
await dashboardControls.updateFilterSyncSetting(true);
|
||||
afterRange = await getRange();
|
||||
expect(afterRange).to.be.lessThan(beforeRange);
|
||||
await dashboardControls.rangeSliderEnsurePopoverIsClosed(rangeSliderId);
|
||||
await queryBar.clearQuery();
|
||||
await queryBar.submitQuery();
|
||||
});
|
||||
});
|
||||
|
||||
it('do not apply time range', async () => {
|
||||
await timePicker.setCommonlyUsedTime('Today');
|
||||
await dashboardControls.optionsListOpenPopover(firstOptionsListId);
|
||||
let afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
|
||||
expect(afterCount).to.be.equal(0);
|
||||
await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
|
||||
|
||||
await dashboardControls.updateTimeRangeSyncSetting(false);
|
||||
await dashboardControls.optionsListOpenPopover(firstOptionsListId);
|
||||
afterCount = await dashboardControls.optionsListPopoverGetAvailableOptionsCount();
|
||||
expect(afterCount).to.be.equal(beforeCount);
|
||||
await dashboardControls.optionsListEnsurePopoverIsClosed(firstOptionsListId);
|
||||
await timePicker.setDefaultDataRange();
|
||||
await dashboardControls.updateTimeRangeSyncSetting(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('flyout only show settings that are relevant', async () => {
|
||||
before(async () => {
|
||||
await dashboard.switchToEditMode();
|
||||
|
|
|
@ -185,48 +185,20 @@ export class DashboardPageControls extends FtrService {
|
|||
await this.testSubjects.click('control-group-editor-save');
|
||||
}
|
||||
|
||||
public async updateAllQuerySyncSettings(querySync: boolean) {
|
||||
this.log.debug(`Update all control group query sync settings to ${querySync}`);
|
||||
public async updateFilterSyncSetting(querySync: boolean) {
|
||||
this.log.debug(`Update filter sync setting to ${querySync}`);
|
||||
await this.openControlGroupSettingsFlyout();
|
||||
await this.setSwitchState(querySync, 'control-group-query-sync');
|
||||
await this.setSwitchState(querySync, 'control-group-filter-sync');
|
||||
await this.testSubjects.click('control-group-editor-save');
|
||||
}
|
||||
|
||||
public async ensureAdvancedQuerySyncIsOpened() {
|
||||
const advancedAccordion = await this.testSubjects.find(`control-group-query-sync-advanced`);
|
||||
const opened = await advancedAccordion.elementHasClass('euiAccordion-isOpen');
|
||||
if (!opened) {
|
||||
await this.testSubjects.click(`control-group-query-sync-advanced`);
|
||||
await this.retry.try(async () => {
|
||||
expect(await advancedAccordion.elementHasClass('euiAccordion-isOpen')).to.be(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async updateSyncTimeRangeAdvancedSetting(syncTimeRange: boolean) {
|
||||
this.log.debug(`Update filter sync advanced setting to ${syncTimeRange}`);
|
||||
public async updateTimeRangeSyncSetting(syncTimeRange: boolean) {
|
||||
this.log.debug(`Update time range sync setting to ${syncTimeRange}`);
|
||||
await this.openControlGroupSettingsFlyout();
|
||||
await this.ensureAdvancedQuerySyncIsOpened();
|
||||
await this.setSwitchState(syncTimeRange, 'control-group-query-sync-time-range');
|
||||
await this.testSubjects.click('control-group-editor-save');
|
||||
}
|
||||
|
||||
public async updateSyncQueryAdvancedSetting(syncQuery: boolean) {
|
||||
this.log.debug(`Update filter sync advanced setting to ${syncQuery}`);
|
||||
await this.openControlGroupSettingsFlyout();
|
||||
await this.ensureAdvancedQuerySyncIsOpened();
|
||||
await this.setSwitchState(syncQuery, 'control-group-query-sync-query');
|
||||
await this.testSubjects.click('control-group-editor-save');
|
||||
}
|
||||
|
||||
public async updateSyncFilterAdvancedSetting(syncFilters: boolean) {
|
||||
this.log.debug(`Update filter sync advanced setting to ${syncFilters}`);
|
||||
await this.openControlGroupSettingsFlyout();
|
||||
await this.ensureAdvancedQuerySyncIsOpened();
|
||||
await this.setSwitchState(syncFilters, 'control-group-query-sync-filters');
|
||||
await this.testSubjects.click('control-group-editor-save');
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------
|
||||
Individual controls functions
|
||||
----------------------------------------------------------- */
|
||||
|
@ -392,10 +364,11 @@ export class DashboardPageControls extends FtrService {
|
|||
|
||||
public async optionsListOpenPopover(controlId: string) {
|
||||
this.log.debug(`Opening popover for Options List: ${controlId}`);
|
||||
|
||||
await this.testSubjects.click(`optionsList-control-${controlId}`);
|
||||
await this.retry.try(async () => {
|
||||
await this.testSubjects.existOrFail(`optionsList-control-popover`);
|
||||
await this.testSubjects.click(`optionsList-control-${controlId}`);
|
||||
await this.retry.waitForWithTimeout('popover to open', 500, async () => {
|
||||
return await this.testSubjects.exists(`optionsList-control-popover`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -488,12 +488,6 @@
|
|||
"controls.controlGroup.management.layout.large": "Large",
|
||||
"controls.controlGroup.management.layout.medium": "Moyenne",
|
||||
"controls.controlGroup.management.layout.small": "Petite",
|
||||
"controls.controlGroup.management.query.advancedSettings": "Avancé",
|
||||
"controls.controlGroup.management.query.ignoreFilterPills": "Ignorer les pilules de filtre",
|
||||
"controls.controlGroup.management.query.ignoreQuery": "Ignorer la barre de requête",
|
||||
"controls.controlGroup.management.query.ignoreTimerange": "Ignorer la plage temporelle",
|
||||
"controls.controlGroup.management.query.searchSettingsTitle": "Synchronisation avec la barre de requête",
|
||||
"controls.controlGroup.management.query.useAllSearchSettingsTitle": "Assure la synchronisation entre le groupe de contrôle et la barre de requête, en appliquant une plage temporelle, des pilules de filtre et des requêtes de la barre de requête",
|
||||
"controls.controlGroup.management.validate.subtitle": "Ignorez automatiquement toutes les sélections de contrôle qui ne donneraient aucune donnée.",
|
||||
"controls.controlGroup.management.validate.title": "Valider les sélections utilisateur",
|
||||
"controls.controlGroup.timeSlider.title": "Curseur temporel",
|
||||
|
|
|
@ -488,12 +488,6 @@
|
|||
"controls.controlGroup.management.layout.large": "大",
|
||||
"controls.controlGroup.management.layout.medium": "中",
|
||||
"controls.controlGroup.management.layout.small": "小",
|
||||
"controls.controlGroup.management.query.advancedSettings": "高度な設定",
|
||||
"controls.controlGroup.management.query.ignoreFilterPills": "フィルターピルを無視",
|
||||
"controls.controlGroup.management.query.ignoreQuery": "クエリバーを無視",
|
||||
"controls.controlGroup.management.query.ignoreTimerange": "時間範囲を無視",
|
||||
"controls.controlGroup.management.query.searchSettingsTitle": "クエリバーと同期",
|
||||
"controls.controlGroup.management.query.useAllSearchSettingsTitle": "時間範囲、フィルターピル、クエリバーからのクエリを適用して、コントロールグループを常にクエリと同期します",
|
||||
"controls.controlGroup.management.validate.subtitle": "データがないコントロール選択は自動的に無視されます。",
|
||||
"controls.controlGroup.management.validate.title": "ユーザー選択を検証",
|
||||
"controls.controlGroup.timeSlider.title": "時間スライダー",
|
||||
|
|
|
@ -488,12 +488,6 @@
|
|||
"controls.controlGroup.management.layout.large": "大",
|
||||
"controls.controlGroup.management.layout.medium": "中",
|
||||
"controls.controlGroup.management.layout.small": "小",
|
||||
"controls.controlGroup.management.query.advancedSettings": "高级",
|
||||
"controls.controlGroup.management.query.ignoreFilterPills": "忽略筛选胶囊",
|
||||
"controls.controlGroup.management.query.ignoreQuery": "忽略查询栏",
|
||||
"controls.controlGroup.management.query.ignoreTimerange": "忽略时间范围",
|
||||
"controls.controlGroup.management.query.searchSettingsTitle": "与查询栏同步",
|
||||
"controls.controlGroup.management.query.useAllSearchSettingsTitle": "通过从查询栏应用时间范围、筛选胶囊和查询,使控件组与查询栏保持同步",
|
||||
"controls.controlGroup.management.validate.subtitle": "自动忽略所有不会生成数据的控件选择。",
|
||||
"controls.controlGroup.management.validate.title": "验证用户选择",
|
||||
"controls.controlGroup.timeSlider.title": "时间滑块",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue