[Index Management] Implement index details page (#165705)

## Summary
This PR removes the feature flag and enables the new index details page
by default. The index details page was implemented in following PRs:
- https://github.com/elastic/kibana/pull/163521
- https://github.com/elastic/kibana/pull/163955
- https://github.com/elastic/kibana/pull/164741
- https://github.com/elastic/kibana/pull/165027
- https://github.com/elastic/kibana/pull/165038
- https://github.com/elastic/kibana/pull/165456

In this PR we completely remove now obsolete code for the old index
details flyout: react components and corresponding redux code. All
related tests are updated and cleaned up. The config value for Index
Management plugin `xpack.index_management.dev.enableIndexDetailsPage` is
deprecated as unused and can be removed in v9.0.


### How to test
1. Start ES and Kibana with `yarn es snapshot` and `yarn start`
3. Navigate to Index Management and create an index
4. Click the index name in the table and check the tabs of the details
page
### Screenshots
#### Stateful
Overview 
<img width="1387" alt="Screenshot 2023-09-27 at 14 41 57"
src="e58b15e7-d10c-4473-873c-d0f128392404">


Mappings
<img width="1392" alt="Screenshot 2023-09-27 at 14 42 05"
src="441157cb-5a26-47c3-8da0-b4df51ebec5d">


Settings 
<img width="1385" alt="Screenshot 2023-09-27 at 14 42 13"
src="da66a2eb-1f21-44c1-9356-484c66caab88">


Statistics
<img width="1380" alt="Screenshot 2023-09-27 at 14 42 22"
src="ec93d85c-e754-4c21-88ab-0124dc114fc9">


Error loading data
<img width="1333" alt="Screenshot 2023-09-26 at 19 05 37"
src="fc1804b3-6aa0-4019-bae6-e7bb40113b28">
<img width="1327" alt="Screenshot 2023-09-26 at 19 06 07"
src="ca711697-cc74-4ba8-b17c-ec9b01f3026e">
<img width="1329" alt="Screenshot 2023-09-26 at 19 06 28"
src="0cb46b09-8542-452a-8845-40d060057e95">
<img width="1331" alt="Screenshot 2023-09-26 at 19 06 48"
src="87de8d3d-b6e5-4e8f-b27c-18a1c6e950d8">


Error saving index settings
<img width="1332" alt="Screenshot 2023-09-26 at 19 07 31"
src="e6e4b3d0-c237-4d0a-995a-4562bc78f88e">


### Serverless
Overview 
<img width="1336" alt="Screenshot 2023-09-26 at 19 51 47"
src="6c76c23b-4be6-4ab3-ae1d-c7ae751e100d">


Mappings
<img width="1336" alt="Screenshot 2023-09-26 at 19 23 51"
src="625fa703-506f-4389-9df0-86441a655074">


Settings
<img width="1332" alt="Screenshot 2023-09-26 at 19 24 02"
src="c496ab09-f2db-4c1b-9fb6-1e9b64b1c142">


# Release note
Index details can now be viewed on a new index details page in Index
Management.
<img width="1387" alt="Screenshot 2023-09-27 at 14 41 57"
src="b90c706d-8b15-49e4-8f6a-cb66f3ed1822">

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Yulia Čech 2023-09-27 20:22:26 +02:00 committed by GitHub
parent e70181aea5
commit e1b37a6aa3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 326 additions and 1591 deletions

View file

@ -278,7 +278,6 @@ 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

@ -247,7 +247,6 @@ 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.index_management.enableIndexStats (any)',
'xpack.infra.sources.default.fields.message (array)',
'xpack.license_management.ui.enabled (boolean)',

View file

@ -64,6 +64,7 @@ export type TestSubjects =
| 'updateEditIndexSettingsButton'
| 'updateIndexSettingsErrorCallout'
| 'viewButton'
| 'indexTableRowCheckbox'
| 'enrichPoliciesTable'
| 'deletePolicyModal'
| 'executePolicyModal'

View file

@ -30,12 +30,14 @@ const testBedConfig: AsyncTestBedConfig = {
export interface IndicesTestBed extends TestBed<TestSubjects> {
actions: {
clickIndexNameAt: (index: number) => Promise<void>;
findIndexDetailsPageTitle: () => string;
selectIndexDetailsTab: (
tab: 'settings' | 'mappings' | 'stats' | 'edit_settings'
) => Promise<void>;
getIncludeHiddenIndicesToggleStatus: () => boolean;
clickIncludeHiddenIndicesToggle: () => void;
clickDataStreamAt: (index: number) => void;
clickDataStreamAt: (index: number) => Promise<void>;
dataStreamLinkExistsAt: (index: number) => boolean;
clickManageContextMenuButton: () => void;
clickContextMenuOption: (optionDataTestSubject: string) => void;
@ -90,6 +92,11 @@ export const setup = async (
return Boolean(props['aria-checked']);
};
const findIndexDetailsPageTitle = () => {
const { find } = testBed;
return find('indexDetailsHeader').text();
};
const selectIndexDetailsTab = async (
tab: 'settings' | 'mappings' | 'stats' | 'edit_settings'
) => {
@ -101,6 +108,18 @@ export const setup = async (
component.update();
};
const clickIndexNameAt = async (index: number) => {
const { component, table } = testBed;
const { rows } = table.getMetaData('indexTable');
const indexNameLink = findTestSubject(rows[index].reactWrapper, 'indexTableIndexNameLink');
await act(async () => {
indexNameLink.simulate('click');
});
component.update();
};
const clickDataStreamAt = async (index: number) => {
const { component, table, router } = testBed;
const { rows } = table.getMetaData('indexTable');
@ -170,6 +189,8 @@ export const setup = async (
return {
...testBed,
actions: {
clickIndexNameAt,
findIndexDetailsPageTitle,
selectIndexDetailsTab,
getIncludeHiddenIndicesToggleStatus,
clickIncludeHiddenIndicesToggle,

View file

@ -12,31 +12,6 @@ import { setupEnvironment, nextTick } from '../helpers';
import { IndicesTestBed, setup } from './indices_tab.helpers';
import { createDataStreamPayload, createNonDataStreamIndex } from './data_streams_tab.helpers';
// Since the editor component being used for editing index settings is not a React
// component but an editor being instantiated on a div reference, we cannot mock
// the component and replace it with something else. In this particular case we're
// mocking the returned instance of the editor to always have the same values.
const mockGetAceEditorValue = jest.fn().mockReturnValue(`{}`);
jest.mock('../../../public/application/lib/ace', () => {
const createAceEditor = () => {
return {
getValue: mockGetAceEditorValue,
getSession: () => {
return {
on: () => null,
getValue: () => null,
};
},
destroy: () => null,
};
};
return {
createAceEditor,
};
});
/**
* The below import is required to avoid a console error warn from the "brace" package
* console.warn ../node_modules/brace/index.js:3999
@ -165,55 +140,32 @@ describe('<IndexManagementHome />', () => {
});
});
describe('index detail panel with % character in index name', () => {
it('navigates to the index details page when the index name is clicked', async () => {
const indexName = 'testIndex';
httpRequestsMockHelpers.setLoadIndicesResponse([createNonDataStreamIndex(indexName)]);
testBed = await setup(httpSetup, {
history: createMemoryHistory(),
});
const { component, actions } = testBed;
component.update();
await actions.clickIndexNameAt(0);
expect(testBed.actions.findIndexDetailsPageTitle()).toContain('testIndex');
});
it('index page works with % character in index name', async () => {
const indexName = 'test%';
httpRequestsMockHelpers.setLoadIndicesResponse([createNonDataStreamIndex(indexName)]);
beforeEach(async () => {
httpRequestsMockHelpers.setLoadIndicesResponse([createNonDataStreamIndex(indexName)]);
testBed = await setup(httpSetup);
const { component, actions } = testBed;
testBed = await setup(httpSetup);
const { component, find } = testBed;
component.update();
component.update();
find('indexTableIndexNameLink').at(0).simulate('click');
});
test('should encode indexName when loading settings in detail panel', async () => {
const { actions } = testBed;
await actions.selectIndexDetailsTab('settings');
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/settings/${encodeURIComponent(indexName)}`
);
});
test('should encode indexName when loading mappings in detail panel', async () => {
const { actions } = testBed;
await actions.selectIndexDetailsTab('mappings');
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/mapping/${encodeURIComponent(indexName)}`
);
});
test('should encode indexName when loading stats in detail panel', async () => {
const { actions } = testBed;
await actions.selectIndexDetailsTab('stats');
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/stats/${encodeURIComponent(indexName)}`
);
});
test('should encode indexName when editing settings in detail panel', async () => {
const { actions } = testBed;
await actions.selectIndexDetailsTab('edit_settings');
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/settings/${encodeURIComponent(indexName)}`
);
});
await actions.clickIndexNameAt(0);
expect(testBed.actions.findIndexDetailsPageTitle()).toContain(indexName);
});
describe('index actions', () => {
@ -242,7 +194,9 @@ describe('<IndexManagementHome />', () => {
const { component, find } = testBed;
component.update();
find('indexTableIndexNameLink').at(0).simulate('click');
find('indexTableRowCheckbox')
.at(0)
.simulate('change', { target: { checked: true } });
});
test('should be able to refresh index', async () => {
@ -287,7 +241,9 @@ describe('<IndexManagementHome />', () => {
component.update();
find('indexTableIndexNameLink').at(1).simulate('click');
find('indexTableRowCheckbox')
.at(1)
.simulate('change', { target: { checked: true } });
await actions.clickManageContextMenuButton();
await actions.clickContextMenuOption('openIndexMenuButton');
@ -341,7 +297,7 @@ describe('<IndexManagementHome />', () => {
});
test('should be able to unfreeze a frozen index', async () => {
const { actions, exists } = testBed;
const { actions, exists, find } = testBed;
httpRequestsMockHelpers.setReloadIndicesResponse([{ ...indexMockA, isFrozen: false }]);
@ -362,6 +318,10 @@ describe('<IndexManagementHome />', () => {
expect.anything()
);
find('indexTableRowCheckbox')
.at(0)
.simulate('change', { target: { checked: true } });
// Open context menu once again, since clicking an action will close it.
await actions.clickManageContextMenuButton();
// The unfreeze action should not be present anymore
@ -394,46 +354,6 @@ describe('<IndexManagementHome />', () => {
});
});
describe('Edit index settings', () => {
const indexName = 'test';
beforeEach(async () => {
httpRequestsMockHelpers.setLoadIndicesResponse([createNonDataStreamIndex(indexName)]);
testBed = await setup(httpSetup);
const { component, find } = testBed;
component.update();
find('indexTableIndexNameLink').at(0).simulate('click');
});
test('shows error callout when request fails', async () => {
const { actions, find, component, exists } = testBed;
mockGetAceEditorValue.mockReturnValue(`{
"index.routing.allocation.include._tier_preference": "non_existent_tier"
}`);
const error = {
statusCode: 400,
error: 'Bad Request',
message: 'invalid tier names found in ...',
};
httpRequestsMockHelpers.setUpdateIndexSettingsResponse(indexName, undefined, error);
await actions.selectIndexDetailsTab('edit_settings');
await act(async () => {
find('updateEditIndexSettingsButton').simulate('click');
});
component.update();
expect(exists('updateIndexSettingsErrorCallout')).toBe(true);
});
});
describe('Index stats', () => {
const indexName = 'test';
@ -458,36 +378,6 @@ describe('<IndexManagementHome />', () => {
]);
});
test('renders index stats in details flyout by default', async () => {
const { component, find } = testBed;
await act(async () => {
find('indexTableIndexNameLink').at(0).simulate('click');
});
component.update();
const descriptions = find('descriptionTitle');
const descriptionText = descriptions
.map((description) => {
return description.text();
})
.sort();
expect(descriptionText).toEqual([
'Aliases',
'Docs count',
'Docs deleted',
'Health',
'Primaries',
'Primary storage size',
'Replicas',
'Status',
'Storage size',
]);
});
describe('Disabled', () => {
beforeEach(async () => {
await act(async () => {
@ -511,25 +401,6 @@ describe('<IndexManagementHome />', () => {
expect(tableCellsValues).toEqual([['', 'test', '1', '1', '']]);
});
test('hides index stats information from details panel', async () => {
const { component, find } = testBed;
await act(async () => {
find('indexTableIndexNameLink').at(0).simulate('click');
});
component.update();
const descriptions = find('descriptionTitle');
const descriptionText = descriptions
.map((description) => {
return description.text();
})
.sort();
expect(descriptionText).toEqual(['Aliases', 'Primaries', 'Replicas']);
});
});
});

View file

@ -42,6 +42,12 @@ jest.mock('@kbn/kibana-react-plugin/public', () => {
};
});
const requestOptions = {
asSystemRequest: undefined,
body: undefined,
query: undefined,
version: undefined,
};
describe('<IndexDetailsPage />', () => {
let testBed: IndexDetailsPageTestBed;
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
@ -120,12 +126,10 @@ describe('<IndexDetailsPage />', () => {
it('loads index stats from the API', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Stats);
expect(httpSetup.get).toHaveBeenLastCalledWith(`${API_BASE_PATH}/stats/${testIndexName}`, {
asSystemRequest: undefined,
body: undefined,
query: undefined,
version: undefined,
});
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/stats/${testIndexName}`,
requestOptions
);
});
it('renders index stats', async () => {
@ -208,7 +212,7 @@ describe('<IndexDetailsPage />', () => {
it('loads index details from the API', async () => {
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${INTERNAL_API_BASE_PATH}/indices/${testIndexName}`,
{ asSystemRequest: undefined, body: undefined, query: undefined, version: undefined }
requestOptions
);
});
@ -310,12 +314,10 @@ describe('<IndexDetailsPage />', () => {
});
it('loads mappings from the API', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Mappings);
expect(httpSetup.get).toHaveBeenLastCalledWith(`${API_BASE_PATH}/mapping/${testIndexName}`, {
asSystemRequest: undefined,
body: undefined,
query: undefined,
version: undefined,
});
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/mapping/${testIndexName}`,
requestOptions
);
});
it('displays the mappings in the code block', async () => {
@ -372,12 +374,10 @@ describe('<IndexDetailsPage />', () => {
it('loads settings from the API', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Settings);
expect(httpSetup.get).toHaveBeenLastCalledWith(`${API_BASE_PATH}/settings/${testIndexName}`, {
asSystemRequest: undefined,
body: undefined,
query: undefined,
version: undefined,
});
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/settings/${testIndexName}`,
requestOptions
);
});
it('displays the settings in the code block', async () => {
@ -458,12 +458,7 @@ describe('<IndexDetailsPage />', () => {
expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests + 1);
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/settings/${testIndexName}`,
{
asSystemRequest: undefined,
body: undefined,
query: undefined,
version: undefined,
}
requestOptions
);
});
@ -625,4 +620,69 @@ describe('<IndexDetailsPage />', () => {
expect(httpSetup.get).toHaveBeenCalledTimes(numberOfRequests + 1);
});
});
describe('index name with a percent sign', () => {
const percentSignName = 'test%';
beforeEach(async () => {
httpRequestsMockHelpers.setLoadIndexDetailsResponse(encodeURIComponent(percentSignName), {
...testIndexMock,
name: percentSignName,
});
httpRequestsMockHelpers.setLoadIndexSettingsResponse(
encodeURIComponent(percentSignName),
testIndexSettings
);
await act(async () => {
testBed = await setup({
httpSetup,
initialEntry: `/indices/index_details?indexName=${encodeURIComponent(percentSignName)}`,
});
});
testBed.component.update();
});
it('loads the index details with the encoded index name', () => {
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${INTERNAL_API_BASE_PATH}/indices/${encodeURIComponent(percentSignName)}`,
requestOptions
);
});
it('loads mappings with the encoded index name', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Mappings);
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/mapping/${encodeURIComponent(percentSignName)}`,
requestOptions
);
});
it('loads settings with the encoded index name', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Settings);
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/settings/${encodeURIComponent(percentSignName)}`,
requestOptions
);
});
it('updates settings with the encoded index name', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Settings);
await testBed.actions.settings.clickEditModeSwitch();
const updatedSettings = { ...testIndexEditableSettings, 'index.priority': '2' };
await testBed.actions.settings.updateCodeEditorContent(JSON.stringify(updatedSettings));
await testBed.actions.settings.saveSettings();
expect(httpSetup.put).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/settings/${encodeURIComponent(percentSignName)}`,
{
asSystemRequest: undefined,
body: JSON.stringify({ 'index.priority': '2' }),
query: undefined,
version: undefined,
}
);
});
it('loads stats with the encoded index name', async () => {
await testBed.actions.clickIndexDetailsTab(IndexDetailsSection.Stats);
expect(httpSetup.get).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/stats/${encodeURIComponent(percentSignName)}`,
requestOptions
);
});
});
});

View file

@ -8,8 +8,6 @@ exports[`index table close index button works from context menu 1`] = `"closing.
exports[`index table close index button works from context menu 2`] = `"closed"`;
exports[`index table edit index button works from context menu 1`] = `"Edit settings"`;
exports[`index table flush button works from context menu 1`] = `"flushing..."`;
exports[`index table flush button works from context menu 2`] = `"open"`;
@ -114,9 +112,9 @@ Array [
exports[`index table should show the right context menu options when one index is selected and closed 1`] = `
Array [
"Show index overview",
"Show index settings",
"Show index mapping",
"Edit index settings",
"Open index",
"Delete index",
]
@ -124,10 +122,10 @@ Array [
exports[`index table should show the right context menu options when one index is selected and open 1`] = `
Array [
"Show index overview",
"Show index settings",
"Show index mapping",
"Show index stats",
"Edit index settings",
"Close index",
"Force merge index",
"Refresh index",
@ -173,9 +171,3 @@ Array [
"testy90",
]
`;
exports[`index table show mappings button works from context menu 1`] = `"Mappings"`;
exports[`index table show settings button works from context menu 1`] = `"Settings"`;
exports[`index table show stats button works from context menu 1`] = `"Stats"`;

View file

@ -108,12 +108,6 @@ const openMenuAndClickButton = (rendered, rowIndex, buttonSelector) => {
rendered.update();
};
const testEditor = (rendered, buttonSelector, rowIndex = 0) => {
openMenuAndClickButton(rendered, rowIndex, buttonSelector);
rendered.update();
snapshot(findTestSubject(rendered, 'detailPanelTabSelected').text());
};
const testAction = (rendered, buttonSelector, indexName = 'testy0') => {
const rowIndex = namesText(rendered).indexOf(indexName);
// This is leaking some implementation details about how Redux works. Not sure exactly what's going on
@ -326,20 +320,6 @@ describe('index table', () => {
snapshot(namesText(rendered));
});
test('should open the index detail slideout when the index name is clicked', async () => {
const rendered = mountWithIntl(component);
await runAllPromises();
rendered.update();
expect(findTestSubject(rendered, 'indexDetailFlyout').length).toBe(0);
const indexNameLink = names(rendered).at(0);
indexNameLink.simulate('click');
rendered.update();
expect(findTestSubject(rendered, 'indexDetailFlyout').length).toBe(1);
expect(findTestSubject(rendered, 'discoverIconLink').length).toBe(1);
});
test('should show the right context menu options when one index is selected and open', async () => {
const rendered = mountWithIntl(component);
await runAllPromises();
@ -490,34 +470,6 @@ describe('index table', () => {
testAction(rendered, 'openIndexMenuButton', 'testy1');
});
test('show settings button works from context menu', async () => {
const rendered = mountWithIntl(component);
await runAllPromises();
rendered.update();
testEditor(rendered, 'showSettingsIndexMenuButton');
});
test('show mappings button works from context menu', async () => {
const rendered = mountWithIntl(component);
await runAllPromises();
rendered.update();
testEditor(rendered, 'showMappingsIndexMenuButton');
});
test('show stats button works from context menu', async () => {
const rendered = mountWithIntl(component);
await runAllPromises();
rendered.update();
testEditor(rendered, 'showStatsIndexMenuButton');
});
test('edit index button works from context menu', async () => {
const rendered = mountWithIntl(component);
await runAllPromises();
rendered.update();
testEditor(rendered, 'editIndexMenuButton');
});
describe('Common index actions', () => {
beforeEach(() => {
// Mock initialization of services; set enableIndexActions=false to verify config behavior

View file

@ -31,12 +31,6 @@ export {
UIM_INDEX_UNFREEZE,
UIM_INDEX_UNFREEZE_MANY,
UIM_INDEX_SETTINGS_EDIT,
UIM_SHOW_DETAILS_CLICK,
UIM_DETAIL_PANEL_SUMMARY_TAB,
UIM_DETAIL_PANEL_SETTINGS_TAB,
UIM_DETAIL_PANEL_MAPPING_TAB,
UIM_DETAIL_PANEL_STATS_TAB,
UIM_DETAIL_PANEL_EDIT_SETTINGS_TAB,
UIM_TEMPLATE_LIST_LOAD,
UIM_TEMPLATE_DELETE,
UIM_TEMPLATE_DELETE_MANY,

View file

@ -26,12 +26,6 @@ export const UIM_INDEX_REFRESH_MANY = 'index_refresh_many';
export const UIM_INDEX_SETTINGS_EDIT = 'index_settings_edit';
export const UIM_INDEX_UNFREEZE = 'index_unfreeze';
export const UIM_INDEX_UNFREEZE_MANY = 'index_unfreeze_many';
export const UIM_SHOW_DETAILS_CLICK = 'show_details_click';
export const UIM_DETAIL_PANEL_EDIT_SETTINGS_TAB = 'detail_panel_edit_settings_tab';
export const UIM_DETAIL_PANEL_MAPPING_TAB = 'detail_panel_mapping_tab';
export const UIM_DETAIL_PANEL_SETTINGS_TAB = 'detail_panel_settings_tab';
export const UIM_DETAIL_PANEL_STATS_TAB = 'detail_panel_stats_tab';
export const UIM_DETAIL_PANEL_SUMMARY_TAB = 'detail_panel_summary_tab';
export const UIM_TEMPLATE_LIST_LOAD = 'template_list_load';
export const UIM_TEMPLATE_DELETE = 'template_delete';
export const UIM_TEMPLATE_DELETE_MANY = 'template_delete_many';

View file

@ -52,7 +52,6 @@ export interface AppDependencies {
config: {
enableIndexActions: boolean;
enableLegacyTemplates: boolean;
enableIndexDetailsPage: boolean;
enableIndexStats: boolean;
};
history: ScopedHistory;

View file

@ -56,7 +56,6 @@ export async function mountManagementSection({
kibanaVersion,
enableIndexActions = true,
enableLegacyTemplates = true,
enableIndexDetailsPage = false,
enableIndexStats = true,
cloud,
}: {
@ -68,7 +67,6 @@ export async function mountManagementSection({
kibanaVersion: SemVer;
enableIndexActions?: boolean;
enableLegacyTemplates?: boolean;
enableIndexDetailsPage?: boolean;
enableIndexStats?: boolean;
cloud?: CloudSetup;
}) {
@ -119,7 +117,6 @@ export async function mountManagementSection({
config: {
enableIndexActions,
enableLegacyTemplates,
enableIndexDetailsPage,
enableIndexStats,
},
history,

View file

@ -13,7 +13,6 @@ import { EuiButtonEmpty, EuiPageHeader, EuiSpacer } from '@elastic/eui';
import { Section } from '../../../../common/constants';
import { documentationService } from '../../services/documentation';
import { useAppContext } from '../../app_context';
import { ComponentTemplateList } from '../../components/component_templates';
import { IndexList } from './index_list';
import { EnrichPoliciesList } from './enrich_policies_list';
@ -39,9 +38,6 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma
},
history,
}) => {
const {
config: { enableIndexDetailsPage },
} = useAppContext();
const tabs = [
{
id: Section.Indices,
@ -147,15 +143,10 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma
</Routes>
</>
);
if (enableIndexDetailsPage) {
return (
<>
<Routes>
<Route path={`/${Section.Indices}/index_details`} component={IndexDetailsPage} />
<Route render={() => indexManagementTabs} />
</Routes>
</>
);
}
return indexManagementTabs;
return (
<Routes>
<Route path={`/${Section.Indices}/index_details`} component={IndexDetailsPage} />
<Route render={() => indexManagementTabs} />
</Routes>
);
};

View file

@ -1,8 +0,0 @@
/*
* 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 declare function DetailPanel(props: any): any;

View file

@ -1,64 +0,0 @@
/*
* 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 { connect } from 'react-redux';
import { DetailPanel as PresentationComponent } from './detail_panel';
import {
getDetailPanelType,
getDetailPanelIndexName,
getIndexByIndexName,
} from '../../../../store/selectors';
import {
openDetailPanel,
closeDetailPanel,
clearCacheIndices,
closeIndices,
deleteIndices,
flushIndices,
forcemergeIndices,
openIndices,
refreshIndices,
} from '../../../../store/actions';
const mapStateToProps = (state) => {
const indexName = getDetailPanelIndexName(state);
return {
panelType: getDetailPanelType(state),
indexName,
index: getIndexByIndexName(state, indexName),
};
};
const mapDispatchToProps = (dispatch) => {
return {
clearCacheIndex: (indexName) => {
dispatch(clearCacheIndices({ indexNames: [indexName] }));
},
closeIndex: (indexName) => {
dispatch(closeIndices({ indexNames: [indexName] }));
},
flushIndex: (indexName) => {
dispatch(flushIndices({ indexNames: [indexName] }));
},
openIndex: (indexName) => {
dispatch(openIndices({ indexNames: [indexName] }));
},
refreshIndex: (indexName) => {
dispatch(refreshIndices({ indexNames: [indexName] }));
},
forcemergeIndex: (indexName) => {
dispatch(forcemergeIndices({ indexNames: [indexName] }));
},
deleteIndex: (indexName) => {
dispatch(deleteIndices({ indexNames: [indexName] }));
},
closeDetailPanel: () => dispatch(closeDetailPanel()),
openDetailPanel: (indexName, panelType) => dispatch(openDetailPanel(indexName, panelType)),
};
};
export const DetailPanel = connect(mapStateToProps, mapDispatchToProps)(PresentationComponent);

View file

@ -1,176 +0,0 @@
/*
* 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, { Fragment } from 'react';
import { Route } from '@kbn/shared-ux-router';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiSpacer,
EuiTabs,
EuiTab,
EuiTitle,
} from '@elastic/eui';
import { renderBadges } from '../../../../lib/render_badges';
import { INDEX_OPEN } from '../../../../../../common/constants';
import {
TAB_SUMMARY,
TAB_SETTINGS,
TAB_MAPPING,
TAB_STATS,
TAB_EDIT_SETTINGS,
} from '../../../../constants';
import { IndexActionsContextMenu } from '../index_actions_context_menu';
import { ShowJson } from './show_json';
import { Summary } from './summary';
import { EditSettingsJson } from './edit_settings_json';
import { useServices, useAppContext } from '../../../../app_context';
import { DiscoverLink } from '../../../../lib/discover_link';
const tabToHumanizedMap = {
[TAB_SUMMARY]: (
<FormattedMessage id="xpack.idxMgmt.detailPanel.tabSummaryLabel" defaultMessage="Summary" />
),
[TAB_SETTINGS]: (
<FormattedMessage id="xpack.idxMgmt.detailPanel.tabSettingsLabel" defaultMessage="Settings" />
),
[TAB_MAPPING]: (
<FormattedMessage id="xpack.idxMgmt.detailPanel.tabMappingLabel" defaultMessage="Mappings" />
),
[TAB_STATS]: (
<FormattedMessage id="xpack.idxMgmt.detailPanel.tabStatsLabel" defaultMessage="Stats" />
),
[TAB_EDIT_SETTINGS]: (
<FormattedMessage
id="xpack.idxMgmt.detailPanel.tabEditSettingsLabel"
defaultMessage="Edit settings"
/>
),
};
const getTabs = (showStats) => {
if (showStats) {
return [TAB_SUMMARY, TAB_SETTINGS, TAB_MAPPING, TAB_STATS, TAB_EDIT_SETTINGS];
}
return [TAB_SUMMARY, TAB_SETTINGS, TAB_MAPPING, TAB_EDIT_SETTINGS];
};
export const DetailPanel = ({ panelType, indexName, index, openDetailPanel, closeDetailPanel }) => {
const { extensionsService } = useServices();
const { config } = useAppContext();
const renderTabs = () => {
const tabs = getTabs(config.enableIndexStats);
return tabs.map((tab, i) => {
const isSelected = tab === panelType;
return (
<EuiTab
onClick={() => openDetailPanel({ panelType: tab, indexName })}
isSelected={isSelected}
data-test-subj={`detailPanelTab${isSelected ? 'Selected' : ''}`}
disabled={tab === TAB_STATS && index.status !== INDEX_OPEN}
key={i}
>
{tabToHumanizedMap[tab]}
</EuiTab>
);
});
};
if (!panelType) {
return null;
}
let component = null;
switch (panelType) {
case TAB_EDIT_SETTINGS:
component = <EditSettingsJson />;
break;
case TAB_MAPPING:
case TAB_SETTINGS:
case TAB_STATS:
component = <ShowJson />;
break;
default:
component = <Summary />;
}
const content = index ? (
<Fragment>
<EuiFlyoutBody>{component}</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<Route
key="menu"
render={() => (
<IndexActionsContextMenu
indexNames={[indexName]}
anchorPosition="upRight"
iconSide="left"
iconType="arrowUp"
label={
<FormattedMessage
id="xpack.idxMgmt.detailPanel.manageContextMenuLabel"
defaultMessage="Manage"
/>
}
/>
)}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</Fragment>
) : (
<EuiFlyoutBody>
<EuiSpacer size="l" />
<EuiCallOut
title={
<FormattedMessage
id="xpack.idxMgmt.detailPanel.missingIndexTitle"
defaultMessage="Missing index"
/>
}
color="danger"
iconType="cross"
>
<FormattedMessage
id="xpack.idxMgmt.detailPanel.missingIndexMessage"
defaultMessage="This index does not exist.
It might have been deleted by a running job or another system."
/>
</EuiCallOut>
</EuiFlyoutBody>
);
return (
<EuiFlyout
data-test-subj="indexDetailFlyout"
onClose={closeDetailPanel}
aria-labelledby="indexDetailsFlyoutTitle"
>
<EuiFlyoutHeader>
<EuiTitle id="indexDetailsFlyoutTitle">
<h2>
{indexName}
<DiscoverLink indexName={indexName} />
{renderBadges(index, undefined, extensionsService)}
</h2>
</EuiTitle>
{index ? <EuiTabs>{renderTabs()}</EuiTabs> : null}
</EuiFlyoutHeader>
{content}
</EuiFlyout>
);
};

View file

@ -1,34 +0,0 @@
/*
* 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 { connect } from 'react-redux';
import { EditSettingsJson as PresentationComponent } from './edit_settings_json';
import { closeDetailPanel, loadIndexData, updateIndexSettings } from '../../../../../store/actions';
import {
getDetailPanelData,
getDetailPanelError,
getDetailPanelIndexName,
getIndexStatusByIndexName,
} from '../../../../../store/selectors';
const mapStateToProps = (state) => {
const indexName = getDetailPanelIndexName(state);
return {
error: getDetailPanelError(state),
data: getDetailPanelData(state),
indexName,
indexStatus: getIndexStatusByIndexName(state, indexName),
};
};
const mapDispatchToProps = {
loadIndexData,
closeDetailPanel,
updateIndexSettings,
};
export const EditSettingsJson = connect(mapStateToProps, mapDispatchToProps)(PresentationComponent);

View file

@ -1,170 +0,0 @@
/*
* 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 from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { documentationService } from '../../../../../services/documentation';
import {
EuiButton,
EuiFlexGroup,
EuiFlexItem,
EuiCallOut,
EuiLink,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { TAB_SETTINGS } from '../../../../../constants';
import { settingsToDisplay, readOnlySettings } from '../../../../../lib/edit_settings';
import { createAceEditor } from '../../../../../lib/ace';
import _ from 'lodash';
import { flattenObject } from '../../../../../lib/flatten_object';
export class EditSettingsJson extends React.PureComponent {
constructor() {
super();
this.state = {
valid: true,
};
}
//API expects settings in flattened dotted form,
//whereas they come back as nested objects from ES
transformSettingsForApi(data, isOpen) {
const { defaults, settings } = data;
//settings user has actually set
const flattenedSettings = flattenObject(settings);
//settings with their defaults
const flattenedDefaults = flattenObject(defaults);
const filteredDefaults = _.pick(flattenedDefaults, settingsToDisplay);
const newSettings = { ...filteredDefaults, ...flattenedSettings };
//store these to be used as autocomplete values later
this.settingsKeys = Object.keys(newSettings);
readOnlySettings.forEach((e) => delete newSettings[e]);
//can't change codec on open index
if (isOpen) {
delete newSettings['index.codec'];
}
return newSettings;
}
UNSAFE_componentWillMount() {
const { indexName } = this.props;
this.props.loadIndexData({ dataType: TAB_SETTINGS, indexName });
}
componentDidUpdate() {
const { data, indexStatus } = this.props;
if (data && !this.editor) {
const isOpen = indexStatus === 'open';
const newSettings = this.transformSettingsForApi(data, isOpen);
this.originalSettings = newSettings;
const prettyJson = JSON.stringify(newSettings, null, 2);
const settingsKeys = Object.keys(newSettings);
const editor = (this.editor = createAceEditor(this.aceDiv, prettyJson, false, settingsKeys));
const session = editor.getSession();
session.on('changeAnnotation', () => {
const isEmptyString = session.getValue() === '';
this.setState({ valid: !isEmptyString && session.getAnnotations().length === 0 });
});
}
}
componentWillUnmount() {
this.editor && this.editor.destroy();
}
commitSettings = () => {
const { updateIndexSettings, indexName } = this.props;
const json = this.editor.getValue();
const settings = JSON.parse(json);
//don't set if the values have not changed
Object.keys(this.originalSettings).forEach((key) => {
if (_.isEqual(this.originalSettings[key], settings[key])) {
delete settings[key];
}
});
updateIndexSettings({ indexName, settings });
};
errorMessage() {
const { error } = this.props;
if (!error) {
return null;
}
return (
<>
<EuiSpacer />
<EuiCallOut
title={i18n.translate('xpack.idxMgmt.editSettingsJSON.saveJSONCalloutErrorTitle', {
defaultMessage: 'There was an error while trying to save your settings',
})}
color="danger"
iconType="warning"
data-test-subj="updateIndexSettingsErrorCallout"
>
<p>{error}</p>
</EuiCallOut>
</>
);
}
render() {
const { data } = this.props;
if (!data) {
return null;
}
return (
<div>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem>
<EuiTitle>
<p>
<FormattedMessage
id="xpack.idxMgmt.editSettingsJSON.saveJSONDescription"
defaultMessage="Edit, then save your JSON"
/>
</p>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
size="s"
fill
data-test-subj="updateEditIndexSettingsButton"
onClick={this.commitSettings}
disabled={!this.state.valid}
>
<FormattedMessage
id="xpack.idxMgmt.editSettingsJSON.saveJSONButtonLabel"
defaultMessage="Save"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
{this.errorMessage()}
<EuiSpacer />
<EuiLink
href={documentationService.getSettingsDocumentationLink()}
target="_blank"
rel="noopener"
>
<FormattedMessage
id="xpack.idxMgmt.editSettingsJSON.settingsReferenceLinkText"
defaultMessage="Settings reference"
/>
</EuiLink>
<EuiSpacer />
<div
data-test-subj="indexJsonEditor"
ref={(aceDiv) => {
this.aceDiv = aceDiv;
}}
/>
<EuiSpacer />
</div>
);
}
}

View file

@ -1,8 +0,0 @@
/*
* 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 { EditSettingsJson } from './edit_settings_json.container';

View file

@ -1,8 +0,0 @@
/*
* 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 { DetailPanel } from './detail_panel.container';

View file

@ -1,8 +0,0 @@
/*
* 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 { ShowJson } from './show_json.container';

View file

@ -1,36 +0,0 @@
/*
* 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 { connect } from 'react-redux';
import { ShowJson as PresentationComponent } from './show_json';
import { loadIndexData, closeDetailPanel } from '../../../../../store/actions';
import {
getDetailPanelData,
getDetailPanelError,
getDetailPanelIndexName,
getDetailPanelType,
getIndexStatusByIndexName,
} from '../../../../../store/selectors';
const mapStateToProps = (state) => {
const indexName = getDetailPanelIndexName(state);
return {
error: getDetailPanelError(state),
data: getDetailPanelData(state),
dataType: getDetailPanelType(state),
indexName,
indexStatus: getIndexStatusByIndexName(state, indexName),
};
};
const mapDispatchToProps = {
loadIndexData,
closeDetailPanel,
};
export const ShowJson = connect(mapStateToProps, mapDispatchToProps)(PresentationComponent);

View file

@ -1,31 +0,0 @@
/*
* 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 from 'react';
import { EuiCodeBlock } from '@elastic/eui';
import 'brace/theme/textmate';
export class ShowJson extends React.PureComponent {
UNSAFE_componentWillMount() {
this.props.loadIndexData(this.props);
}
UNSAFE_componentWillUpdate(newProps) {
const { data, loadIndexData } = newProps;
if (!data) {
loadIndexData(newProps);
}
}
render() {
const { data } = this.props;
if (!data) {
return null;
}
const json = JSON.stringify(data, null, 2);
return <EuiCodeBlock language="json">{json}</EuiCodeBlock>;
}
}

View file

@ -1,8 +0,0 @@
/*
* 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 { Summary } from './summary.container';

View file

@ -1,21 +0,0 @@
/*
* 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 { connect } from 'react-redux';
import { Summary as PresentationComponent } from './summary';
import { getIndexByIndexName, getDetailPanelIndexName } from '../../../../../store/selectors';
const mapStateToProps = (state) => {
const indexName = getDetailPanelIndexName(state);
return {
indexName,
index: getIndexByIndexName(state, indexName),
};
};
export const Summary = connect(mapStateToProps)(PresentationComponent);

View file

@ -1,147 +0,0 @@
/*
* 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, { Fragment } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiDescriptionList,
EuiHorizontalRule,
EuiDescriptionListTitle,
EuiDescriptionListDescription,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';
import { DataHealth } from '../../../../../components';
import { AppContextConsumer } from '../../../../../app_context';
const getHeaders = (showStats) => {
const baseHeaders = {
primary: i18n.translate('xpack.idxMgmt.summary.headers.primaryHeader', {
defaultMessage: 'Primaries',
}),
replica: i18n.translate('xpack.idxMgmt.summary.headers.replicaHeader', {
defaultMessage: 'Replicas',
}),
aliases: i18n.translate('xpack.idxMgmt.summary.headers.aliases', {
defaultMessage: 'Aliases',
}),
};
if (showStats) {
return {
...baseHeaders,
health: i18n.translate('xpack.idxMgmt.summary.headers.healthHeader', {
defaultMessage: 'Health',
}),
status: i18n.translate('xpack.idxMgmt.summary.headers.statusHeader', {
defaultMessage: 'Status',
}),
documents: i18n.translate('xpack.idxMgmt.summary.headers.documentsHeader', {
defaultMessage: 'Docs count',
}),
documents_deleted: i18n.translate('xpack.idxMgmt.summary.headers.deletedDocumentsHeader', {
defaultMessage: 'Docs deleted',
}),
size: i18n.translate('xpack.idxMgmt.summary.headers.storageSizeHeader', {
defaultMessage: 'Storage size',
}),
primary_size: i18n.translate('xpack.idxMgmt.summary.headers.primaryStorageSizeHeader', {
defaultMessage: 'Primary storage size',
}),
};
}
return baseHeaders;
};
export class Summary extends React.PureComponent {
getAdditionalContent(extensionsService, getUrlForApp) {
const { index } = this.props;
const extensions = extensionsService.summaries;
return extensions.map((summaryExtension, i) => {
const ExtensionSummaryComponent = summaryExtension;
return (
<Fragment key={`summaryExtension-${i}`}>
<EuiHorizontalRule />
<ExtensionSummaryComponent index={index} getUrlForApp={getUrlForApp} />
</Fragment>
);
});
}
buildRows(config) {
const { index } = this.props;
const headers = getHeaders(config.enableIndexStats);
const rows = {
left: [],
right: [],
};
Object.keys(headers).forEach((fieldName, arrayIndex) => {
const value = index[fieldName];
let content = value;
if (fieldName === 'health') {
content = <DataHealth health={value} />;
}
if (Array.isArray(content)) {
content = content.join(', ');
}
const cell = [
<EuiDescriptionListTitle key={fieldName} data-test-subj="descriptionTitle">
<strong>{headers[fieldName]}</strong>
</EuiDescriptionListTitle>,
<EuiDescriptionListDescription key={fieldName + '_desc'}>
{content}
</EuiDescriptionListDescription>,
];
if (arrayIndex % 2 === 0) {
rows.left.push(cell);
} else {
rows.right.push(cell);
}
});
return rows;
}
render() {
return (
<AppContextConsumer>
{({ services, core, config }) => {
const { left, right } = this.buildRows(config);
const additionalContent = this.getAdditionalContent(
services.extensionsService,
core.getUrlForApp
);
return (
<Fragment>
<EuiTitle size="s">
<h3>
<FormattedMessage
id="xpack.idxMgmt.summary.summaryTitle"
defaultMessage="General"
/>
</h3>
</EuiTitle>
<EuiSpacer size="s" />
<EuiFlexGroup>
<EuiFlexItem>
<EuiDescriptionList type="column">{left}</EuiDescriptionList>
</EuiFlexItem>
<EuiFlexItem>
<EuiDescriptionList type="column">{right}</EuiDescriptionList>
</EuiFlexItem>
</EuiFlexGroup>
{additionalContent}
</Fragment>
);
}}
</AppContextConsumer>
);
}
}

View file

@ -59,7 +59,7 @@ const defaultTabs = [
const statsTab = {
id: IndexDetailsSection.Stats,
name: <FormattedMessage id="xpack.idxMgmt.indexDetails.statsTitle" defaultMessage="Stats" />,
name: <FormattedMessage id="xpack.idxMgmt.indexDetails.statsTitle" defaultMessage="Statistics" />,
};
const getSelectedTabContent = ({

View file

@ -34,7 +34,7 @@ export const DetailsPageError = ({
<EuiText color="subdued">
<FormattedMessage
id="xpack.idxMgmt.indexDetails.errorDescription"
defaultMessage="There was an error loading data for index {indexName}. Make sure the index name in the url is correct and try again."
defaultMessage="We encountered an error loading data for index {indexName}. Make sure that the index name in the URL is correct and try again."
values={{
indexName,
}}

View file

@ -61,10 +61,9 @@ export const DetailsPageMappings: FunctionComponent<{ indexName: string }> = ({
<EuiText color="subdued">
<FormattedMessage
id="xpack.idxMgmt.indexDetails.mappings.errorDescription"
defaultMessage="There was an error loading mappings for index {indexName}: {error}"
defaultMessage="We encountered an error loading mappings for index {indexName}. Make sure that the index name in the URL is correct and try again."
values={{
indexName,
error: error.error,
}}
/>
</EuiText>
@ -138,7 +137,7 @@ export const DetailsPageMappings: FunctionComponent<{ indexName: string }> = ({
>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.mappings.docsCardLink"
defaultMessage="Learn more"
defaultMessage="Learn more about mappings"
/>
</EuiLink>
</EuiPanel>

View file

@ -7,6 +7,7 @@
import React, { useState, useMemo, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiSpacer,
EuiPanel,
@ -16,6 +17,7 @@ import {
EuiTitle,
EuiText,
EuiTextColor,
EuiLink,
} from '@elastic/eui';
import {
CodeBox,
@ -26,6 +28,7 @@ import {
} from '@kbn/search-api-panels';
import type { Index } from '../../../../../../../common';
import { useAppContext } from '../../../../../app_context';
import { documentationService } from '../../../../../services';
import { breadcrumbService, IndexManagementBreadcrumb } from '../../../../../services/breadcrumbs';
import { languageDefinitions, curlDefinition } from './languages';
import { ExtensionsSummary } from './extensions_summary';
@ -165,7 +168,7 @@ export const DetailsPageOverview: React.FunctionComponent<Props> = ({ indexDetai
<EuiTitle size="s">
<h2>
{i18n.translate('xpack.idxMgmt.indexDetails.overviewTab.addMoreDataTitle', {
defaultMessage: 'Add more data to this index',
defaultMessage: 'Add data to this index',
})}
</h2>
</EuiTitle>
@ -175,10 +178,20 @@ export const DetailsPageOverview: React.FunctionComponent<Props> = ({ indexDetai
<EuiTextColor color="subdued">
<EuiText size="s">
<p>
{i18n.translate('xpack.idxMgmt.indexDetails.overviewTab.addMoreDataDescription', {
defaultMessage:
'Keep adding more documents to your already created index using the API',
})}
<FormattedMessage
id="xpack.idxMgmt.indexDetails.overviewTab.addMoreDataDescription"
defaultMessage="Use the bulk API to add data to your index. {docsLink}"
values={{
docsLink: (
<EuiLink href={documentationService.getBulkApi()} target="_blank" external>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.overviewTab.addDocsLink"
defaultMessage="Learn more."
/>
</EuiLink>
),
}}
/>
</p>
</EuiText>
</EuiTextColor>

View file

@ -53,10 +53,9 @@ export const DetailsPageSettings: FunctionComponent<{
<EuiText color="subdued">
<FormattedMessage
id="xpack.idxMgmt.indexDetails.settings.errorDescription"
defaultMessage="There was an error loading settings for index {indexName}: {error}"
defaultMessage="We encountered an error loading settings for index {indexName}. Make sure that the index name in the URL is correct and try again."
values={{
indexName,
error: error?.error,
}}
/>
</EuiText>

View file

@ -153,7 +153,7 @@ export const DetailsPageSettingsContent: FunctionComponent<Props> = ({
<b>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.settings.docsCardTitle"
defaultMessage="Index settings"
defaultMessage="Edit index settings"
/>
</b>
</EuiText>
@ -183,7 +183,7 @@ export const DetailsPageSettingsContent: FunctionComponent<Props> = ({
>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.settings.saveButtonLabel"
defaultMessage="Save"
defaultMessage="Save changes"
/>
</EuiButton>
</EuiFlexItem>
@ -208,16 +208,13 @@ export const DetailsPageSettingsContent: FunctionComponent<Props> = ({
title={i18n.translate(
'xpack.idxMgmt.indexDetails.settings.saveSettingsErrorMessage',
{
defaultMessage: 'Unable to save the settings',
defaultMessage: 'Unable to save settings',
}
)}
color="danger"
iconType="error"
>
<p>
{updateError.error}
{updateError.message && <span>: {updateError.message}</span>}
</p>
{updateError.message && <p>{updateError.message}</p>}
</EuiCallOut>
</>
)}
@ -230,7 +227,7 @@ export const DetailsPageSettingsContent: FunctionComponent<Props> = ({
>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.settings.docsCardLink"
defaultMessage="Settings reference"
defaultMessage="Learn more about settings"
/>
</EuiLink>
</EuiPanel>

View file

@ -69,7 +69,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
<h2>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.statsNotAvailableTitle"
defaultMessage="Index stats not available"
defaultMessage="Index statistics not available"
/>
</h2>
}
@ -77,7 +77,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
<p>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.statsNotAvailableDescription"
defaultMessage="To view index stats, verify your index is open."
defaultMessage="To view index statistics, verify your index is open."
/>
</p>
}
@ -90,7 +90,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
<SectionLoading>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.loadingIndexStats"
defaultMessage="Loading index stats…"
defaultMessage="Loading index statistics…"
/>
</SectionLoading>
);
@ -106,7 +106,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
<h2>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.errorTitle"
defaultMessage="Unable to load index stats"
defaultMessage="Unable to load index statistics"
/>
</h2>
}
@ -115,7 +115,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
<EuiText color="subdued">
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.errorDescription"
defaultMessage="We encountered an error loading the stats for index {indexName}."
defaultMessage="We encountered an error loading statistics for index {indexName}. Make sure that the index name in the URL is correct and try again."
values={{
indexName,
}}
@ -168,7 +168,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
<h2>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.indexStatsTitle"
defaultMessage="About index stats"
defaultMessage="About index statistics"
/>
</h2>
</EuiTitle>
@ -181,7 +181,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
<p>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.indexStatsDescription"
defaultMessage="Index stats contain high-level aggregation and statistics for an index. The {primariesField} field represents the values for only primary shards, while the {totalField} field contains the accumulated values for both primary and replica shards."
defaultMessage="Index stats contain high-level aggregation and statistics for an index. The {primariesField} field represents the values for only primary shards, and the {totalField} field contains the accumulated values for both primary and replica shards."
values={{
primariesField: <EuiCode>primaries</EuiCode>,
totalField: <EuiCode>total</EuiCode>,
@ -199,7 +199,7 @@ export const DetailsPageStats: FunctionComponent<{ indexName: string; isIndexOpe
>
<FormattedMessage
id="xpack.idxMgmt.indexDetails.stats.learnMoreLink"
defaultMessage="Learn more"
defaultMessage="Learn more about statistics"
/>
</EuiLink>
</EuiPanel>

View file

@ -73,8 +73,8 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await reloadIndices();
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.closeIndicesAction.successfullyClosedIndicesMessage', {
defaultMessage: 'Successfully closed: [{indexNames}]',
i18n.translate('xpack.idxMgmt.closeIndicesAction.indexClosedMessage', {
defaultMessage: 'The index {indexNames} was closed.',
values: { indexNames: indexNames.join(', ') },
})
);
@ -91,8 +91,8 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await reloadIndices();
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.openIndicesAction.successfullyOpenedIndicesMessage', {
defaultMessage: 'Successfully opened: [{indexNames}]',
i18n.translate('xpack.idxMgmt.openIndicesAction.indexOpenedMessage', {
defaultMessage: 'The index {indexNames} was opened.',
values: { indexNames: indexNames.join(', ') },
})
);
@ -109,8 +109,8 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await reloadIndices();
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.flushIndicesAction.successfullyFlushedIndicesMessage', {
defaultMessage: 'Successfully flushed: [{indexNames}]',
i18n.translate('xpack.idxMgmt.flushIndicesAction.indexFlushedMessage', {
defaultMessage: 'The index {indexNames} was flushed.',
values: { indexNames: indexNames.join(', ') },
})
);
@ -127,8 +127,8 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await reloadIndices();
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.refreshIndicesAction.successfullyRefreshedIndicesMessage', {
defaultMessage: 'Successfully refreshed: [{indexNames}]',
i18n.translate('xpack.idxMgmt.refreshIndicesAction.indexRefreshedMessage', {
defaultMessage: 'The index {indexNames} was refreshed.',
values: { indexNames: indexNames.join(', ') },
})
);
@ -145,8 +145,8 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await reloadIndices();
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.clearCacheIndicesAction.successMessage', {
defaultMessage: 'Successfully cleared cache: [{indexNames}]',
i18n.translate('xpack.idxMgmt.clearCacheIndicesAction.indexCacheClearedMessage', {
defaultMessage: 'The cache of the index {indexNames} was cleared.',
values: { indexNames: indexNames.join(', ') },
})
);
@ -163,8 +163,8 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await reloadIndices();
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.unfreezeIndicesAction.successfullyUnfrozeIndicesMessage', {
defaultMessage: 'Successfully unfroze: [{indexNames}]',
i18n.translate('xpack.idxMgmt.unfreezeIndicesAction.indexUnfrozenMessage', {
defaultMessage: 'The index {indexNames} was unfrozen.',
values: { indexNames: indexNames.join(', ') },
})
);
@ -182,13 +182,10 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await reloadIndices();
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate(
'xpack.idxMgmt.forceMergeIndicesAction.successfullyForceMergedIndicesMessage',
{
defaultMessage: 'Successfully force merged: [{indexNames}]',
values: { indexNames: indexNames.join(', ') },
}
)
i18n.translate('xpack.idxMgmt.forceMergeIndicesAction.indexForcemergedMessage', {
defaultMessage: 'The index {indexNames} was force merged.',
values: { indexNames: indexNames.join(', ') },
})
);
} catch (error) {
setIsLoading(false);
@ -204,8 +201,8 @@ export const ManageIndexButton: FunctionComponent<Props> = ({
await deleteIndicesRequest(indexNames);
setIsLoading(false);
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.deleteIndicesAction.successfullyDeletedIndicesMessage', {
defaultMessage: 'Successfully deleted: [{indexNames}]',
i18n.translate('xpack.idxMgmt.deleteIndicesAction.indexDeletedMessage', {
defaultMessage: 'The index {indexNames} was deleted.',
values: { indexNames: indexNames.join(', ') },
})
);

View file

@ -7,7 +7,6 @@
import { connect } from 'react-redux';
import { IndexActionsContextMenu as PresentationComponent } from './index_actions_context_menu';
import { TAB_SETTINGS, TAB_MAPPING, TAB_STATS, TAB_EDIT_SETTINGS } from '../../../../constants';
import {
clearCacheIndices,
closeIndices,
@ -15,9 +14,7 @@ import {
flushIndices,
forcemergeIndices,
openIndices,
editIndexSettings,
refreshIndices,
openDetailPanel,
performExtensionAction,
reloadIndices,
unfreezeIndices,
@ -41,9 +38,6 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = (dispatch, { indexNames }) => {
return {
editIndexSettings: () => {
dispatch(editIndexSettings({ indexName: indexNames[0] }));
},
clearCacheIndices: () => {
dispatch(clearCacheIndices({ indexNames }));
},
@ -65,21 +59,6 @@ const mapDispatchToProps = (dispatch, { indexNames }) => {
forcemergeIndices: (maxNumSegments) => {
dispatch(forcemergeIndices({ indexNames, maxNumSegments }));
},
showSettings: () => {
dispatch(openDetailPanel({ indexName: indexNames[0], panelType: TAB_SETTINGS }));
},
showMapping: () => {
dispatch(openDetailPanel({ indexName: indexNames[0], panelType: TAB_MAPPING }));
},
showStats: () => {
dispatch(openDetailPanel({ indexName: indexNames[0], panelType: TAB_STATS }));
},
editIndex: () => {
const indexName = indexNames ? indexNames[0] : null;
if (indexName) {
dispatch(openDetailPanel({ indexName, panelType: TAB_EDIT_SETTINGS }));
}
},
deleteIndices: () => {
dispatch(deleteIndices({ indexNames }));
},

View file

@ -37,12 +37,6 @@ export interface IndexActionsContextMenuProps {
forcemergeIndices: (maxNumSegments: string) => Promise<void>;
deleteIndices: () => Promise<void>;
// following 4 actions are only added when on the list view and only 1 index is selected
showSettings?: () => void; // opens the settings tab for the 1st index in the indexNames array
showMapping?: () => void; // opens the mapping tab for the 1st index in the indexNames array
showStats?: () => void; // opens the stats tab for the 1st index in the indexNames array
editIndex?: () => void; // opens the edit settings tab for the 1st index in the indexNames array
// used to determine if all indices are open
indexStatusByName: {
[indexName: string]: Index['status'] | undefined;

View file

@ -22,8 +22,9 @@ import {
} from '@elastic/eui';
import { flattenPanelTree } from '../../../../lib/flatten_panel_tree';
import { INDEX_OPEN } from '../../../../../../common/constants';
import { AppContextConsumer, AppContext } from '../../../../app_context';
import { INDEX_OPEN, IndexDetailsSection } from '../../../../../../common/constants';
import { getIndexDetailsLink } from '../../../../services/routing';
import { AppContext } from '../../../../app_context';
export class IndexActionsContextMenu extends Component {
static contextType = AppContext;
@ -46,8 +47,11 @@ export class IndexActionsContextMenu extends Component {
confirmAction = (isActionConfirmed) => {
this.setState({ isActionConfirmed });
};
panels({ services: { extensionsService }, core: { getUrlForApp } }) {
panels() {
const {
services: { extensionsService },
core: { getUrlForApp },
history,
config: { enableIndexActions },
} = this.context;
@ -57,10 +61,6 @@ export class IndexActionsContextMenu extends Component {
flushIndices,
refreshIndices,
clearCacheIndices,
editIndex,
showMapping,
showStats,
showSettings,
isOnListView,
indexNames,
indexStatusByName,
@ -77,49 +77,43 @@ export class IndexActionsContextMenu extends Component {
const items = [];
if (isOnListView && selectedIndexCount === 1) {
items.push({
'data-test-subj': 'showSettingsIndexMenuButton',
name: i18n.translate('xpack.idxMgmt.indexActionsMenu.showIndexSettingsLabel', {
defaultMessage:
'Show {selectedIndexCount, plural, one {index} other {indices} } settings',
values: { selectedIndexCount },
'data-test-subj': 'showOverviewIndexMenuButton',
name: i18n.translate('xpack.idxMgmt.indexActionsMenu.showIndexOverviewLabel', {
defaultMessage: 'Show index overview',
}),
onClick: () => {
this.closePopoverAndExecute(showSettings);
history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Overview));
},
});
items.push({
'data-test-subj': 'showSettingsIndexMenuButton',
name: i18n.translate('xpack.idxMgmt.indexActionsMenu.showIndexSettingsLabel', {
defaultMessage: 'Show index settings',
}),
onClick: () => {
history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Settings));
},
});
items.push({
'data-test-subj': 'showMappingsIndexMenuButton',
name: i18n.translate('xpack.idxMgmt.indexActionsMenu.showIndexMappingLabel', {
defaultMessage: 'Show {selectedIndexCount, plural, one {index} other {indices} } mapping',
values: { selectedIndexCount },
defaultMessage: 'Show index mapping',
}),
onClick: () => {
this.closePopoverAndExecute(showMapping);
history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Mappings));
},
});
if (allOpen && enableIndexActions) {
items.push({
'data-test-subj': 'showStatsIndexMenuButton',
name: i18n.translate('xpack.idxMgmt.indexActionsMenu.showIndexStatsLabel', {
defaultMessage: 'Show {selectedIndexCount, plural, one {index} other {indices} } stats',
values: { selectedIndexCount },
defaultMessage: 'Show index stats',
}),
onClick: () => {
this.closePopoverAndExecute(showStats);
history.push(getIndexDetailsLink(indexNames[0], IndexDetailsSection.Stats));
},
});
}
items.push({
'data-test-subj': 'editIndexMenuButton',
name: i18n.translate('xpack.idxMgmt.indexActionsMenu.editIndexSettingsLabel', {
defaultMessage:
'Edit {selectedIndexCount, plural, one {index} other {indices} } settings',
values: { selectedIndexCount },
}),
onClick: () => {
this.closePopoverAndExecute(editIndex);
},
});
}
if (allOpen && enableIndexActions) {
items.push({
@ -451,68 +445,57 @@ export class IndexActionsContextMenu extends Component {
};
render() {
const { indexNames } = this.props;
const selectedIndexCount = indexNames.length;
const {
iconSide = 'right',
anchorPosition = 'rightUp',
label = i18n.translate('xpack.idxMgmt.indexActionsMenu.manageButtonLabel', {
defaultMessage:
'Manage {selectedIndexCount, plural, one {index} other {{selectedIndexCount} indices}}',
values: { selectedIndexCount },
}),
iconType = 'arrowDown',
fill = true,
isLoading = false,
} = this.props;
const panels = this.panels();
const button = (
<EuiButton
data-test-subj="indexActionsContextMenuButton"
iconSide={iconSide}
aria-label={i18n.translate('xpack.idxMgmt.indexActionsMenu.manageButtonAriaLabel', {
defaultMessage: '{selectedIndexCount, plural, one {index} other {indices} } options',
values: { selectedIndexCount },
})}
onClick={this.onButtonClick}
iconType={iconType}
fill={fill}
isLoading={isLoading}
>
{label}
</EuiButton>
);
return (
<AppContextConsumer>
{(appDependencies) => {
const { indexNames } = this.props;
const selectedIndexCount = indexNames.length;
const {
iconSide = 'right',
anchorPosition = 'rightUp',
label = i18n.translate('xpack.idxMgmt.indexActionsMenu.manageButtonLabel', {
defaultMessage:
'Manage {selectedIndexCount, plural, one {index} other {{selectedIndexCount} indices}}',
values: { selectedIndexCount },
}),
iconType = 'arrowDown',
fill = true,
isLoading = false,
} = this.props;
const panels = this.panels(appDependencies);
const button = (
<EuiButton
data-test-subj="indexActionsContextMenuButton"
iconSide={iconSide}
aria-label={i18n.translate('xpack.idxMgmt.indexActionsMenu.manageButtonAriaLabel', {
defaultMessage:
'{selectedIndexCount, plural, one {index} other {indices} } options',
values: { selectedIndexCount },
})}
onClick={this.onButtonClick}
iconType={iconType}
fill={fill}
isLoading={isLoading}
>
{label}
</EuiButton>
);
return (
<div>
{this.state.renderConfirmModal
? this.state.renderConfirmModal(this.closeConfirmModal)
: null}
<EuiPopover
id="contextMenuIndices"
button={button}
isOpen={this.state.isPopoverOpen}
closePopover={this.closePopover}
panelPaddingSize="none"
anchorPosition={anchorPosition}
repositionOnScroll
>
<EuiContextMenu
data-test-subj="indexContextMenu"
initialPanelId={0}
panels={panels}
/>
</EuiPopover>
</div>
);
}}
</AppContextConsumer>
<div>
{this.state.renderConfirmModal
? this.state.renderConfirmModal(this.closeConfirmModal)
: null}
<EuiPopover
id="contextMenuIndices"
button={button}
isOpen={this.state.isPopoverOpen}
closePopover={this.closePopover}
panelPaddingSize="none"
anchorPosition={anchorPosition}
repositionOnScroll
>
<EuiContextMenu data-test-subj="indexContextMenu" initialPanelId={0} panels={panels} />
</EuiPopover>
</div>
);
}
}

View file

@ -5,21 +5,18 @@
* 2.0.
*/
import React, { useCallback, useEffect } from 'react';
import React, { useEffect } from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { ScopedHistory } from '@kbn/core/public';
import { getIndexDetailsLink } from '../../../services/routing';
import { APP_WRAPPER_CLASS, useExecutionContext } from '../../../../shared_imports';
import { breadcrumbService, IndexManagementBreadcrumb } from '../../../services/breadcrumbs';
import { useAppContext } from '../../../app_context';
import { DetailPanel } from './detail_panel';
import { IndexTable } from './index_table';
export const IndexList: React.FunctionComponent<RouteComponentProps> = ({ history }) => {
const {
core: { executionContext },
config: { enableIndexDetailsPage },
} = useAppContext();
useExecutionContext(executionContext, {
@ -31,19 +28,9 @@ export const IndexList: React.FunctionComponent<RouteComponentProps> = ({ histor
breadcrumbService.setBreadcrumbs(IndexManagementBreadcrumb.indices);
}, []);
const openDetailPanel = useCallback(
(indexName: string) => {
return history.push(getIndexDetailsLink(indexName));
},
[history]
);
return (
<div className={`${APP_WRAPPER_CLASS} im-snapshotTestSubject`} data-test-subj="indicesList">
<IndexTable
history={history as ScopedHistory}
openDetailPanel={enableIndexDetailsPage ? openDetailPanel : undefined}
/>
{!enableIndexDetailsPage && <DetailPanel />}
<IndexTable history={history as ScopedHistory} />
</div>
);
};

View file

@ -9,7 +9,6 @@ import { ScopedHistory } from '@kbn/core/public';
interface IndexTableProps {
history: ScopedHistory;
openDetailPanel?: (indexName: string) => void;
}
export declare const IndexTable: React.FunctionComponent<IndexTableProps>;

View file

@ -8,11 +8,9 @@
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import {
getDetailPanelIndexName,
getPageOfIndices,
getPager,
getFilter,
isDetailPanelOpen,
getSortField,
isSortAscending,
getIndicesAsArray,
@ -22,8 +20,6 @@ import {
} from '../../../../store/selectors';
import {
filterChanged,
closeDetailPanel,
openDetailPanel,
pageChanged,
pageSizeChanged,
sortChanged,
@ -37,8 +33,6 @@ import { IndexTable as PresentationComponent } from './index_table';
const mapStateToProps = (state, props) => {
return {
allIndices: getIndicesAsArray(state),
isDetailPanelOpen: isDetailPanelOpen(state),
detailPanelIndexName: getDetailPanelIndexName(state),
indices: getPageOfIndices(state, props),
pager: getPager(state, props),
filter: getFilter(state),
@ -67,12 +61,6 @@ const mapDispatchToProps = (dispatch) => {
toggleChanged: (toggleName, toggleValue) => {
dispatch(toggleChanged({ toggleName, toggleValue }));
},
openDetailPanel: (indexName) => {
dispatch(openDetailPanel({ indexName }));
},
closeDetailPanel: () => {
dispatch(closeDetailPanel());
},
loadIndices: () => {
dispatch(loadIndices());
},
@ -82,15 +70,6 @@ const mapDispatchToProps = (dispatch) => {
};
};
const mergeProps = (stateProps, dispatchProps, ownProps) => {
return {
...ownProps,
...stateProps,
...dispatchProps,
openDetailPanel: ownProps.openDetailPanel ?? dispatchProps.openDetailPanel,
};
};
export const IndexTable = withRouter(
connect(mapStateToProps, mapDispatchToProps, mergeProps)(PresentationComponent)
connect(mapStateToProps, mapDispatchToProps)(PresentationComponent)
);

View file

@ -7,7 +7,6 @@
import React, { Component, Fragment } from 'react';
import { i18n } from '@kbn/i18n';
import { METRIC_TYPE } from '@kbn/analytics';
import { FormattedMessage } from '@kbn/i18n-react';
import { Route } from '@kbn/shared-ux-router';
import qs from 'query-string';
@ -36,7 +35,6 @@ import {
EuiText,
} from '@elastic/eui';
import { UIM_SHOW_DETAILS_CLICK } from '../../../../../../common/constants';
import {
PageLoading,
PageError,
@ -44,7 +42,7 @@ import {
attemptToURIDecode,
} from '../../../../../shared_imports';
import { REFRESH_RATE_INDEX_LIST } from '../../../../constants';
import { getDataStreamDetailsLink } from '../../../../services/routing';
import { getDataStreamDetailsLink, getIndexDetailsLink } from '../../../../services/routing';
import { documentationService } from '../../../../services/documentation';
import { AppContextConsumer } from '../../../../app_context';
import { renderBadges } from '../../../../lib/render_badges';
@ -283,7 +281,7 @@ export class IndexTable extends Component {
}
buildRowCell(fieldName, value, index, appServices) {
const { openDetailPanel, filterChanged, history } = this.props;
const { filterChanged, history } = this.props;
if (fieldName === 'health') {
return <DataHealth health={value} />;
@ -292,10 +290,7 @@ export class IndexTable extends Component {
<Fragment>
<EuiLink
data-test-subj="indexTableIndexNameLink"
onClick={() => {
appServices.uiMetricService.trackMetric(METRIC_TYPE.CLICK, UIM_SHOW_DETAILS_CLICK);
openDetailPanel(value);
}}
onClick={() => history.push(getIndexDetailsLink(value))}
>
{value}
</EuiLink>
@ -382,13 +377,13 @@ export class IndexTable extends Component {
}
buildRows(appServices, config) {
const { indices = [], detailPanelIndexName } = this.props;
const { indices = [] } = this.props;
return indices.map((index) => {
const { name } = index;
return (
<EuiTableRow
data-test-subj="indexTableRow"
isSelected={this.isItemSelected(name) || name === detailPanelIndexName}
isSelected={this.isItemSelected(name)}
isSelectable
key={`${name}-row`}
>

View file

@ -63,6 +63,7 @@ class DocumentationService {
private indicesComponentTemplate: string = '';
private bulkIndexAlias: string = '';
private indexStats: string = '';
private bulkApi: string = '';
public setup(docLinks: DocLinksStart): void {
const { links } = docLinks;
@ -119,6 +120,7 @@ class DocumentationService {
this.indicesComponentTemplate = links.apis.putComponentTemplate;
this.bulkIndexAlias = links.apis.bulkIndexAlias;
this.indexStats = links.apis.indexStats;
this.bulkApi = links.enterpriseSearch.bulkApi;
}
public getEsDocsBase() {
@ -335,6 +337,10 @@ class DocumentationService {
return this.indexStats;
}
public getBulkApi() {
return this.bulkApi;
}
public getWellKnownTextLink() {
return 'http://docs.opengeospatial.org/is/12-063r5/12-063r5.html';
}

View file

@ -1,11 +0,0 @@
/*
* 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 { createAction } from 'redux-actions';
export const openDetailPanel = createAction('INDEX_MANAGEMENT_OPEN_DETAIL_PANEL');
export const closeDetailPanel = createAction('INDEX_MANAGEMENT_CLOSE_DETAIL_PANEL');

View file

@ -1,38 +0,0 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { loadIndexSettings as request } from '../../services';
import { notificationService } from '../../services/notification';
import { loadIndexDataSuccess } from './load_index_data';
export const editIndexSettings =
({ indexName }) =>
async (dispatch) => {
let indexSettings;
try {
indexSettings = await request(indexName);
} catch (error) {
return notificationService.showDangerToast(error.message);
}
notificationService.showSuccessToast(
i18n.translate(
'xpack.idxMgmt.editIndexSettingsAction.successfullySavedSettingsForIndicesMessage',
{
defaultMessage: 'Successfully saved settings for {indexName}',
values: { indexName },
}
)
);
dispatch(
loadIndexDataSuccess({
data: indexSettings,
panelType: 'editIndexSettings',
indexName,
})
);
};

View file

@ -12,13 +12,9 @@ export * from './delete_indices';
export * from './flush_indices';
export * from './forcemerge_indices';
export * from './load_indices';
export * from './load_index_data';
export * from './open_indices';
export * from './refresh_indices';
export * from './unfreeze_indices';
export * from './reload_indices';
export * from './table_state';
export * from './edit_index_settings';
export * from './update_index_settings';
export * from './detail_panel';
export * from './extension_action';

View file

@ -1,24 +0,0 @@
/*
* 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 { createAction } from 'redux-actions';
import { loadIndexData as request } from '../../services';
import { notificationService } from '../../services/notification';
export const loadIndexDataSuccess = createAction('INDEX_MANAGEMENT_LOAD_INDEX_DATA_SUCCESS');
export const loadIndexData =
({ indexName, dataType }) =>
async (dispatch) => {
let data;
try {
data = await request(dataType, indexName);
} catch (error) {
notificationService.showDangerToast(error.message);
}
dispatch(loadIndexDataSuccess({ data, indexName }));
};

View file

@ -1,39 +0,0 @@
/*
* 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 { createAction } from 'redux-actions';
import { i18n } from '@kbn/i18n';
import { updateIndexSettings as request } from '../../services';
import { reloadIndices } from './reload_indices';
import { notificationService } from '../../services/notification';
export const updateIndexSettingsSuccess = createAction(
'INDEX_MANAGEMENT_UPDATE_INDEX_SETTINGS_SUCCESS'
);
export const updateIndexSettingsError = createAction(
'INDEX_MANAGEMENT_UPDATE_INDEX_SETTINGS_ERROR'
);
export const updateIndexSettings =
({ indexName, settings }) =>
async (dispatch) => {
if (Object.keys(settings).length !== 0) {
const { error } = await request(indexName, settings);
if (error) {
return dispatch(updateIndexSettingsError({ error: error.message }));
}
}
dispatch(updateIndexSettingsSuccess());
dispatch(reloadIndices([indexName]));
notificationService.showSuccessToast(
i18n.translate('xpack.idxMgmt.updateIndexSettingsAction.settingsSuccessUpdateMessage', {
defaultMessage: 'Successfully updated settings for index {indexName}',
values: { indexName },
})
);
};

View file

@ -1,91 +0,0 @@
/*
* 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 { handleActions } from 'redux-actions';
import {
UIM_DETAIL_PANEL_SUMMARY_TAB,
UIM_DETAIL_PANEL_SETTINGS_TAB,
UIM_DETAIL_PANEL_MAPPING_TAB,
UIM_DETAIL_PANEL_STATS_TAB,
UIM_DETAIL_PANEL_EDIT_SETTINGS_TAB,
} from '../../../../common/constants';
import {
TAB_SUMMARY,
TAB_SETTINGS,
TAB_MAPPING,
TAB_STATS,
TAB_EDIT_SETTINGS,
} from '../../constants';
import { openDetailPanel, closeDetailPanel } from '../actions/detail_panel';
import { loadIndexDataSuccess } from '../actions/load_index_data';
import {
updateIndexSettingsSuccess,
updateIndexSettingsError,
} from '../actions/update_index_settings';
import { deleteIndicesSuccess } from '../actions/delete_indices';
import { METRIC_TYPE } from '@kbn/analytics';
const defaultState = {};
export const getDetailPanelReducer = (uiMetricService) =>
handleActions(
{
[deleteIndicesSuccess](state, action) {
const { indexNames } = action.payload;
const { indexName } = state;
if (indexNames.includes(indexName)) {
return {};
} else {
return state;
}
},
[openDetailPanel](state, action) {
const { panelType, indexName, title } = action.payload;
const panelTypeToUiMetricMap = {
[TAB_SUMMARY]: UIM_DETAIL_PANEL_SUMMARY_TAB,
[TAB_SETTINGS]: UIM_DETAIL_PANEL_SETTINGS_TAB,
[TAB_MAPPING]: UIM_DETAIL_PANEL_MAPPING_TAB,
[TAB_STATS]: UIM_DETAIL_PANEL_STATS_TAB,
[TAB_EDIT_SETTINGS]: UIM_DETAIL_PANEL_EDIT_SETTINGS_TAB,
};
if (panelTypeToUiMetricMap[panelType]) {
uiMetricService.trackMetric(METRIC_TYPE.COUNT, panelTypeToUiMetricMap[panelType]);
}
return {
panelType: panelType || state.panelType || TAB_SUMMARY,
indexName,
title,
};
},
[closeDetailPanel]() {
return {};
},
[loadIndexDataSuccess](state, action) {
const { data } = action.payload;
const newState = {
...state,
data,
};
return newState;
},
[updateIndexSettingsError](state, action) {
const { error } = action.payload;
const newState = {
...state,
error,
};
return newState;
},
[updateIndexSettingsSuccess]() {
return {};
},
},
defaultState
);

View file

@ -6,15 +6,13 @@
*/
import { combineReducers } from 'redux';
import { getDetailPanelReducer } from './detail_panel';
import { indices } from './indices';
import { rowStatus } from './row_status';
import { tableState } from './table_state';
export const getReducer = ({ uiMetricService }) =>
export const getReducer = () =>
combineReducers({
indices,
rowStatus,
tableState,
detailPanel: getDetailPanelReducer(uiMetricService),
});

View file

@ -16,11 +16,6 @@ import { extensionsService } from './extension_service';
export { extensionsService };
export const getDetailPanelData = (state) => state.detailPanel.data;
export const getDetailPanelError = (state) => state.detailPanel.error;
export const getDetailPanelType = (state) => state.detailPanel.panelType;
export const isDetailPanelOpen = (state) => !!getDetailPanelType(state);
export const getDetailPanelIndexName = (state) => state.detailPanel.indexName;
export const getIndices = (state) => state.indices.byId;
export const indicesLoading = (state) => state.indices.loading;
export const indicesError = (state) => state.indices.error;

View file

@ -20,5 +20,5 @@ export function indexManagementStore(services) {
const enhancers = [applyMiddleware(thunk)];
window.__REDUX_DEVTOOLS_EXTENSION__ && enhancers.push(window.__REDUX_DEVTOOLS_EXTENSION__());
return createStore(getReducer(services), initialState, compose(...enhancers));
return createStore(getReducer(), initialState, compose(...enhancers));
}

View file

@ -20,7 +20,3 @@
word-break: break-all;
}
}
.indDetail__codeBlock {
background: transparent;
}

View file

@ -41,7 +41,6 @@ export class IndexMgmtUIPlugin {
enableIndexActions,
enableLegacyTemplates,
enableIndexStats,
dev: { enableIndexDetailsPage },
} = this.ctx.config.get<ClientConfigType>();
if (isIndexManagementUiEnabled) {
@ -62,7 +61,6 @@ export class IndexMgmtUIPlugin {
kibanaVersion,
enableIndexActions,
enableLegacyTemplates,
enableIndexDetailsPage,
enableIndexStats,
cloud,
});

View file

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

View file

@ -32,7 +32,10 @@ const schemaLatest = schema.object(
// We take this approach in order to have a central place (serverless.yml) for serverless config across Kibana
serverless: schema.boolean({ defaultValue: true }),
}),
dev: schema.object({ enableIndexDetailsPage: schema.boolean({ defaultValue: false }) }),
dev: schema.object({
// deprecated as unused after index details page has been implemented
enableIndexDetailsPage: schema.boolean({ defaultValue: false }),
}),
enableIndexStats: offeringBasedSchema({
// Index stats information is disabled in serverless; refer to the serverless.yml file as the source of truth
// We take this approach in order to have a central place (serverless.yml) for serverless config across Kibana
@ -47,13 +50,10 @@ const configLatest: PluginConfigDescriptor<IndexManagementConfig> = {
ui: true,
enableIndexActions: true,
enableLegacyTemplates: true,
dev: {
enableIndexDetailsPage: true,
},
enableIndexStats: true,
},
schema: schemaLatest,
deprecations: () => [],
deprecations: ({ unused }) => [unused('dev.enableIndexDetailsPage', { level: 'warning' })],
};
export type IndexManagementConfig = TypeOf<typeof schemaLatest>;

View file

@ -17104,7 +17104,6 @@
"xpack.idxMgmt.deleteTemplatesModal.modalTitleText": "Supprimer {numTemplatesToDelete, plural, one {modèle} many {# modèles} other {# modèles}}",
"xpack.idxMgmt.deleteTemplatesModal.multipleErrorsNotificationMessageText": "Erreur lors de la suppression de {count} modèles",
"xpack.idxMgmt.deleteTemplatesModal.successDeleteMultipleNotificationMessageText": "{numSuccesses, plural, one {# modèle} many {# modèles} other {# modèles}} supprimé",
"xpack.idxMgmt.editIndexSettingsAction.successfullySavedSettingsForIndicesMessage": "Les paramètres ont bien été enregistrés pour {indexName}",
"xpack.idxMgmt.flushIndicesAction.successfullyFlushedIndicesMessage": "Vidage effectué avec succès : [{indexNames}]",
"xpack.idxMgmt.forceMergeIndicesAction.successfullyForceMergedIndicesMessage": "Fusion forcée effectué avec succès : [{indexNames}]",
"xpack.idxMgmt.formWizard.stepAliases.aliasesEditorHelpText": "Utiliser le format JSON : {code}",
@ -17124,7 +17123,6 @@
"xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.modalTitle": "Supprimer {selectedIndexCount, plural, one {index} many {# index} other {# index}}",
"xpack.idxMgmt.indexActionsMenu.deleteIndex.deleteDescription": "Vous êtes sur le point de supprimer {selectedIndexCount, plural, one {cet index} many {ces index} other {ces index}} :",
"xpack.idxMgmt.indexActionsMenu.deleteIndexLabel": "Supprimer {selectedIndexCount, plural, one {index} many {index système non migrés} other {les index}}",
"xpack.idxMgmt.indexActionsMenu.editIndexSettingsLabel": "Modifier les paramètres {selectedIndexCount, plural, one {index} many {index système non migrés} other {des index}}",
"xpack.idxMgmt.indexActionsMenu.flushIndexLabel": "Vider {selectedIndexCount, plural, one {index} many {index système non migrés} other {les index}}",
"xpack.idxMgmt.indexActionsMenu.forceMerge.forceMergeDescription": "Vous êtes sur le point de fusionner {selectedIndexCount, plural, one {cet index} many {ces index} other {ces index}} :",
"xpack.idxMgmt.indexActionsMenu.forceMergeIndexLabel": "Forcer la fusion {selectedIndexCount, plural, one {index} many {index système non migrés} other {des index}}",
@ -17133,9 +17131,6 @@
"xpack.idxMgmt.indexActionsMenu.openIndexLabel": "Ouvrir {selectedIndexCount, plural, one {index} many {index système non migrés} other {des index}}",
"xpack.idxMgmt.indexActionsMenu.panelTitle": "Options {selectedIndexCount, plural, one {Index} many {Index} other {Index}}",
"xpack.idxMgmt.indexActionsMenu.refreshIndexLabel": "Actualiser {selectedIndexCount, plural, one {index} many {index système non migrés} other {les index}}",
"xpack.idxMgmt.indexActionsMenu.showIndexMappingLabel": "Afficher le mapping {selectedIndexCount, plural, one {index} many {index système non migrés} other {d'index}}",
"xpack.idxMgmt.indexActionsMenu.showIndexSettingsLabel": "Modifier les paramètres {selectedIndexCount, plural, one {index} many {index système non migrés} other {des index}}",
"xpack.idxMgmt.indexActionsMenu.showIndexStatsLabel": "Afficher les statistiques {selectedIndexCount, plural, one {index} many {index système non migrés} other {des index}}",
"xpack.idxMgmt.indexActionsMenu.unfreezeIndexLabel": "Dégeler {selectedIndexCount, plural, one {index} many {index système non migrés} other {les index}}",
"xpack.idxMgmt.indexTable.captionText": "Vous trouverez ci-après le tableau des index contenant {count, plural, one {# ligne} many {# lignes} other {# lignes}} sur {total}.",
"xpack.idxMgmt.indexTable.invalidSearchErrorMessage": "Recherche non valide : {errorMessage}",
@ -17208,7 +17203,6 @@
"xpack.idxMgmt.templateList.table.deleteTemplatesButtonLabel": "Supprimer {count, plural, one {modèle} many {modèles} other {modèles}}",
"xpack.idxMgmt.templateValidation.templateNameInvalidaCharacterError": "Un nom de modèle ne doit pas contenir le caractère \"{invalidChar}\"",
"xpack.idxMgmt.unfreezeIndicesAction.successfullyUnfrozeIndicesMessage": "Déblocage effectué : [{indexNames}]",
"xpack.idxMgmt.updateIndexSettingsAction.settingsSuccessUpdateMessage": "Les paramètres de l'index {indexName} ont bien été mis à jour",
"xpack.idxMgmt.aliasesTab.noAliasesTitle": "Aucun alias défini.",
"xpack.idxMgmt.appTitle": "Gestion des index",
"xpack.idxMgmt.breadcrumb.cloneTemplateLabel": "Cloner le modèle",
@ -17389,18 +17383,6 @@
"xpack.idxMgmt.deprecations.enabled.manualStepTwoMessage": "Remplacez le paramètre \"xpack.index_management.enabled\" par \"xpack.index_management.ui.enabled\".",
"xpack.idxMgmt.deprecations.enabledMessage": "Pour empêcher les utilisateurs d'accéder à linterface utilisateur de gestion des index, utilisez le paramètre \"xpack.index_management.ui.enabled\" au lieu de \"xpack.index_management.enabled\".",
"xpack.idxMgmt.deprecations.enabledTitle": "Le paramètre \"xpack.index_management.enabled\" est déclassé.",
"xpack.idxMgmt.detailPanel.manageContextMenuLabel": "Gérer",
"xpack.idxMgmt.detailPanel.missingIndexMessage": "Cet index n'existe pas. Il a peut-être été supprimé par une tâche en cours d'exécution ou par un autre système.",
"xpack.idxMgmt.detailPanel.missingIndexTitle": "Index manquant",
"xpack.idxMgmt.detailPanel.tabEditSettingsLabel": "Modifier les paramètres",
"xpack.idxMgmt.detailPanel.tabMappingLabel": "Mappings",
"xpack.idxMgmt.detailPanel.tabSettingsLabel": "Paramètres",
"xpack.idxMgmt.detailPanel.tabStatsLabel": "Statistiques",
"xpack.idxMgmt.detailPanel.tabSummaryLabel": "Résumé",
"xpack.idxMgmt.editSettingsJSON.saveJSONButtonLabel": "Enregistrer",
"xpack.idxMgmt.editSettingsJSON.saveJSONCalloutErrorTitle": "Une erreur est survenue lors de lenregistrement de vos paramètres.",
"xpack.idxMgmt.editSettingsJSON.saveJSONDescription": "Modifiez, puis enregistrez votre JSON",
"xpack.idxMgmt.editSettingsJSON.settingsReferenceLinkText": "Référence des paramètres",
"xpack.idxMgmt.editTemplate.editTemplatePageTitle": "Modifier le modèle \"{name}\"",
"xpack.idxMgmt.formWizard.stepAliases.aliasesDescription": "Configurez les alias à associer à vos index.",
"xpack.idxMgmt.formWizard.stepAliases.docsButtonLabel": "Documentation sur les alias d'index",
@ -17975,16 +17957,6 @@
"xpack.idxMgmt.simulateTemplate.noFilterSelected": "Sélectionnez au moins une option pour afficher l'aperçu.",
"xpack.idxMgmt.simulateTemplate.title": "Prévisualiser le modèle d'index",
"xpack.idxMgmt.simulateTemplate.updateButtonLabel": "Mettre à jour",
"xpack.idxMgmt.summary.headers.aliases": "Alias",
"xpack.idxMgmt.summary.headers.deletedDocumentsHeader": "Documents supprimés",
"xpack.idxMgmt.summary.headers.documentsHeader": "Nombre de documents",
"xpack.idxMgmt.summary.headers.healthHeader": "Intégrité",
"xpack.idxMgmt.summary.headers.primaryHeader": "Partitions principales",
"xpack.idxMgmt.summary.headers.primaryStorageSizeHeader": "Taille du stockage principal",
"xpack.idxMgmt.summary.headers.replicaHeader": "Répliques",
"xpack.idxMgmt.summary.headers.statusHeader": "Statut",
"xpack.idxMgmt.summary.headers.storageSizeHeader": "Taille du stockage",
"xpack.idxMgmt.summary.summaryTitle": "Général",
"xpack.idxMgmt.templateBadgeType.cloudManaged": "Géré dans le cloud",
"xpack.idxMgmt.templateBadgeType.managed": "Géré",
"xpack.idxMgmt.templateBadgeType.system": "Système",

View file

@ -17118,7 +17118,6 @@
"xpack.idxMgmt.deleteTemplatesModal.modalTitleText": "{numTemplatesToDelete, plural, other {#個のテンプレート}}削除",
"xpack.idxMgmt.deleteTemplatesModal.multipleErrorsNotificationMessageText": "{count}個のテンプレートの削除中にエラーが発生",
"xpack.idxMgmt.deleteTemplatesModal.successDeleteMultipleNotificationMessageText": "{numSuccesses, plural, other {#個のテンプレート}}が削除されました",
"xpack.idxMgmt.editIndexSettingsAction.successfullySavedSettingsForIndicesMessage": "{indexName}の設定が保存されました",
"xpack.idxMgmt.flushIndicesAction.successfullyFlushedIndicesMessage": "[{indexNames}]がフラッシュされました",
"xpack.idxMgmt.forceMergeIndicesAction.successfullyForceMergedIndicesMessage": "[{indexNames}]が強制結合されました",
"xpack.idxMgmt.formWizard.stepAliases.aliasesEditorHelpText": "JSONフォーマットを使用{code}",
@ -17138,7 +17137,6 @@
"xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.modalTitle": "{selectedIndexCount, plural, other {#個のインデックス}}削除",
"xpack.idxMgmt.indexActionsMenu.deleteIndex.deleteDescription": "{selectedIndexCount, plural, other {これらのインデックス}}を削除しようとしています:",
"xpack.idxMgmt.indexActionsMenu.deleteIndexLabel": "{selectedIndexCount, plural, other {インデックス}}削除",
"xpack.idxMgmt.indexActionsMenu.editIndexSettingsLabel": "{selectedIndexCount, plural, other {インデックス}}設定を編集",
"xpack.idxMgmt.indexActionsMenu.flushIndexLabel": "{selectedIndexCount, plural, other {インデックス}}をフラッシュ",
"xpack.idxMgmt.indexActionsMenu.forceMerge.forceMergeDescription": "{selectedIndexCount, plural, other {これらのインデックス}}を強制結合しようとしています:",
"xpack.idxMgmt.indexActionsMenu.forceMergeIndexLabel": "{selectedIndexCount, plural, other {インデックス}}を強制結合",
@ -17147,9 +17145,6 @@
"xpack.idxMgmt.indexActionsMenu.openIndexLabel": "{selectedIndexCount, plural, other {インデックス}}を開く",
"xpack.idxMgmt.indexActionsMenu.panelTitle": "{selectedIndexCount, plural, other {インデックス}}オプション",
"xpack.idxMgmt.indexActionsMenu.refreshIndexLabel": "{selectedIndexCount, plural, other {インデックス}}を更新",
"xpack.idxMgmt.indexActionsMenu.showIndexMappingLabel": "{selectedIndexCount, plural, other {インデックス}}マッピングを表示",
"xpack.idxMgmt.indexActionsMenu.showIndexSettingsLabel": "{selectedIndexCount, plural, other {インデックス}}設定を表示",
"xpack.idxMgmt.indexActionsMenu.showIndexStatsLabel": "{selectedIndexCount, plural, other {インデックス}}統計を表示",
"xpack.idxMgmt.indexActionsMenu.unfreezeIndexLabel": "{selectedIndexCount, plural, other {インデックス}}をフリーズ解除",
"xpack.idxMgmt.indexTable.captionText": "以下は、{total}中{count, plural, other {#行}}を含むインデックステーブルです。",
"xpack.idxMgmt.indexTable.invalidSearchErrorMessage": "無効な検索:{errorMessage}",
@ -17222,7 +17217,6 @@
"xpack.idxMgmt.templateList.table.deleteTemplatesButtonLabel": "{count, plural, other {テンプレート}}削除",
"xpack.idxMgmt.templateValidation.templateNameInvalidaCharacterError": "テンプレート名に「{invalidChar}」は使用できません",
"xpack.idxMgmt.unfreezeIndicesAction.successfullyUnfrozeIndicesMessage": "[{indexNames}] の凍結が解除されました",
"xpack.idxMgmt.updateIndexSettingsAction.settingsSuccessUpdateMessage": "インデックス {indexName} の設定が更新されました",
"xpack.idxMgmt.aliasesTab.noAliasesTitle": "エイリアスが定義されていません。",
"xpack.idxMgmt.appTitle": "インデックス管理",
"xpack.idxMgmt.breadcrumb.cloneTemplateLabel": "テンプレートのクローンを作成",
@ -17403,18 +17397,6 @@
"xpack.idxMgmt.deprecations.enabled.manualStepTwoMessage": "「xpack.index_management.enabled」設定を「xpack.index_management.ui.enabled」に変更します。",
"xpack.idxMgmt.deprecations.enabledMessage": "ユーザーがインデックス管理UIにアクセスすることを禁止するには、「xpack.index_management.enabled」ではなく、「xpack.index_management.ui.enabled」設定を使用します。",
"xpack.idxMgmt.deprecations.enabledTitle": "「xpack.index_management.enabled」設定は廃止予定です。",
"xpack.idxMgmt.detailPanel.manageContextMenuLabel": "管理",
"xpack.idxMgmt.detailPanel.missingIndexMessage": "このインデックスは存在しません。実行中のジョブや別のシステムにより削除された可能性があります。",
"xpack.idxMgmt.detailPanel.missingIndexTitle": "インデックスがありません",
"xpack.idxMgmt.detailPanel.tabEditSettingsLabel": "設定の変更",
"xpack.idxMgmt.detailPanel.tabMappingLabel": "マッピング",
"xpack.idxMgmt.detailPanel.tabSettingsLabel": "設定",
"xpack.idxMgmt.detailPanel.tabStatsLabel": "統計",
"xpack.idxMgmt.detailPanel.tabSummaryLabel": "まとめ",
"xpack.idxMgmt.editSettingsJSON.saveJSONButtonLabel": "保存",
"xpack.idxMgmt.editSettingsJSON.saveJSONCalloutErrorTitle": "設定の保存中にエラーが発生しました",
"xpack.idxMgmt.editSettingsJSON.saveJSONDescription": "変更して JSON を保存します",
"xpack.idxMgmt.editSettingsJSON.settingsReferenceLinkText": "設定リファレンス",
"xpack.idxMgmt.editTemplate.editTemplatePageTitle": "テンプレート「{name}」を編集",
"xpack.idxMgmt.formWizard.stepAliases.aliasesDescription": "エイリアスをセットアップして、インデックスに関連付けてください。",
"xpack.idxMgmt.formWizard.stepAliases.docsButtonLabel": "インデックスエイリアスドキュメント",
@ -17989,16 +17971,6 @@
"xpack.idxMgmt.simulateTemplate.noFilterSelected": "プレビューするオプションを1つ以上選択してください。",
"xpack.idxMgmt.simulateTemplate.title": "インデックステンプレートをプレビュー",
"xpack.idxMgmt.simulateTemplate.updateButtonLabel": "更新",
"xpack.idxMgmt.summary.headers.aliases": "エイリアス",
"xpack.idxMgmt.summary.headers.deletedDocumentsHeader": "ドキュメントが削除されました",
"xpack.idxMgmt.summary.headers.documentsHeader": "ドキュメント数",
"xpack.idxMgmt.summary.headers.healthHeader": "ヘルス",
"xpack.idxMgmt.summary.headers.primaryHeader": "プライマリ",
"xpack.idxMgmt.summary.headers.primaryStorageSizeHeader": "プライマリストレージサイズ",
"xpack.idxMgmt.summary.headers.replicaHeader": "レプリカ",
"xpack.idxMgmt.summary.headers.statusHeader": "ステータス",
"xpack.idxMgmt.summary.headers.storageSizeHeader": "ストレージサイズ",
"xpack.idxMgmt.summary.summaryTitle": "一般",
"xpack.idxMgmt.templateBadgeType.cloudManaged": "クラウド管理",
"xpack.idxMgmt.templateBadgeType.managed": "管理中",
"xpack.idxMgmt.templateBadgeType.system": "システム",

View file

@ -17118,7 +17118,6 @@
"xpack.idxMgmt.deleteTemplatesModal.modalTitleText": "删除 {numTemplatesToDelete, plural, other {# 个模板}}",
"xpack.idxMgmt.deleteTemplatesModal.multipleErrorsNotificationMessageText": "删除 {count} 个模板时出错",
"xpack.idxMgmt.deleteTemplatesModal.successDeleteMultipleNotificationMessageText": "已删除 {numSuccesses, plural, other {# 个模板}}",
"xpack.idxMgmt.editIndexSettingsAction.successfullySavedSettingsForIndicesMessage": "已成功保存 {indexName} 的设置",
"xpack.idxMgmt.flushIndicesAction.successfullyFlushedIndicesMessage": "已成功清空:[{indexNames}]",
"xpack.idxMgmt.forceMergeIndicesAction.successfullyForceMergedIndicesMessage": "已成功强制合并:[{indexNames}]",
"xpack.idxMgmt.formWizard.stepAliases.aliasesEditorHelpText": "使用 JSON 格式:{code}",
@ -17138,7 +17137,6 @@
"xpack.idxMgmt.indexActionsMenu.deleteIndex.confirmModal.modalTitle": "删除 {selectedIndexCount, plural, other {# 个索引}}",
"xpack.idxMgmt.indexActionsMenu.deleteIndex.deleteDescription": "您即将删除{selectedIndexCount, plural, other {以下索引}}",
"xpack.idxMgmt.indexActionsMenu.deleteIndexLabel": "删除 {selectedIndexCount, plural, other {索引}}",
"xpack.idxMgmt.indexActionsMenu.editIndexSettingsLabel": "编辑{selectedIndexCount, plural, other {索引}}设置",
"xpack.idxMgmt.indexActionsMenu.flushIndexLabel": "清空{selectedIndexCount, plural, other {索引}}",
"xpack.idxMgmt.indexActionsMenu.forceMerge.forceMergeDescription": "您即将强制合并{selectedIndexCount, plural, other {以下索引}}",
"xpack.idxMgmt.indexActionsMenu.forceMergeIndexLabel": "强制合并{selectedIndexCount, plural, other {索引}}",
@ -17147,9 +17145,6 @@
"xpack.idxMgmt.indexActionsMenu.openIndexLabel": "打开 {selectedIndexCount, plural, other {索引}}",
"xpack.idxMgmt.indexActionsMenu.panelTitle": "{selectedIndexCount, plural, other {索引}}选项",
"xpack.idxMgmt.indexActionsMenu.refreshIndexLabel": "刷新{selectedIndexCount, plural, other {索引}}",
"xpack.idxMgmt.indexActionsMenu.showIndexMappingLabel": "显示{selectedIndexCount, plural, other {索引}}映射",
"xpack.idxMgmt.indexActionsMenu.showIndexSettingsLabel": "显示{selectedIndexCount, plural, other {索引}}设置",
"xpack.idxMgmt.indexActionsMenu.showIndexStatsLabel": "显示{selectedIndexCount, plural, other {索引}}统计",
"xpack.idxMgmt.indexActionsMenu.unfreezeIndexLabel": "取消冻结{selectedIndexCount, plural, other {索引}}",
"xpack.idxMgmt.indexTable.captionText": "以下索引表包含 {count, plural, other {# 行}}(总计 {total} 行)。",
"xpack.idxMgmt.indexTable.invalidSearchErrorMessage": "无效搜索:{errorMessage}",
@ -17222,7 +17217,6 @@
"xpack.idxMgmt.templateList.table.deleteTemplatesButtonLabel": "删除 {count, plural, other {模板}}",
"xpack.idxMgmt.templateValidation.templateNameInvalidaCharacterError": "模板名称不得包含字符“{invalidChar}”",
"xpack.idxMgmt.unfreezeIndicesAction.successfullyUnfrozeIndicesMessage": "成功取消冻结:[{indexNames}]",
"xpack.idxMgmt.updateIndexSettingsAction.settingsSuccessUpdateMessage": "已成功更新索引 {indexName} 的设置",
"xpack.idxMgmt.aliasesTab.noAliasesTitle": "未定义任何别名。",
"xpack.idxMgmt.appTitle": "索引管理",
"xpack.idxMgmt.breadcrumb.cloneTemplateLabel": "克隆模板",
@ -17403,18 +17397,6 @@
"xpack.idxMgmt.deprecations.enabled.manualStepTwoMessage": "将“xpack.index_management.enabled”设置更改为“xpack.index_management.ui.enabled”。",
"xpack.idxMgmt.deprecations.enabledMessage": "要禁止用户访问索引管理 UI请使用“xpack.index_management.ui.enabled”设置而不是“xpack.index_management.enabled”。",
"xpack.idxMgmt.deprecations.enabledTitle": "设置“xpack.index_management.enabled”已过时",
"xpack.idxMgmt.detailPanel.manageContextMenuLabel": "管理",
"xpack.idxMgmt.detailPanel.missingIndexMessage": "此索引不存在。它可能已被正在运行的作业或其他系统删除。",
"xpack.idxMgmt.detailPanel.missingIndexTitle": "缺少索引",
"xpack.idxMgmt.detailPanel.tabEditSettingsLabel": "编辑设置",
"xpack.idxMgmt.detailPanel.tabMappingLabel": "映射",
"xpack.idxMgmt.detailPanel.tabSettingsLabel": "设置",
"xpack.idxMgmt.detailPanel.tabStatsLabel": "统计信息",
"xpack.idxMgmt.detailPanel.tabSummaryLabel": "摘要",
"xpack.idxMgmt.editSettingsJSON.saveJSONButtonLabel": "保存",
"xpack.idxMgmt.editSettingsJSON.saveJSONCalloutErrorTitle": "尝试保存您的设置时出错",
"xpack.idxMgmt.editSettingsJSON.saveJSONDescription": "编辑并保存您的 JSON",
"xpack.idxMgmt.editSettingsJSON.settingsReferenceLinkText": "设置参考",
"xpack.idxMgmt.editTemplate.editTemplatePageTitle": "编辑模板“{name}”",
"xpack.idxMgmt.formWizard.stepAliases.aliasesDescription": "设置要与索引关联的别名。",
"xpack.idxMgmt.formWizard.stepAliases.docsButtonLabel": "索引别名文档",
@ -17989,16 +17971,6 @@
"xpack.idxMgmt.simulateTemplate.noFilterSelected": "至少选择一个选项进行预览。",
"xpack.idxMgmt.simulateTemplate.title": "预览索引模板",
"xpack.idxMgmt.simulateTemplate.updateButtonLabel": "更新",
"xpack.idxMgmt.summary.headers.aliases": "别名",
"xpack.idxMgmt.summary.headers.deletedDocumentsHeader": "文档已删除",
"xpack.idxMgmt.summary.headers.documentsHeader": "文档计数",
"xpack.idxMgmt.summary.headers.healthHeader": "运行状况",
"xpack.idxMgmt.summary.headers.primaryHeader": "主分片",
"xpack.idxMgmt.summary.headers.primaryStorageSizeHeader": "主存储大小",
"xpack.idxMgmt.summary.headers.replicaHeader": "副本分片",
"xpack.idxMgmt.summary.headers.statusHeader": "状态",
"xpack.idxMgmt.summary.headers.storageSizeHeader": "存储大小",
"xpack.idxMgmt.summary.summaryTitle": "常规",
"xpack.idxMgmt.templateBadgeType.cloudManaged": "云托管",
"xpack.idxMgmt.templateBadgeType.managed": "托管",
"xpack.idxMgmt.templateBadgeType.system": "系统",

View file

@ -48,30 +48,31 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await a11y.testAppSnapshot();
});
describe('index panel', async () => {
it('index panel - summary', async () => {
describe('index details', async () => {
it('index details - overview', async () => {
await PageObjects.settings.clickIndexManagement();
await PageObjects.indexManagement.clickIndexAt(0);
await a11y.testAppSnapshot();
});
it('index panel - settings', async () => {
await PageObjects.indexManagement.clickDetailPanelTabAt(0);
it('index details - settings', async () => {
await PageObjects.indexManagement.clickIndexDetailsTab('settings');
await a11y.testAppSnapshot();
});
it('index panel - mappings', async () => {
await PageObjects.indexManagement.clickDetailPanelTabAt(1);
it('index details - edit settings', async () => {
await PageObjects.indexManagement.clickIndexDetailsTab('settings');
await PageObjects.indexManagement.clickIndexDetailsEditSettingsSwitch();
await a11y.testAppSnapshot();
});
it('index panel - stats', async () => {
await PageObjects.indexManagement.clickDetailPanelTabAt(2);
it('index details - mappings', async () => {
await PageObjects.indexManagement.clickIndexDetailsTab('mappings');
await a11y.testAppSnapshot();
});
it('index panel - edit settings', async () => {
await PageObjects.indexManagement.clickDetailPanelTabAt(3);
it('index details - stats', async () => {
await PageObjects.indexManagement.clickIndexDetailsTab('stats');
await a11y.testAppSnapshot();
});
});

View file

@ -12,6 +12,7 @@ export default ({ loadTestFile }: FtrProviderContext) => {
loadTestFile(require.resolve('./feature_controls'));
loadTestFile(require.resolve('./home_page'));
loadTestFile(require.resolve('./index_template_wizard'));
loadTestFile(require.resolve('./index_details_page'));
loadTestFile(require.resolve('./enrich_policies_tab'));
loadTestFile(require.resolve('./create_enrich_policy'));
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { FtrProviderContext } from '../../../ftr_provider_context';
import { FtrProviderContext } from '../../ftr_provider_context';
export default ({ getPageObjects, getService }: FtrProviderContext) => {
const pageObjects = getPageObjects(['common', 'indexManagement', 'header']);

View file

@ -1,25 +0,0 @@
/*
* 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

@ -1,14 +0,0 @@
/*
* 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

@ -82,16 +82,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
body: { a: 'b' },
});
await pageObjects.common.navigateToApp('indexManagement');
await retry.waitForWithTimeout('indice table to be visible', 15000, async () => {
await retry.waitForWithTimeout('indices table to be visible', 15000, async () => {
return await testSubjects.isDisplayed('indicesList');
});
});
it('Verify that the follower index is duplicating from the remote.', async () => {
await pageObjects.indexManagement.clickIndexAt(0);
await pageObjects.indexManagement.performIndexActionInDetailPanel('flush');
await testSubjects.click('euiFlyoutCloseButton');
await pageObjects.indexManagement.performIndexAction('flush');
await testSubjects.click('indexDetailsBackToIndicesButton');
await pageObjects.common.navigateToApp('indexManagement');
await retry.waitForWithTimeout('indice table to be visible', 15000, async () => {
await retry.waitForWithTimeout('indices table to be visible', 15000, async () => {
return await testSubjects.isDisplayed('indicesList');
const indicesList = await pageObjects.indexManagement.getIndexList();
const followerIndex = indicesList.filter(

View file

@ -11,7 +11,6 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
const retry = getService('retry');
const find = getService('find');
const testSubjects = getService('testSubjects');
const log = getService('log');
return {
async sectionHeadingText() {
@ -49,28 +48,30 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
await testSubjects.click('confirmModalConfirmButton');
},
async clickDetailPanelTabAt(indexOfTab: number): Promise<void> {
const tabList = await testSubjects.findAll('detailPanelTab');
log.debug(tabList.length);
await tabList[indexOfTab].click();
async clickIndexDetailsTab(tabName: string): Promise<void> {
await testSubjects.click(`indexDetailsTab-${tabName}`);
},
async clickIndexDetailsEditSettingsSwitch(): Promise<void> {
await testSubjects.click('indexDetailsSettingsEditModeSwitch');
},
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 () => {
return (await testSubjects.isDisplayed('detailPanelTabSelected')) === true;
await retry.waitFor('details page title to show up', async () => {
return (await testSubjects.isDisplayed('indexDetailsHeader')) === true;
});
},
async performIndexActionInDetailPanel(action: string) {
await this.clickContextMenuInDetailPanel();
async performIndexAction(action: string) {
await this.clickContextMenu();
if (action === 'flush') {
await testSubjects.click('flushIndexMenuButton');
}
},
async clickContextMenuInDetailPanel() {
async clickContextMenu() {
await testSubjects.click('indexActionsContextMenuButton');
},