[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))

![image](8a0ffab3-4783-4e64-9585-ee20ee765d6f)
- [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:
Hannah Mudge 2023-12-19 16:24:05 -07:00 committed by GitHub
parent ea580e69f1
commit 2486ed5bd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 264 additions and 193 deletions

View file

@ -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>
);

View file

@ -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',
}),
},
},

View file

@ -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>

View file

@ -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()}
/>

View file

@ -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();

View file

@ -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`);
});
});
}

View file

@ -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",

View file

@ -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": "時間スライダー",

View file

@ -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": "时间滑块",