mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[TSVB] Disables the input string mode (#110571)
* [TSVB] Remove the input string mode * Fix some tests * Add some functional tests and fix failing CI * Update telemetry mappings * Rename useStringIndices to allowStringIndices, move it from TSVB to Data constants and refactor test * Apply text suggestions from code review Co-authored-by: Kaarina Tungseth <kaarina.tungseth@elastic.co> * Apply formatting and remove unused translations * Fix labels * Remove unused import * Move popover toggling to checkIndexPatternSelectionModeSwitchIsEnabled function to prevent flakiness * Update some visual_builder_page functions * Remove accidentally added newlines * Move TSVB ui settings to constants, remove tooltip and update popover text * Handle the case of editing advanced settings is restricted * Add requiresPageReload to UI setting and condition for the case the setting is already enabled Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kaarina Tungseth <kaarina.tungseth@elastic.co>
This commit is contained in:
parent
da1ae4923a
commit
abdb7a4c49
16 changed files with 158 additions and 22 deletions
|
@ -276,6 +276,10 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
|
|||
type: 'long',
|
||||
_meta: { description: 'Non-default value of setting.' },
|
||||
},
|
||||
'metrics:allowStringIndices': {
|
||||
type: 'boolean',
|
||||
_meta: { description: 'Non-default value of setting.' },
|
||||
},
|
||||
'query:allowLeadingWildcards': {
|
||||
type: 'boolean',
|
||||
_meta: { description: 'Non-default value of setting.' },
|
||||
|
|
|
@ -91,6 +91,7 @@ export interface UsageStats {
|
|||
'savedObjects:listingLimit': number;
|
||||
'query:queryString:options': string;
|
||||
'metrics:max_buckets': number;
|
||||
'metrics:allowStringIndices': boolean;
|
||||
'query:allowLeadingWildcards': boolean;
|
||||
metaFields: string[];
|
||||
'indexPattern:placeholder': string;
|
||||
|
|
|
@ -7428,6 +7428,12 @@
|
|||
"description": "Non-default value of setting."
|
||||
}
|
||||
},
|
||||
"metrics:allowStringIndices": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
"description": "Non-default value of setting."
|
||||
}
|
||||
},
|
||||
"query:allowLeadingWildcards": {
|
||||
"type": "boolean",
|
||||
"_meta": {
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export const MAX_BUCKETS_SETTING = 'metrics:max_buckets';
|
||||
export const UI_SETTINGS = {
|
||||
MAX_BUCKETS_SETTING: 'metrics:max_buckets',
|
||||
ALLOW_STRING_INDICES: 'metrics:allowStringIndices',
|
||||
};
|
||||
export const INDEXES_SEPARATOR = ',';
|
||||
export const AUTO_INTERVAL = 'auto';
|
||||
export const ROUTES = {
|
||||
|
|
|
@ -17,9 +17,17 @@ import {
|
|||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
EuiText,
|
||||
EuiLink,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import type { PopoverProps } from './types';
|
||||
import { getCoreStart, getUISettings } from '../../../../services';
|
||||
import { UI_SETTINGS } from '../../../../../common/constants';
|
||||
|
||||
const allowStringIndicesMessage = i18n.translate(
|
||||
'visTypeTimeseries.indexPatternSelect.switchModePopover.allowStringIndices',
|
||||
{ defaultMessage: 'Allow string indices in TSVB' }
|
||||
);
|
||||
|
||||
export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverProps) => {
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
|
@ -30,6 +38,39 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro
|
|||
onModeChange(!useKibanaIndices);
|
||||
}, [onModeChange, useKibanaIndices]);
|
||||
|
||||
const { application } = getCoreStart();
|
||||
const canEditAdvancedSettings = application.capabilities.advancedSettings.save;
|
||||
|
||||
const handleAllowStringIndicesLinkClick = useCallback(
|
||||
() =>
|
||||
application.navigateToApp('management', {
|
||||
path: `/kibana/settings?query=${UI_SETTINGS.ALLOW_STRING_INDICES}`,
|
||||
}),
|
||||
[application]
|
||||
);
|
||||
|
||||
const stringIndicesAllowed = getUISettings().get(UI_SETTINGS.ALLOW_STRING_INDICES);
|
||||
const isSwitchDisabled = useKibanaIndices && !stringIndicesAllowed;
|
||||
|
||||
let allowStringIndicesLabel;
|
||||
if (!stringIndicesAllowed) {
|
||||
allowStringIndicesLabel = (
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.indexPatternSelect.switchModePopover.enableAllowStringIndices"
|
||||
defaultMessage="To search by Elasticsearch indices enable {allowStringIndices} setting."
|
||||
values={{
|
||||
allowStringIndices: canEditAdvancedSettings ? (
|
||||
<EuiLink color="accent" onClick={handleAllowStringIndicesLinkClick}>
|
||||
{allowStringIndicesMessage}
|
||||
</EuiLink>
|
||||
) : (
|
||||
<strong>{allowStringIndicesMessage}</strong>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiPopover
|
||||
button={
|
||||
|
@ -42,14 +83,18 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro
|
|||
}
|
||||
)}
|
||||
onClick={onButtonClick}
|
||||
data-test-subj="switchIndexPatternSelectionModePopover"
|
||||
data-test-subj="switchIndexPatternSelectionModePopoverButton"
|
||||
/>
|
||||
}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={closePopover}
|
||||
style={{ height: 'auto' }}
|
||||
initialFocus={false}
|
||||
>
|
||||
<div style={{ width: '360px' }}>
|
||||
<div
|
||||
style={{ width: '360px' }}
|
||||
data-test-subj="switchIndexPatternSelectionModePopoverContent"
|
||||
>
|
||||
<EuiPopoverTitle>
|
||||
{i18n.translate('visTypeTimeseries.indexPatternSelect.switchModePopover.title', {
|
||||
defaultMessage: 'Index pattern selection mode',
|
||||
|
@ -59,7 +104,10 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro
|
|||
<FormattedMessage
|
||||
id="visTypeTimeseries.indexPatternSelect.switchModePopover.text"
|
||||
defaultMessage="An index pattern identifies one or more Elasticsearch indices that you want to explore.
|
||||
You can use Elasticsearch indices or Kibana index patterns (recommended)."
|
||||
Kibana index patterns are used by default. {allowStringIndicesLabel}"
|
||||
values={{
|
||||
allowStringIndicesLabel,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
|
@ -68,10 +116,11 @@ export const SwitchModePopover = ({ onModeChange, useKibanaIndices }: PopoverPro
|
|||
label={i18n.translate(
|
||||
'visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices',
|
||||
{
|
||||
defaultMessage: 'Use only Kibana index patterns',
|
||||
defaultMessage: 'Use only index patterns',
|
||||
}
|
||||
)}
|
||||
onChange={switchMode}
|
||||
disabled={isSwitchDisabled}
|
||||
data-test-subj="switchIndexPatternSelectionMode"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -43,7 +43,7 @@ export const UseIndexPatternModeCallout = () => {
|
|||
<p>
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationMessage"
|
||||
defaultMessage="Great news! You can now visualize the data from Elasticsearch indices or Kibana index patterns. {indexPatternModeLink}."
|
||||
defaultMessage="Great news! You can now visualize the data from Kibana index patterns (recommended) or Elasticsearch indices. {indexPatternModeLink}."
|
||||
values={{
|
||||
indexPatternModeLink: (
|
||||
<EuiLink href={indexPatternModeLink} target="_blank" external>
|
||||
|
|
|
@ -20,8 +20,8 @@ import { getSeriesData } from './vis_data/get_series_data';
|
|||
import { getTableData } from './vis_data/get_table_data';
|
||||
import { getEsQueryConfig } from './vis_data/helpers/get_es_query_uisettings';
|
||||
import { getCachedIndexPatternFetcher } from './search_strategies/lib/cached_index_pattern_fetcher';
|
||||
import { MAX_BUCKETS_SETTING } from '../../common/constants';
|
||||
import { getIntervalAndTimefield } from './vis_data/get_interval_and_timefield';
|
||||
import { UI_SETTINGS } from '../../common/constants';
|
||||
|
||||
export async function getVisData(
|
||||
requestContext: VisTypeTimeseriesRequestHandlerContext,
|
||||
|
@ -57,7 +57,7 @@ export async function getVisData(
|
|||
index = await cachedIndexPatternFetcher(index.indexPatternString, true);
|
||||
}
|
||||
|
||||
const maxBuckets = await uiSettings.get<number>(MAX_BUCKETS_SETTING);
|
||||
const maxBuckets = await uiSettings.get<number>(UI_SETTINGS.MAX_BUCKETS_SETTING);
|
||||
const { min, max } = request.body.timerange;
|
||||
|
||||
return getIntervalAndTimefield(
|
||||
|
|
|
@ -15,7 +15,7 @@ import type {
|
|||
VisTypeTimeseriesRequestHandlerContext,
|
||||
VisTypeTimeseriesRequest,
|
||||
} from '../../../types';
|
||||
import { MAX_BUCKETS_SETTING } from '../../../../common/constants';
|
||||
import { UI_SETTINGS } from '../../../../common/constants';
|
||||
|
||||
export class DefaultSearchStrategy extends AbstractSearchStrategy {
|
||||
async checkForViability(
|
||||
|
@ -29,7 +29,7 @@ export class DefaultSearchStrategy extends AbstractSearchStrategy {
|
|||
capabilities: new DefaultSearchCapabilities({
|
||||
panel: req.body.panels ? req.body.panels[0] : null,
|
||||
timezone: req.body.timerange?.timezone,
|
||||
maxBucketsLimit: await uiSettings.get(MAX_BUCKETS_SETTING),
|
||||
maxBucketsLimit: await uiSettings.get(UI_SETTINGS.MAX_BUCKETS_SETTING),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import type {
|
|||
VisTypeTimeseriesRequestHandlerContext,
|
||||
VisTypeTimeseriesVisDataRequest,
|
||||
} from '../../../types';
|
||||
import { MAX_BUCKETS_SETTING } from '../../../../common/constants';
|
||||
import { UI_SETTINGS } from '../../../../common/constants';
|
||||
|
||||
const getRollupIndices = (rollupData: { [key: string]: any }) => Object.keys(rollupData);
|
||||
const isIndexPatternContainsWildcard = (indexPattern: string) => indexPattern.includes('*');
|
||||
|
@ -75,7 +75,7 @@ export class RollupSearchStrategy extends AbstractSearchStrategy {
|
|||
|
||||
capabilities = new RollupSearchCapabilities(
|
||||
{
|
||||
maxBucketsLimit: await uiSettings.get(MAX_BUCKETS_SETTING),
|
||||
maxBucketsLimit: await uiSettings.get(UI_SETTINGS.MAX_BUCKETS_SETTING),
|
||||
panel: req.body.panels ? req.body.panels[0] : null,
|
||||
},
|
||||
fieldsCapabilities,
|
||||
|
|
|
@ -10,11 +10,10 @@ import { i18n } from '@kbn/i18n';
|
|||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { UiSettingsParams } from 'kibana/server';
|
||||
|
||||
import { MAX_BUCKETS_SETTING } from '../common/constants';
|
||||
import { UI_SETTINGS } from '../common/constants';
|
||||
|
||||
export const getUiSettings: () => Record<string, UiSettingsParams> = () => ({
|
||||
[MAX_BUCKETS_SETTING]: {
|
||||
[UI_SETTINGS.MAX_BUCKETS_SETTING]: {
|
||||
name: i18n.translate('visTypeTimeseries.advancedSettings.maxBucketsTitle', {
|
||||
defaultMessage: 'TSVB buckets limit',
|
||||
}),
|
||||
|
@ -25,4 +24,16 @@ export const getUiSettings: () => Record<string, UiSettingsParams> = () => ({
|
|||
}),
|
||||
schema: schema.number(),
|
||||
},
|
||||
[UI_SETTINGS.ALLOW_STRING_INDICES]: {
|
||||
name: i18n.translate('visTypeTimeseries.advancedSettings.allowStringIndicesTitle', {
|
||||
defaultMessage: 'Allow string indices in TSVB',
|
||||
}),
|
||||
value: false,
|
||||
requiresPageReload: true,
|
||||
description: i18n.translate('visTypeTimeseries.advancedSettings.allowStringIndicesText', {
|
||||
defaultMessage:
|
||||
'Enables you to use index patterns and Elasticsearch indices in <strong>TSVB</strong> visualizations.',
|
||||
}),
|
||||
schema: schema.boolean(),
|
||||
},
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const inspector = getService('inspector');
|
||||
const retry = getService('retry');
|
||||
const security = getService('security');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
const { timePicker, visChart, visualBuilder, visualize, settings } = getPageObjects([
|
||||
'timePicker',
|
||||
|
@ -95,6 +96,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await visualBuilder.setFieldForAggregation('machine.ram');
|
||||
const kibanaIndexPatternModeValue = await visualBuilder.getMetricValue();
|
||||
|
||||
await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': true });
|
||||
await browser.refresh();
|
||||
await visualBuilder.clickPanelOptions('metric');
|
||||
await visualBuilder.switchIndexPatternSelectionMode(false);
|
||||
const stringIndexPatternModeValue = await visualBuilder.getMetricValue();
|
||||
|
|
|
@ -433,6 +433,49 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
|
||||
after(async () => await visualBuilder.toggleNewChartsLibraryWithDebug(false));
|
||||
});
|
||||
|
||||
describe('index pattern selection mode', () => {
|
||||
it('should disable switch for Kibana index patterns mode by default', async () => {
|
||||
await visualBuilder.clickPanelOptions('timeSeries');
|
||||
const isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled();
|
||||
expect(isEnabled).to.be(false);
|
||||
});
|
||||
|
||||
describe('metrics:allowStringIndices = true', () => {
|
||||
before(async () => {
|
||||
await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': true });
|
||||
await browser.refresh();
|
||||
});
|
||||
|
||||
beforeEach(async () => await visualBuilder.clickPanelOptions('timeSeries'));
|
||||
|
||||
it('should not disable switch for Kibana index patterns mode', async () => {
|
||||
await visualBuilder.switchIndexPatternSelectionMode(true);
|
||||
|
||||
const isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled();
|
||||
expect(isEnabled).to.be(true);
|
||||
});
|
||||
|
||||
it('should disable switch after selecting Kibana index patterns mode and metrics:allowStringIndices = false', async () => {
|
||||
await visualBuilder.switchIndexPatternSelectionMode(false);
|
||||
await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': false });
|
||||
await browser.refresh();
|
||||
await visualBuilder.clickPanelOptions('timeSeries');
|
||||
|
||||
let isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled();
|
||||
expect(isEnabled).to.be(true);
|
||||
|
||||
await visualBuilder.switchIndexPatternSelectionMode(true);
|
||||
isEnabled = await visualBuilder.checkIndexPatternSelectionModeSwitchIsEnabled();
|
||||
expect(isEnabled).to.be(false);
|
||||
});
|
||||
|
||||
after(
|
||||
async () =>
|
||||
await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': false })
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -502,12 +502,32 @@ export class VisualBuilderPageObject extends FtrService {
|
|||
return await annotationTooltipDetails.getVisibleText();
|
||||
}
|
||||
|
||||
public async toggleIndexPatternSelectionModePopover(shouldOpen: boolean) {
|
||||
const isPopoverOpened = await this.testSubjects.exists(
|
||||
'switchIndexPatternSelectionModePopoverContent'
|
||||
);
|
||||
if ((shouldOpen && !isPopoverOpened) || (!shouldOpen && isPopoverOpened)) {
|
||||
await this.testSubjects.click('switchIndexPatternSelectionModePopoverButton');
|
||||
}
|
||||
}
|
||||
|
||||
public async switchIndexPatternSelectionMode(useKibanaIndices: boolean) {
|
||||
await this.testSubjects.click('switchIndexPatternSelectionModePopover');
|
||||
await this.toggleIndexPatternSelectionModePopover(true);
|
||||
await this.testSubjects.setEuiSwitch(
|
||||
'switchIndexPatternSelectionMode',
|
||||
useKibanaIndices ? 'check' : 'uncheck'
|
||||
);
|
||||
await this.toggleIndexPatternSelectionModePopover(false);
|
||||
}
|
||||
|
||||
public async checkIndexPatternSelectionModeSwitchIsEnabled() {
|
||||
await this.toggleIndexPatternSelectionModePopover(true);
|
||||
let isEnabled;
|
||||
await this.testSubjects.retry.tryForTime(2000, async () => {
|
||||
isEnabled = await this.testSubjects.isEnabled('switchIndexPatternSelectionMode');
|
||||
});
|
||||
await this.toggleIndexPatternSelectionModePopover(false);
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public async setIndexPatternValue(value: string, useKibanaIndices?: boolean) {
|
||||
|
|
|
@ -5227,9 +5227,7 @@
|
|||
"visTypeTimeseries.indexPatternSelect.label": "インデックスパターン",
|
||||
"visTypeTimeseries.indexPatternSelect.queryAllIndexesText": "すべてのインデックスにクエリを実行するには * を使用します",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.areaLabel": "インデックスパターン選択モードを構成",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.text": "インデックスパターンは、データ探索で対象とする1つ以上のElasticsearchインデックスを定義します。ElasticsearchインデックスまたはKibanaインデックスパターン(推奨)を使用できます。",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.title": "インデックスパターン選択モード",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "Kibanaインデックスパターンのみを使用",
|
||||
"visTypeTimeseries.kbnVisTypes.metricsDescription": "時系列データの高度な分析を実行します。",
|
||||
"visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB",
|
||||
"visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "バケット:{lastBucketDate}",
|
||||
|
@ -5556,7 +5554,6 @@
|
|||
"visTypeTimeseries.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage": "変更が自動的に適用されます。",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.dismissNoticeButtonText": "閉じる",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.link": "確認してください。",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationMessage": "お知らせElasticsearchインデックスまたはKibanaインデックスパターンからデータを可視化できるようになりました。{indexPatternModeLink}。",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationTitle": "TSVBはインデックスパターンをサポートします",
|
||||
"visTypeTimeseries.visPicker.gaugeLabel": "ゲージ",
|
||||
"visTypeTimeseries.visPicker.metricLabel": "メトリック",
|
||||
|
|
|
@ -5272,9 +5272,7 @@
|
|||
"visTypeTimeseries.indexPatternSelect.label": "索引模式",
|
||||
"visTypeTimeseries.indexPatternSelect.queryAllIndexesText": "要查询所有索引,请使用 *",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.areaLabel": "配置索引模式选择模式",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.text": "索引模式可识别一个或多个您希望浏览的 Elasticsearch 索引。可用使用 Elasticsearch 索引或 Kibana 索引模式(推荐)。",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.title": "索引模式选择模式",
|
||||
"visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "仅使用 Kibana 索引模式",
|
||||
"visTypeTimeseries.kbnVisTypes.metricsDescription": "对时间序列数据执行高级分析。",
|
||||
"visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB",
|
||||
"visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "存储桶:{lastBucketDate}",
|
||||
|
@ -5602,7 +5600,6 @@
|
|||
"visTypeTimeseries.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage": "将自动应用更改。",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.dismissNoticeButtonText": "关闭",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.link": "请查看。",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationMessage": "好消息!现在可以可视化 Elasticsearch 索引或 Kibana 索引模式的数据。{indexPatternModeLink}。",
|
||||
"visTypeTimeseries.visEditorVisualization.indexPatternMode.notificationTitle": "TSVB 现在支持索引模式",
|
||||
"visTypeTimeseries.visPicker.gaugeLabel": "仪表盘",
|
||||
"visTypeTimeseries.visPicker.metricLabel": "指标",
|
||||
|
|
|
@ -43,6 +43,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
await kibanaServer.uiSettings.replace({
|
||||
defaultIndex: 'rollup',
|
||||
});
|
||||
await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': true });
|
||||
});
|
||||
|
||||
it('create rollup tsvb', async () => {
|
||||
|
@ -110,6 +111,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
await kibanaServer.importExport.unload(
|
||||
'x-pack/test/functional/fixtures/kbn_archiver/rollup/rollup.json'
|
||||
);
|
||||
await kibanaServer.uiSettings.update({ 'metrics:allowStringIndices': false });
|
||||
await security.testUser.restoreDefaults();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue