mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
parent
3a078811f8
commit
f530fecdd8
179 changed files with 1328 additions and 772 deletions
166
src/plugins/es_ui_shared/public/request/np_ready_request.ts
Normal file
166
src/plugins/es_ui_shared/public/request/np_ready_request.ts
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
|
||||
import { HttpServiceBase } from '../../../../../src/core/public';
|
||||
|
||||
export interface SendRequestConfig {
|
||||
path: string;
|
||||
method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head';
|
||||
body?: any;
|
||||
}
|
||||
|
||||
export interface SendRequestResponse {
|
||||
data: any;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
export interface UseRequestConfig extends SendRequestConfig {
|
||||
pollIntervalMs?: number;
|
||||
initialData?: any;
|
||||
deserializer?: (data: any) => any;
|
||||
}
|
||||
|
||||
export interface UseRequestResponse {
|
||||
isInitialRequest: boolean;
|
||||
isLoading: boolean;
|
||||
error: null | unknown;
|
||||
data: any;
|
||||
sendRequest: (...args: any[]) => Promise<SendRequestResponse>;
|
||||
}
|
||||
|
||||
export const sendRequest = async (
|
||||
httpClient: HttpServiceBase,
|
||||
{ path, method, body }: SendRequestConfig
|
||||
): Promise<SendRequestResponse> => {
|
||||
try {
|
||||
const response = await httpClient[method](path, { body });
|
||||
|
||||
return {
|
||||
data: response.data ? response.data : response,
|
||||
error: null,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
data: null,
|
||||
error: e.response && e.response.data ? e.response.data : e.body,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const useRequest = (
|
||||
httpClient: HttpServiceBase,
|
||||
{
|
||||
path,
|
||||
method,
|
||||
body,
|
||||
pollIntervalMs,
|
||||
initialData,
|
||||
deserializer = (data: any): any => data,
|
||||
}: UseRequestConfig
|
||||
): UseRequestResponse => {
|
||||
// Main states for tracking request status and data
|
||||
const [error, setError] = useState<null | any>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [data, setData] = useState<any>(initialData);
|
||||
|
||||
// Consumers can use isInitialRequest to implement a polling UX.
|
||||
const [isInitialRequest, setIsInitialRequest] = useState<boolean>(true);
|
||||
const pollInterval = useRef<any>(null);
|
||||
const pollIntervalId = useRef<any>(null);
|
||||
|
||||
// We always want to use the most recently-set interval in scheduleRequest.
|
||||
pollInterval.current = pollIntervalMs;
|
||||
|
||||
// Tied to every render and bound to each request.
|
||||
let isOutdatedRequest = false;
|
||||
|
||||
const scheduleRequest = () => {
|
||||
// Clear current interval
|
||||
if (pollIntervalId.current) {
|
||||
clearTimeout(pollIntervalId.current);
|
||||
}
|
||||
|
||||
// Set new interval
|
||||
if (pollInterval.current) {
|
||||
pollIntervalId.current = setTimeout(_sendRequest, pollInterval.current);
|
||||
}
|
||||
};
|
||||
|
||||
const _sendRequest = async () => {
|
||||
// We don't clear error or data, so it's up to the consumer to decide whether to display the
|
||||
// "old" error/data or loading state when a new request is in-flight.
|
||||
setIsLoading(true);
|
||||
|
||||
const requestBody = {
|
||||
path,
|
||||
method,
|
||||
body,
|
||||
};
|
||||
|
||||
const response = await sendRequest(httpClient, requestBody);
|
||||
const { data: serializedResponseData, error: responseError } = response;
|
||||
const responseData = deserializer(serializedResponseData);
|
||||
|
||||
// If an outdated request has resolved, DON'T update state, but DO allow the processData handler
|
||||
// to execute side effects like update telemetry.
|
||||
if (isOutdatedRequest) {
|
||||
return { data: null, error: null };
|
||||
}
|
||||
|
||||
setError(responseError);
|
||||
setData(responseData);
|
||||
setIsLoading(false);
|
||||
setIsInitialRequest(false);
|
||||
|
||||
// If we're on an interval, we need to schedule the next request. This also allows us to reset
|
||||
// the interval if the user has manually requested the data, to avoid doubled-up requests.
|
||||
scheduleRequest();
|
||||
|
||||
return { data: serializedResponseData, error: responseError };
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
_sendRequest();
|
||||
// To be functionally correct we'd send a new request if the method, path, or body changes.
|
||||
// But it doesn't seem likely that the method will change and body is likely to be a new
|
||||
// object even if its shape hasn't changed, so for now we're just watching the path.
|
||||
}, [path]);
|
||||
|
||||
useEffect(() => {
|
||||
scheduleRequest();
|
||||
|
||||
// Clean up intervals and inflight requests and corresponding state changes
|
||||
return () => {
|
||||
isOutdatedRequest = true;
|
||||
if (pollIntervalId.current) {
|
||||
clearTimeout(pollIntervalId.current);
|
||||
}
|
||||
};
|
||||
}, [pollIntervalMs]);
|
||||
|
||||
return {
|
||||
isInitialRequest,
|
||||
isLoading,
|
||||
error,
|
||||
data,
|
||||
sendRequest: _sendRequest, // Gives the user the ability to manually request data
|
||||
};
|
||||
};
|
|
@ -9,7 +9,7 @@ import { PLUGIN } from './common/constants';
|
|||
import { registerLicenseChecker } from './server/lib/register_license_checker';
|
||||
import { registerRoutes } from './server/routes/register_routes';
|
||||
import { ccrDataEnricher } from './cross_cluster_replication_data';
|
||||
import { addIndexManagementDataEnricher } from '../index_management/index_management_data';
|
||||
import { addIndexManagementDataEnricher } from '../index_management/server/index_management_data';
|
||||
export function crossClusterReplication(kibana) {
|
||||
return new kibana.Plugin({
|
||||
id: PLUGIN.ID,
|
||||
|
|
|
@ -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/services/navigation';
|
||||
import { getIndexListUri } from '../../../../../../../../index_management/public/app/services/navigation';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
|
|
|
@ -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/services/navigation';
|
||||
import { getIndexListUri } from '../../../../../../../../index_management/public/app/services/navigation';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
|
|
|
@ -36,7 +36,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
|
||||
|
||||
import { getIndexListUri } from '../../../../../../index_management/public/services/navigation';
|
||||
import { getIndexListUri } from '../../../../../../index_management/public/app/services/navigation';
|
||||
import { BASE_PATH, UIM_EDIT_CLICK } from '../../../../../common/constants';
|
||||
import { getPolicyPath } from '../../../../services/navigation';
|
||||
import { flattenPanelTree } from '../../../../services/flatten_panel_tree';
|
||||
|
|
|
@ -13,9 +13,9 @@ import {
|
|||
findTestSubject,
|
||||
nextTick,
|
||||
} from '../../../../../../test_utils';
|
||||
import { IndexManagementHome } from '../../../public/sections/home';
|
||||
import { IndexManagementHome } from '../../../public/app/sections/home';
|
||||
import { BASE_PATH } from '../../../common/constants';
|
||||
import { indexManagementStore } from '../../../public/store';
|
||||
import { indexManagementStore } from '../../../public/app/store';
|
||||
import { Template } from '../../../common/types';
|
||||
|
||||
const testBedConfig: TestBedConfig = {
|
||||
|
|
|
@ -5,15 +5,14 @@
|
|||
*/
|
||||
|
||||
import sinon, { SinonFakeServer } from 'sinon';
|
||||
|
||||
const API_PATH = '/api/index_management';
|
||||
import { API_BASE_PATH } from '../../../common/constants';
|
||||
|
||||
type HttpResponse = Record<string, any> | any[];
|
||||
|
||||
// Register helpers to mock HTTP Requests
|
||||
const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
||||
const setLoadTemplatesResponse = (response: HttpResponse = []) => {
|
||||
server.respondWith('GET', `${API_PATH}/templates`, [
|
||||
server.respondWith('GET', `${API_BASE_PATH}/templates`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(response),
|
||||
|
@ -21,7 +20,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
|||
};
|
||||
|
||||
const setLoadIndicesResponse = (response: HttpResponse = []) => {
|
||||
server.respondWith('GET', `${API_PATH}/indices`, [
|
||||
server.respondWith('GET', `${API_BASE_PATH}/indices`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(response),
|
||||
|
@ -29,7 +28,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
|||
};
|
||||
|
||||
const setDeleteTemplateResponse = (response: HttpResponse = []) => {
|
||||
server.respondWith('DELETE', `${API_PATH}/templates`, [
|
||||
server.respondWith('DELETE', `${API_BASE_PATH}/templates`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(response),
|
||||
|
@ -40,7 +39,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
|||
const status = error ? error.status || 400 : 200;
|
||||
const body = error ? error.body : response;
|
||||
|
||||
server.respondWith('GET', `${API_PATH}/templates/:id`, [
|
||||
server.respondWith('GET', `${API_BASE_PATH}/templates/:id`, [
|
||||
status,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(body),
|
||||
|
@ -48,10 +47,10 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
|||
};
|
||||
|
||||
const setCreateTemplateResponse = (response?: HttpResponse, error?: any) => {
|
||||
const status = error ? error.status || 400 : 200;
|
||||
const status = error ? error.body.status || 400 : 200;
|
||||
const body = error ? JSON.stringify(error.body) : JSON.stringify(response);
|
||||
|
||||
server.respondWith('PUT', `${API_PATH}/templates`, [
|
||||
server.respondWith('PUT', `${API_BASE_PATH}/templates`, [
|
||||
status,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
body,
|
||||
|
@ -62,7 +61,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
|||
const status = error ? error.status || 400 : 200;
|
||||
const body = error ? JSON.stringify(error.body) : JSON.stringify(response);
|
||||
|
||||
server.respondWith('PUT', `${API_PATH}/templates/:name`, [
|
||||
server.respondWith('PUT', `${API_BASE_PATH}/templates/:name`, [
|
||||
status,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
body,
|
||||
|
|
|
@ -7,15 +7,30 @@
|
|||
import axios from 'axios';
|
||||
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
|
||||
import { init as initHttpRequests } from './http_requests';
|
||||
import { setHttpClient } from '../../../public/services/api';
|
||||
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 = () => {
|
||||
const { server, httpRequestsMockHelpers } = initHttpRequests();
|
||||
|
||||
// Mock initialization of services
|
||||
// @ts-ignore
|
||||
setHttpClient(mockHttpClient);
|
||||
httpService.init(mockHttpClient);
|
||||
breadcrumbService.init(chromeServiceMock.createStartContract(), '');
|
||||
documentationService.init(docLinksServiceMock.createStartContract());
|
||||
notificationService.init(notificationServiceMock.createStartContract());
|
||||
uiMetricService.init(createUiStatsReporter);
|
||||
|
||||
const { server, httpRequestsMockHelpers } = initHttpRequests();
|
||||
|
||||
return {
|
||||
server,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
|
||||
import { BASE_PATH } from '../../../common/constants';
|
||||
import { TemplateClone } from '../../../public/sections/template_clone';
|
||||
import { TemplateClone } from '../../../public/app/sections/template_clone';
|
||||
import { formSetup } from './template_form.helpers';
|
||||
import { TEMPLATE_NAME } from './constants';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
|
||||
import { BASE_PATH } from '../../../common/constants';
|
||||
import { TemplateCreate } from '../../../public/sections/template_create';
|
||||
import { TemplateCreate } from '../../../public/app/sections/template_create';
|
||||
import { formSetup, TestSubjects } from './template_form.helpers';
|
||||
|
||||
const testBedConfig: TestBedConfig = {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
|
||||
import { BASE_PATH } from '../../../common/constants';
|
||||
import { TemplateEdit } from '../../../public/sections/template_edit';
|
||||
import { TemplateEdit } from '../../../public/app/sections/template_edit';
|
||||
import { formSetup, TestSubjects } from './template_form.helpers';
|
||||
import { TEMPLATE_NAME } from './constants';
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@ import { act } from 'react-dom/test-utils';
|
|||
import * as fixtures from '../../test/fixtures';
|
||||
import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers';
|
||||
import { IdxMgmtHomeTestBed } from './helpers/home.helpers';
|
||||
|
||||
const API_PATH = '/api/index_management';
|
||||
import { API_BASE_PATH } from '../../common/constants';
|
||||
|
||||
const { setup } = pageHelpers.home;
|
||||
|
||||
|
@ -21,16 +20,7 @@ const removeWhiteSpaceOnArrayValues = (array: any[]) =>
|
|||
return value.trim();
|
||||
});
|
||||
|
||||
jest.mock('ui/index_patterns', () => ({
|
||||
ILLEGAL_CHARACTERS: '',
|
||||
CONTAINS_SPACES: '',
|
||||
validateIndexPattern: () => {},
|
||||
}));
|
||||
|
||||
jest.mock('ui/chrome', () => ({
|
||||
breadcrumbs: { set: () => {} },
|
||||
addBasePath: (path: string) => path || '/api/index_management',
|
||||
}));
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
// We need to skip the tests until react 16.9.0 is released
|
||||
// which supports asynchronous code inside act()
|
||||
|
@ -204,7 +194,9 @@ describe.skip('<IndexManagementHome />', () => {
|
|||
});
|
||||
|
||||
expect(server.requests.length).toBe(totalRequests + 1);
|
||||
expect(server.requests[server.requests.length - 1].url).toBe(`${API_PATH}/templates`);
|
||||
expect(server.requests[server.requests.length - 1].url).toBe(
|
||||
`${API_BASE_PATH}/templates`
|
||||
);
|
||||
});
|
||||
|
||||
test('should have a button to create a new template', () => {
|
||||
|
@ -346,7 +338,7 @@ describe.skip('<IndexManagementHome />', () => {
|
|||
const latestRequest = server.requests[server.requests.length - 1];
|
||||
|
||||
expect(latestRequest.method).toBe('DELETE');
|
||||
expect(latestRequest.url).toBe(`${API_PATH}/templates/${template1.name}`);
|
||||
expect(latestRequest.url).toBe(`${API_BASE_PATH}/templates/${template1.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
|
||||
import axios from 'axios';
|
||||
|
||||
import { setupEnvironment, pageHelpers, nextTick } from './helpers';
|
||||
import { TemplateFormTestBed } from './helpers/template_form.helpers';
|
||||
|
@ -15,27 +13,7 @@ import { TEMPLATE_NAME, INDEX_PATTERNS as DEFAULT_INDEX_PATTERNS } from './helpe
|
|||
|
||||
const { setup } = pageHelpers.templateClone;
|
||||
|
||||
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
|
||||
|
||||
jest.mock('ui/index_patterns', () => ({
|
||||
ILLEGAL_CHARACTERS: 'ILLEGAL_CHARACTERS',
|
||||
CONTAINS_SPACES: 'CONTAINS_SPACES',
|
||||
validateIndexPattern: () => {
|
||||
return {
|
||||
errors: {},
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('ui/chrome', () => ({
|
||||
breadcrumbs: { set: () => {} },
|
||||
addBasePath: (path: string) => path || '/api/index_management',
|
||||
}));
|
||||
|
||||
jest.mock('../../public/services/api', () => ({
|
||||
...jest.requireActual('../../public/services/api'),
|
||||
getHttpClient: () => mockHttpClient,
|
||||
}));
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
jest.mock('@elastic/eui', () => ({
|
||||
...jest.requireActual('@elastic/eui'),
|
||||
|
@ -135,16 +113,13 @@ describe.skip('<TemplateClone />', () => {
|
|||
|
||||
const latestRequest = server.requests[server.requests.length - 1];
|
||||
|
||||
const body = JSON.parse(latestRequest.requestBody);
|
||||
const expected = {
|
||||
const expected = JSON.stringify({
|
||||
...templateToClone,
|
||||
name: `${templateToClone.name}-copy`,
|
||||
indexPatterns: DEFAULT_INDEX_PATTERNS,
|
||||
aliases: {},
|
||||
mappings: {},
|
||||
settings: {},
|
||||
};
|
||||
expect(body).toEqual(expected);
|
||||
});
|
||||
|
||||
expect(JSON.parse(latestRequest.requestBody).body).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
|
||||
import axios from 'axios';
|
||||
|
||||
import { setupEnvironment, pageHelpers, nextTick } from './helpers';
|
||||
import { TemplateFormTestBed } from './helpers/template_form.helpers';
|
||||
|
@ -20,27 +18,7 @@ import {
|
|||
|
||||
const { setup } = pageHelpers.templateCreate;
|
||||
|
||||
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
|
||||
|
||||
jest.mock('ui/index_patterns', () => ({
|
||||
ILLEGAL_CHARACTERS: 'ILLEGAL_CHARACTERS',
|
||||
CONTAINS_SPACES: 'CONTAINS_SPACES',
|
||||
validateIndexPattern: () => {
|
||||
return {
|
||||
errors: {},
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('ui/chrome', () => ({
|
||||
breadcrumbs: { set: () => {} },
|
||||
addBasePath: (path: string) => path || '/api/index_management',
|
||||
}));
|
||||
|
||||
jest.mock('../../public/services/api', () => ({
|
||||
...jest.requireActual('../../public/services/api'),
|
||||
getHttpClient: () => mockHttpClient,
|
||||
}));
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
jest.mock('@elastic/eui', () => ({
|
||||
...jest.requireActual('@elastic/eui'),
|
||||
|
@ -332,15 +310,16 @@ describe.skip('<TemplateCreate />', () => {
|
|||
|
||||
const latestRequest = server.requests[server.requests.length - 1];
|
||||
|
||||
const expected = {
|
||||
const expected = JSON.stringify({
|
||||
isManaged: false,
|
||||
name: TEMPLATE_NAME,
|
||||
indexPatterns: DEFAULT_INDEX_PATTERNS,
|
||||
settings: SETTINGS,
|
||||
mappings: MAPPINGS,
|
||||
aliases: ALIASES,
|
||||
isManaged: false,
|
||||
};
|
||||
expect(JSON.parse(latestRequest.requestBody)).toEqual(expected);
|
||||
});
|
||||
|
||||
expect(JSON.parse(latestRequest.requestBody).body).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should surface the API errors from the put HTTP request', async () => {
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
|
||||
import axios from 'axios';
|
||||
|
||||
import { setupEnvironment, pageHelpers, nextTick } from './helpers';
|
||||
import { TemplateFormTestBed } from './helpers/template_form.helpers';
|
||||
|
@ -17,27 +15,7 @@ const UPDATED_INDEX_PATTERN = ['updatedIndexPattern'];
|
|||
|
||||
const { setup } = pageHelpers.templateEdit;
|
||||
|
||||
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
|
||||
|
||||
jest.mock('ui/index_patterns', () => ({
|
||||
ILLEGAL_CHARACTERS: 'ILLEGAL_CHARACTERS',
|
||||
CONTAINS_SPACES: 'CONTAINS_SPACES',
|
||||
validateIndexPattern: () => {
|
||||
return {
|
||||
errors: {},
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('ui/chrome', () => ({
|
||||
breadcrumbs: { set: () => {} },
|
||||
addBasePath: (path: string) => path || '/api/index_management',
|
||||
}));
|
||||
|
||||
jest.mock('../../public/services/api', () => ({
|
||||
...jest.requireActual('../../public/services/api'),
|
||||
getHttpClient: () => mockHttpClient,
|
||||
}));
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
jest.mock('@elastic/eui', () => ({
|
||||
...jest.requireActual('@elastic/eui'),
|
||||
|
@ -140,17 +118,18 @@ describe.skip('<TemplateEdit />', () => {
|
|||
|
||||
const { version, order } = templateToEdit;
|
||||
|
||||
const expected = {
|
||||
const expected = JSON.stringify({
|
||||
name: TEMPLATE_NAME,
|
||||
version,
|
||||
order,
|
||||
indexPatterns: UPDATED_INDEX_PATTERN,
|
||||
isManaged: false,
|
||||
settings: SETTINGS,
|
||||
mappings: MAPPINGS,
|
||||
aliases: ALIASES,
|
||||
isManaged: false,
|
||||
};
|
||||
expect(JSON.parse(latestRequest.requestBody)).toEqual(expected);
|
||||
});
|
||||
|
||||
expect(JSON.parse(latestRequest.requestBody).body).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,33 +5,31 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { AppWithoutRouter } from '../../public/app';
|
||||
import { Provider } from 'react-redux';
|
||||
import { loadIndicesSuccess } from '../../public/store/actions';
|
||||
import { indexManagementStore } from '../../public/store';
|
||||
import { BASE_PATH } from '../../common/constants';
|
||||
import { mountWithIntl } from '../../../../../test_utils/enzyme_helpers';
|
||||
// axios has a $http like interface so using it to simulate $http
|
||||
import axios from 'axios';
|
||||
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
|
||||
import { setHttpClient } from '../../public/services/api';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { AppWithoutRouter } from '../../public/app/app';
|
||||
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 { BASE_PATH, API_BASE_PATH } from '../../common/constants';
|
||||
import { mountWithIntl } from '../../../../../test_utils/enzyme_helpers';
|
||||
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/chrome', () => ({
|
||||
breadcrumbs: { set: () => { } },
|
||||
addBasePath: path => path || '/api/index_management',
|
||||
}));
|
||||
jest.mock('ui/new_platform');
|
||||
|
||||
jest.mock('ui/index_patterns', () => ({
|
||||
ILLEGAL_CHARACTERS: '',
|
||||
CONTAINS_SPACES: '',
|
||||
validateIndexPattern: () => { },
|
||||
}));
|
||||
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
|
||||
|
||||
setHttpClient(axios.create({ adapter: axiosXhrAdapter }));
|
||||
let server = null;
|
||||
|
||||
let store = null;
|
||||
|
@ -114,6 +112,14 @@ 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());
|
||||
|
||||
|
||||
store = indexManagementStore();
|
||||
component = (
|
||||
<Provider store={store}>
|
||||
|
@ -124,7 +130,7 @@ describe('index table', () => {
|
|||
);
|
||||
store.dispatch(loadIndicesSuccess({ indices }));
|
||||
server = sinon.fakeServer.create();
|
||||
server.respondWith('/api/index_management/indices', [
|
||||
server.respondWith(`${API_BASE_PATH}/indices`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(indices)
|
||||
|
@ -134,7 +140,7 @@ describe('index table', () => {
|
|||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({ acknowledged: true })
|
||||
]);
|
||||
server.respondWith('/api/index_management/indices/reload', [
|
||||
server.respondWith(`${API_BASE_PATH}/indices/reload`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(indices)
|
||||
|
@ -347,7 +353,8 @@ describe('index table', () => {
|
|||
status: index.name === 'testy0' ? 'close' : index.status
|
||||
};
|
||||
});
|
||||
server.respondWith('/api/index_management/indices/reload', [
|
||||
|
||||
server.respondWith(`${API_BASE_PATH}/indices/reload`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(modifiedIndices)
|
||||
|
@ -361,7 +368,7 @@ describe('index table', () => {
|
|||
status: index.name === 'testy1' ? 'open' : index.status
|
||||
};
|
||||
});
|
||||
server.respondWith('/api/index_management/indices/reload', [
|
||||
server.respondWith(`${API_BASE_PATH}/indices/reload`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(modifiedIndices)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { flattenObject } from '../../public/lib/flatten_object';
|
||||
import { flattenObject } from '../../public/app/lib/flatten_object';
|
||||
describe('flatten_object', () => {
|
||||
test('it flattens an object', () => {
|
||||
const obj = {
|
||||
|
|
|
@ -4,6 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import './register_management_section';
|
||||
import './register_routes';
|
||||
import './index_management_extensions';
|
||||
export const API_BASE_PATH = '/api/index_management';
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
export { PLUGIN } from './plugin';
|
||||
export { BASE_PATH } from './base_path';
|
||||
export { API_BASE_PATH } from './api_base_path';
|
||||
export { INVALID_INDEX_PATTERN_CHARS, INVALID_TEMPLATE_NAME_CHARS } from './invalid_characters';
|
||||
export * from './index_statuses';
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { LICENSE_TYPE_BASIC } from '../../../../common/constants';
|
||||
|
||||
export const PLUGIN = {
|
||||
ID: 'index_management',
|
||||
NAME: i18n.translate('xpack.idxMgmt.appTitle', {
|
||||
defaultMessage: 'Index Management',
|
||||
}),
|
||||
getI18nName: (i18n: any): string =>
|
||||
i18n.translate('xpack.idxMgmt.appTitle', {
|
||||
defaultMessage: 'Index Management',
|
||||
}),
|
||||
MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC,
|
||||
};
|
||||
|
|
|
@ -1,41 +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 { resolve } from 'path';
|
||||
import { createRouter } from '../../server/lib/create_router';
|
||||
import { registerIndicesRoutes } from './server/routes/api/indices';
|
||||
import { registerTemplateRoutes } from './server/routes/api/templates';
|
||||
import { registerMappingRoute } from './server/routes/api/mapping';
|
||||
import { registerSettingsRoutes } from './server/routes/api/settings';
|
||||
import { registerStatsRoute } from './server/routes/api/stats';
|
||||
import { registerLicenseChecker } from '../../server/lib/register_license_checker';
|
||||
import { PLUGIN } from './common/constants';
|
||||
import { addIndexManagementDataEnricher } from './index_management_data';
|
||||
|
||||
export function indexManagement(kibana) {
|
||||
return new kibana.Plugin({
|
||||
id: PLUGIN.ID,
|
||||
configPrefix: 'xpack.index_management',
|
||||
publicDir: resolve(__dirname, 'public'),
|
||||
require: ['kibana', 'elasticsearch', 'xpack_main'],
|
||||
uiExports: {
|
||||
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
||||
managementSections: [
|
||||
'plugins/index_management',
|
||||
]
|
||||
},
|
||||
init: function (server) {
|
||||
const router = createRouter(server, PLUGIN.ID, '/api/index_management/');
|
||||
server.expose('addIndexManagementDataEnricher', addIndexManagementDataEnricher);
|
||||
registerLicenseChecker(server, PLUGIN.ID, PLUGIN.NAME, PLUGIN.MINIMUM_LICENSE_REQUIRED);
|
||||
registerIndicesRoutes(router);
|
||||
registerTemplateRoutes(router, server);
|
||||
registerSettingsRoutes(router);
|
||||
registerStatsRoute(router);
|
||||
registerMappingRoute(router);
|
||||
}
|
||||
});
|
||||
}
|
60
x-pack/legacy/plugins/index_management/index.ts
Normal file
60
x-pack/legacy/plugins/index_management/index.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 { resolve } from 'path';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Legacy } from 'kibana';
|
||||
import { createRouter } from '../../server/lib/create_router';
|
||||
import { registerLicenseChecker } from '../../server/lib/register_license_checker';
|
||||
import { PLUGIN, API_BASE_PATH } from './common/constants';
|
||||
import { LegacySetup } from './server/plugin';
|
||||
import { plugin as initServerPlugin } from './server';
|
||||
|
||||
export type ServerFacade = Legacy.Server;
|
||||
|
||||
export function indexManagement(kibana: any) {
|
||||
return new kibana.Plugin({
|
||||
id: PLUGIN.ID,
|
||||
configPrefix: 'xpack.index_management',
|
||||
publicDir: resolve(__dirname, 'public'),
|
||||
require: ['kibana', 'elasticsearch', 'xpack_main'],
|
||||
|
||||
uiExports: {
|
||||
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
|
||||
managementSections: ['plugins/index_management'],
|
||||
},
|
||||
|
||||
init(server: ServerFacade) {
|
||||
const coreSetup = server.newPlatform.setup.core;
|
||||
|
||||
const pluginsSetup = {};
|
||||
|
||||
const __LEGACY: LegacySetup = {
|
||||
router: createRouter(server, PLUGIN.ID, `${API_BASE_PATH}/`),
|
||||
plugins: {
|
||||
license: {
|
||||
registerLicenseChecker: registerLicenseChecker.bind(
|
||||
null,
|
||||
server,
|
||||
PLUGIN.ID,
|
||||
PLUGIN.getI18nName(i18n),
|
||||
PLUGIN.MINIMUM_LICENSE_REQUIRED as 'basic'
|
||||
),
|
||||
},
|
||||
elasticsearch: server.plugins.elasticsearch,
|
||||
},
|
||||
};
|
||||
|
||||
const serverPlugin = initServerPlugin();
|
||||
const indexMgmtSetup = serverPlugin.setup(coreSetup, pluginsSetup, __LEGACY);
|
||||
|
||||
server.expose(
|
||||
'addIndexManagementDataEnricher',
|
||||
indexMgmtSetup.addIndexManagementDataEnricher
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
.indTable {
|
||||
// The index table is a bespoke table and can't make use of EuiBasicTable's width settings
|
||||
thead th.indTable__header--name {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
// The index name can't contain spaces, so this is a rare case of break being OK.
|
||||
.indTable__cell--name {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.indTable__link {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.indTable__link {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.indDetail__codeBlock {
|
||||
background: transparent;
|
||||
}
|
|
@ -6,15 +6,15 @@
|
|||
|
||||
import React, { useEffect } from 'react';
|
||||
import { HashRouter, Switch, Route, Redirect } from 'react-router-dom';
|
||||
import { BASE_PATH, UIM_APP_LOAD } from '../common/constants';
|
||||
import { BASE_PATH, UIM_APP_LOAD } from '../../common/constants';
|
||||
import { IndexManagementHome } from './sections/home';
|
||||
import { TemplateCreate } from './sections/template_create';
|
||||
import { TemplateClone } from './sections/template_clone';
|
||||
import { TemplateEdit } from './sections/template_edit';
|
||||
import { trackUiMetric } from './services';
|
||||
import { uiMetricService } from './services/ui_metric';
|
||||
|
||||
export const App = () => {
|
||||
useEffect(() => trackUiMetric('loaded', UIM_APP_LOAD), []);
|
||||
useEffect(() => uiMetricService.trackMetric('loaded', UIM_APP_LOAD), []);
|
||||
|
||||
return (
|
||||
<HashRouter>
|
||||
|
@ -28,12 +28,8 @@ export const AppWithoutRouter = () => (
|
|||
<Switch>
|
||||
<Route exact path={`${BASE_PATH}create_template`} component={TemplateCreate} />
|
||||
<Route exact path={`${BASE_PATH}clone_template/:name*`} component={TemplateClone} />
|
||||
<Route
|
||||
exact
|
||||
path={`${BASE_PATH}edit_template/:name*`}
|
||||
component={TemplateEdit}
|
||||
/>
|
||||
<Route exact path={`${BASE_PATH}edit_template/:name*`} component={TemplateEdit} />
|
||||
<Route path={`${BASE_PATH}:section(indices|templates)`} component={IndexManagementHome} />
|
||||
<Redirect from={`${BASE_PATH}`} to={`${BASE_PATH}indices`}/>
|
||||
<Redirect from={`${BASE_PATH}`} to={`${BASE_PATH}indices`} />
|
||||
</Switch>
|
||||
);
|
|
@ -8,11 +8,9 @@ import { EuiCallOut, EuiSpacer } from '@elastic/eui';
|
|||
import React, { Fragment } from 'react';
|
||||
|
||||
export interface Error {
|
||||
data: {
|
||||
error: string;
|
||||
cause?: string[];
|
||||
message?: string;
|
||||
};
|
||||
cause?: string[];
|
||||
message?: string;
|
||||
statusText?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
|
@ -22,14 +20,14 @@ interface Props {
|
|||
|
||||
export const SectionError: React.FunctionComponent<Props> = ({ title, error, ...rest }) => {
|
||||
const {
|
||||
error: errorString,
|
||||
cause, // wrapEsError() on the server adds a "cause" array
|
||||
message,
|
||||
} = error.data;
|
||||
statusText,
|
||||
} = error;
|
||||
|
||||
return (
|
||||
<EuiCallOut title={title} color="danger" iconType="alert" {...rest}>
|
||||
<div>{message || errorString}</div>
|
||||
<div>{message || statusText}</div>
|
||||
{cause && (
|
||||
<Fragment>
|
||||
<EuiSpacer size="m" />
|
|
@ -8,9 +8,9 @@ import { EuiConfirmModal, EuiOverlayMask, EuiCallOut, EuiCheckbox, EuiBadge } fr
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { deleteTemplates } from '../services/api';
|
||||
import { Template } from '../../common/types';
|
||||
import { notificationService } from '../services/notification';
|
||||
import { Template } from '../../../common/types';
|
||||
|
||||
export const TemplateDeleteModal = ({
|
||||
templatesToDelete,
|
||||
|
@ -51,7 +51,7 @@ export const TemplateDeleteModal = ({
|
|||
);
|
||||
|
||||
callback({ hasDeletedTemplates });
|
||||
toastNotifications.addSuccess(successMessage);
|
||||
notificationService.showSuccessToast(successMessage);
|
||||
}
|
||||
|
||||
if (error || (errors && errors.length)) {
|
||||
|
@ -71,7 +71,7 @@ export const TemplateDeleteModal = ({
|
|||
defaultMessage: "Error deleting template '{name}'",
|
||||
values: { name: (errors && errors[0].name) || templatesToDelete[0] },
|
||||
});
|
||||
toastNotifications.addDanger(errorMessage);
|
||||
notificationService.showDangerToast(errorMessage);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -18,7 +18,7 @@ import {
|
|||
EuiCode,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { templatesDocumentationLink } from '../../../lib/documentation_links';
|
||||
import { documentationService } from '../../../services/documentation';
|
||||
import { StepProps } from '../types';
|
||||
import { useJsonStep } from './use_json_step';
|
||||
|
||||
|
@ -63,7 +63,7 @@ export const StepAliases: React.FunctionComponent<StepProps> = ({
|
|||
<EuiButtonEmpty
|
||||
size="s"
|
||||
flush="right"
|
||||
href={templatesDocumentationLink}
|
||||
href={documentationService.getTemplatesDocumentationLink()}
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
>
|
|
@ -11,12 +11,12 @@ import {
|
|||
useForm,
|
||||
Form,
|
||||
getUseField,
|
||||
} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib';
|
||||
} from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib';
|
||||
import {
|
||||
getFormRow,
|
||||
Field,
|
||||
} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/components';
|
||||
import { templatesDocumentationLink } from '../../../lib/documentation_links';
|
||||
} from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/components';
|
||||
import { documentationService } from '../../../services/documentation';
|
||||
import { StepProps } from '../types';
|
||||
import { schemas } from '../template_form_schemas';
|
||||
|
||||
|
@ -110,7 +110,7 @@ export const StepLogistics: React.FunctionComponent<StepProps> = ({
|
|||
<EuiButtonEmpty
|
||||
size="s"
|
||||
flush="right"
|
||||
href={templatesDocumentationLink}
|
||||
href={documentationService.getTemplatesDocumentationLink()}
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
>
|
|
@ -18,7 +18,7 @@ import {
|
|||
EuiCodeEditor,
|
||||
EuiCode,
|
||||
} from '@elastic/eui';
|
||||
import { mappingDocumentationLink } from '../../../lib/documentation_links';
|
||||
import { documentationService } from '../../../services/documentation';
|
||||
import { StepProps } from '../types';
|
||||
import { useJsonStep } from './use_json_step';
|
||||
|
||||
|
@ -63,7 +63,7 @@ export const StepMappings: React.FunctionComponent<StepProps> = ({
|
|||
<EuiButtonEmpty
|
||||
size="s"
|
||||
flush="right"
|
||||
href={mappingDocumentationLink}
|
||||
href={documentationService.getMappingDocumentationLink()}
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
>
|
|
@ -20,10 +20,10 @@ import {
|
|||
EuiCodeBlock,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { serializers } from '../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers';
|
||||
import { serializers } from '../../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers';
|
||||
|
||||
import { serializeTemplate } from '../../../../common/lib/template_serialization';
|
||||
import { Template } from '../../../../common/types';
|
||||
import { serializeTemplate } from '../../../../../common/lib/template_serialization';
|
||||
import { Template } from '../../../../../common/types';
|
||||
import { StepProps } from '../types';
|
||||
|
||||
const { stripEmptyFields } = serializers;
|
|
@ -18,7 +18,7 @@ import {
|
|||
EuiCode,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { settingsDocumentationLink } from '../../../lib/documentation_links';
|
||||
import { documentationService } from '../../../services/documentation';
|
||||
import { StepProps } from '../types';
|
||||
import { useJsonStep } from './use_json_step';
|
||||
|
||||
|
@ -63,7 +63,7 @@ export const StepSettings: React.FunctionComponent<StepProps> = ({
|
|||
<EuiButtonEmpty
|
||||
size="s"
|
||||
flush="right"
|
||||
href={settingsDocumentationLink}
|
||||
href={documentationService.getSettingsDocumentationLink()}
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
>
|
|
@ -7,7 +7,7 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { isJSON } from '../../../../../../../../src/plugins/es_ui_shared/static/validators/string';
|
||||
import { isJSON } from '../../../../../../../../../src/plugins/es_ui_shared/static/validators/string';
|
||||
import { StepProps } from '../types';
|
||||
|
||||
interface Parameters {
|
|
@ -14,8 +14,8 @@ import {
|
|||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { serializers } from '../../../../../../../src/plugins/es_ui_shared/static/forms/helpers';
|
||||
import { Template } from '../../../common/types';
|
||||
import { serializers } from '../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers';
|
||||
import { Template } from '../../../../common/types';
|
||||
import { TemplateSteps } from './template_steps';
|
||||
import { StepAliases, StepLogistics, StepMappings, StepSettings, StepReview } from './steps';
|
||||
import { StepProps, DataGetterFunc } from './types';
|
|
@ -12,17 +12,17 @@ import {
|
|||
FormSchema,
|
||||
FIELD_TYPES,
|
||||
VALIDATION_TYPES,
|
||||
} from '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib';
|
||||
} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib';
|
||||
|
||||
import {
|
||||
fieldFormatters,
|
||||
fieldValidators,
|
||||
} from '../../../../../../../src/plugins/es_ui_shared/static/forms/helpers';
|
||||
} from '../../../../../../../../src/plugins/es_ui_shared/static/forms/helpers';
|
||||
|
||||
import {
|
||||
INVALID_INDEX_PATTERN_CHARS,
|
||||
INVALID_TEMPLATE_NAME_CHARS,
|
||||
} from '../../../common/constants';
|
||||
} from '../../../../common/constants';
|
||||
|
||||
const { emptyField, containsCharsField, startsWithField, indexPatternField } = fieldValidators;
|
||||
const { toInt } = fieldFormatters;
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Template } from '../../../common/types';
|
||||
import { Template } from '../../../../common/types';
|
||||
|
||||
export interface StepProps {
|
||||
template: Partial<Template>;
|
|
@ -13,3 +13,5 @@ export {
|
|||
TAB_STATS,
|
||||
TAB_EDIT_SETTINGS,
|
||||
} from './detail_panel_tabs';
|
||||
|
||||
export const REACT_ROOT_ID = 'indexManagementReactRoot';
|
36
x-pack/legacy/plugins/index_management/public/app/index.tsx
Normal file
36
x-pack/legacy/plugins/index_management/public/app/index.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
};
|
|
@ -14,7 +14,7 @@ import {
|
|||
INDEX_REFRESHING,
|
||||
INDEX_FLUSHING,
|
||||
INDEX_FORCEMERGING,
|
||||
} from '../../common/constants';
|
||||
} from '../../../common/constants';
|
||||
|
||||
export const indexStatusLabels = {
|
||||
[INDEX_CLEARING_CACHE]: i18n.translate('xpack.idxMgmt.indexStatusLabels.clearingCacheStatusLabel', {
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { unmountComponentAtNode } from 'react-dom';
|
||||
|
||||
export const manageAngularLifecycle = ($scope, $route, elem) => {
|
||||
export const manageAngularLifecycle = ($scope: any, $route: any, elem: HTMLElement | null) => {
|
||||
const lastRoute = $route.current;
|
||||
|
||||
const deregister = $scope.$on('$locationChangeSuccess', () => {
|
||||
|
@ -17,7 +17,12 @@ export const manageAngularLifecycle = ($scope, $route, elem) => {
|
|||
});
|
||||
|
||||
$scope.$on('$destroy', () => {
|
||||
deregister && deregister();
|
||||
elem && unmountComponentAtNode(elem);
|
||||
if (deregister) {
|
||||
deregister();
|
||||
}
|
||||
|
||||
if (elem) {
|
||||
unmountComponentAtNode(elem);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -8,7 +8,7 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiBadge, EuiSearchBar } from '@elastic/eui';
|
||||
import { getBadgeExtensions } from '../index_management_extensions';
|
||||
import { getBadgeExtensions } from '../../index_management_extensions';
|
||||
export const renderBadges = (index, filterChanged) => {
|
||||
const badgeLabels = [];
|
||||
getBadgeExtensions().forEach(({ matchIndex, label, color, filterExpression }) => {
|
|
@ -18,11 +18,11 @@ import {
|
|||
EuiTabs,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { BASE_PATH } from '../../../common/constants';
|
||||
import { idxMgmtDocumentationLink } from '../../lib/documentation_links';
|
||||
import { BASE_PATH } from '../../../../common/constants';
|
||||
import { documentationService } from '../../services/documentation';
|
||||
import { IndexList } from './index_list';
|
||||
import { TemplateList } from './template_list';
|
||||
import { setBreadcrumbs } from '../../services/set_breadcrumbs';
|
||||
import { breadcrumbService } from '../../services/breadcrumbs';
|
||||
|
||||
type Section = 'indices' | 'templates';
|
||||
|
||||
|
@ -57,7 +57,7 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
setBreadcrumbs();
|
||||
breadcrumbService.setBreadcrumbs('home');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
@ -75,7 +75,7 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
href={idxMgmtDocumentationLink}
|
||||
href={documentationService.getIdxMgmtDocumentationLink()}
|
||||
target="_blank"
|
||||
iconType="help"
|
||||
data-test-subj="documentationLink"
|
|
@ -21,7 +21,7 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { renderBadges } from '../../../../lib/render_badges';
|
||||
import { INDEX_OPEN } from '../../../../../common/constants';
|
||||
import { INDEX_OPEN } from '../../../../../../common/constants';
|
||||
import {
|
||||
TAB_SUMMARY,
|
||||
TAB_SETTINGS,
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { settingsDocumentationLink } from '../../../../../lib/documentation_links';
|
||||
import { documentationService } from '../../../../../services/documentation';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
|
@ -22,7 +22,7 @@ import { TAB_SETTINGS } from '../../../../../constants';
|
|||
import {
|
||||
settingsToDisplay,
|
||||
readOnlySettings
|
||||
} from '../../../../../lib/editSettings';
|
||||
} from '../../../../../lib/edit_settings';
|
||||
import { createAceEditor } from '../../../../../lib/ace';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
@ -144,7 +144,7 @@ export class EditSettingsJson extends React.PureComponent {
|
|||
</EuiFlexGroup>
|
||||
<EuiSpacer />
|
||||
<EuiLink
|
||||
href={settingsDocumentationLink}
|
||||
href={documentationService.getSettingsDocumentationLink()}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
|
@ -7,7 +7,6 @@
|
|||
import React, { Fragment } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { healthToColor } from '../../../../../services';
|
||||
import { getUrlService } from '../../../../../services/navigation';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
|
@ -20,7 +19,7 @@ import {
|
|||
EuiSpacer,
|
||||
EuiTitle
|
||||
} from '@elastic/eui';
|
||||
import { getSummaryExtensions } from '../../../../../index_management_extensions';
|
||||
import { getSummaryExtensions } from '../../../../../../index_management_extensions';
|
||||
const getHeaders = () =>{
|
||||
return {
|
||||
health: i18n.translate('xpack.idxMgmt.summary.headers.healthHeader', {
|
||||
|
@ -61,7 +60,7 @@ export class Summary extends React.PureComponent {
|
|||
return (
|
||||
<Fragment key={`summaryExtension-${i}`}>
|
||||
<EuiHorizontalRule />
|
||||
{ summaryExtension(index, getUrlService()) }
|
||||
{ summaryExtension(index) }
|
||||
</Fragment>
|
||||
);
|
||||
});
|
|
@ -23,8 +23,8 @@ import {
|
|||
EuiCheckbox
|
||||
} from '@elastic/eui';
|
||||
import { flattenPanelTree } from '../../../../lib/flatten_panel_tree';
|
||||
import { INDEX_OPEN } from '../../../../../common/constants';
|
||||
import { getActionExtensions } from '../../../../index_management_extensions';
|
||||
import { INDEX_OPEN } from '../../../../../../common/constants';
|
||||
import { getActionExtensions } from '../../../../../index_management_extensions';
|
||||
import { getHttpClient } from '../../../../services/api';
|
||||
export class IndexActionsContextMenu extends Component {
|
||||
constructor(props) {
|
|
@ -35,14 +35,15 @@ import {
|
|||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { UIM_SHOW_DETAILS_CLICK } from '../../../../../common/constants';
|
||||
import { UIM_SHOW_DETAILS_CLICK } from '../../../../../../common/constants';
|
||||
import { REFRESH_RATE_INDEX_LIST } from '../../../../constants';
|
||||
import { healthToColor, trackUiMetric } from '../../../../services';
|
||||
import { healthToColor } from '../../../../services';
|
||||
import { uiMetricService } from '../../../../services/ui_metric';
|
||||
import {
|
||||
getBannerExtensions,
|
||||
getFilterExtensions,
|
||||
getToggleExtensions,
|
||||
} from '../../../../index_management_extensions';
|
||||
} from '../../../../../index_management_extensions';
|
||||
import { renderBadges } from '../../../../lib/render_badges';
|
||||
import { NoMatch, PageErrorForbidden } from '../../../../components';
|
||||
import { IndexActionsContextMenu } from '../index_actions_context_menu';
|
||||
|
@ -218,10 +219,9 @@ export class IndexTable extends Component {
|
|||
return (
|
||||
<Fragment>
|
||||
<EuiLink
|
||||
className="indTable__link"
|
||||
data-test-subj="indexTableIndexNameLink"
|
||||
onClick={() => {
|
||||
trackUiMetric('click', UIM_SHOW_DETAILS_CLICK);
|
||||
uiMetricService.trackMetric('click', UIM_SHOW_DETAILS_CLICK);
|
||||
openDetailPanel(value);
|
||||
}}
|
||||
>
|
||||
|
@ -271,7 +271,8 @@ export class IndexTable extends Component {
|
|||
|
||||
renderError() {
|
||||
const { indicesError } = this.props;
|
||||
const data = indicesError.data ? indicesError.data : indicesError;
|
||||
|
||||
const data = indicesError.body ? indicesError.body : indicesError;
|
||||
|
||||
const {
|
||||
error: errorString,
|
|
@ -7,7 +7,7 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiCodeBlock, EuiCallOut } from '@elastic/eui';
|
||||
import { Template } from '../../../../../../common/types';
|
||||
import { Template } from '../../../../../../../common/types';
|
||||
|
||||
interface Props {
|
||||
templateDetails: Template;
|
|
@ -7,7 +7,7 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiCodeBlock, EuiCallOut } from '@elastic/eui';
|
||||
import { Template } from '../../../../../../common/types';
|
||||
import { Template } from '../../../../../../../common/types';
|
||||
|
||||
interface Props {
|
||||
templateDetails: Template;
|
|
@ -7,7 +7,7 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiCodeBlock, EuiCallOut } from '@elastic/eui';
|
||||
import { Template } from '../../../../../../common/types';
|
||||
import { Template } from '../../../../../../../common/types';
|
||||
|
||||
interface Props {
|
||||
templateDetails: Template;
|
|
@ -14,7 +14,7 @@ import {
|
|||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { Template } from '../../../../../../common/types';
|
||||
import { Template } from '../../../../../../../common/types';
|
||||
import { getILMPolicyPath } from '../../../../../services/navigation';
|
||||
|
||||
interface Props {
|
|
@ -29,13 +29,13 @@ import {
|
|||
UIM_TEMPLATE_DETAIL_PANEL_SUMMARY_TAB,
|
||||
UIM_TEMPLATE_DETAIL_PANEL_SETTINGS_TAB,
|
||||
UIM_TEMPLATE_DETAIL_PANEL_ALIASES_TAB,
|
||||
} from '../../../../../common/constants';
|
||||
import { Template } from '../../../../../common/types';
|
||||
} from '../../../../../../common/constants';
|
||||
import { Template } from '../../../../../../common/types';
|
||||
import { TemplateDeleteModal, SectionLoading, SectionError, Error } from '../../../../components';
|
||||
import { loadIndexTemplate } from '../../../../services/api';
|
||||
import { decodePath } from '../../../../services/routing';
|
||||
import { trackUiMetric, METRIC_TYPE } from '../../../../services/track_ui_metric';
|
||||
import { SendRequestResponse } from '../../../../shared_imports';
|
||||
import { uiMetricService } from '../../../../services/ui_metric';
|
||||
import { SendRequestResponse } from '../../../../../shared_imports';
|
||||
import { TabSummary, TabMappings, TabSettings, TabAliases } from './tabs';
|
||||
|
||||
interface Props {
|
||||
|
@ -164,7 +164,7 @@ export const TemplateDetails: React.FunctionComponent<Props> = ({
|
|||
{TABS.map(tab => (
|
||||
<EuiTab
|
||||
onClick={() => {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, tabToUiMetricMap[tab.id]);
|
||||
uiMetricService.trackMetric('click', tabToUiMetricMap[tab.id]);
|
||||
setActiveTab(tab.id);
|
||||
}}
|
||||
isSelected={tab.id === activeTab}
|
|
@ -19,14 +19,14 @@ import {
|
|||
import { SectionError, SectionLoading, Error } from '../../../components';
|
||||
import { TemplateTable } from './template_table';
|
||||
import { loadIndexTemplates } from '../../../services/api';
|
||||
import { Template } from '../../../../common/types';
|
||||
import { trackUiMetric, METRIC_TYPE } from '../../../services/track_ui_metric';
|
||||
import { Template } from '../../../../../common/types';
|
||||
import { uiMetricService } from '../../../services/ui_metric';
|
||||
import {
|
||||
getTemplateEditLink,
|
||||
getTemplateListLink,
|
||||
getTemplateCloneLink,
|
||||
} from '../../../services/routing';
|
||||
import { UIM_TEMPLATE_LIST_LOAD } from '../../../../common/constants';
|
||||
import { UIM_TEMPLATE_LIST_LOAD } from '../../../../../common/constants';
|
||||
import { TemplateDetails } from './template_details';
|
||||
|
||||
interface MatchParams {
|
||||
|
@ -66,7 +66,7 @@ export const TemplateList: React.FunctionComponent<RouteComponentProps<MatchPara
|
|||
|
||||
// Track component loaded
|
||||
useEffect(() => {
|
||||
trackUiMetric(METRIC_TYPE.LOADED, UIM_TEMPLATE_LIST_LOAD);
|
||||
uiMetricService.trackMetric('loaded', UIM_TEMPLATE_LIST_LOAD);
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
|
@ -8,12 +8,12 @@ import React, { useState, Fragment } from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiInMemoryTable, EuiIcon, EuiButton, EuiLink } from '@elastic/eui';
|
||||
import { TemplateListItem, Template } from '../../../../../common/types';
|
||||
import { BASE_PATH, UIM_TEMPLATE_SHOW_DETAILS_CLICK } from '../../../../../common/constants';
|
||||
import { TemplateListItem, Template } from '../../../../../../common/types';
|
||||
import { BASE_PATH, UIM_TEMPLATE_SHOW_DETAILS_CLICK } from '../../../../../../common/constants';
|
||||
import { TemplateDeleteModal } from '../../../../components';
|
||||
import { trackUiMetric, METRIC_TYPE } from '../../../../services/track_ui_metric';
|
||||
import { uiMetricService } from '../../../../services/ui_metric';
|
||||
import { getTemplateDetailsLink } from '../../../../services/routing';
|
||||
import { SendRequestResponse } from '../../../../shared_imports';
|
||||
import { SendRequestResponse } from '../../../../../shared_imports';
|
||||
|
||||
interface Props {
|
||||
templates: TemplateListItem[];
|
||||
|
@ -45,7 +45,7 @@ export const TemplateTable: React.FunctionComponent<Props> = ({
|
|||
<EuiLink
|
||||
href={getTemplateDetailsLink(name, true)}
|
||||
data-test-subj="templateDetailsLink"
|
||||
onClick={() => trackUiMetric(METRIC_TYPE.CLICK, UIM_TEMPLATE_SHOW_DETAILS_CLICK)}
|
||||
onClick={() => uiMetricService.trackMetric('click', UIM_TEMPLATE_SHOW_DETAILS_CLICK)}
|
||||
>
|
||||
{name}
|
||||
</EuiLink>
|
|
@ -8,9 +8,9 @@ import { RouteComponentProps } from 'react-router-dom';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import { TemplateForm, SectionLoading, SectionError, Error } from '../../components';
|
||||
import { setBreadcrumbs } from '../../services/set_breadcrumbs';
|
||||
import { breadcrumbService } from '../../services/breadcrumbs';
|
||||
import { decodePath, getTemplateDetailsLink } from '../../services/routing';
|
||||
import { Template } from '../../../common/types';
|
||||
import { Template } from '../../../../common/types';
|
||||
import { saveTemplate, loadIndexTemplate } from '../../services/api';
|
||||
|
||||
interface MatchParams {
|
||||
|
@ -56,7 +56,7 @@ export const TemplateClone: React.FunctionComponent<RouteComponentProps<MatchPar
|
|||
let content;
|
||||
|
||||
useEffect(() => {
|
||||
setBreadcrumbs('templateClone');
|
||||
breadcrumbService.setBreadcrumbs('templateClone');
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
|
@ -8,8 +8,8 @@ import { RouteComponentProps } from 'react-router-dom';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import { TemplateForm } from '../../components';
|
||||
import { setBreadcrumbs } from '../../services/set_breadcrumbs';
|
||||
import { Template } from '../../../common/types';
|
||||
import { breadcrumbService } from '../../services/breadcrumbs';
|
||||
import { Template } from '../../../../common/types';
|
||||
import { saveTemplate } from '../../services/api';
|
||||
import { getTemplateDetailsLink } from '../../services/routing';
|
||||
|
||||
|
@ -40,7 +40,7 @@ export const TemplateCreate: React.FunctionComponent<RouteComponentProps> = ({ h
|
|||
};
|
||||
|
||||
useEffect(() => {
|
||||
setBreadcrumbs('templateCreate');
|
||||
breadcrumbService.setBreadcrumbs('templateCreate');
|
||||
}, []);
|
||||
|
||||
return (
|
|
@ -7,11 +7,11 @@ import React, { useEffect, useState, Fragment } from 'react';
|
|||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiPageBody, EuiPageContent, EuiTitle, EuiSpacer, EuiCallOut } from '@elastic/eui';
|
||||
import { setBreadcrumbs } from '../../services/set_breadcrumbs';
|
||||
import { breadcrumbService } from '../../services/breadcrumbs';
|
||||
import { loadIndexTemplate, updateTemplate } from '../../services/api';
|
||||
import { decodePath, getTemplateDetailsLink } from '../../services/routing';
|
||||
import { SectionLoading, SectionError, TemplateForm, Error } from '../../components';
|
||||
import { Template } from '../../../common/types';
|
||||
import { Template } from '../../../../common/types';
|
||||
|
||||
interface MatchParams {
|
||||
name: string;
|
||||
|
@ -30,7 +30,7 @@ export const TemplateEdit: React.FunctionComponent<RouteComponentProps<MatchPara
|
|||
const { error, data: template, isLoading } = loadIndexTemplate(decodedTemplateName);
|
||||
|
||||
useEffect(() => {
|
||||
setBreadcrumbs('templateEdit');
|
||||
breadcrumbService.setBreadcrumbs('templateEdit');
|
||||
}, []);
|
||||
|
||||
const onSave = async (updatedTemplate: Template) => {
|
|
@ -4,9 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
import {
|
||||
API_BASE_PATH,
|
||||
UIM_UPDATE_SETTINGS,
|
||||
UIM_INDEX_CLEAR_CACHE,
|
||||
UIM_INDEX_CLEAR_CACHE_MANY,
|
||||
|
@ -31,13 +30,14 @@ import {
|
|||
UIM_TEMPLATE_CREATE,
|
||||
UIM_TEMPLATE_UPDATE,
|
||||
UIM_TEMPLATE_CLONE,
|
||||
} from '../../common/constants';
|
||||
} from '../../../common/constants';
|
||||
|
||||
import { TAB_SETTINGS, TAB_MAPPING, TAB_STATS } from '../constants';
|
||||
|
||||
import { trackUiMetric, METRIC_TYPE } from './track_ui_metric';
|
||||
import { uiMetricService } from './ui_metric';
|
||||
import { useRequest, sendRequest } from './use_request';
|
||||
import { Template } from '../../common/types';
|
||||
import { httpService } from './http';
|
||||
import { Template } from '../../../common/types';
|
||||
|
||||
let httpClient: ng.IHttpService;
|
||||
|
||||
|
@ -49,139 +49,143 @@ export const getHttpClient = () => {
|
|||
return httpClient;
|
||||
};
|
||||
|
||||
const apiPrefix = chrome.addBasePath('/api/index_management');
|
||||
|
||||
export async function loadIndices() {
|
||||
const response = await httpClient.get(`${apiPrefix}/indices`);
|
||||
return response.data;
|
||||
const response = await httpService.httpClient.get(`${API_BASE_PATH}/indices`);
|
||||
return response.data ? response.data : response;
|
||||
}
|
||||
|
||||
export async function reloadIndices(indexNames: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indexNames,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/reload`, body);
|
||||
return response.data;
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/reload`, { body });
|
||||
return response.data ? response.data : response;
|
||||
}
|
||||
|
||||
export async function closeIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/close`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/close`, { body });
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_CLOSE_MANY : UIM_INDEX_CLOSE;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function deleteIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/delete`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/delete`, { body });
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_DELETE_MANY : UIM_INDEX_DELETE;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function openIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/open`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/open`, { body });
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_OPEN_MANY : UIM_INDEX_OPEN;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function refreshIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/refresh`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/refresh`, { body });
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_REFRESH_MANY : UIM_INDEX_REFRESH;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function flushIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/flush`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/flush`, { body });
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_FLUSH_MANY : UIM_INDEX_FLUSH;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function forcemergeIndices(indices: string[], maxNumSegments: string) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
maxNumSegments,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/forcemerge`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/forcemerge`, {
|
||||
body,
|
||||
});
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_FORCE_MERGE_MANY : UIM_INDEX_FORCE_MERGE;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function clearCacheIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/clear_cache`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/clear_cache`, {
|
||||
body,
|
||||
});
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_CLEAR_CACHE_MANY : UIM_INDEX_CLEAR_CACHE;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
export async function freezeIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/freeze`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/freeze`, { body });
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_FREEZE_MANY : UIM_INDEX_FREEZE;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
export async function unfreezeIndices(indices: string[]) {
|
||||
const body = {
|
||||
const body = JSON.stringify({
|
||||
indices,
|
||||
};
|
||||
const response = await httpClient.post(`${apiPrefix}/indices/unfreeze`, body);
|
||||
});
|
||||
const response = await httpService.httpClient.post(`${API_BASE_PATH}/indices/unfreeze`, { body });
|
||||
// Only track successful requests.
|
||||
const eventName = indices.length > 1 ? UIM_INDEX_UNFREEZE_MANY : UIM_INDEX_UNFREEZE;
|
||||
trackUiMetric(METRIC_TYPE.COUNT, eventName);
|
||||
return response.data;
|
||||
uiMetricService.trackMetric('count', eventName);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function loadIndexSettings(indexName: string) {
|
||||
const response = await httpClient.get(`${apiPrefix}/settings/${indexName}`);
|
||||
return response.data;
|
||||
const response = await httpService.httpClient.get(`${API_BASE_PATH}/settings/${indexName}`);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function updateIndexSettings(indexName: string, settings: object) {
|
||||
const response = await httpClient.put(`${apiPrefix}/settings/${indexName}`, settings);
|
||||
export async function updateIndexSettings(indexName: string, body: object) {
|
||||
const response = await httpService.httpClient.put(`${API_BASE_PATH}/settings/${indexName}`, {
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
// Only track successful requests.
|
||||
trackUiMetric(METRIC_TYPE.COUNT, UIM_UPDATE_SETTINGS);
|
||||
uiMetricService.trackMetric('count', UIM_UPDATE_SETTINGS);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function loadIndexStats(indexName: string) {
|
||||
const response = await httpClient.get(`${apiPrefix}/stats/${indexName}`);
|
||||
return response.data;
|
||||
const response = await httpService.httpClient.get(`${API_BASE_PATH}/stats/${indexName}`);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function loadIndexMapping(indexName: string) {
|
||||
const response = await httpClient.get(`${apiPrefix}/mapping/${indexName}`);
|
||||
return response.data;
|
||||
const response = await httpService.httpClient.get(`${API_BASE_PATH}/mapping/${indexName}`);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function loadIndexData(type: string, indexName: string) {
|
||||
|
@ -199,61 +203,54 @@ export async function loadIndexData(type: string, indexName: string) {
|
|||
|
||||
export function loadIndexTemplates() {
|
||||
return useRequest({
|
||||
path: `${apiPrefix}/templates`,
|
||||
path: `${API_BASE_PATH}/templates`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteTemplates(names: Array<Template['name']>) {
|
||||
const result = sendRequest({
|
||||
path: `${apiPrefix}/templates/${names.map(name => encodeURIComponent(name)).join(',')}`,
|
||||
path: `${API_BASE_PATH}/templates/${names.map(name => encodeURIComponent(name)).join(',')}`,
|
||||
method: 'delete',
|
||||
});
|
||||
|
||||
const uimActionType = names.length > 1 ? UIM_TEMPLATE_DELETE_MANY : UIM_TEMPLATE_DELETE;
|
||||
|
||||
trackUiMetric(METRIC_TYPE.COUNT, uimActionType);
|
||||
uiMetricService.trackMetric('count', uimActionType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function loadIndexTemplate(name: Template['name']) {
|
||||
return useRequest({
|
||||
path: `${apiPrefix}/templates/${encodeURIComponent(name)}`,
|
||||
path: `${API_BASE_PATH}/templates/${encodeURIComponent(name)}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
export async function saveTemplate(template: Template, isClone?: boolean) {
|
||||
const result = sendRequest({
|
||||
path: `${apiPrefix}/templates`,
|
||||
const result = await sendRequest({
|
||||
path: `${API_BASE_PATH}/templates`,
|
||||
method: 'put',
|
||||
body: template,
|
||||
body: JSON.stringify(template),
|
||||
});
|
||||
|
||||
const uimActionType = isClone ? UIM_TEMPLATE_CLONE : UIM_TEMPLATE_CREATE;
|
||||
|
||||
trackUiMetric(METRIC_TYPE.COUNT, uimActionType);
|
||||
uiMetricService.trackMetric('count', uimActionType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function updateTemplate(template: Template) {
|
||||
const { name } = template;
|
||||
const result = sendRequest({
|
||||
path: `${apiPrefix}/templates/${encodeURIComponent(name)}`,
|
||||
const result = await sendRequest({
|
||||
path: `${API_BASE_PATH}/templates/${encodeURIComponent(name)}`,
|
||||
method: 'put',
|
||||
body: template,
|
||||
body: JSON.stringify(template),
|
||||
});
|
||||
|
||||
trackUiMetric(METRIC_TYPE.COUNT, UIM_TEMPLATE_UPDATE);
|
||||
uiMetricService.trackMetric('count', UIM_TEMPLATE_UPDATE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function loadTemplateToClone(name: Template['name']) {
|
||||
return sendRequest({
|
||||
path: `${apiPrefix}/templates/${encodeURIComponent(name)}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { BASE_PATH } from '../../../common/constants';
|
||||
import { ChromeStart } from '../../../../../../../src/core/public';
|
||||
|
||||
class BreadcrumbService {
|
||||
private chrome: ChromeStart | undefined;
|
||||
private breadcrumbs: {
|
||||
[key: string]: Array<{
|
||||
text: string;
|
||||
href?: string;
|
||||
}>;
|
||||
} = {
|
||||
management: [],
|
||||
home: [],
|
||||
};
|
||||
|
||||
public init(chrome: ChromeStart, managementBreadcrumb: any): void {
|
||||
this.chrome = chrome;
|
||||
this.breadcrumbs.management = [managementBreadcrumb];
|
||||
|
||||
this.breadcrumbs.home = [
|
||||
...this.breadcrumbs.management,
|
||||
{
|
||||
text: i18n.translate('xpack.idxMgmt.breadcrumb.homeLabel', {
|
||||
defaultMessage: 'Index Management',
|
||||
}),
|
||||
href: `#${BASE_PATH}`,
|
||||
},
|
||||
];
|
||||
|
||||
this.breadcrumbs.templates = [
|
||||
...this.breadcrumbs.home,
|
||||
{
|
||||
text: i18n.translate('xpack.idxMgmt.breadcrumb.templatesLabel', {
|
||||
defaultMessage: 'Templates',
|
||||
}),
|
||||
href: `#${BASE_PATH}templates`,
|
||||
},
|
||||
];
|
||||
|
||||
this.breadcrumbs.templateCreate = [
|
||||
...this.breadcrumbs.templates,
|
||||
{
|
||||
text: i18n.translate('xpack.idxMgmt.breadcrumb.createTemplateLabel', {
|
||||
defaultMessage: 'Create template',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
this.breadcrumbs.templateEdit = [
|
||||
...this.breadcrumbs.templates,
|
||||
{
|
||||
text: i18n.translate('xpack.idxMgmt.breadcrumb.editTemplateLabel', {
|
||||
defaultMessage: 'Edit template',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
this.breadcrumbs.templateClone = [
|
||||
...this.breadcrumbs.templates,
|
||||
{
|
||||
text: i18n.translate('xpack.idxMgmt.breadcrumb.cloneTemplateLabel', {
|
||||
defaultMessage: 'Clone template',
|
||||
}),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
public setBreadcrumbs(type: string): void {
|
||||
const newBreadcrumbs = this.breadcrumbs[type]
|
||||
? [...this.breadcrumbs[type]]
|
||||
: [...this.breadcrumbs.home];
|
||||
|
||||
// Pop off last breadcrumb
|
||||
const lastBreadcrumb = newBreadcrumbs.pop() as {
|
||||
text: string;
|
||||
href?: string;
|
||||
};
|
||||
|
||||
// Put last breadcrumb back without href
|
||||
newBreadcrumbs.push({
|
||||
...lastBreadcrumb,
|
||||
href: undefined,
|
||||
});
|
||||
|
||||
if (this.chrome) {
|
||||
this.chrome.setBreadcrumbs(newBreadcrumbs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const breadcrumbService = new BreadcrumbService();
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 { DocLinksStart } from '../../../../../../../src/core/public';
|
||||
|
||||
class DocumentationService {
|
||||
private esDocsBase: string = '';
|
||||
private kibanaDocsBase: string = '';
|
||||
|
||||
public init(docLinks: DocLinksStart): void {
|
||||
const { DOC_LINK_VERSION, ELASTIC_WEBSITE_URL } = docLinks;
|
||||
const docsBase = `${ELASTIC_WEBSITE_URL}guide/en`;
|
||||
|
||||
this.esDocsBase = `${docsBase}/elasticsearch/reference/${DOC_LINK_VERSION}`;
|
||||
this.kibanaDocsBase = `${docsBase}/kibana/${DOC_LINK_VERSION}`;
|
||||
}
|
||||
|
||||
public getSettingsDocumentationLink() {
|
||||
return `${this.esDocsBase}/index-modules.html#index-modules-settings`;
|
||||
}
|
||||
|
||||
public getMappingDocumentationLink() {
|
||||
return `${this.esDocsBase}/mapping.html`;
|
||||
}
|
||||
|
||||
public getTemplatesDocumentationLink() {
|
||||
return `${this.esDocsBase}/indices-templates.html`;
|
||||
}
|
||||
|
||||
public getIdxMgmtDocumentationLink() {
|
||||
return `${this.kibanaDocsBase}/managing-indices.html`;
|
||||
}
|
||||
}
|
||||
|
||||
export const documentationService = new DocumentationService();
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const healthToColor = health => {
|
||||
export const healthToColor = (health: 'green' | 'yellow' | 'red') => {
|
||||
switch (health) {
|
||||
case 'green':
|
||||
return 'success';
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 { HttpServiceBase } from '../../../../../../../src/core/public';
|
||||
|
||||
class HttpService {
|
||||
private client: any;
|
||||
|
||||
public init(httpClient: HttpServiceBase): void {
|
||||
this.client = httpClient;
|
||||
}
|
||||
|
||||
public get httpClient(): HttpServiceBase {
|
||||
return this.client;
|
||||
}
|
||||
}
|
||||
|
||||
export const httpService = new HttpService();
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue