From 279e57fa8e692e28de098ac398d62d83aee97fa2 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 28 Feb 2019 10:51:08 -0800 Subject: [PATCH 01/11] Initial plugin set up --- .i18nrc.json | 1 + x-pack/index.js | 2 + .../snapshot_restore/common/constants.ts | 12 +++ x-pack/plugins/snapshot_restore/index.ts | 27 +++++++ x-pack/plugins/snapshot_restore/plugin.ts | 32 ++++++++ .../public/_snapshot_restore.scss | 1 + .../snapshot_restore/public/app/index.tsx | 22 ++++++ .../snapshot_restore/public/index.html | 3 + .../snapshot_restore/public/index.scss | 13 ++++ .../plugins/snapshot_restore/public/index.ts | 9 +++ .../plugins/snapshot_restore/public/plugin.ts | 75 +++++++++++++++++++ .../plugins/snapshot_restore/public/shim.ts | 48 ++++++++++++ x-pack/plugins/snapshot_restore/shim.ts | 23 ++++++ x-pack/server/lib/create_router/index.d.ts | 26 +++++++ .../lib/register_license_checker/index.d.ts | 14 ++++ 15 files changed, 308 insertions(+) create mode 100644 x-pack/plugins/snapshot_restore/common/constants.ts create mode 100644 x-pack/plugins/snapshot_restore/index.ts create mode 100644 x-pack/plugins/snapshot_restore/plugin.ts create mode 100644 x-pack/plugins/snapshot_restore/public/_snapshot_restore.scss create mode 100644 x-pack/plugins/snapshot_restore/public/app/index.tsx create mode 100644 x-pack/plugins/snapshot_restore/public/index.html create mode 100644 x-pack/plugins/snapshot_restore/public/index.scss create mode 100644 x-pack/plugins/snapshot_restore/public/index.ts create mode 100644 x-pack/plugins/snapshot_restore/public/plugin.ts create mode 100644 x-pack/plugins/snapshot_restore/public/shim.ts create mode 100644 x-pack/plugins/snapshot_restore/shim.ts create mode 100644 x-pack/server/lib/create_router/index.d.ts create mode 100644 x-pack/server/lib/register_license_checker/index.d.ts diff --git a/.i18nrc.json b/.i18nrc.json index 6527a06b3fb7b..0a3b51bdeb73e 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -42,6 +42,7 @@ "xpack.searchProfiler": "x-pack/plugins/searchprofiler", "xpack.security": "x-pack/plugins/security", "xpack.server": "x-pack/server", + "xpack.snapshotRestore": "x-pack/plugins/snapshot_restore", "xpack.spaces": "x-pack/plugins/spaces", "xpack.upgradeAssistant": "x-pack/plugins/upgrade_assistant", "xpack.uptime": "x-pack/plugins/uptime", diff --git a/x-pack/index.js b/x-pack/index.js index 3c9f683ed0796..2fd774ee14219 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -37,6 +37,7 @@ import { translations } from './plugins/translations'; import { upgradeAssistant } from './plugins/upgrade_assistant'; import { uptime } from './plugins/uptime'; import { ossTelemetry } from './plugins/oss_telemetry'; +import { snapshotRestore } from './plugins/snapshot_restore'; module.exports = function (kibana) { return [ @@ -73,5 +74,6 @@ module.exports = function (kibana) { upgradeAssistant(kibana), uptime(kibana), ossTelemetry(kibana), + snapshotRestore(kibana), ]; }; diff --git a/x-pack/plugins/snapshot_restore/common/constants.ts b/x-pack/plugins/snapshot_restore/common/constants.ts new file mode 100644 index 0000000000000..1bb069cc2e445 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/common/constants.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export const PLUGIN = { + ID: 'snapshot_restore', + NAME: 'Snapshot and Restore', + MINIMUM_LICENSE_REQUIRED: 'basic', + CLIENT_BASE_PATH: '/management/elasticsearch/snapshot_restore', +}; diff --git a/x-pack/plugins/snapshot_restore/index.ts b/x-pack/plugins/snapshot_restore/index.ts new file mode 100644 index 0000000000000..53028f15aacf5 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/index.ts @@ -0,0 +1,27 @@ +/* + * 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 { Legacy } from 'kibana'; +import { resolve } from 'path'; +import { PLUGIN } from './common/constants'; +import { Plugin as SnapshotRestorePlugin } from './plugin'; + +export function snapshotRestore(kibana) { + return new kibana.Plugin({ + id: PLUGIN.ID, + configPrefix: 'xpack.snapshot_restore', + publicDir: resolve(__dirname, 'public'), + require: ['kibana', 'elasticsearch', 'xpack_main'], + uiExports: { + styleSheetPaths: resolve(__dirname, 'public/index.scss'), + managementSections: ['plugins/snapshot_restore'], + }, + init(server: Legacy.Server) { + const snapshotRestorePlugin = new SnapshotRestorePlugin(server); + snapshotRestorePlugin.start(); + }, + }); +} diff --git a/x-pack/plugins/snapshot_restore/plugin.ts b/x-pack/plugins/snapshot_restore/plugin.ts new file mode 100644 index 0000000000000..e2d8697e65162 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/plugin.ts @@ -0,0 +1,32 @@ +/* + * 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 { Legacy } from 'kibana'; +import { PLUGIN } from './common/constants'; +import { createShim } from './shim'; + +export class Plugin { + public server: Legacy.Server; + + constructor(server: Legacy.Server) { + this.server = server; + } + + public start(): void { + const server = this.server; + const { core, plugins } = createShim(server, PLUGIN.ID); + const router = core.http.createRouter('/api/snapshot/'); + + plugins.license.registerLicenseChecker( + server, + PLUGIN.ID, + PLUGIN.NAME, + PLUGIN.MINIMUM_LICENSE_REQUIRED + ); + router.get('test', async (req, callWithRequest, responseToolkit) => { + return responseToolkit.response('hello world'); + }); + } +} diff --git a/x-pack/plugins/snapshot_restore/public/_snapshot_restore.scss b/x-pack/plugins/snapshot_restore/public/_snapshot_restore.scss new file mode 100644 index 0000000000000..3a8e55e66336c --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/_snapshot_restore.scss @@ -0,0 +1 @@ +/* Snapshot and restore plugin styles */ diff --git a/x-pack/plugins/snapshot_restore/public/app/index.tsx b/x-pack/plugins/snapshot_restore/public/app/index.tsx new file mode 100644 index 0000000000000..5d11499240c0c --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/index.tsx @@ -0,0 +1,22 @@ +/* + * 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 { render } from 'react-dom'; +// import { Provider } from 'react-redux'; +import { HashRouter } from 'react-router-dom'; + +// import { App } from './app'; +// import { srStore } from './store'; + +export const renderReact = async (elem: Element, I18nContext: any): void => { + render( + + {/**/} + {/**/} + , + elem + ); +}; diff --git a/x-pack/plugins/snapshot_restore/public/index.html b/x-pack/plugins/snapshot_restore/public/index.html new file mode 100644 index 0000000000000..daa3283b7805d --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/index.html @@ -0,0 +1,3 @@ + +
+
diff --git a/x-pack/plugins/snapshot_restore/public/index.scss b/x-pack/plugins/snapshot_restore/public/index.scss new file mode 100644 index 0000000000000..7e9717645bf1f --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/index.scss @@ -0,0 +1,13 @@ +// Import the EUI global scope so we can use EUI constants +@import 'src/legacy/ui/public/styles/_styling_constants'; + +// Snapshot and restore plugin styles + +// Prefix all styles with "snapshot" to avoid conflicts. +// Examples +// snapshot +// snapshot__legend +// snapshot__legend--small +// snapshot__legend-isLoading + +@import 'snapshot_restore'; diff --git a/x-pack/plugins/snapshot_restore/public/index.ts b/x-pack/plugins/snapshot_restore/public/index.ts new file mode 100644 index 0000000000000..2e1cf15a00e65 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/index.ts @@ -0,0 +1,9 @@ +/* + * 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 { Plugin as SnapshotRestorePlugin } from './plugin'; + +const snapshotRestorePlugin = new SnapshotRestorePlugin(); +snapshotRestorePlugin.start(); diff --git a/x-pack/plugins/snapshot_restore/public/plugin.ts b/x-pack/plugins/snapshot_restore/public/plugin.ts new file mode 100644 index 0000000000000..0b23f6df321e9 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/plugin.ts @@ -0,0 +1,75 @@ +/* + * 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 { PLUGIN } from '../common/constants'; +import { renderReact } from './app'; +import template from './index.html'; +import { createShim } from './shim'; + +const REACT_ROOT_ID = 'snapshotRestoreReactRoot'; + +export class Plugin { + public start(): void { + const { + core: { i18n, routes, http }, + plugins: { management }, + } = createShim(); + + // Register management section + const esSection = management.getSection('elasticsearch'); + esSection.register(PLUGIN.ID, { + visible: true, + display: i18n.translate('xpack.snapshotRestore.appName', { + defaultMessage: 'Snapshot and Restore', + }), + order: 7, + url: `#${PLUGIN.CLIENT_BASE_PATH}/repositories`, + }); + + // Register react root + routes.when(`${PLUGIN.CLIENT_BASE_PATH}/:section?/:subsection?/:view?/:id`, { + template, + controller: ($scope, $route, $http, $q) => { + let elem; + + // React-router's does not play well with the angular router. It will cause this controller + // to re-execute without the $destroy handler being called. This means that the app will be mounted twice + // creating a memory leak when leaving (only 1 app will be unmounted). + // To avoid this, we unmount the React app each time we enter the controller. + routes.unmountReactApp(elem); + + // NOTE: We depend upon Angular's $http service because it's decorated with interceptors, + // e.g. to check license status per request. + http.setClient($http, $q); + + $scope.$$postDigest(() => { + elem = document.getElementById(REACT_ROOT_ID); + renderReact(elem, i18n.Context); + + // Angular Lifecycle + const appRoute = $route.current; + const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { + const currentRoute = $route.current; + const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; + + // When we navigate within SR, prevent Angular from re-matching the route and rebuild the app + if (isNavigationInApp) { + $route.current = appRoute; + } else { + // Any clean up when user leaves SR + } + + $scope.$on('$destroy', () => { + if (stopListeningForLocationChange) { + stopListeningForLocationChange(); + } + routes.unmountReactApp(elem); + }); + }); + }); + }, + }); + } +} diff --git a/x-pack/plugins/snapshot_restore/public/shim.ts b/x-pack/plugins/snapshot_restore/public/shim.ts new file mode 100644 index 0000000000000..8b8086e50d5cd --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/shim.ts @@ -0,0 +1,48 @@ +/* + * 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 { unmountComponentAtNode } from 'react-dom'; +import { I18nContext } from 'ui/i18n'; +import { management } from 'ui/management'; +import routes from 'ui/routes'; + +export function createShim() { + // This is an Angular service, which is why we use this provider pattern + // to access it within our React app. + let httpClient; + + // The deffered AngularJS api allows us to create deferred promise + // to be resolved later. This allows us to cancel in flight Http Requests + // https://docs.angularjs.org/api/ng/service/$q#the-deferred-api + let $q; + + return { + core: { + i18n: { + ...i18n, + Context: I18nContext, + }, + routes: { + when: routes.when, + unmountReactApp: (elem: Element | undefined): void => { + if (elem) { + unmountComponentAtNode(elem); + } + }, + }, + http: { + setClient: (client: any, $deferred: any): void => { + httpClient = client; + $q = $deferred; + }, + getClient: (): any => httpClient, + }, + }, + plugins: { + management, + }, + }; +} diff --git a/x-pack/plugins/snapshot_restore/shim.ts b/x-pack/plugins/snapshot_restore/shim.ts new file mode 100644 index 0000000000000..ff1a12dacad11 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/shim.ts @@ -0,0 +1,23 @@ +/* + * 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 { createRouter } from '../../server/lib/create_router'; +import { registerLicenseChecker } from '../../server/lib/register_license_checker'; + +export function createShim(server: any, pluginId: string) { + return { + core: { + http: { + createRouter: (basePath: string) => createRouter(server, pluginId, basePath), + }, + }, + plugins: { + license: { + registerLicenseChecker, + }, + }, + }; +} diff --git a/x-pack/server/lib/create_router/index.d.ts b/x-pack/server/lib/create_router/index.d.ts new file mode 100644 index 0000000000000..7049defd09e3d --- /dev/null +++ b/x-pack/server/lib/create_router/index.d.ts @@ -0,0 +1,26 @@ +/* + * 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 { Request, ResponseObject, ResponseToolkit } from 'hapi'; + +type CallWithRequest = (request: any, action: string, params: any) => any; +type RouterRoute = ( + path: string, + handler: ( + req: Request, + callWithRequest: CallWithRequest, + responseToolkit: ResponseToolkit + ) => Promise +) => Router; +interface Router { + get: RouterRoute; + post: RouterRoute; + put: RouterRoute; + delete: RouterRoute; + patch: RouterRoute; +} + +export declare function createRouter(server: any, pluginId: string, apiBasePath: string): Router; diff --git a/x-pack/server/lib/register_license_checker/index.d.ts b/x-pack/server/lib/register_license_checker/index.d.ts new file mode 100644 index 0000000000000..4bfcb56d9fa43 --- /dev/null +++ b/x-pack/server/lib/register_license_checker/index.d.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { LicenseType } from '../../../common/constants'; + +export declare function registerLicenseChecker( + server: any, + pluginId: string, + pluginName: string, + minimumLicenseRequired: LicenseType +): void; From dbba8b71c65a027ccca9168205dace180abdca36 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 28 Feb 2019 19:11:26 -0800 Subject: [PATCH 02/11] Set up client shell --- src/legacy/ui/public/management/index.d.ts | 4 + .../snapshot_restore/common/constants.ts | 1 - .../snapshot_restore/public/app/app.tsx | 32 +++++ .../public/app/constants/index.ts | 7 + .../snapshot_restore/public/app/index.tsx | 20 ++- .../public/app/sections/home/home.tsx | 124 ++++++++++++++++++ .../public/app/sections/home/index.ts | 7 + .../public/app/sections/index.ts | 9 ++ .../app/sections/repository_list/index.ts | 7 + .../repository_list/repository_list.tsx | 17 +++ .../app/sections/snapshot_list/index.ts | 7 + .../sections/snapshot_list/snapshot_list.tsx | 17 +++ .../public/app/services/app_context.ts | 9 ++ .../plugins/snapshot_restore/public/plugin.ts | 19 +-- .../plugins/snapshot_restore/public/shim.ts | 36 ++++- 15 files changed, 297 insertions(+), 19 deletions(-) create mode 100644 x-pack/plugins/snapshot_restore/public/app/app.tsx create mode 100644 x-pack/plugins/snapshot_restore/public/app/constants/index.ts create mode 100644 x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx create mode 100644 x-pack/plugins/snapshot_restore/public/app/sections/home/index.ts create mode 100644 x-pack/plugins/snapshot_restore/public/app/sections/index.ts create mode 100644 x-pack/plugins/snapshot_restore/public/app/sections/repository_list/index.ts create mode 100644 x-pack/plugins/snapshot_restore/public/app/sections/repository_list/repository_list.tsx create mode 100644 x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/index.ts create mode 100644 x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx create mode 100644 x-pack/plugins/snapshot_restore/public/app/services/app_context.ts diff --git a/src/legacy/ui/public/management/index.d.ts b/src/legacy/ui/public/management/index.d.ts index ed4658f82dea3..b5d927cd90433 100644 --- a/src/legacy/ui/public/management/index.d.ts +++ b/src/legacy/ui/public/management/index.d.ts @@ -28,4 +28,8 @@ declare module 'ui/management' { allowOverride: boolean ): void; export const management: any; // TODO - properly provide types + export const MANAGEMENT_BREADCRUMB: { + text: string; + href: string; + }; } diff --git a/x-pack/plugins/snapshot_restore/common/constants.ts b/x-pack/plugins/snapshot_restore/common/constants.ts index 1bb069cc2e445..ea1fa44316531 100644 --- a/x-pack/plugins/snapshot_restore/common/constants.ts +++ b/x-pack/plugins/snapshot_restore/common/constants.ts @@ -8,5 +8,4 @@ export const PLUGIN = { ID: 'snapshot_restore', NAME: 'Snapshot and Restore', MINIMUM_LICENSE_REQUIRED: 'basic', - CLIENT_BASE_PATH: '/management/elasticsearch/snapshot_restore', }; diff --git a/x-pack/plugins/snapshot_restore/public/app/app.tsx b/x-pack/plugins/snapshot_restore/public/app/app.tsx new file mode 100644 index 0000000000000..d018cbcfc5c51 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/app.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { Component } from 'react'; +import { Redirect, Route, Switch } from 'react-router-dom'; + +import { BASE_PATH } from './constants'; +import { AppContext } from './services/app_context'; + +import { SnapshotRestoreHome } from './sections'; + +export class App extends Component { + public static contextType = AppContext; + + constructor(...args) { + super(...args); + } + + public render() { + return ( +
+ + + + +
+ ); + } +} diff --git a/x-pack/plugins/snapshot_restore/public/app/constants/index.ts b/x-pack/plugins/snapshot_restore/public/app/constants/index.ts new file mode 100644 index 0000000000000..23c935b60a4b7 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/constants/index.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export const BASE_PATH = '/management/elasticsearch/snapshot_restore'; diff --git a/x-pack/plugins/snapshot_restore/public/app/index.tsx b/x-pack/plugins/snapshot_restore/public/app/index.tsx index 5d11499240c0c..888562c21d483 100644 --- a/x-pack/plugins/snapshot_restore/public/app/index.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/index.tsx @@ -3,19 +3,31 @@ * 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 React, { Component } from 'react'; import { render } from 'react-dom'; +import { AppContext } from './services/app_context'; + // import { Provider } from 'react-redux'; import { HashRouter } from 'react-router-dom'; -// import { App } from './app'; +import { App } from './app'; // import { srStore } from './store'; -export const renderReact = async (elem: Element, I18nContext: any): void => { +export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; + +export const renderReact = async (elem: Element, core: object, plugins: object): void => { + const { + i18n: { Context: I18nContext }, + } = core; + render( {/**/} - {/**/} + + + + + , elem ); diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx new file mode 100644 index 0000000000000..ae453aabcafb7 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx @@ -0,0 +1,124 @@ +/* + * 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, { PureComponent } from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs, EuiTitle } from '@elastic/eui'; + +import { BASE_PATH } from '../../constants'; +import { AppContext } from '../../services/app_context'; + +import { RepositoryList } from '../repository_list'; +import { SnapshotList } from '../snapshot_list'; + +export class SnapshotRestoreHome extends PureComponent { + public static contextType = AppContext; + + public static getDerivedStateFromProps(props) { + const { + match: { + params: { section }, + }, + } = props; + return { + activeSection: section, + }; + } + + public state = { + activeSection: 'repositories', + }; + + public componentDidMount() { + const { + core: { i18n, chrome }, + plugins: { management }, + } = this.context; + + chrome.breadcrumbs.set([ + management.constants.BREADCRUMB, + { + text: i18n.translate('xpack.snapshotRestore.home.BreadcrumbTitle', { + defaultMessage: 'Snapshot and Restore', + }), + href: `#${BASE_PATH}`, + }, + ]); + } + + public onSectionChange = section => { + const { history } = this.props; + history.push(`${BASE_PATH}/${section}`); + }; + + public render() { + const { + core: { + i18n: { FormattedMessage }, + }, + } = this.context; + const tabs = [ + { + id: 'snapshots', + name: ( + + ), + testSubj: 'srSnapshotsTab', + }, + { + id: 'repositories', + name: ( + + ), + testSubj: 'srRepositoriesTab', + }, + ]; + + return ( + + + +

+ +

+
+ + + + + {tabs.map(tab => ( + this.onSectionChange(tab.id)} + isSelected={tab.id === this.state.activeSection} + key={tab.id} + data-test-subject={tab.testSubj} + > + {tab.name} + + ))} + + + + + + + + +
+
+ ); + } +} diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/home/index.ts b/x-pack/plugins/snapshot_restore/public/app/sections/home/index.ts new file mode 100644 index 0000000000000..eef70309b49cf --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/sections/home/index.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export { SnapshotRestoreHome } from './home'; diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/index.ts b/x-pack/plugins/snapshot_restore/public/app/sections/index.ts new file mode 100644 index 0000000000000..fdd85f572aa88 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/sections/index.ts @@ -0,0 +1,9 @@ +/* + * 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. + */ + +export { SnapshotRestoreHome } from './home'; +// export { RepositoryAdd } from './repository_add'; +// export { RepositoryEdit } from './repository_edit'; diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/index.ts b/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/index.ts new file mode 100644 index 0000000000000..63d63db1d81cc --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/index.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export { RepositoryList } from './repository_list'; diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/repository_list.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/repository_list.tsx new file mode 100644 index 0000000000000..71f753aa3fe13 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/repository_list.tsx @@ -0,0 +1,17 @@ +/* + * 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, { PureComponent } from 'react'; + +import { AppContext } from '../../services/app_context'; + +export class RepositoryList extends PureComponent { + public static contextType = AppContext; + + public render() { + return
List of repositories
; + } +} diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/index.ts b/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/index.ts new file mode 100644 index 0000000000000..f7029f9693e0b --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/index.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export { SnapshotList } from './snapshot_list'; diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx new file mode 100644 index 0000000000000..7825d568f09d9 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx @@ -0,0 +1,17 @@ +/* + * 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, { PureComponent } from 'react'; + +import { AppContext } from '../../services/app_context'; + +export class SnapshotList extends PureComponent { + public static contextType = AppContext; + + public render() { + return
List of snapshots
; + } +} diff --git a/x-pack/plugins/snapshot_restore/public/app/services/app_context.ts b/x-pack/plugins/snapshot_restore/public/app/services/app_context.ts new file mode 100644 index 0000000000000..d6f5b213f6cf9 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/app/services/app_context.ts @@ -0,0 +1,9 @@ +/* + * 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'; + +export const AppContext = React.createContext({}); diff --git a/x-pack/plugins/snapshot_restore/public/plugin.ts b/x-pack/plugins/snapshot_restore/public/plugin.ts index 0b23f6df321e9..15a54340710bf 100644 --- a/x-pack/plugins/snapshot_restore/public/plugin.ts +++ b/x-pack/plugins/snapshot_restore/public/plugin.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { PLUGIN } from '../common/constants'; -import { renderReact } from './app'; +import { CLIENT_BASE_PATH, renderReact } from './app'; import template from './index.html'; import { createShim } from './shim'; @@ -12,24 +12,25 @@ const REACT_ROOT_ID = 'snapshotRestoreReactRoot'; export class Plugin { public start(): void { + const shim = createShim(); const { - core: { i18n, routes, http }, + core: { i18n, routing, http }, plugins: { management }, - } = createShim(); + } = shim; // Register management section - const esSection = management.getSection('elasticsearch'); + const esSection = management.sections.getSection('elasticsearch'); esSection.register(PLUGIN.ID, { visible: true, display: i18n.translate('xpack.snapshotRestore.appName', { defaultMessage: 'Snapshot and Restore', }), order: 7, - url: `#${PLUGIN.CLIENT_BASE_PATH}/repositories`, + url: `#${CLIENT_BASE_PATH}/repositories`, }); // Register react root - routes.when(`${PLUGIN.CLIENT_BASE_PATH}/:section?/:subsection?/:view?/:id`, { + routing.registerAngularRoute(`${CLIENT_BASE_PATH}/:section?/:subsection?/:view?/:id`, { template, controller: ($scope, $route, $http, $q) => { let elem; @@ -38,7 +39,7 @@ export class Plugin { // to re-execute without the $destroy handler being called. This means that the app will be mounted twice // creating a memory leak when leaving (only 1 app will be unmounted). // To avoid this, we unmount the React app each time we enter the controller. - routes.unmountReactApp(elem); + routing.unmountReactApp(elem); // NOTE: We depend upon Angular's $http service because it's decorated with interceptors, // e.g. to check license status per request. @@ -46,7 +47,7 @@ export class Plugin { $scope.$$postDigest(() => { elem = document.getElementById(REACT_ROOT_ID); - renderReact(elem, i18n.Context); + renderReact(elem, shim.core, shim.plugins); // Angular Lifecycle const appRoute = $route.current; @@ -65,7 +66,7 @@ export class Plugin { if (stopListeningForLocationChange) { stopListeningForLocationChange(); } - routes.unmountReactApp(elem); + routing.unmountReactApp(elem); }); }); }); diff --git a/x-pack/plugins/snapshot_restore/public/shim.ts b/x-pack/plugins/snapshot_restore/public/shim.ts index 8b8086e50d5cd..73cf8959624da 100644 --- a/x-pack/plugins/snapshot_restore/public/shim.ts +++ b/x-pack/plugins/snapshot_restore/public/shim.ts @@ -4,11 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import { unmountComponentAtNode } from 'react-dom'; +import { FormattedMessage } from '@kbn/i18n/react'; import { I18nContext } from 'ui/i18n'; -import { management } from 'ui/management'; + +import chrome from 'ui/chrome'; +import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; +import { fatalError } from 'ui/notify'; import routes from 'ui/routes'; +import { unmountComponentAtNode } from 'react-dom'; +import { HashRouter } from 'react-router-dom'; + export function createShim() { // This is an Angular service, which is why we use this provider pattern // to access it within our React app. @@ -19,19 +25,30 @@ export function createShim() { // https://docs.angularjs.org/api/ng/service/$q#the-deferred-api let $q; + let reactRouter; + return { core: { i18n: { ...i18n, Context: I18nContext, + FormattedMessage, }, - routes: { - when: routes.when, + routing: { + registerAngularRoute: (path: string, config: object): void => { + routes.when(path, config); + }, unmountReactApp: (elem: Element | undefined): void => { if (elem) { unmountComponentAtNode(elem); } }, + registerRouter: (router: HashRouter): void => { + reactRouter = router; + }, + getRouter: (): HashRouter => { + return reactRouter; + }, }, http: { setClient: (client: any, $deferred: any): void => { @@ -40,9 +57,18 @@ export function createShim() { }, getClient: (): any => httpClient, }, + chrome, + notification: { + fatalError, + }, }, plugins: { - management, + management: { + sections: management, + constants: { + BREADCRUMB: MANAGEMENT_BREADCRUMB, + }, + }, }, }; } From bc0171da3ea8808c6cc13b5ea39f2e739106c5ea Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 28 Feb 2019 21:20:01 -0800 Subject: [PATCH 03/11] Add initial repository list routes --- x-pack/plugins/snapshot_restore/plugin.ts | 10 +++--- .../server/routes/api/register_routes.ts | 11 ++++++ .../server/routes/api/repositories.ts | 36 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts create mode 100644 x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts diff --git a/x-pack/plugins/snapshot_restore/plugin.ts b/x-pack/plugins/snapshot_restore/plugin.ts index e2d8697e65162..88c0ac45742eb 100644 --- a/x-pack/plugins/snapshot_restore/plugin.ts +++ b/x-pack/plugins/snapshot_restore/plugin.ts @@ -5,6 +5,7 @@ */ import { Legacy } from 'kibana'; import { PLUGIN } from './common/constants'; +import { registerRoutes } from './server/routes/api/register_routes'; import { createShim } from './shim'; export class Plugin { @@ -17,16 +18,17 @@ export class Plugin { public start(): void { const server = this.server; const { core, plugins } = createShim(server, PLUGIN.ID); - const router = core.http.createRouter('/api/snapshot/'); + const router = core.http.createRouter('/api/snapshot_restore/'); + // Register license checker plugins.license.registerLicenseChecker( server, PLUGIN.ID, PLUGIN.NAME, PLUGIN.MINIMUM_LICENSE_REQUIRED ); - router.get('test', async (req, callWithRequest, responseToolkit) => { - return responseToolkit.response('hello world'); - }); + + // Register routes + registerRoutes(router); } } diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts b/x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts new file mode 100644 index 0000000000000..737fd70381c55 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts @@ -0,0 +1,11 @@ +/* + * 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 { getAll, getOne } from './repositories'; + +export const registerRoutes = (router: any): void => { + router[getAll.method](getAll.path, getAll.handler); + router[getOne.method](getOne.path, getOne.handler); +}; diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts b/x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts new file mode 100644 index 0000000000000..d54f6241d131a --- /dev/null +++ b/x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts @@ -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. + */ + +export const getAll = { + path: 'repositories', + method: 'get', + handler: async (req: any, callWithRequest: any, responseToolkit: any) => { + const repositoriesByName = await callWithRequest('snapshot.getRepository', { + repository: '_all', + }); + const repositories = Object.keys(repositoriesByName).map(name => { + return { + name, + ...repositoriesByName[name], + }; + }); + return repositories; + }, +}; + +export const getOne = { + path: 'repositories/{name}', + method: 'get', + handler: async (req: any, callWithRequest: any, responseToolkit: any) => { + const { name } = req.params; + const repositoryByName = await callWithRequest('snapshot.getRepository', { repository: name }); + if (repositoryByName[name]) { + return repositoryByName[name]; + } else { + return {}; + } + }, +}; From d312b2224707d42cae898bb1102bb31127dbefbb Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Wed, 6 Mar 2019 13:15:20 -0800 Subject: [PATCH 04/11] Fix merge issues and some typings --- x-pack/plugins/snapshot_restore/common/constants.ts | 4 +++- x-pack/plugins/snapshot_restore/public/app/index.tsx | 2 +- x-pack/plugins/snapshot_restore/public/plugin.ts | 4 ++-- x-pack/plugins/snapshot_restore/public/shim.ts | 10 +++++----- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/snapshot_restore/common/constants.ts b/x-pack/plugins/snapshot_restore/common/constants.ts index ea1fa44316531..4589fa3f885d8 100644 --- a/x-pack/plugins/snapshot_restore/common/constants.ts +++ b/x-pack/plugins/snapshot_restore/common/constants.ts @@ -4,8 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import { LicenseType } from '../../../common/constants'; + export const PLUGIN = { ID: 'snapshot_restore', NAME: 'Snapshot and Restore', - MINIMUM_LICENSE_REQUIRED: 'basic', + MINIMUM_LICENSE_REQUIRED: 'basic', }; diff --git a/x-pack/plugins/snapshot_restore/public/app/index.tsx b/x-pack/plugins/snapshot_restore/public/app/index.tsx index 888562c21d483..6b2904f7cbf4c 100644 --- a/x-pack/plugins/snapshot_restore/public/app/index.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/index.tsx @@ -15,7 +15,7 @@ import { App } from './app'; export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; -export const renderReact = async (elem: Element, core: object, plugins: object): void => { +export const renderReact = async (elem: Element | null, core: object, plugins: object): Promise => { const { i18n: { Context: I18nContext }, } = core; diff --git a/x-pack/plugins/snapshot_restore/public/plugin.ts b/x-pack/plugins/snapshot_restore/public/plugin.ts index 15a54340710bf..1b59987452077 100644 --- a/x-pack/plugins/snapshot_restore/public/plugin.ts +++ b/x-pack/plugins/snapshot_restore/public/plugin.ts @@ -32,8 +32,8 @@ export class Plugin { // Register react root routing.registerAngularRoute(`${CLIENT_BASE_PATH}/:section?/:subsection?/:view?/:id`, { template, - controller: ($scope, $route, $http, $q) => { - let elem; + controller: ($scope: any, $route: any, $http: any, $q: any) => { + let elem: Element | null | undefined; // React-router's does not play well with the angular router. It will cause this controller // to re-execute without the $destroy handler being called. This means that the app will be mounted twice diff --git a/x-pack/plugins/snapshot_restore/public/shim.ts b/x-pack/plugins/snapshot_restore/public/shim.ts index 73cf8959624da..399d77aaa9435 100644 --- a/x-pack/plugins/snapshot_restore/public/shim.ts +++ b/x-pack/plugins/snapshot_restore/public/shim.ts @@ -18,14 +18,14 @@ import { HashRouter } from 'react-router-dom'; export function createShim() { // This is an Angular service, which is why we use this provider pattern // to access it within our React app. - let httpClient; + let httpClient: any; // The deffered AngularJS api allows us to create deferred promise // to be resolved later. This allows us to cancel in flight Http Requests // https://docs.angularjs.org/api/ng/service/$q#the-deferred-api - let $q; + let $q: any; - let reactRouter; + let reactRouter: HashRouter | undefined; return { core: { @@ -38,7 +38,7 @@ export function createShim() { registerAngularRoute: (path: string, config: object): void => { routes.when(path, config); }, - unmountReactApp: (elem: Element | undefined): void => { + unmountReactApp: (elem: Element | undefined | null): void => { if (elem) { unmountComponentAtNode(elem); } @@ -46,7 +46,7 @@ export function createShim() { registerRouter: (router: HashRouter): void => { reactRouter = router; }, - getRouter: (): HashRouter => { + getRouter: (): undefined | HashRouter => { return reactRouter; }, }, From 4f329b591debb94478e1a2a7133ac2a51a1e8a56 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Wed, 6 Mar 2019 15:56:16 -0800 Subject: [PATCH 05/11] Decouple server from plugin.ts files, tighten up typings --- .../snapshot_restore/common/constants.ts | 2 +- x-pack/plugins/snapshot_restore/index.ts | 18 +++++++-- x-pack/plugins/snapshot_restore/plugin.ts | 22 +--------- .../snapshot_restore/public/app/app.tsx | 4 -- .../snapshot_restore/public/app/index.tsx | 18 +++++++-- .../public/app/sections/home/home.tsx | 38 ++++++++++++------ .../repository_list/repository_list.tsx | 1 + .../sections/snapshot_list/snapshot_list.tsx | 1 + .../public/app/services/app_context.ts | 8 +++- .../plugins/snapshot_restore/public/index.ts | 4 +- .../plugins/snapshot_restore/public/plugin.ts | 17 ++++---- .../plugins/snapshot_restore/public/shim.ts | 40 ++++++++++++++++++- x-pack/plugins/snapshot_restore/shim.ts | 20 +++++++++- x-pack/server/lib/create_router/index.d.ts | 11 +++-- .../lib/register_license_checker/index.d.ts | 3 +- 15 files changed, 145 insertions(+), 62 deletions(-) diff --git a/x-pack/plugins/snapshot_restore/common/constants.ts b/x-pack/plugins/snapshot_restore/common/constants.ts index 4589fa3f885d8..6868eef082af1 100644 --- a/x-pack/plugins/snapshot_restore/common/constants.ts +++ b/x-pack/plugins/snapshot_restore/common/constants.ts @@ -9,5 +9,5 @@ import { LicenseType } from '../../../common/constants'; export const PLUGIN = { ID: 'snapshot_restore', NAME: 'Snapshot and Restore', - MINIMUM_LICENSE_REQUIRED: 'basic', + MINIMUM_LICENSE_REQUIRED: 'basic' as LicenseType, }; diff --git a/x-pack/plugins/snapshot_restore/index.ts b/x-pack/plugins/snapshot_restore/index.ts index 53028f15aacf5..dedaad5a428a9 100644 --- a/x-pack/plugins/snapshot_restore/index.ts +++ b/x-pack/plugins/snapshot_restore/index.ts @@ -8,8 +8,9 @@ import { Legacy } from 'kibana'; import { resolve } from 'path'; import { PLUGIN } from './common/constants'; import { Plugin as SnapshotRestorePlugin } from './plugin'; +import { createShim } from './shim'; -export function snapshotRestore(kibana) { +export function snapshotRestore(kibana: any) { return new kibana.Plugin({ id: PLUGIN.ID, configPrefix: 'xpack.snapshot_restore', @@ -20,8 +21,19 @@ export function snapshotRestore(kibana) { managementSections: ['plugins/snapshot_restore'], }, init(server: Legacy.Server) { - const snapshotRestorePlugin = new SnapshotRestorePlugin(server); - snapshotRestorePlugin.start(); + const { core, plugins } = createShim(server, PLUGIN.ID); + const snapshotRestorePlugin = new SnapshotRestorePlugin(); + + // Start plugin + snapshotRestorePlugin.start(core, plugins); + + // Register license checker + plugins.license.registerLicenseChecker( + server, + PLUGIN.ID, + PLUGIN.NAME, + PLUGIN.MINIMUM_LICENSE_REQUIRED + ); }, }); } diff --git a/x-pack/plugins/snapshot_restore/plugin.ts b/x-pack/plugins/snapshot_restore/plugin.ts index 88c0ac45742eb..7668eb5cee9dd 100644 --- a/x-pack/plugins/snapshot_restore/plugin.ts +++ b/x-pack/plugins/snapshot_restore/plugin.ts @@ -3,31 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Legacy } from 'kibana'; -import { PLUGIN } from './common/constants'; import { registerRoutes } from './server/routes/api/register_routes'; -import { createShim } from './shim'; +import { Core, Plugins } from './shim'; export class Plugin { - public server: Legacy.Server; - - constructor(server: Legacy.Server) { - this.server = server; - } - - public start(): void { - const server = this.server; - const { core, plugins } = createShim(server, PLUGIN.ID); + public start(core: Core, plugins: Plugins): void { const router = core.http.createRouter('/api/snapshot_restore/'); - // Register license checker - plugins.license.registerLicenseChecker( - server, - PLUGIN.ID, - PLUGIN.NAME, - PLUGIN.MINIMUM_LICENSE_REQUIRED - ); - // Register routes registerRoutes(router); } diff --git a/x-pack/plugins/snapshot_restore/public/app/app.tsx b/x-pack/plugins/snapshot_restore/public/app/app.tsx index d018cbcfc5c51..28c40d15be1d8 100644 --- a/x-pack/plugins/snapshot_restore/public/app/app.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/app.tsx @@ -15,10 +15,6 @@ import { SnapshotRestoreHome } from './sections'; export class App extends Component { public static contextType = AppContext; - constructor(...args) { - super(...args); - } - public render() { return (
diff --git a/x-pack/plugins/snapshot_restore/public/app/index.tsx b/x-pack/plugins/snapshot_restore/public/app/index.tsx index 6b2904f7cbf4c..3354d84fce23d 100644 --- a/x-pack/plugins/snapshot_restore/public/app/index.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/index.tsx @@ -3,9 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Component } from 'react'; +import React from 'react'; import { render } from 'react-dom'; -import { AppContext } from './services/app_context'; +import { AppCore, AppPlugins } from '../shim'; +import { AppContext, AppContextInterface } from './services/app_context'; // import { Provider } from 'react-redux'; import { HashRouter } from 'react-router-dom'; @@ -15,16 +16,25 @@ import { App } from './app'; export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; -export const renderReact = async (elem: Element | null, core: object, plugins: object): Promise => { +export const renderReact = async ( + elem: Element | null, + core: AppCore, + plugins: AppPlugins +): Promise => { const { i18n: { Context: I18nContext }, } = core; + const appContext: AppContextInterface = { + core, + plugins, + }; + render( {/**/} - + diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx index ae453aabcafb7..3216af5c3246f 100644 --- a/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx @@ -5,39 +5,52 @@ */ import React, { PureComponent } from 'react'; -import { Route, Switch } from 'react-router-dom'; +import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs, EuiTitle } from '@elastic/eui'; import { BASE_PATH } from '../../constants'; -import { AppContext } from '../../services/app_context'; +import { AppContext, AppContextInterface } from '../../services/app_context'; import { RepositoryList } from '../repository_list'; import { SnapshotList } from '../snapshot_list'; -export class SnapshotRestoreHome extends PureComponent { +type Section = 'repositories' | 'snapshots'; + +interface MatchParams { + section: Section; +} + +interface Props extends RouteComponentProps {} + +interface State { + activeSection: Section; +} + +export class SnapshotRestoreHome extends PureComponent { public static contextType = AppContext; - public static getDerivedStateFromProps(props) { + public static getDerivedStateFromProps(nextProps: Props) { const { match: { params: { section }, }, - } = props; + } = nextProps; return { activeSection: section, }; } + public context!: React.ContextType; - public state = { - activeSection: 'repositories', + public readonly state: Readonly = { + activeSection: 'repositories' as Section, }; public componentDidMount() { const { core: { i18n, chrome }, plugins: { management }, - } = this.context; + } = this.context as AppContextInterface; chrome.breadcrumbs.set([ management.constants.BREADCRUMB, @@ -50,7 +63,7 @@ export class SnapshotRestoreHome extends PureComponent { ]); } - public onSectionChange = section => { + public onSectionChange = (section: Section): void => { const { history } = this.props; history.push(`${BASE_PATH}/${section}`); }; @@ -60,10 +73,11 @@ export class SnapshotRestoreHome extends PureComponent { core: { i18n: { FormattedMessage }, }, - } = this.context; + } = this.context as AppContextInterface; + const tabs = [ { - id: 'snapshots', + id: 'snapshots' as Section, name: ( ; public render() { return
List of repositories
; diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx index 7825d568f09d9..383d5d86e46cb 100644 --- a/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx @@ -10,6 +10,7 @@ import { AppContext } from '../../services/app_context'; export class SnapshotList extends PureComponent { public static contextType = AppContext; + public context!: React.ContextType; public render() { return
List of snapshots
; diff --git a/x-pack/plugins/snapshot_restore/public/app/services/app_context.ts b/x-pack/plugins/snapshot_restore/public/app/services/app_context.ts index d6f5b213f6cf9..7d31c2744ab8b 100644 --- a/x-pack/plugins/snapshot_restore/public/app/services/app_context.ts +++ b/x-pack/plugins/snapshot_restore/public/app/services/app_context.ts @@ -5,5 +5,11 @@ */ import React from 'react'; +import { AppCore, AppPlugins } from '../../shim'; -export const AppContext = React.createContext({}); +export interface AppContextInterface { + core: AppCore; + plugins: AppPlugins; +} + +export const AppContext = React.createContext(null); diff --git a/x-pack/plugins/snapshot_restore/public/index.ts b/x-pack/plugins/snapshot_restore/public/index.ts index 2e1cf15a00e65..b23ce6232c2d4 100644 --- a/x-pack/plugins/snapshot_restore/public/index.ts +++ b/x-pack/plugins/snapshot_restore/public/index.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { Plugin as SnapshotRestorePlugin } from './plugin'; +import { createShim } from './shim'; +const { core, plugins } = createShim(); const snapshotRestorePlugin = new SnapshotRestorePlugin(); -snapshotRestorePlugin.start(); +snapshotRestorePlugin.start(core, plugins); diff --git a/x-pack/plugins/snapshot_restore/public/plugin.ts b/x-pack/plugins/snapshot_restore/public/plugin.ts index 1b59987452077..05743b1dcb715 100644 --- a/x-pack/plugins/snapshot_restore/public/plugin.ts +++ b/x-pack/plugins/snapshot_restore/public/plugin.ts @@ -6,17 +6,14 @@ import { PLUGIN } from '../common/constants'; import { CLIENT_BASE_PATH, renderReact } from './app'; import template from './index.html'; -import { createShim } from './shim'; +import { AppCore, AppPlugins, Core, Plugins } from './shim'; const REACT_ROOT_ID = 'snapshotRestoreReactRoot'; export class Plugin { - public start(): void { - const shim = createShim(); - const { - core: { i18n, routing, http }, - plugins: { management }, - } = shim; + public start(core: Core, plugins: Plugins): void { + const { i18n, routing, http, chrome, notification } = core; + const { management } = plugins; // Register management section const esSection = management.sections.getSection('elasticsearch'); @@ -47,7 +44,11 @@ export class Plugin { $scope.$$postDigest(() => { elem = document.getElementById(REACT_ROOT_ID); - renderReact(elem, shim.core, shim.plugins); + renderReact( + elem, + { i18n, chrome, notification } as AppCore, + { management } as AppPlugins + ); // Angular Lifecycle const appRoute = $route.current; diff --git a/x-pack/plugins/snapshot_restore/public/shim.ts b/x-pack/plugins/snapshot_restore/public/shim.ts index 399d77aaa9435..c42bfec82036d 100644 --- a/x-pack/plugins/snapshot_restore/public/shim.ts +++ b/x-pack/plugins/snapshot_restore/public/shim.ts @@ -15,7 +15,43 @@ import routes from 'ui/routes'; import { unmountComponentAtNode } from 'react-dom'; import { HashRouter } from 'react-router-dom'; -export function createShim() { +export interface AppCore { + i18n: { + [i18nPackage: string]: any; + Context: typeof I18nContext; + FormattedMessage: typeof FormattedMessage; + }; + chrome: typeof chrome; + notification: { + fatalError: typeof fatalError; + }; +} + +export interface AppPlugins { + management: { + sections: typeof management; + constants: { + BREADCRUMB: typeof MANAGEMENT_BREADCRUMB; + }; + }; +} + +export interface Core extends AppCore { + routing: { + registerAngularRoute(path: string, config: object): void; + unmountReactApp(elem: Element | undefined | null): void; + registerRouter(router: HashRouter): void; + getRouter(): HashRouter | undefined; + }; + http: { + setClient(client: any, $deferred: any): void; + getClient(): any; + }; +} + +export interface Plugins extends AppPlugins {} // tslint:disable-line no-empty-interface + +export function createShim(): { core: Core; plugins: Plugins } { // This is an Angular service, which is why we use this provider pattern // to access it within our React app. let httpClient: any; @@ -46,7 +82,7 @@ export function createShim() { registerRouter: (router: HashRouter): void => { reactRouter = router; }, - getRouter: (): undefined | HashRouter => { + getRouter: (): HashRouter | undefined => { return reactRouter; }, }, diff --git a/x-pack/plugins/snapshot_restore/shim.ts b/x-pack/plugins/snapshot_restore/shim.ts index ff1a12dacad11..8246289988a5e 100644 --- a/x-pack/plugins/snapshot_restore/shim.ts +++ b/x-pack/plugins/snapshot_restore/shim.ts @@ -4,10 +4,26 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createRouter } from '../../server/lib/create_router'; +import { Legacy } from 'kibana'; +import { createRouter, Router } from '../../server/lib/create_router'; import { registerLicenseChecker } from '../../server/lib/register_license_checker'; -export function createShim(server: any, pluginId: string) { +export interface Core { + http: { + createRouter(basePath: string): Router; + }; +} + +export interface Plugins { + license: { + registerLicenseChecker: typeof registerLicenseChecker; + }; +} + +export function createShim( + server: Legacy.Server, + pluginId: string +): { core: Core; plugins: Plugins } { return { core: { http: { diff --git a/x-pack/server/lib/create_router/index.d.ts b/x-pack/server/lib/create_router/index.d.ts index 7049defd09e3d..79f4efbb38497 100644 --- a/x-pack/server/lib/create_router/index.d.ts +++ b/x-pack/server/lib/create_router/index.d.ts @@ -3,8 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - import { Request, ResponseObject, ResponseToolkit } from 'hapi'; +import { Legacy } from 'kibana'; type CallWithRequest = (request: any, action: string, params: any) => any; type RouterRoute = ( @@ -15,7 +15,8 @@ type RouterRoute = ( responseToolkit: ResponseToolkit ) => Promise ) => Router; -interface Router { + +export interface Router { get: RouterRoute; post: RouterRoute; put: RouterRoute; @@ -23,4 +24,8 @@ interface Router { patch: RouterRoute; } -export declare function createRouter(server: any, pluginId: string, apiBasePath: string): Router; +export declare function createRouter( + server: Legacy.Server, + pluginId: string, + apiBasePath: string +): Router; diff --git a/x-pack/server/lib/register_license_checker/index.d.ts b/x-pack/server/lib/register_license_checker/index.d.ts index 4bfcb56d9fa43..555008921df42 100644 --- a/x-pack/server/lib/register_license_checker/index.d.ts +++ b/x-pack/server/lib/register_license_checker/index.d.ts @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Legacy } from 'kibana'; import { LicenseType } from '../../../common/constants'; export declare function registerLicenseChecker( - server: any, + server: Legacy.Server, pluginId: string, pluginName: string, minimumLicenseRequired: LicenseType From 48a82919dc73670bd60f87475934071fb608e9b3 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 7 Mar 2019 14:47:21 -0800 Subject: [PATCH 06/11] Use exported constant for required license --- x-pack/plugins/snapshot_restore/common/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/snapshot_restore/common/constants.ts b/x-pack/plugins/snapshot_restore/common/constants.ts index 6868eef082af1..121be14e4cf4f 100644 --- a/x-pack/plugins/snapshot_restore/common/constants.ts +++ b/x-pack/plugins/snapshot_restore/common/constants.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { LicenseType } from '../../../common/constants'; +import { LICENSE_TYPE_BASIC } from '../../../common/constants'; export const PLUGIN = { ID: 'snapshot_restore', NAME: 'Snapshot and Restore', - MINIMUM_LICENSE_REQUIRED: 'basic' as LicenseType, + MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC, }; From 7353ec7bedb613d6bfad1ede64667d520e31bd5a Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 7 Mar 2019 18:04:51 -0800 Subject: [PATCH 07/11] Translate plugin name, more typings --- .../snapshot_restore/common/constants.ts | 12 +++-- x-pack/plugins/snapshot_restore/index.ts | 3 +- .../server/routes/api/register_routes.ts | 8 +-- .../server/routes/api/repositories.ts | 52 +++++++++---------- x-pack/plugins/snapshot_restore/shim.ts | 5 ++ .../call_with_request_factory/index.d.ts | 16 ++++++ x-pack/server/lib/create_router/index.d.ts | 19 ++++--- 7 files changed, 70 insertions(+), 45 deletions(-) create mode 100644 x-pack/server/lib/create_router/call_with_request_factory/index.d.ts diff --git a/x-pack/plugins/snapshot_restore/common/constants.ts b/x-pack/plugins/snapshot_restore/common/constants.ts index 121be14e4cf4f..2b27fea98ef28 100644 --- a/x-pack/plugins/snapshot_restore/common/constants.ts +++ b/x-pack/plugins/snapshot_restore/common/constants.ts @@ -4,10 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import { LICENSE_TYPE_BASIC } from '../../../common/constants'; +import { LICENSE_TYPE_BASIC, LicenseType } from '../../../common/constants'; + +const PLUGIN_NAME = 'Snapshot and Restore'; export const PLUGIN = { ID: 'snapshot_restore', - NAME: 'Snapshot and Restore', - MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC, + MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC as LicenseType, + getI18nName: (translate: (key: string, config: object) => string): string => { + return translate('xpack.snapshotRestore.appName', { + defaultMessage: PLUGIN_NAME, + }); + }, }; diff --git a/x-pack/plugins/snapshot_restore/index.ts b/x-pack/plugins/snapshot_restore/index.ts index dedaad5a428a9..a3a5c9458e438 100644 --- a/x-pack/plugins/snapshot_restore/index.ts +++ b/x-pack/plugins/snapshot_restore/index.ts @@ -22,6 +22,7 @@ export function snapshotRestore(kibana: any) { }, init(server: Legacy.Server) { const { core, plugins } = createShim(server, PLUGIN.ID); + const { i18n } = core; const snapshotRestorePlugin = new SnapshotRestorePlugin(); // Start plugin @@ -31,7 +32,7 @@ export function snapshotRestore(kibana: any) { plugins.license.registerLicenseChecker( server, PLUGIN.ID, - PLUGIN.NAME, + PLUGIN.getI18nName(i18n.translate), PLUGIN.MINIMUM_LICENSE_REQUIRED ); }, diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts b/x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts index 737fd70381c55..f67be9fb1f720 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/register_routes.ts @@ -3,9 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { getAll, getOne } from './repositories'; +import { Router } from '../../../../../server/lib/create_router'; +import { registerRepositoriesRoutes } from './repositories'; -export const registerRoutes = (router: any): void => { - router[getAll.method](getAll.path, getAll.handler); - router[getOne.method](getOne.path, getOne.handler); +export const registerRoutes = (router: Router): void => { + registerRepositoriesRoutes(router); }; diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts b/x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts index d54f6241d131a..ee1a260ecba4e 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts @@ -3,34 +3,32 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { Router, RouterRouteHandler } from '../../../../../server/lib/create_router'; -export const getAll = { - path: 'repositories', - method: 'get', - handler: async (req: any, callWithRequest: any, responseToolkit: any) => { - const repositoriesByName = await callWithRequest('snapshot.getRepository', { - repository: '_all', - }); - const repositories = Object.keys(repositoriesByName).map(name => { - return { - name, - ...repositoriesByName[name], - }; - }); - return repositories; - }, +export function registerRepositoriesRoutes(router: Router) { + router.get('repositories', getAllHandler); + router.get('repositories/{name}', getOneHandler); +} + +const getAllHandler: RouterRouteHandler = async (req, callWithRequest) => { + const repositoriesByName = await callWithRequest('snapshot.getRepository', { + repository: '_all', + }); + const repositories = Object.keys(repositoriesByName).map(name => { + return { + name, + test: repositoriesByName[name], + }; + }); + return repositories; }; -export const getOne = { - path: 'repositories/{name}', - method: 'get', - handler: async (req: any, callWithRequest: any, responseToolkit: any) => { - const { name } = req.params; - const repositoryByName = await callWithRequest('snapshot.getRepository', { repository: name }); - if (repositoryByName[name]) { - return repositoryByName[name]; - } else { - return {}; - } - }, +const getOneHandler: RouterRouteHandler = async (req, callWithRequest) => { + const { name } = req.params; + const repositoryByName = await callWithRequest('snapshot.getRepository', { repository: name }); + if (repositoryByName[name]) { + return repositoryByName[name]; + } else { + return {}; + } }; diff --git a/x-pack/plugins/snapshot_restore/shim.ts b/x-pack/plugins/snapshot_restore/shim.ts index 8246289988a5e..186da1a39d3d9 100644 --- a/x-pack/plugins/snapshot_restore/shim.ts +++ b/x-pack/plugins/snapshot_restore/shim.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { Legacy } from 'kibana'; import { createRouter, Router } from '../../server/lib/create_router'; import { registerLicenseChecker } from '../../server/lib/register_license_checker'; @@ -12,6 +13,9 @@ export interface Core { http: { createRouter(basePath: string): Router; }; + i18n: { + [i18nPackage: string]: any; + }; } export interface Plugins { @@ -29,6 +33,7 @@ export function createShim( http: { createRouter: (basePath: string) => createRouter(server, pluginId, basePath), }, + i18n, }, plugins: { license: { diff --git a/x-pack/server/lib/create_router/call_with_request_factory/index.d.ts b/x-pack/server/lib/create_router/call_with_request_factory/index.d.ts new file mode 100644 index 0000000000000..74acce59e85ea --- /dev/null +++ b/x-pack/server/lib/create_router/call_with_request_factory/index.d.ts @@ -0,0 +1,16 @@ +/* + * 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 { Request } from 'hapi'; +import { Legacy } from 'kibana'; +import { CallClusterWithRequest } from 'src/legacy/core_plugins/elasticsearch'; + +export type CallWithRequest = (...args: any[]) => CallClusterWithRequest; + +export declare function callWithRequestFactory( + server: Legacy.Server, + request: Request +): CallWithRequest; diff --git a/x-pack/server/lib/create_router/index.d.ts b/x-pack/server/lib/create_router/index.d.ts index 79f4efbb38497..af7d5421632c3 100644 --- a/x-pack/server/lib/create_router/index.d.ts +++ b/x-pack/server/lib/create_router/index.d.ts @@ -3,18 +3,17 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Request, ResponseObject, ResponseToolkit } from 'hapi'; +import { Request, ResponseToolkit } from 'hapi'; import { Legacy } from 'kibana'; +import { CallWithRequest } from './call_with_request_factory'; -type CallWithRequest = (request: any, action: string, params: any) => any; -type RouterRoute = ( - path: string, - handler: ( - req: Request, - callWithRequest: CallWithRequest, - responseToolkit: ResponseToolkit - ) => Promise -) => Router; +export type RouterRouteHandler = ( + req: Request, + callWithRequest: CallWithRequest, + responseToolkit: ResponseToolkit +) => Promise; + +export type RouterRoute = (path: string, handler: RouterRouteHandler) => Router; export interface Router { get: RouterRoute; From 13083602296a08b8de809b1ef47fd4394e50c446 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 7 Mar 2019 21:46:43 -0800 Subject: [PATCH 08/11] Fix more types, move list components under /home --- .../snapshot_restore/public/app/sections/home/home.tsx | 4 ++-- .../public/app/sections/{ => home}/repository_list/index.ts | 0 .../sections/{ => home}/repository_list/repository_list.tsx | 2 +- .../public/app/sections/{ => home}/snapshot_list/index.ts | 0 .../app/sections/{ => home}/snapshot_list/snapshot_list.tsx | 2 +- .../lib/create_router/call_with_request_factory/index.d.ts | 4 ++-- x-pack/server/lib/create_router/index.d.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename x-pack/plugins/snapshot_restore/public/app/sections/{ => home}/repository_list/index.ts (100%) rename x-pack/plugins/snapshot_restore/public/app/sections/{ => home}/repository_list/repository_list.tsx (89%) rename x-pack/plugins/snapshot_restore/public/app/sections/{ => home}/snapshot_list/index.ts (100%) rename x-pack/plugins/snapshot_restore/public/app/sections/{ => home}/snapshot_list/snapshot_list.tsx (89%) diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx index 3216af5c3246f..452b661a1caa1 100644 --- a/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/sections/home/home.tsx @@ -12,8 +12,8 @@ import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs, EuiTitle } fro import { BASE_PATH } from '../../constants'; import { AppContext, AppContextInterface } from '../../services/app_context'; -import { RepositoryList } from '../repository_list'; -import { SnapshotList } from '../snapshot_list'; +import { RepositoryList } from './repository_list'; +import { SnapshotList } from './snapshot_list'; type Section = 'repositories' | 'snapshots'; diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/index.ts b/x-pack/plugins/snapshot_restore/public/app/sections/home/repository_list/index.ts similarity index 100% rename from x-pack/plugins/snapshot_restore/public/app/sections/repository_list/index.ts rename to x-pack/plugins/snapshot_restore/public/app/sections/home/repository_list/index.ts diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/repository_list.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/home/repository_list/repository_list.tsx similarity index 89% rename from x-pack/plugins/snapshot_restore/public/app/sections/repository_list/repository_list.tsx rename to x-pack/plugins/snapshot_restore/public/app/sections/home/repository_list/repository_list.tsx index 964d85046d270..0d4bdd44d7cb0 100644 --- a/x-pack/plugins/snapshot_restore/public/app/sections/repository_list/repository_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/sections/home/repository_list/repository_list.tsx @@ -6,7 +6,7 @@ import React, { PureComponent } from 'react'; -import { AppContext } from '../../services/app_context'; +import { AppContext } from '../../../services/app_context'; export class RepositoryList extends PureComponent { public static contextType = AppContext; diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/index.ts b/x-pack/plugins/snapshot_restore/public/app/sections/home/snapshot_list/index.ts similarity index 100% rename from x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/index.ts rename to x-pack/plugins/snapshot_restore/public/app/sections/home/snapshot_list/index.ts diff --git a/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx b/x-pack/plugins/snapshot_restore/public/app/sections/home/snapshot_list/snapshot_list.tsx similarity index 89% rename from x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx rename to x-pack/plugins/snapshot_restore/public/app/sections/home/snapshot_list/snapshot_list.tsx index 383d5d86e46cb..7281b9599d725 100644 --- a/x-pack/plugins/snapshot_restore/public/app/sections/snapshot_list/snapshot_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/sections/home/snapshot_list/snapshot_list.tsx @@ -6,7 +6,7 @@ import React, { PureComponent } from 'react'; -import { AppContext } from '../../services/app_context'; +import { AppContext } from '../../../services/app_context'; export class SnapshotList extends PureComponent { public static contextType = AppContext; diff --git a/x-pack/server/lib/create_router/call_with_request_factory/index.d.ts b/x-pack/server/lib/create_router/call_with_request_factory/index.d.ts index 74acce59e85ea..fd767ffb89358 100644 --- a/x-pack/server/lib/create_router/call_with_request_factory/index.d.ts +++ b/x-pack/server/lib/create_router/call_with_request_factory/index.d.ts @@ -6,9 +6,9 @@ import { Request } from 'hapi'; import { Legacy } from 'kibana'; -import { CallClusterWithRequest } from 'src/legacy/core_plugins/elasticsearch'; +import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; -export type CallWithRequest = (...args: any[]) => CallClusterWithRequest; +export type CallWithRequest = (...args: any[]) => CallCluster; export declare function callWithRequestFactory( server: Legacy.Server, diff --git a/x-pack/server/lib/create_router/index.d.ts b/x-pack/server/lib/create_router/index.d.ts index af7d5421632c3..d73dd7fcc7ea1 100644 --- a/x-pack/server/lib/create_router/index.d.ts +++ b/x-pack/server/lib/create_router/index.d.ts @@ -9,7 +9,7 @@ import { CallWithRequest } from './call_with_request_factory'; export type RouterRouteHandler = ( req: Request, - callWithRequest: CallWithRequest, + callWithRequest: ReturnType, responseToolkit: ResponseToolkit ) => Promise; From a3ce7516526aee88965f1353e25493cf7a4fd798 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Thu, 7 Mar 2019 22:08:09 -0800 Subject: [PATCH 09/11] Remove unused var --- x-pack/plugins/snapshot_restore/public/plugin.ts | 2 +- x-pack/plugins/snapshot_restore/public/shim.ts | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/snapshot_restore/public/plugin.ts b/x-pack/plugins/snapshot_restore/public/plugin.ts index 05743b1dcb715..7f3aefed77154 100644 --- a/x-pack/plugins/snapshot_restore/public/plugin.ts +++ b/x-pack/plugins/snapshot_restore/public/plugin.ts @@ -40,7 +40,7 @@ export class Plugin { // NOTE: We depend upon Angular's $http service because it's decorated with interceptors, // e.g. to check license status per request. - http.setClient($http, $q); + http.setClient($http); $scope.$$postDigest(() => { elem = document.getElementById(REACT_ROOT_ID); diff --git a/x-pack/plugins/snapshot_restore/public/shim.ts b/x-pack/plugins/snapshot_restore/public/shim.ts index c42bfec82036d..35748f2826049 100644 --- a/x-pack/plugins/snapshot_restore/public/shim.ts +++ b/x-pack/plugins/snapshot_restore/public/shim.ts @@ -44,7 +44,7 @@ export interface Core extends AppCore { getRouter(): HashRouter | undefined; }; http: { - setClient(client: any, $deferred: any): void; + setClient(client: any): void; getClient(): any; }; } @@ -56,11 +56,6 @@ export function createShim(): { core: Core; plugins: Plugins } { // to access it within our React app. let httpClient: any; - // The deffered AngularJS api allows us to create deferred promise - // to be resolved later. This allows us to cancel in flight Http Requests - // https://docs.angularjs.org/api/ng/service/$q#the-deferred-api - let $q: any; - let reactRouter: HashRouter | undefined; return { @@ -87,9 +82,8 @@ export function createShim(): { core: Core; plugins: Plugins } { }, }, http: { - setClient: (client: any, $deferred: any): void => { + setClient: (client: any): void => { httpClient = client; - $q = $deferred; }, getClient: (): any => httpClient, }, From 7da8a71263c949b2b16746d62dd98d5a3f7a5ed2 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Fri, 8 Mar 2019 13:07:19 -0800 Subject: [PATCH 10/11] Change scss prefix --- x-pack/plugins/snapshot_restore/public/index.scss | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/snapshot_restore/public/index.scss b/x-pack/plugins/snapshot_restore/public/index.scss index 7e9717645bf1f..f3354a4a29630 100644 --- a/x-pack/plugins/snapshot_restore/public/index.scss +++ b/x-pack/plugins/snapshot_restore/public/index.scss @@ -3,11 +3,11 @@ // Snapshot and restore plugin styles -// Prefix all styles with "snapshot" to avoid conflicts. +// Prefix all styles with "ssr" to avoid conflicts. // Examples -// snapshot -// snapshot__legend -// snapshot__legend--small -// snapshot__legend-isLoading +// ssr +// ssr__legend +// ssr__legend--small +// ssr__legend-isLoading @import 'snapshot_restore'; From 358dfa82d94a46f37d073978724573729de38635 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Fri, 8 Mar 2019 14:54:53 -0800 Subject: [PATCH 11/11] Uncouple unmount logic from routing shim, and some other PR feedback --- .../snapshot_restore/public/app/index.tsx | 10 ++----- .../plugins/snapshot_restore/public/plugin.ts | 29 +++++++++++++------ .../plugins/snapshot_restore/public/shim.ts | 9 +----- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/snapshot_restore/public/app/index.tsx b/x-pack/plugins/snapshot_restore/public/app/index.tsx index 3354d84fce23d..a66d925cb9766 100644 --- a/x-pack/plugins/snapshot_restore/public/app/index.tsx +++ b/x-pack/plugins/snapshot_restore/public/app/index.tsx @@ -5,19 +5,16 @@ */ import React from 'react'; import { render } from 'react-dom'; -import { AppCore, AppPlugins } from '../shim'; -import { AppContext, AppContextInterface } from './services/app_context'; - -// import { Provider } from 'react-redux'; import { HashRouter } from 'react-router-dom'; +import { AppCore, AppPlugins } from '../shim'; import { App } from './app'; -// import { srStore } from './store'; +import { AppContext, AppContextInterface } from './services/app_context'; export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; export const renderReact = async ( - elem: Element | null, + elem: Element, core: AppCore, plugins: AppPlugins ): Promise => { @@ -32,7 +29,6 @@ export const renderReact = async ( render( - {/**/} diff --git a/x-pack/plugins/snapshot_restore/public/plugin.ts b/x-pack/plugins/snapshot_restore/public/plugin.ts index 7f3aefed77154..0b6bbc198485d 100644 --- a/x-pack/plugins/snapshot_restore/public/plugin.ts +++ b/x-pack/plugins/snapshot_restore/public/plugin.ts @@ -3,11 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { unmountComponentAtNode } from 'react-dom'; + import { PLUGIN } from '../common/constants'; import { CLIENT_BASE_PATH, renderReact } from './app'; -import template from './index.html'; import { AppCore, AppPlugins, Core, Plugins } from './shim'; +import template from './index.html'; + const REACT_ROOT_ID = 'snapshotRestoreReactRoot'; export class Plugin { @@ -26,17 +29,23 @@ export class Plugin { url: `#${CLIENT_BASE_PATH}/repositories`, }); + const unmountReactApp = (elem: Element | undefined | null): void => { + if (elem) { + unmountComponentAtNode(elem); + } + }; + // Register react root routing.registerAngularRoute(`${CLIENT_BASE_PATH}/:section?/:subsection?/:view?/:id`, { template, - controller: ($scope: any, $route: any, $http: any, $q: any) => { + controller: ($scope: any, $route: any, $http: ng.IHttpService, $q: any) => { let elem: Element | null | undefined; // React-router's does not play well with the angular router. It will cause this controller // to re-execute without the $destroy handler being called. This means that the app will be mounted twice // creating a memory leak when leaving (only 1 app will be unmounted). // To avoid this, we unmount the React app each time we enter the controller. - routing.unmountReactApp(elem); + unmountReactApp(elem); // NOTE: We depend upon Angular's $http service because it's decorated with interceptors, // e.g. to check license status per request. @@ -44,11 +53,13 @@ export class Plugin { $scope.$$postDigest(() => { elem = document.getElementById(REACT_ROOT_ID); - renderReact( - elem, - { i18n, chrome, notification } as AppCore, - { management } as AppPlugins - ); + if (elem) { + renderReact( + elem, + { i18n, chrome, notification } as AppCore, + { management } as AppPlugins + ); + } // Angular Lifecycle const appRoute = $route.current; @@ -67,7 +78,7 @@ export class Plugin { if (stopListeningForLocationChange) { stopListeningForLocationChange(); } - routing.unmountReactApp(elem); + unmountReactApp(elem); }); }); }); diff --git a/x-pack/plugins/snapshot_restore/public/shim.ts b/x-pack/plugins/snapshot_restore/public/shim.ts index 35748f2826049..86de665c39bc9 100644 --- a/x-pack/plugins/snapshot_restore/public/shim.ts +++ b/x-pack/plugins/snapshot_restore/public/shim.ts @@ -12,7 +12,6 @@ import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; import { fatalError } from 'ui/notify'; import routes from 'ui/routes'; -import { unmountComponentAtNode } from 'react-dom'; import { HashRouter } from 'react-router-dom'; export interface AppCore { @@ -39,7 +38,6 @@ export interface AppPlugins { export interface Core extends AppCore { routing: { registerAngularRoute(path: string, config: object): void; - unmountReactApp(elem: Element | undefined | null): void; registerRouter(router: HashRouter): void; getRouter(): HashRouter | undefined; }; @@ -54,7 +52,7 @@ export interface Plugins extends AppPlugins {} // tslint:disable-line no-empty-i export function createShim(): { core: Core; plugins: Plugins } { // This is an Angular service, which is why we use this provider pattern // to access it within our React app. - let httpClient: any; + let httpClient: ng.IHttpService; let reactRouter: HashRouter | undefined; @@ -69,11 +67,6 @@ export function createShim(): { core: Core; plugins: Plugins } { registerAngularRoute: (path: string, config: object): void => { routes.when(path, config); }, - unmountReactApp: (elem: Element | undefined | null): void => { - if (elem) { - unmountComponentAtNode(elem); - } - }, registerRouter: (router: HashRouter): void => { reactRouter = router; },