[Index Management] Add an index details page behind a dev feature flag (#163521)

## Summary
This PR adds a dev feature flag
`xpack.index_management.dev.enableIndexDetailsPage` that will allow us
to build out the new index details page in small iterations. Without the
flag, the UI of Index Management is not changed. A skeleton component is
created for the details page (see screenshot below).

### How to test
1. Test the Index Management UI (Indices tab) without the flag and check
that no changes were introduced
1. Add `xpack.index_management.dev.enableIndexDetailsPage: true` to the
file `/config/kibana.dev.yml`
2. Navigate to the Indices tab in Index Management, toggle "hidden
indices" if no indices exist and click any index name
3. Check that the new index details page is displayed
4. Check that the tabs on the page are working

### Screenshots 
<img width="1209" alt="Screenshot 2023-08-09 at 19 17 46"
src="e654ef36-ccf3-40a4-8c7b-750b83defef5">

### Checklist

Delete any items that are not applicable to this PR.

- [ ] 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)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [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
- [ ] Any UI touched in this PR is usable by keyboard only (learn more
about [keyboard accessibility](https://webaim.org/techniques/keyboard/))
- [ ] 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))
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] 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))
- [ ] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)


### Risk Matrix

Delete this section if it is not applicable to this PR.

Before closing this PR, invite QA, stakeholders, and other developers to
identify risks that should be tested prior to the change/feature
release.

When forming the risk matrix, consider some of the following examples
and how they may potentially impact the change:

| Risk | Probability | Severity | Mitigation/Notes |

|---------------------------|-------------|----------|-------------------------|
| Multiple Spaces&mdash;unexpected behavior in non-default Kibana Space.
| Low | High | Integration tests will verify that all features are still
supported in non-default Kibana Space and when user switches between
spaces. |
| Multiple nodes&mdash;Elasticsearch polling might have race conditions
when multiple Kibana nodes are polling for the same tasks. | High | Low
| Tasks are idempotent, so executing them multiple times will not result
in logical error, but will degrade performance. To test for this case we
add plenty of unit tests around this logic and document manual testing
procedure. |
| Code should gracefully handle cases when feature X or plugin Y are
disabled. | Medium | High | Unit tests will verify that any feature flag
or plugin combination still results in our service operational. |
| [See more potential risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx) |


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

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Yulia Čech 2023-08-15 13:11:54 +02:00 committed by GitHub
parent 54442daf06
commit 3efc0a7c45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 440 additions and 31 deletions

View file

@ -277,6 +277,7 @@ enabled:
- x-pack/test/functional/apps/home/config.ts
- x-pack/test/functional/apps/index_lifecycle_management/config.ts
- x-pack/test/functional/apps/index_management/config.ts
- x-pack/test/functional/apps/index_management/index_details_page/config.ts
- x-pack/test/functional/apps/infra/config.ts
- x-pack/test/functional/apps/ingest_pipelines/config.ts
- x-pack/test/functional/apps/lens/group1/config.ts

View file

@ -241,6 +241,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'xpack.index_management.ui.enabled (boolean)',
'xpack.index_management.enableIndexActions (any)',
'xpack.index_management.enableLegacyTemplates (any)',
'xpack.index_management.dev.enableIndexDetailsPage (boolean)',
'xpack.infra.sources.default.fields.message (array)',
/**
* xpack.infra.logs is conditional and will resolve to an object of properties

View file

@ -0,0 +1,68 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { AsyncTestBedConfig, registerTestBed, TestBed } from '@kbn/test-jest-helpers';
import { HttpSetup } from '@kbn/core/public';
import { act } from 'react-dom/test-utils';
import {
IndexDetailsPage,
IndexDetailsSection,
} from '../../../public/application/sections/home/index_list/details_page';
import { WithAppDependencies } from '../helpers';
const testBedConfig: AsyncTestBedConfig = {
memoryRouter: {
initialEntries: [`/indices/test_index`],
componentRoutePath: `/indices/:indexName/:indexDetailsSection?`,
},
doMountAsync: true,
};
export interface IndexDetailsPageTestBed extends TestBed {
actions: {
getHeader: () => string;
clickIndexDetailsTab: (tab: IndexDetailsSection) => Promise<void>;
getActiveTabContent: () => string;
};
}
export const setup = async (
httpSetup: HttpSetup,
overridingDependencies: any = {}
): Promise<IndexDetailsPageTestBed> => {
const initTestBed = registerTestBed(
WithAppDependencies(IndexDetailsPage, httpSetup, overridingDependencies),
testBedConfig
);
const testBed = await initTestBed();
const getHeader = () => {
return testBed.component.find('[data-test-subj="indexDetailsHeader"] h1').text();
};
const clickIndexDetailsTab = async (tab: IndexDetailsSection) => {
const { find, component } = testBed;
await act(async () => {
find(`indexDetailsTab-${tab}`).simulate('click');
});
component.update();
};
const getActiveTabContent = () => {
return testBed.find('indexDetailsContent').text();
};
return {
...testBed,
actions: {
getHeader,
clickIndexDetailsTab,
getActiveTabContent,
},
};
};

View file

@ -0,0 +1,61 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { setupEnvironment } from '../helpers';
import { IndexDetailsPageTestBed, setup } from './index_details_page.helpers';
import { act } from 'react-dom/test-utils';
import { httpServiceMock } from '@kbn/core/public/mocks';
import { IndexDetailsSection } from '../../../public/application/sections/home/index_list/details_page';
describe('<IndexDetailsPage />', () => {
let testBed: IndexDetailsPageTestBed;
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
beforeEach(async () => {
httpSetup = httpServiceMock.createSetupContract();
await act(async () => {
testBed = await setup(httpSetup);
});
testBed.component.update();
});
it('displays index name in the header', () => {
const header = testBed.actions.getHeader();
// test_index is configured in initialEntries of the memory router
expect(header).toEqual('test_index');
});
it('defaults to overview tab', () => {
const tabContent = testBed.actions.getActiveTabContent();
expect(tabContent).toEqual('Overview');
});
it('documents tab', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Documents);
const tabContent = testBed.actions.getActiveTabContent();
expect(tabContent).toEqual('Documents');
});
it('mappings tab', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Mappings);
const tabContent = testBed.actions.getActiveTabContent();
expect(tabContent).toEqual('Mappings');
});
it('settings tab', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Settings);
const tabContent = testBed.actions.getActiveTabContent();
expect(tabContent).toEqual('Settings');
});
it('pipelines tab', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Pipelines);
const tabContent = testBed.actions.getActiveTabContent();
expect(tabContent).toEqual('Pipelines');
});
});

View file

@ -13,7 +13,7 @@ import { Router, Routes, Route } from '@kbn/shared-ux-router';
import { ScopedHistory } from '@kbn/core/public';
import { UIM_APP_LOAD } from '../../common/constants';
import { IndexManagementHome, homeSections } from './sections/home';
import { IndexManagementHome, homeSections, Section } from './sections/home';
import { TemplateCreate } from './sections/template_create';
import { TemplateClone } from './sections/template_clone';
import { TemplateEdit } from './sections/template_edit';
@ -52,6 +52,6 @@ export const AppWithoutRouter = () => (
/>
<Route exact path="/edit_component_template/:name*" component={ComponentTemplateEdit} />
<Route path={`/:section(${homeSections.join('|')})`} component={IndexManagementHome} />
<Redirect from={`/`} to={`/indices`} />
<Redirect from={`/`} to={`/${Section.Indices}`} />
</Routes>
);

View file

@ -47,6 +47,7 @@ export interface AppDependencies {
config: {
enableIndexActions: boolean;
enableLegacyTemplates: boolean;
enableIndexDetailsPage: boolean;
};
history: ScopedHistory;
setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs'];

View file

@ -46,16 +46,27 @@ function initSetup({
return { uiMetricService };
}
export async function mountManagementSection(
coreSetup: CoreSetup<StartDependencies>,
usageCollection: UsageCollectionSetup,
params: ManagementAppMountParams,
extensionsService: ExtensionsService,
isFleetEnabled: boolean,
kibanaVersion: SemVer,
enableIndexActions: boolean = true,
enableLegacyTemplates: boolean = true
) {
export async function mountManagementSection({
coreSetup,
usageCollection,
params,
extensionsService,
isFleetEnabled,
kibanaVersion,
enableIndexActions = true,
enableLegacyTemplates = true,
enableIndexDetailsPage = false,
}: {
coreSetup: CoreSetup<StartDependencies>;
usageCollection: UsageCollectionSetup;
params: ManagementAppMountParams;
extensionsService: ExtensionsService;
isFleetEnabled: boolean;
kibanaVersion: SemVer;
enableIndexActions?: boolean;
enableLegacyTemplates?: boolean;
enableIndexDetailsPage?: boolean;
}) {
const { element, setBreadcrumbs, history, theme$ } = params;
const [core, startDependencies] = await coreSetup.getStartServices();
const {
@ -99,6 +110,7 @@ export async function mountManagementSection(
config: {
enableIndexActions,
enableLegacyTemplates,
enableIndexDetailsPage,
},
history,
setBreadcrumbs,

View file

@ -10,12 +10,14 @@ import { RouteComponentProps } from 'react-router-dom';
import { Routes, Route } from '@kbn/shared-ux-router';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiButtonEmpty, EuiPageHeader, EuiSpacer } from '@elastic/eui';
import { documentationService } from '../../services/documentation';
import { DataStreamList } from './data_stream_list';
import { IndexList } from './index_list';
import { TemplateList } from './template_list';
import { ComponentTemplateList } from '../../components/component_templates';
import { breadcrumbService } from '../../services/breadcrumbs';
import { documentationService } from '../../services/documentation';
import { useAppContext } from '../../app_context';
import { ComponentTemplateList } from '../../components/component_templates';
import { IndexList } from './index_list';
import { IndexDetailsPage } from './index_list/details_page';
import { DataStreamList } from './data_stream_list';
import { TemplateList } from './template_list';
export enum Section {
Indices = 'indices',
@ -41,6 +43,9 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma
},
history,
}) => {
const {
config: { enableIndexDetailsPage },
} = useAppContext();
const tabs = [
{
id: Section.Indices,
@ -83,7 +88,7 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma
breadcrumbService.setBreadcrumbs('home');
}, []);
return (
const indexManagementTabs = (
<>
<EuiPageHeader
data-test-subj="indexManagementHeaderContent"
@ -140,4 +145,18 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma
</Routes>
</>
);
if (enableIndexDetailsPage) {
return (
<>
<Routes>
<Route
path={`/${Section.Indices}/:indexName/:indexDetailsSection?`}
component={IndexDetailsPage}
/>
<Route render={() => indexManagementTabs} />
</Routes>
</>
);
}
return indexManagementTabs;
};

View file

@ -0,0 +1,121 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useCallback, useMemo } from 'react';
import { Redirect, RouteComponentProps } from 'react-router-dom';
import { Route, Routes } from '@kbn/shared-ux-router';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiPageHeader, EuiSpacer, EuiPageHeaderProps } from '@elastic/eui';
import { Section } from '../../home';
export enum IndexDetailsSection {
Overview = 'overview',
Documents = 'documents',
Mappings = 'mappings',
Settings = 'settings',
Pipelines = 'pipelines',
}
const tabs = [
{
id: IndexDetailsSection.Overview,
name: (
<FormattedMessage id="xpack.idxMgmt.indexDetails.overviewTitle" defaultMessage="Overview" />
),
},
{
id: IndexDetailsSection.Documents,
name: (
<FormattedMessage id="xpack.idxMgmt.indexDetails.documentsTitle" defaultMessage="Documents" />
),
},
{
id: IndexDetailsSection.Mappings,
name: (
<FormattedMessage id="xpack.idxMgmt.indexDetails.mappingsTitle" defaultMessage="Mappings" />
),
},
{
id: IndexDetailsSection.Settings,
name: (
<FormattedMessage id="xpack.idxMgmt.indexDetails.settingsTitle" defaultMessage="Settings" />
),
},
{
id: IndexDetailsSection.Pipelines,
name: (
<FormattedMessage id="xpack.idxMgmt.indexDetails.pipelinesTitle" defaultMessage="Pipelines" />
),
},
];
export const DetailsPage: React.FunctionComponent<
RouteComponentProps<{ indexName: string; indexDetailsSection: IndexDetailsSection }>
> = ({
match: {
params: { indexName, indexDetailsSection },
},
history,
}) => {
const onSectionChange = useCallback(
(newSection: IndexDetailsSection) => {
return history.push(encodeURI(`/indices/${indexName}/${newSection}`));
},
[history, indexName]
);
const headerTabs = useMemo<EuiPageHeaderProps['tabs']>(() => {
return tabs.map((tab) => ({
onClick: () => onSectionChange(tab.id),
isSelected: tab.id === indexDetailsSection,
key: tab.id,
'data-test-subj': `indexDetailsTab-${tab.id}`,
label: tab.name,
}));
}, [indexDetailsSection, onSectionChange]);
return (
<>
<EuiPageHeader
data-test-subj="indexDetailsHeader"
pageTitle={indexName}
bottomBorder
rightSideItems={[]}
tabs={headerTabs}
/>
<EuiSpacer size="l" />
<div data-test-subj={`indexDetailsContent`}>
<Routes>
<Route
path={`/${Section.Indices}/${indexName}/${IndexDetailsSection.Overview}`}
render={() => <div>Overview</div>}
/>
<Route
path={`/${Section.Indices}/${indexName}/${IndexDetailsSection.Documents}`}
render={() => <div>Documents</div>}
/>
<Route
path={`/${Section.Indices}/${indexName}/${IndexDetailsSection.Mappings}`}
render={() => <div>Mappings</div>}
/>
<Route
path={`/${Section.Indices}/${indexName}/${IndexDetailsSection.Settings}`}
render={() => <div>Settings</div>}
/>
<Route
path={`/${Section.Indices}/${indexName}/${IndexDetailsSection.Pipelines}`}
render={() => <div>Pipelines</div>}
/>
<Redirect
from={`/${Section.Indices}/${indexName}`}
to={`/${Section.Indices}/${indexName}/${IndexDetailsSection.Overview}`}
/>
</Routes>
</div>
</>
);
};

View file

@ -0,0 +1,8 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { DetailsPage as IndexDetailsPage, IndexDetailsSection } from './details_page';

View file

@ -5,9 +5,10 @@
* 2.0.
*/
import React from 'react';
import React, { useCallback } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { ScopedHistory } from '@kbn/core/public';
import { APP_WRAPPER_CLASS, useExecutionContext } from '../../../../shared_imports';
import { useAppContext } from '../../../app_context';
import { DetailPanel } from './detail_panel';
@ -16,6 +17,7 @@ import { IndexTable } from './index_table';
export const IndexList: React.FunctionComponent<RouteComponentProps> = ({ history }) => {
const {
core: { executionContext },
config: { enableIndexDetailsPage },
} = useAppContext();
useExecutionContext(executionContext, {
@ -23,10 +25,19 @@ export const IndexList: React.FunctionComponent<RouteComponentProps> = ({ histor
page: 'indexManagementIndicesTab',
});
const openDetailPanel = useCallback(
(indexName: string) => {
return history.push(encodeURI(`/indices/${indexName}`));
},
[history]
);
return (
<div className={`${APP_WRAPPER_CLASS} im-snapshotTestSubject`} data-test-subj="indicesList">
<IndexTable history={history} />
<DetailPanel />
<IndexTable
history={history as ScopedHistory}
openDetailPanel={enableIndexDetailsPage ? openDetailPanel : undefined}
/>
{!enableIndexDetailsPage && <DetailPanel />}
</div>
);
};

View file

@ -4,5 +4,12 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { ScopedHistory } from '@kbn/core/public';
export declare function IndexTable(props: any): any;
interface IndexTableProps {
history: ScopedHistory;
openDetailPanel?: (indexName: string) => void;
}
export declare const IndexTable: React.FunctionComponent<IndexTableProps>;

View file

@ -82,6 +82,15 @@ const mapDispatchToProps = (dispatch) => {
};
};
const mergeProps = (stateProps, dispatchProps, ownProps) => {
return {
...ownProps,
...stateProps,
...dispatchProps,
openDetailPanel: ownProps.openDetailPanel ?? dispatchProps.openDetailPanel,
};
};
export const IndexTable = withRouter(
connect(mapStateToProps, mapDispatchToProps)(PresentationComponent)
connect(mapStateToProps, mapDispatchToProps, mergeProps)(PresentationComponent)
);

View file

@ -40,6 +40,7 @@ export class IndexMgmtUIPlugin {
ui: { enabled: isIndexManagementUiEnabled },
enableIndexActions,
enableLegacyTemplates,
dev: { enableIndexDetailsPage },
} = this.ctx.config.get<ClientConfigType>();
if (isIndexManagementUiEnabled) {
@ -51,16 +52,17 @@ export class IndexMgmtUIPlugin {
order: 0,
mount: async (params) => {
const { mountManagementSection } = await import('./application/mount_management_section');
return mountManagementSection(
return mountManagementSection({
coreSetup,
usageCollection,
params,
this.extensionsService,
Boolean(fleet),
extensionsService: this.extensionsService,
isFleetEnabled: Boolean(fleet),
kibanaVersion,
enableIndexActions,
enableLegacyTemplates
);
enableLegacyTemplates,
enableIndexDetailsPage,
});
},
});
}

View file

@ -31,4 +31,7 @@ export interface ClientConfigType {
};
enableIndexActions?: boolean;
enableLegacyTemplates?: boolean;
dev: {
enableIndexDetailsPage?: boolean;
};
}

View file

@ -38,6 +38,7 @@ const schemaLatest = schema.object(
schema.boolean({ defaultValue: true }),
schema.never()
),
dev: schema.object({ enableIndexDetailsPage: schema.boolean({ defaultValue: false }) }),
},
{ defaultValue: undefined }
);
@ -47,6 +48,9 @@ const configLatest: PluginConfigDescriptor<IndexManagementConfig> = {
ui: true,
enableIndexActions: true,
enableLegacyTemplates: true,
dev: {
enableIndexDetailsPage: true,
},
},
schema: schemaLatest,
deprecations: () => [],

View file

@ -51,7 +51,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
describe('index panel', async () => {
it('index panel - summary', async () => {
await PageObjects.settings.clickIndexManagement();
await PageObjects.indexManagement.clickIndiceAt(0);
await PageObjects.indexManagement.clickIndexAt(0);
await a11y.testAppSnapshot();
});

View file

@ -0,0 +1,25 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrConfigProviderContext } from '@kbn/test';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const functionalConfig = await readConfigFile(require.resolve('../config.ts'));
return {
...functionalConfig.getAll(),
testFiles: [require.resolve('.')],
kbnTestServer: {
...functionalConfig.get('kbnTestServer'),
serverArgs: [
...functionalConfig.get('kbnTestServer.serverArgs'),
// setting the feature flag to enable details page
`--xpack.index_management.dev.enableIndexDetailsPage=true`,
],
},
};
}

View file

@ -0,0 +1,14 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrProviderContext } from '../../../ftr_provider_context';
export default ({ loadTestFile }: FtrProviderContext) => {
describe('Index Management: index details page', function () {
loadTestFile(require.resolve('./index_details_page'));
});
};

View file

@ -0,0 +1,30 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrProviderContext } from '../../../ftr_provider_context';
export default ({ getPageObjects, getService }: FtrProviderContext) => {
const pageObjects = getPageObjects(['common', 'indexManagement', 'header']);
const log = getService('log');
const security = getService('security');
describe('Index details page', function () {
before(async () => {
await security.testUser.setRoles(['index_management_user']);
await pageObjects.common.navigateToApp('indexManagement');
});
it('Navigates to the index details page from the home page', async () => {
await log.debug('Navigating to the index details page');
// display hidden indices to have some rows in the indices table
await pageObjects.indexManagement.toggleHiddenIndices();
// click the first index in the table and wait for the index details page
await pageObjects.indexManagement.indexDetailsPage.openIndexDetailsPage(0);
});
});
};

View file

@ -87,7 +87,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
});
it('Verify that the follower index is duplicating from the remote.', async () => {
await pageObjects.indexManagement.clickIndiceAt(0);
await pageObjects.indexManagement.clickIndexAt(0);
await pageObjects.indexManagement.performIndexActionInDetailPanel('flush');
await testSubjects.click('euiFlyoutCloseButton');
await pageObjects.common.navigateToApp('indexManagement');

View file

@ -26,6 +26,9 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
async toggleRollupIndices() {
await testSubjects.click('checkboxToggles-rollupToggle');
},
async toggleHiddenIndices() {
await testSubjects.click('indexTableIncludeHiddenIndicesToggle');
},
async clickDetailPanelTabAt(indexOfTab: number): Promise<void> {
const tabList = await testSubjects.findAll('detailPanelTab');
@ -33,7 +36,7 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
await tabList[indexOfTab].click();
},
async clickIndiceAt(indexOfRow: number): Promise<void> {
async clickIndexAt(indexOfRow: number): Promise<void> {
const indexList = await testSubjects.findAll('indexTableIndexNameLink');
await indexList[indexOfRow].click();
await retry.waitFor('detail panel title to show up', async () => {
@ -92,5 +95,14 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
async clickNextButton() {
await testSubjects.click('nextButton');
},
indexDetailsPage: {
async openIndexDetailsPage(indexOfRow: number) {
const indexList = await testSubjects.findAll('indexTableIndexNameLink');
await indexList[indexOfRow].click();
await retry.waitFor('index details page title to show up', async () => {
return (await testSubjects.isDisplayed('indexDetailsHeader')) === true;
});
},
},
};
}