Skip to content

Commit 03e2a68

Browse files
Index Management new platform migration (#49359)
* server np migration phase i * prep client code for np migration * create plugin definition for client * move to use client http service from core * move to use chrome service from core * move to use documentation service from core * use notification service from core * use i18n context from core * move ui_metric service to shim * fix error messages * fix build errors * clean up request logic * fix tests * fix ilm integration * fix ilm integration, remove unused scss * fix ts * fix ts
1 parent 32436cf commit 03e2a68

File tree

179 files changed

+1325
-769
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

179 files changed

+1325
-769
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { useEffect, useState, useRef } from 'react';
21+
22+
import { HttpServiceBase } from '../../../../../src/core/public';
23+
24+
export interface SendRequestConfig {
25+
path: string;
26+
method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head';
27+
body?: any;
28+
}
29+
30+
export interface SendRequestResponse {
31+
data: any;
32+
error: Error | null;
33+
}
34+
35+
export interface UseRequestConfig extends SendRequestConfig {
36+
pollIntervalMs?: number;
37+
initialData?: any;
38+
deserializer?: (data: any) => any;
39+
}
40+
41+
export interface UseRequestResponse {
42+
isInitialRequest: boolean;
43+
isLoading: boolean;
44+
error: null | unknown;
45+
data: any;
46+
sendRequest: (...args: any[]) => Promise<SendRequestResponse>;
47+
}
48+
49+
export const sendRequest = async (
50+
httpClient: HttpServiceBase,
51+
{ path, method, body }: SendRequestConfig
52+
): Promise<SendRequestResponse> => {
53+
try {
54+
const response = await httpClient[method](path, { body });
55+
56+
return {
57+
data: response.data ? response.data : response,
58+
error: null,
59+
};
60+
} catch (e) {
61+
return {
62+
data: null,
63+
error: e.response && e.response.data ? e.response.data : e.body,
64+
};
65+
}
66+
};
67+
68+
export const useRequest = (
69+
httpClient: HttpServiceBase,
70+
{
71+
path,
72+
method,
73+
body,
74+
pollIntervalMs,
75+
initialData,
76+
deserializer = (data: any): any => data,
77+
}: UseRequestConfig
78+
): UseRequestResponse => {
79+
// Main states for tracking request status and data
80+
const [error, setError] = useState<null | any>(null);
81+
const [isLoading, setIsLoading] = useState<boolean>(true);
82+
const [data, setData] = useState<any>(initialData);
83+
84+
// Consumers can use isInitialRequest to implement a polling UX.
85+
const [isInitialRequest, setIsInitialRequest] = useState<boolean>(true);
86+
const pollInterval = useRef<any>(null);
87+
const pollIntervalId = useRef<any>(null);
88+
89+
// We always want to use the most recently-set interval in scheduleRequest.
90+
pollInterval.current = pollIntervalMs;
91+
92+
// Tied to every render and bound to each request.
93+
let isOutdatedRequest = false;
94+
95+
const scheduleRequest = () => {
96+
// Clear current interval
97+
if (pollIntervalId.current) {
98+
clearTimeout(pollIntervalId.current);
99+
}
100+
101+
// Set new interval
102+
if (pollInterval.current) {
103+
pollIntervalId.current = setTimeout(_sendRequest, pollInterval.current);
104+
}
105+
};
106+
107+
const _sendRequest = async () => {
108+
// We don't clear error or data, so it's up to the consumer to decide whether to display the
109+
// "old" error/data or loading state when a new request is in-flight.
110+
setIsLoading(true);
111+
112+
const requestBody = {
113+
path,
114+
method,
115+
body,
116+
};
117+
118+
const response = await sendRequest(httpClient, requestBody);
119+
const { data: serializedResponseData, error: responseError } = response;
120+
const responseData = deserializer(serializedResponseData);
121+
122+
// If an outdated request has resolved, DON'T update state, but DO allow the processData handler
123+
// to execute side effects like update telemetry.
124+
if (isOutdatedRequest) {
125+
return { data: null, error: null };
126+
}
127+
128+
setError(responseError);
129+
setData(responseData);
130+
setIsLoading(false);
131+
setIsInitialRequest(false);
132+
133+
// If we're on an interval, we need to schedule the next request. This also allows us to reset
134+
// the interval if the user has manually requested the data, to avoid doubled-up requests.
135+
scheduleRequest();
136+
137+
return { data: serializedResponseData, error: responseError };
138+
};
139+
140+
useEffect(() => {
141+
_sendRequest();
142+
// To be functionally correct we'd send a new request if the method, path, or body changes.
143+
// But it doesn't seem likely that the method will change and body is likely to be a new
144+
// object even if its shape hasn't changed, so for now we're just watching the path.
145+
}, [path]);
146+
147+
useEffect(() => {
148+
scheduleRequest();
149+
150+
// Clean up intervals and inflight requests and corresponding state changes
151+
return () => {
152+
isOutdatedRequest = true;
153+
if (pollIntervalId.current) {
154+
clearTimeout(pollIntervalId.current);
155+
}
156+
};
157+
}, [pollIntervalMs]);
158+
159+
return {
160+
isInitialRequest,
161+
isLoading,
162+
error,
163+
data,
164+
sendRequest: _sendRequest, // Gives the user the ability to manually request data
165+
};
166+
};

x-pack/legacy/plugins/cross_cluster_replication/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { PLUGIN } from './common/constants';
99
import { registerLicenseChecker } from './server/lib/register_license_checker';
1010
import { registerRoutes } from './server/routes/register_routes';
1111
import { ccrDataEnricher } from './cross_cluster_replication_data';
12-
import { addIndexManagementDataEnricher } from '../index_management/index_management_data';
12+
import { addIndexManagementDataEnricher } from '../index_management/server/index_management_data';
1313
export function crossClusterReplication(kibana) {
1414
return new kibana.Plugin({
1515
id: PLUGIN.ID,

x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import React, { Component } from 'react';
88
import PropTypes from 'prop-types';
99
import { FormattedMessage } from '@kbn/i18n/react';
10-
import { getIndexListUri } from '../../../../../../../../index_management/public/services/navigation';
10+
import { getIndexListUri } from '../../../../../../../../index_management/public/app/services/navigation';
1111

1212
import {
1313
EuiButton,

x-pack/legacy/plugins/cross_cluster_replication/public/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import React, { Component, Fragment } from 'react';
88
import PropTypes from 'prop-types';
99
import { FormattedMessage } from '@kbn/i18n/react';
10-
import { getIndexListUri } from '../../../../../../../../index_management/public/services/navigation';
10+
import { getIndexListUri } from '../../../../../../../../index_management/public/app/services/navigation';
1111

1212
import {
1313
EuiButton,

x-pack/legacy/plugins/index_lifecycle_management/public/sections/policy_table/components/policy_table/policy_table.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
} from '@elastic/eui';
3737
import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services';
3838

39-
import { getIndexListUri } from '../../../../../../index_management/public/services/navigation';
39+
import { getIndexListUri } from '../../../../../../index_management/public/app/services/navigation';
4040
import { BASE_PATH, UIM_EDIT_CLICK } from '../../../../../common/constants';
4141
import { getPolicyPath } from '../../../../services/navigation';
4242
import { flattenPanelTree } from '../../../../services/flatten_panel_tree';

x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import {
1313
findTestSubject,
1414
nextTick,
1515
} from '../../../../../../test_utils';
16-
import { IndexManagementHome } from '../../../public/sections/home';
16+
import { IndexManagementHome } from '../../../public/app/sections/home';
1717
import { BASE_PATH } from '../../../common/constants';
18-
import { indexManagementStore } from '../../../public/store';
18+
import { indexManagementStore } from '../../../public/app/store';
1919
import { Template } from '../../../common/types';
2020

2121
const testBedConfig: TestBedConfig = {

x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,30 @@
55
*/
66

77
import sinon, { SinonFakeServer } from 'sinon';
8-
9-
const API_PATH = '/api/index_management';
8+
import { API_BASE_PATH } from '../../../common/constants';
109

1110
type HttpResponse = Record<string, any> | any[];
1211

1312
// Register helpers to mock HTTP Requests
1413
const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
1514
const setLoadTemplatesResponse = (response: HttpResponse = []) => {
16-
server.respondWith('GET', `${API_PATH}/templates`, [
15+
server.respondWith('GET', `${API_BASE_PATH}/templates`, [
1716
200,
1817
{ 'Content-Type': 'application/json' },
1918
JSON.stringify(response),
2019
]);
2120
};
2221

2322
const setLoadIndicesResponse = (response: HttpResponse = []) => {
24-
server.respondWith('GET', `${API_PATH}/indices`, [
23+
server.respondWith('GET', `${API_BASE_PATH}/indices`, [
2524
200,
2625
{ 'Content-Type': 'application/json' },
2726
JSON.stringify(response),
2827
]);
2928
};
3029

3130
const setDeleteTemplateResponse = (response: HttpResponse = []) => {
32-
server.respondWith('DELETE', `${API_PATH}/templates`, [
31+
server.respondWith('DELETE', `${API_BASE_PATH}/templates`, [
3332
200,
3433
{ 'Content-Type': 'application/json' },
3534
JSON.stringify(response),
@@ -40,18 +39,18 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
4039
const status = error ? error.status || 400 : 200;
4140
const body = error ? error.body : response;
4241

43-
server.respondWith('GET', `${API_PATH}/templates/:id`, [
42+
server.respondWith('GET', `${API_BASE_PATH}/templates/:id`, [
4443
status,
4544
{ 'Content-Type': 'application/json' },
4645
JSON.stringify(body),
4746
]);
4847
};
4948

5049
const setCreateTemplateResponse = (response?: HttpResponse, error?: any) => {
51-
const status = error ? error.status || 400 : 200;
50+
const status = error ? error.body.status || 400 : 200;
5251
const body = error ? JSON.stringify(error.body) : JSON.stringify(response);
5352

54-
server.respondWith('PUT', `${API_PATH}/templates`, [
53+
server.respondWith('PUT', `${API_BASE_PATH}/templates`, [
5554
status,
5655
{ 'Content-Type': 'application/json' },
5756
body,
@@ -62,7 +61,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
6261
const status = error ? error.status || 400 : 200;
6362
const body = error ? JSON.stringify(error.body) : JSON.stringify(response);
6463

65-
server.respondWith('PUT', `${API_PATH}/templates/:name`, [
64+
server.respondWith('PUT', `${API_BASE_PATH}/templates/:name`, [
6665
status,
6766
{ 'Content-Type': 'application/json' },
6867
body,

x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/setup_environment.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,30 @@
77
import axios from 'axios';
88
import axiosXhrAdapter from 'axios/lib/adapters/xhr';
99
import { init as initHttpRequests } from './http_requests';
10-
import { setHttpClient } from '../../../public/services/api';
10+
import { httpService } from '../../../public/app/services/http';
11+
import { breadcrumbService } from '../../../public/app/services/breadcrumbs';
12+
import { documentationService } from '../../../public/app/services/documentation';
13+
import { notificationService } from '../../../public/app/services/notification';
14+
import { uiMetricService } from '../../../public/app/services/ui_metric';
15+
import { createUiStatsReporter } from '../../../../../../../src/legacy/core_plugins/ui_metric/public';
16+
17+
/* eslint-disable @kbn/eslint/no-restricted-paths */
18+
import { notificationServiceMock } from '../../../../../../../src/core/public/notifications/notifications_service.mock';
19+
import { chromeServiceMock } from '../../../../../../../src/core/public/chrome/chrome_service.mock';
20+
import { docLinksServiceMock } from '../../../../../../../src/core/public/doc_links/doc_links_service.mock';
1121

1222
const mockHttpClient = axios.create({ adapter: axiosXhrAdapter });
1323

1424
export const setupEnvironment = () => {
15-
const { server, httpRequestsMockHelpers } = initHttpRequests();
16-
25+
// Mock initialization of services
1726
// @ts-ignore
18-
setHttpClient(mockHttpClient);
27+
httpService.init(mockHttpClient);
28+
breadcrumbService.init(chromeServiceMock.createStartContract(), '');
29+
documentationService.init(docLinksServiceMock.createStartContract());
30+
notificationService.init(notificationServiceMock.createStartContract());
31+
uiMetricService.init(createUiStatsReporter);
32+
33+
const { server, httpRequestsMockHelpers } = initHttpRequests();
1934

2035
return {
2136
server,

x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
88
import { BASE_PATH } from '../../../common/constants';
9-
import { TemplateClone } from '../../../public/sections/template_clone';
9+
import { TemplateClone } from '../../../public/app/sections/template_clone';
1010
import { formSetup } from './template_form.helpers';
1111
import { TEMPLATE_NAME } from './constants';
1212

x-pack/legacy/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import { registerTestBed, TestBedConfig } from '../../../../../../test_utils';
88
import { BASE_PATH } from '../../../common/constants';
9-
import { TemplateCreate } from '../../../public/sections/template_create';
9+
import { TemplateCreate } from '../../../public/app/sections/template_create';
1010
import { formSetup, TestSubjects } from './template_form.helpers';
1111

1212
const testBedConfig: TestBedConfig = {

0 commit comments

Comments
 (0)