[Index management] Client-side NP ready (#57295) (#58090)

This commit is contained in:
Sébastien Loix 2020-02-20 15:31:46 +05:30 committed by GitHub
parent df1fc9bf69
commit faa22e9aeb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
293 changed files with 1136 additions and 901 deletions

View file

@ -29,6 +29,7 @@ export {
ManagementStart,
RegisterManagementApp,
RegisterManagementAppArgs,
ManagementAppMountParams,
} from './types';
export { ManagementApp } from './management_app';
export { ManagementSection } from './management_section';

View file

@ -64,7 +64,7 @@ export type RegisterManagementApp = (managementApp: RegisterManagementAppArgs) =
export type Unmount = () => Promise<void> | void;
interface ManagementAppMountParams {
export interface ManagementAppMountParams {
basePath: string; // base path for setting up your router
element: HTMLElement; // element the section should render into
setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void;

View file

@ -7,7 +7,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from '@kbn/i18n/react';
import { getIndexListUri } from '../../../../../../../../index_management/public/app/services/navigation';
import { getIndexListUri } from '../../../../../../../../index_management/public/application/services/navigation';
import {
EuiButtonEmpty,

View file

@ -7,7 +7,7 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from '@kbn/i18n/react';
import { getIndexListUri } from '../../../../../../../../index_management/public/app/services/navigation';
import { getIndexListUri } from '../../../../../../../../index_management/public/application/services/navigation';
import {
EuiButton,

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import { addBadgeExtension } from '../../../index_management/public/index_management_extensions';
import { extensionsService } from '../../../index_management/public';
import { get } from 'lodash';
const propertyPath = 'isFollowerIndex';
@ -19,4 +19,4 @@ export const followerBadgeExtension = {
filterExpression: 'isFollowerIndex:true',
};
addBadgeExtension(followerBadgeExtension);
extensionsService.addBadge(followerBadgeExtension);

View file

@ -7,6 +7,7 @@
import moment from 'moment-timezone';
import axios from 'axios';
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
import { mountWithIntl } from '../../../../test_utils/enzyme_helpers';
import {
retryLifecycleActionExtension,
@ -26,6 +27,10 @@ initHttp(axios.create({ adapter: axiosXhrAdapter }), path => path);
initUiMetric(() => () => {});
jest.mock('ui/new_platform');
jest.mock('../../index_management/public', async () => {
const { indexManagementMock } = await import('../../index_management/public/mocks.ts');
return indexManagementMock.createSetup();
});
const indexWithoutLifecyclePolicy = {
health: 'yellow',

View file

@ -37,7 +37,7 @@ import {
import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
import { getIndexListUri } from '../../../../../../../../index_management/public/app/services/navigation';
import { getIndexListUri } from '../../../../../../../../index_management/public/application/services/navigation';
import { BASE_PATH } from '../../../../../../../common/constants';
import { UIM_EDIT_CLICK } from '../../../../constants';
import { getPolicyPath } from '../../../../services/navigation';

View file

@ -9,13 +9,7 @@ import { get, every, any } from 'lodash';
import { i18n } from '@kbn/i18n';
import { EuiSearchBar } from '@elastic/eui';
import {
addSummaryExtension,
addBannerExtension,
addActionExtension,
addFilterExtension,
} from '../../../../index_management/public/index_management_extensions';
import { extensionsService } from '../../../../index_management/public';
import { init as initUiMetric } from '../application/services/ui_metric';
import { init as initNotification } from '../application/services/notification';
import { retryLifecycleForIndex } from '../application/services/api';
@ -27,13 +21,17 @@ const stepPath = 'ilm.step';
export const retryLifecycleActionExtension = ({
indices,
createUiStatsReporter,
usageCollection,
toasts,
fatalErrors,
}) => {
// These are hacks that we can remove once the New Platform migration is done. They're needed here
// because API requests and API errors require them.
initUiMetric(createUiStatsReporter);
const getLegacyReporter = appName => (type, name) => {
usageCollection.reportUiStats(appName, type, name);
};
initUiMetric(getLegacyReporter);
initNotification(toasts, fatalErrors);
const allHaveErrors = every(indices, index => {
@ -207,11 +205,11 @@ export const ilmFilterExtension = indices => {
};
export const addAllExtensions = () => {
addActionExtension(retryLifecycleActionExtension);
addActionExtension(removeLifecyclePolicyActionExtension);
addActionExtension(addLifecyclePolicyActionExtension);
extensionsService.addAction(retryLifecycleActionExtension);
extensionsService.addAction(removeLifecyclePolicyActionExtension);
extensionsService.addAction(addLifecyclePolicyActionExtension);
addBannerExtension(ilmBannerExtension);
addSummaryExtension(ilmSummaryExtension);
addFilterExtension(ilmFilterExtension);
extensionsService.addBanner(ilmBannerExtension);
extensionsService.addSummary(ilmSummaryExtension);
extensionsService.addFilter(ilmFilterExtension);
};

View file

@ -13,13 +13,14 @@ import {
findTestSubject,
nextTick,
} from '../../../../../../test_utils';
import { IndexManagementHome } from '../../../public/app/sections/home';
import { IndexManagementHome } from '../../../public/application/sections/home';
import { BASE_PATH } from '../../../common/constants';
import { indexManagementStore } from '../../../public/app/store';
import { indexManagementStore } from '../../../public/application/store';
import { Template } from '../../../common/types';
import { WithAppDependencies, services } from './setup_environment';
const testBedConfig: TestBedConfig = {
store: indexManagementStore,
store: () => indexManagementStore(services as any),
memoryRouter: {
initialEntries: [`${BASE_PATH}indices`],
componentRoutePath: `${BASE_PATH}:section(indices|templates)`,
@ -27,7 +28,7 @@ const testBedConfig: TestBedConfig = {
doMountAsync: true,
};
const initTestBed = registerTestBed(IndexManagementHome, testBedConfig);
const initTestBed = registerTestBed(WithAppDependencies(IndexManagementHome), testBedConfig);
export interface IdxMgmtHomeTestBed extends TestBed<IdxMgmtTestSubjects> {
findAction: (action: 'edit' | 'clone' | 'delete') => ReactWrapper;

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;
* you may not use this file except in compliance with the Elastic License.
*/
import axios from 'axios';
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
import { init as initHttpRequests } from './http_requests';
import { httpService } from '../../../public/app/services/http';
import { breadcrumbService } from '../../../public/app/services/breadcrumbs';
import { documentationService } from '../../../public/app/services/documentation';
import { notificationService } from '../../../public/app/services/notification';
import { uiMetricService } from '../../../public/app/services/ui_metric';
import { createUiStatsReporter } from '../../../../../../../src/legacy/core_plugins/ui_metric/public';
/* eslint-disable @kbn/eslint/no-restricted-paths */
import { notificationServiceMock } from '../../../../../../../src/core/public/notifications/notifications_service.mock';
import { chromeServiceMock } from '../../../../../../../src/core/public/chrome/chrome_service.mock';
import { docLinksServiceMock } from '../../../../../../../src/core/public/doc_links/doc_links_service.mock';
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
export const setupEnvironment = () => {
// Mock initialization of services
// @ts-ignore
httpService.init(mockHttpClient);
breadcrumbService.init(chromeServiceMock.createStartContract(), '');
documentationService.init(docLinksServiceMock.createStartContract());
notificationService.init(notificationServiceMock.createStartContract());
uiMetricService.init(createUiStatsReporter);
const { server, httpRequestsMockHelpers } = initHttpRequests();
return {
server,
httpRequestsMockHelpers,
};
};

View file

@ -0,0 +1,56 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import axios from 'axios';
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
import {
notificationServiceMock,
docLinksServiceMock,
} from '../../../../../../../src/core/public/mocks';
import { AppContextProvider } from '../../../public/application/app_context';
import { httpService } from '../../../public/application/services/http';
import { breadcrumbService } from '../../../public/application/services/breadcrumbs';
import { documentationService } from '../../../public/application/services/documentation';
import { notificationService } from '../../../public/application/services/notification';
import { ExtensionsService } from '../../../public/services';
import { UiMetricService } from '../../../public/application/services/ui_metric';
import { setUiMetricService } from '../../../public/application/services/api';
import { setExtensionsService } from '../../../public/application/store/selectors';
import { init as initHttpRequests } from './http_requests';
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
export const services = {
extensionsService: new ExtensionsService(),
uiMetricService: new UiMetricService('index_management'),
};
services.uiMetricService.setup({ reportUiStats() {} } as any);
setExtensionsService(services.extensionsService);
setUiMetricService(services.uiMetricService);
const appDependencies = { services, core: {}, plugins: {} } as any;
export const setupEnvironment = () => {
// Mock initialization of services
// @ts-ignore
httpService.setup(mockHttpClient);
breadcrumbService.setup(() => undefined);
documentationService.setup(docLinksServiceMock.createStartContract());
notificationService.setup(notificationServiceMock.createSetupContract());
const { server, httpRequestsMockHelpers } = initHttpRequests();
return {
server,
httpRequestsMockHelpers,
};
};
export const WithAppDependencies = (Comp: any) => (props: any) => (
<AppContextProvider value={appDependencies}>
<Comp {...props} />
</AppContextProvider>
);

View file

@ -6,9 +6,10 @@
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
import { BASE_PATH } from '../../../common/constants';
import { TemplateClone } from '../../../public/app/sections/template_clone';
import { TemplateClone } from '../../../public/application/sections/template_clone';
import { formSetup } from './template_form.helpers';
import { TEMPLATE_NAME } from './constants';
import { WithAppDependencies } from './setup_environment';
const testBedConfig: TestBedConfig = {
memoryRouter: {
@ -18,6 +19,6 @@ const testBedConfig: TestBedConfig = {
doMountAsync: true,
};
const initTestBed = registerTestBed(TemplateClone, testBedConfig);
const initTestBed = registerTestBed(WithAppDependencies(TemplateClone), testBedConfig);
export const setup = formSetup.bind(null, initTestBed);

View file

@ -6,8 +6,9 @@
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
import { BASE_PATH } from '../../../common/constants';
import { TemplateCreate } from '../../../public/app/sections/template_create';
import { TemplateCreate } from '../../../public/application/sections/template_create';
import { formSetup, TestSubjects } from './template_form.helpers';
import { WithAppDependencies } from './setup_environment';
const testBedConfig: TestBedConfig = {
memoryRouter: {
@ -17,6 +18,9 @@ const testBedConfig: TestBedConfig = {
doMountAsync: true,
};
const initTestBed = registerTestBed<TestSubjects>(TemplateCreate, testBedConfig);
const initTestBed = registerTestBed<TestSubjects>(
WithAppDependencies(TemplateCreate),
testBedConfig
);
export const setup = formSetup.bind(null, initTestBed);

View file

@ -6,9 +6,10 @@
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
import { BASE_PATH } from '../../../common/constants';
import { TemplateEdit } from '../../../public/app/sections/template_edit';
import { TemplateEdit } from '../../../public/application/sections/template_edit';
import { formSetup, TestSubjects } from './template_form.helpers';
import { TEMPLATE_NAME } from './constants';
import { WithAppDependencies } from './setup_environment';
const testBedConfig: TestBedConfig = {
memoryRouter: {
@ -18,6 +19,6 @@ const testBedConfig: TestBedConfig = {
doMountAsync: true,
};
const initTestBed = registerTestBed<TestSubjects>(TemplateEdit, testBedConfig);
const initTestBed = registerTestBed<TestSubjects>(WithAppDependencies(TemplateEdit), testBedConfig);
export const setup = formSetup.bind(null, initTestBed);

View file

@ -8,23 +8,25 @@ import React from 'react';
import axios from 'axios';
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
import { MemoryRouter } from 'react-router-dom';
import { AppWithoutRouter } from '../../public/app/app';
import { AppWithoutRouter } from '../../public/application/app';
import { AppContextProvider } from '../../public/application/app_context';
import { Provider } from 'react-redux';
import { loadIndicesSuccess } from '../../public/app/store/actions';
import { breadcrumbService } from '../../public/app/services/breadcrumbs';
import { uiMetricService } from '../../public/app/services/ui_metric';
import { notificationService } from '../../public/app/services/notification';
import { httpService } from '../../public/app/services/http';
import { createUiStatsReporter } from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { indexManagementStore } from '../../public/app/store';
import { loadIndicesSuccess } from '../../public/application/store/actions';
import { breadcrumbService } from '../../public/application/services/breadcrumbs';
import { UiMetricService } from '../../public/application/services/ui_metric';
import { notificationService } from '../../public/application/services/notification';
import { httpService } from '../../public/application/services/http';
import { setUiMetricService } from '../../public/application/services/api';
import { indexManagementStore } from '../../public/application/store';
import { setExtensionsService } from '../../public/application/store/selectors';
import { BASE_PATH, API_BASE_PATH } from '../../common/constants';
import { mountWithIntl } from '../../../../../test_utils/enzyme_helpers';
import { ExtensionsService } from '../../public/services';
import sinon from 'sinon';
import { findTestSubject } from '@elastic/eui/lib/test';
/* eslint-disable @kbn/eslint/no-restricted-paths */
import { notificationServiceMock } from '../../../../../../src/core/public/notifications/notifications_service.mock';
import { chromeServiceMock } from '../../../../../../src/core/public/chrome/chrome_service.mock';
jest.mock('ui/new_platform');
@ -107,17 +109,29 @@ const namesText = rendered => {
describe('index table', () => {
beforeEach(() => {
// Mock initialization of services
// @ts-ignore
httpService.init(mockHttpClient);
breadcrumbService.init(chromeServiceMock.createStartContract(), '');
uiMetricService.init(createUiStatsReporter);
notificationService.init(notificationServiceMock.createStartContract());
const services = {
extensionsService: new ExtensionsService(),
uiMetricService: new UiMetricService('index_management'),
};
services.uiMetricService.setup({ reportUiStats() {} });
setExtensionsService(services.extensionsService);
setUiMetricService(services.uiMetricService);
// @ts-ignore
httpService.setup(mockHttpClient);
breadcrumbService.setup(() => undefined);
notificationService.setup(notificationServiceMock.createStartContract());
store = indexManagementStore(services);
const appDependencies = { services, core: {}, plugins: {} };
store = indexManagementStore();
component = (
<Provider store={store}>
<MemoryRouter initialEntries={[`${BASE_PATH}indices`]}>
<AppWithoutRouter />
<AppContextProvider value={appDependencies}>
<AppWithoutRouter />
</AppContextProvider>
</MemoryRouter>
</Provider>
);
@ -141,6 +155,9 @@ describe('index table', () => {
server.respondImmediately = true;
});
afterEach(() => {
if (!server) {
return;
}
server.restore();
});
@ -294,6 +311,8 @@ describe('index table', () => {
confirmButton.simulate('click');
snapshot(status(rendered, rowIndex));
});
// Commenting the following 2 tests as it works in the browser (status changes to "closed" or "open") but the
// snapshot say the contrary. Need to be investigated.
test('close index button works from context menu', done => {
const modifiedIndices = indices.map(index => {
return {

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { flattenObject } from '../../public/app/lib/flatten_object';
import { flattenObject } from '../../public/application/lib/flatten_object';
describe('flatten_object', () => {
test('it flattens an object', () => {
const obj = {

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;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { Provider } from 'react-redux';
import { render, unmountComponentAtNode } from 'react-dom';
import { CoreStart } from '../../../../../../src/core/public';
import { App } from './app';
import { indexManagementStore } from './store';
export const mountReactApp = (elem: HTMLElement | null, { core }: { core: CoreStart }): void => {
if (elem) {
const { i18n } = core;
const { Context: I18nContext } = i18n;
render(
<I18nContext>
<Provider store={indexManagementStore()}>
<App />
</Provider>
</I18nContext>,
elem
);
}
};
export const unmountReactApp = (elem: HTMLElement | null) => {
if (elem) {
unmountComponentAtNode(elem);
}
};

View file

@ -1,164 +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;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Component, Fragment } from 'react';
import { Route } from 'react-router-dom';
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';
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="Mapping" />
),
[TAB_STATS]: (
<FormattedMessage id="xpack.idxMgmt.detailPanel.tabStatsLabel" defaultMessage="Stats" />
),
[TAB_EDIT_SETTINGS]: (
<FormattedMessage
id="xpack.idxMgmt.detailPanel.tabEditSettingsLabel"
defaultMessage="Edit settings"
/>
),
};
const tabs = [TAB_SUMMARY, TAB_SETTINGS, TAB_MAPPING, TAB_STATS, TAB_EDIT_SETTINGS];
export class DetailPanel extends Component {
renderTabs() {
const { panelType, indexName, index, openDetailPanel } = this.props;
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>
);
});
}
render() {
const { panelType, indexName, index, closeDetailPanel } = this.props;
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
iconSide="left"
indexNames={[indexName]}
anchorPosition="upRight"
detailPanel={true}
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}
{renderBadges(index)}
</h2>
</EuiTitle>
{index ? <EuiTabs>{this.renderTabs()}</EuiTabs> : null}
</EuiFlyoutHeader>
{content}
</EuiFlyout>
);
}
}

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;
* you may not use this file except in compliance with the Elastic License.
*/
import { UIM_APP_NAME } from '../../../common/constants';
import {
createUiStatsReporter,
UiStatsMetricType,
} from '../../../../../../../src/legacy/core_plugins/ui_metric/public';
class UiMetricService {
track?: ReturnType<typeof createUiStatsReporter>;
public init = (getReporter: typeof createUiStatsReporter): void => {
this.track = getReporter(UIM_APP_NAME);
};
public trackMetric = (type: 'loaded' | 'click' | 'count', eventName: string): void => {
if (!this.track) throw Error('UiMetricService not initialized.');
return this.track(type as UiStatsMetricType, eventName);
};
}
export const uiMetricService = new UiMetricService();

View file

@ -1,89 +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;
* you may not use this file except in compliance with the Elastic License.
*/
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 { uiMetricService } from '../../services/ui_metric';
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';
const defaultState = {};
export const detailPanel = 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('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

@ -11,9 +11,11 @@ import { IndexManagementHome } from './sections/home';
import { TemplateCreate } from './sections/template_create';
import { TemplateClone } from './sections/template_clone';
import { TemplateEdit } from './sections/template_edit';
import { uiMetricService } from './services/ui_metric';
import { useServices } from './app_context';
export const App = () => {
const { uiMetricService } = useServices();
useEffect(() => uiMetricService.trackMetric('loaded', UIM_APP_LOAD), []);
return (

View file

@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { createContext, useContext } from 'react';
import { CoreStart } from '../../../../../../src/core/public';
import { UsageCollectionSetup } from '../../../../../../src/plugins/usage_collection/public';
import { IndexMgmtMetricsType } from '../types';
import { UiMetricService, NotificationService, HttpService } from './services';
import { ExtensionsService } from '../services';
const AppContext = createContext<AppDependencies | undefined>(undefined);
export interface AppDependencies {
core: {
fatalErrors: CoreStart['fatalErrors'];
};
plugins: {
usageCollection: UsageCollectionSetup;
};
services: {
uiMetricService: UiMetricService<IndexMgmtMetricsType>;
extensionsService: ExtensionsService;
httpService: HttpService;
notificationService: NotificationService;
};
}
export const AppContextProvider = ({
children,
value,
}: {
value: AppDependencies;
children: React.ReactNode;
}) => {
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
};
export const AppContextConsumer = AppContext.Consumer;
export const useAppContext = () => {
const ctx = useContext(AppContext);
if (!ctx) {
throw new Error('"useAppContext" can only be called inside of AppContext.Provider!');
}
return ctx;
};
export const useServices = () => useAppContext().services;

Some files were not shown because too many files have changed in this diff Show more