From 62f3164166bdbd876d9d4e67b1e50345f060ff67 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Fri, 18 Oct 2019 09:24:11 +0200
Subject: [PATCH 001/132] centralize dependencies
---
.../kibana/public/home/components/add_data.js | 5 ++-
.../public/home/components/add_data.test.js | 12 +++----
.../kibana/public/home/components/home_app.js | 31 +++++++++++--------
.../home/components/sample_data_set_cards.js | 5 ++-
.../sample_data_view_data_button.js | 6 ++--
.../home/components/tutorial/tutorial.js | 4 +--
.../home/components/tutorial_directory.js | 4 +--
.../kibana/public/home/components/welcome.tsx | 12 +++----
.../core_plugins/kibana/public/home/index.js | 13 +++-----
...{kibana_services.js => kibana_services.ts} | 31 ++++++++++++++-----
.../kibana/public/home/load_tutorials.js | 5 ++-
.../kibana/public/home/sample_data_client.js | 14 ++++-----
12 files changed, 78 insertions(+), 64 deletions(-)
rename src/legacy/core_plugins/kibana/public/home/{kibana_services.js => kibana_services.ts} (54%)
diff --git a/src/legacy/core_plugins/kibana/public/home/components/add_data.js b/src/legacy/core_plugins/kibana/public/home/components/add_data.js
index f8c8e0ec8411f..2bb11a46968b5 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/add_data.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/add_data.js
@@ -21,7 +21,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
-import chrome from 'ui/chrome';
+import { getBasePath } from '../kibana_services';
import {
EuiButton,
@@ -38,8 +38,7 @@ import {
EuiFlexGrid,
} from '@elastic/eui';
-/* istanbul ignore next */
-const basePath = chrome.getBasePath();
+const basePath = getBasePath();
const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
const renderCards = () => {
diff --git a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
index d7c8e9daa99da..f0417a6131dfa 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
@@ -20,10 +20,10 @@
import React from 'react';
import { AddData } from './add_data';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
-import chrome from 'ui/chrome';
+import { getBasePath } from '../kibana_services';
jest.mock(
- 'ui/chrome',
+ '../kibana_services',
() => ({
getBasePath: jest.fn(() => 'path'),
}),
@@ -37,7 +37,7 @@ test('render', () => {
isNewKibanaInstance={false}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(chrome.getBasePath).toHaveBeenCalledTimes(1);
+ expect(getBasePath).toHaveBeenCalledTimes(1);
});
test('mlEnabled', () => {
@@ -47,7 +47,7 @@ test('mlEnabled', () => {
isNewKibanaInstance={false}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(chrome.getBasePath).toHaveBeenCalledTimes(1);
+ expect(getBasePath).toHaveBeenCalledTimes(1);
});
test('apmUiEnabled', () => {
@@ -57,7 +57,7 @@ test('apmUiEnabled', () => {
isNewKibanaInstance={false}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(chrome.getBasePath).toHaveBeenCalledTimes(1);
+ expect(getBasePath).toHaveBeenCalledTimes(1);
});
test('isNewKibanaInstance', () => {
@@ -67,5 +67,5 @@ test('isNewKibanaInstance', () => {
isNewKibanaInstance={true}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(chrome.getBasePath).toHaveBeenCalledTimes(1);
+ expect(getBasePath).toHaveBeenCalledTimes(1);
});
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home_app.js b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
index 9aa44863f6d70..998f4e4608da3 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home_app.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
@@ -26,23 +26,28 @@ import { Tutorial } from './tutorial/tutorial';
import {
HashRouter as Router,
Switch,
- Route
+ Route,
} from 'react-router-dom';
import { getTutorial } from '../load_tutorials';
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
-import { telemetryOptInProvider, shouldShowTelemetryOptIn } from '../kibana_services';
-import chrome from 'ui/chrome';
+import {
+ telemetryOptInProvider,
+ shouldShowTelemetryOptIn,
+ getInjected,
+ savedObjectsClient,
+ getBasePath,
+ addBasePath,
+} from '../kibana_services';
export function HomeApp({ directories }) {
- const isCloudEnabled = chrome.getInjected('isCloudEnabled', false);
- const apmUiEnabled = chrome.getInjected('apmUiEnabled', true);
- const mlEnabled = chrome.getInjected('mlEnabled', false);
- const savedObjectsClient = chrome.getSavedObjectsClient();
+ const isCloudEnabled = getInjected('isCloudEnabled', false);
+ const apmUiEnabled = getInjected('apmUiEnabled', true);
+ const mlEnabled = getInjected('mlEnabled', false);
const renderTutorialDirectory = (props) => {
return (
@@ -52,7 +57,7 @@ export function HomeApp({ directories }) {
const renderTutorial = (props) => {
return (
@@ -85,13 +90,13 @@ export function HomeApp({ directories }) {
path="/home"
>
),
- href: chrome.addBasePath(path)
+ href: addBasePath(path)
};
});
const panels = [
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js
index 3d8ea4815dfff..211801643a7a9 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js
@@ -37,7 +37,7 @@ import {
import * as StatusCheckStates from './status_check_states';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
-import chrome from 'ui/chrome';
+import { chrome } from '../../kibana_services';
const INSTRUCTIONS_TYPE = {
ELASTIC_CLOUD: 'elasticCloud',
@@ -94,7 +94,7 @@ class TutorialUi extends React.Component {
});
}
- chrome.breadcrumbs.set([
+ chrome.setBreadcrumbs([
{
text: homeTitle,
href: '#/home'
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
index eae549f8a6ac0..06c194a3f7ca8 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
@@ -22,7 +22,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Synopsis } from './synopsis';
import { SampleDataSetCards } from './sample_data_set_cards';
-import chrome from 'ui/chrome';
+import { chrome } from '../kibana_services';
import {
EuiPage,
@@ -112,7 +112,7 @@ class TutorialDirectoryUi extends React.Component {
async componentDidMount() {
this._isMounted = true;
- chrome.breadcrumbs.set([
+ chrome.setBreadcrumbs([
{
text: homeTitle,
href: '#/home',
diff --git a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
index 8869819290263..089739e380f11 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
+++ b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
@@ -33,15 +33,13 @@ import {
EuiIcon,
EuiPortal,
} from '@elastic/eui';
-// @ts-ignore
-import { banners } from 'ui/notify';
-
import { FormattedMessage } from '@kbn/i18n/react';
-import chrome from 'ui/chrome';
+import { banners } from '../kibana_services';
+
import { SampleDataCard } from './sample_data';
import { TelemetryOptInCard } from './telemetry_opt_in';
// @ts-ignore
-import { trackUiMetric, METRIC_TYPE } from '../kibana_services';
+import { trackUiMetric, METRIC_TYPE, addBasePath } from '../kibana_services';
interface Props {
urlBasePath: string;
@@ -51,6 +49,7 @@ interface Props {
getTelemetryBannerId: () => string;
shouldShowTelemetryOptIn: boolean;
}
+
interface State {
step: number;
}
@@ -70,9 +69,10 @@ export class Welcome extends React.PureComponent {
};
private redirecToSampleData() {
- const path = chrome.addBasePath('#/home/tutorial_directory/sampleData');
+ const path = addBasePath('#/home/tutorial_directory/sampleData');
window.location.href = path;
}
+
private async handleTelemetrySelection(confirm: boolean) {
const metricName = `telemetryOptIn${confirm ? 'Confirm' : 'Decline'}`;
trackUiMetric(METRIC_TYPE.CLICK, metricName);
diff --git a/src/legacy/core_plugins/kibana/public/home/index.js b/src/legacy/core_plugins/kibana/public/home/index.js
index 8233df680edfd..f3edef6f09111 100644
--- a/src/legacy/core_plugins/kibana/public/home/index.js
+++ b/src/legacy/core_plugins/kibana/public/home/index.js
@@ -17,17 +17,14 @@
* under the License.
*/
-import chrome from 'ui/chrome';
+import { chrome, addBasePath, featureCatalogueRegistryProvider, wrapInI18nContext } from './kibana_services';
import routes from 'ui/routes';
import template from './home_ng_wrapper.html';
-import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
-import { wrapInI18nContext } from 'ui/i18n';
import { uiModules } from 'ui/modules';
import {
HomeApp
} from './components/home_app';
import { i18n } from '@kbn/i18n';
-import { npStart } from 'ui/new_platform';
const app = uiModules.get('apps/home', []);
app.directive('homeApp', function (reactDirective) {
@@ -39,10 +36,10 @@ const homeTitle = i18n.translate('kbn.home.breadcrumbs.homeTitle', { defaultMess
function getRoute() {
return {
template,
- controller($scope, Private) {
- $scope.directories = Private(FeatureCatalogueRegistryProvider).inTitleOrder;
- $scope.recentlyAccessed = npStart.core.chrome.recentlyAccessed.get().map(item => {
- item.link = chrome.addBasePath(item.link);
+ controller($scope) {
+ $scope.directories = featureCatalogueRegistryProvider.inTitleOrder;
+ $scope.recentlyAccessed = chrome.recentlyAccessed.get().map(item => {
+ item.link = addBasePath(item.link);
return item;
});
},
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.js b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
similarity index 54%
rename from src/legacy/core_plugins/kibana/public/home/kibana_services.js
rename to src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index 792c5e09435a4..b20175aadfda4 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.js
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -17,24 +17,41 @@
* under the License.
*/
+// @ts-ignore
import { uiModules } from 'ui/modules';
import { npStart } from 'ui/new_platform';
+import { IPrivate } from 'ui/private';
+import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
import { TelemetryOptInProvider } from '../../../telemetry/public/services';
+import { start as data } from '../../../data/public/legacy';
+// @ts-ignore
+export { toastNotifications, banners } from 'ui/notify';
+export { kfetch } from 'ui/kfetch';
-export let indexPatternService;
-export let shouldShowTelemetryOptIn;
-export let telemetryOptInProvider;
+export { wrapInI18nContext } from 'ui/i18n';
+export const getInjected = npStart.core.injectedMetadata.getInjectedVar;
+
+export const savedObjectsClient = npStart.core.savedObjects.client;
+export const chrome = npStart.core.chrome;
+export const uiSettings = npStart.core.uiSettings;
+export const addBasePath = npStart.core.http.basePath.prepend;
+export const getBasePath = npStart.core.http.basePath.get;
+
+export const indexPatternService = data.indexPatterns;
+export let shouldShowTelemetryOptIn: boolean;
+export let telemetryOptInProvider: any;
+export let featureCatalogueRegistryProvider: any;
export const trackUiMetric = createUiStatsReporter('Kibana_home');
export { METRIC_TYPE };
-uiModules.get('kibana').run(($injector) => {
+uiModules.get('kibana').run((Private: IPrivate) => {
const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
- const Private = $injector.get('Private');
telemetryOptInProvider = Private(TelemetryOptInProvider);
- shouldShowTelemetryOptIn = telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn();
- indexPatternService = $injector.get('indexPatterns');
+ shouldShowTelemetryOptIn =
+ telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn();
+ featureCatalogueRegistryProvider = Private(FeatureCatalogueRegistryProvider as any);
});
diff --git a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
index d6b264154d424..f8336a8b5d412 100644
--- a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
+++ b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
@@ -18,11 +18,10 @@
*/
import _ from 'lodash';
-import chrome from 'ui/chrome';
+import { addBasePath, toastNotifications } from './kibana_services';
import { i18n } from '@kbn/i18n';
-import { toastNotifications } from 'ui/notify';
-const baseUrl = chrome.addBasePath('/api/kibana/home/tutorials');
+const baseUrl = addBasePath('/api/kibana/home/tutorials');
const headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/json');
diff --git a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
index da46b3e16c093..b7f7b92eced51 100644
--- a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
+++ b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
@@ -17,9 +17,7 @@
* under the License.
*/
-import { kfetch } from 'ui/kfetch';
-import chrome from 'ui/chrome';
-import { indexPatternService } from './kibana_services';
+import { indexPatternService, uiSettings, kfetch } from './kibana_services';
const sampleDataUrl = '/api/sample_data';
@@ -34,8 +32,8 @@ export async function listSampleDataSets() {
export async function installSampleDataSet(id, sampleDataDefaultIndex) {
await kfetch({ method: 'POST', pathname: `${sampleDataUrl}/${id}` });
- if (chrome.getUiSettingsClient().isDefault('defaultIndex')) {
- chrome.getUiSettingsClient().set('defaultIndex', sampleDataDefaultIndex);
+ if (uiSettings.isDefault('defaultIndex')) {
+ uiSettings.set('defaultIndex', sampleDataDefaultIndex);
}
clearIndexPatternsCache();
@@ -44,9 +42,9 @@ export async function installSampleDataSet(id, sampleDataDefaultIndex) {
export async function uninstallSampleDataSet(id, sampleDataDefaultIndex) {
await kfetch({ method: 'DELETE', pathname: `${sampleDataUrl}/${id}` });
- if (!chrome.getUiSettingsClient().isDefault('defaultIndex')
- && chrome.getUiSettingsClient().get('defaultIndex') === sampleDataDefaultIndex) {
- chrome.getUiSettingsClient().set('defaultIndex', null);
+ if (!uiSettings.isDefault('defaultIndex')
+ && uiSettings.get('defaultIndex') === sampleDataDefaultIndex) {
+ uiSettings.set('defaultIndex', null);
}
clearIndexPatternsCache();
From 0bf00ae96e051ef4faa7d5e18427a1aab86d17e7 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Fri, 18 Oct 2019 10:50:46 +0200
Subject: [PATCH 002/132] move more stuff into kibana_services
---
.../kibana/public/home/components/home.js | 4 +--
.../public/home/components/home.test.mocks.ts | 24 ++++++----------
.../tutorial/replace_template_strings.js | 28 ++++++++-----------
.../core_plugins/kibana/public/home/index.js | 12 ++++----
.../kibana/public/home/kibana_services.ts | 11 ++++++--
5 files changed, 35 insertions(+), 44 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home.js b/src/legacy/core_plugins/kibana/public/home/components/home.js
index 6a8dff2ad4fa7..4cce329846710 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home.js
@@ -22,7 +22,6 @@ import PropTypes from 'prop-types';
import { Synopsis } from './synopsis';
import { AddData } from './add_data';
import { FormattedMessage } from '@kbn/i18n/react';
-import chrome from 'ui/chrome';
import {
EuiButton,
@@ -40,6 +39,7 @@ import {
import { Welcome } from './welcome';
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
+import { getInjected } from '../kibana_services';
const KEY_ENABLE_WELCOME = 'home:welcome:show';
@@ -47,7 +47,7 @@ export class Home extends Component {
constructor(props) {
super(props);
- const isWelcomeEnabled = !(chrome.getInjected('disableWelcomeScreen') || props.localStorage.getItem(KEY_ENABLE_WELCOME) === 'false');
+ const isWelcomeEnabled = !(getInjected('disableWelcomeScreen') || props.localStorage.getItem(KEY_ENABLE_WELCOME) === 'false');
this.state = {
// If welcome is enabled, we wait for loading to complete
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home.test.mocks.ts b/src/legacy/core_plugins/kibana/public/home/components/home.test.mocks.ts
index 621c058c803db..cd7bc82fe3345 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home.test.mocks.ts
+++ b/src/legacy/core_plugins/kibana/public/home/components/home.test.mocks.ts
@@ -17,7 +17,12 @@
* under the License.
*/
-import { notificationServiceMock, overlayServiceMock } from '../../../../../../core/public/mocks';
+import {
+ notificationServiceMock,
+ overlayServiceMock,
+ httpServiceMock,
+ injectedMetadataServiceMock,
+} from '../../../../../../core/public/mocks';
jest.doMock('ui/new_platform', () => {
return {
@@ -29,22 +34,9 @@ jest.doMock('ui/new_platform', () => {
npStart: {
core: {
overlays: overlayServiceMock.createStartContract(),
+ http: httpServiceMock.createStartContract({ basePath: 'path' }),
+ injectedMetadata: injectedMetadataServiceMock.createStartContract(),
},
},
};
});
-
-jest.doMock(
- 'ui/chrome',
- () => ({
- getBasePath: jest.fn(() => 'path'),
- getInjected: jest.fn(() => ''),
- }),
- { virtual: true }
-);
-
-jest.doMock('ui/capabilities', () => ({
- catalogue: {},
- management: {},
- navLinks: {},
-}));
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js
index 7875c629306c5..cdbafadb228a4 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js
@@ -18,13 +18,7 @@
*/
import { Writer } from 'mustache';
-import chrome from 'ui/chrome';
-import { metadata } from 'ui/metadata';
-import {
- DOC_LINK_VERSION,
- ELASTIC_WEBSITE_URL,
- documentationLinks
-} from 'ui/documentation_links/documentation_links';
+import { getInjected, metadata, docLinks } from '../../kibana_services';
const TEMPLATE_TAGS = ['{', '}'];
@@ -46,20 +40,20 @@ export function replaceTemplateStrings(text, params = {}) {
curlyClose: '}',
config: {
cloud: {
- id: chrome.getInjected('cloudId')
+ id: getInjected('cloudId')
},
docs: {
- base_url: ELASTIC_WEBSITE_URL,
+ base_url: docLinks.ELASTIC_WEBSITE_URL,
beats: {
- filebeat: documentationLinks.filebeat.base,
- metricbeat: documentationLinks.metricbeat.base,
- heartbeat: documentationLinks.heartbeat.base,
- functionbeat: documentationLinks.functionbeat.base,
- winlogbeat: documentationLinks.winlogbeat.base,
- auditbeat: documentationLinks.auditbeat.base,
+ filebeat: docLinks.links.filebeat.base,
+ metricbeat: docLinks.links.metricbeat.base,
+ heartbeat: docLinks.links.heartbeat.base,
+ functionbeat: docLinks.links.functionbeat.base,
+ winlogbeat: docLinks.links.winlogbeat.base,
+ auditbeat: docLinks.links.auditbeat.base,
},
- logstash: documentationLinks.logstash.base,
- version: DOC_LINK_VERSION
+ logstash: docLinks.links.logstash.base,
+ version: docLinks.DOC_LINK_VERSION
},
kibana: {
version: metadata.version
diff --git a/src/legacy/core_plugins/kibana/public/home/index.js b/src/legacy/core_plugins/kibana/public/home/index.js
index f3edef6f09111..746cdfcfb4768 100644
--- a/src/legacy/core_plugins/kibana/public/home/index.js
+++ b/src/legacy/core_plugins/kibana/public/home/index.js
@@ -17,10 +17,8 @@
* under the License.
*/
-import { chrome, addBasePath, featureCatalogueRegistryProvider, wrapInI18nContext } from './kibana_services';
-import routes from 'ui/routes';
+import { chrome, addBasePath, featureCatalogueRegistryProvider, wrapInI18nContext, uiRoutes, uiModules } from './kibana_services';
import template from './home_ng_wrapper.html';
-import { uiModules } from 'ui/modules';
import {
HomeApp
} from './components/home_app';
@@ -51,7 +49,7 @@ function getRoute() {
// All routing will be handled inside HomeApp via react, we just need to make sure angular doesn't
// redirect us to the default page by encountering a url it isn't marked as being able to handle.
-routes.when('/home', getRoute());
-routes.when('/home/feature_directory', getRoute());
-routes.when('/home/tutorial_directory/:tab?', getRoute());
-routes.when('/home/tutorial/:id', getRoute());
+uiRoutes.when('/home', getRoute());
+uiRoutes.when('/home/feature_directory', getRoute());
+uiRoutes.when('/home/tutorial_directory/:tab?', getRoute());
+uiRoutes.when('/home/tutorial/:id', getRoute());
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index b20175aadfda4..cafe61fe825a9 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -18,7 +18,8 @@
*/
// @ts-ignore
-import { uiModules } from 'ui/modules';
+import { uiModules as modules } from 'ui/modules';
+import routes from 'ui/routes';
import { npStart } from 'ui/new_platform';
import { IPrivate } from 'ui/private';
import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
@@ -31,6 +32,12 @@ export { kfetch } from 'ui/kfetch';
export { wrapInI18nContext } from 'ui/i18n';
export const getInjected = npStart.core.injectedMetadata.getInjectedVar;
+export const metadata = npStart.core.injectedMetadata.getLegacyMetadata();
+
+export const docLinks = npStart.core.docLinks;
+
+export const uiRoutes = routes;
+export const uiModules = modules;
export const savedObjectsClient = npStart.core.savedObjects.client;
export const chrome = npStart.core.chrome;
@@ -46,7 +53,7 @@ export let featureCatalogueRegistryProvider: any;
export const trackUiMetric = createUiStatsReporter('Kibana_home');
export { METRIC_TYPE };
-uiModules.get('kibana').run((Private: IPrivate) => {
+modules.get('kibana').run((Private: IPrivate) => {
const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
From e72e51a4aa39225d327cf2698b9e1ccf20e83e08 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Fri, 18 Oct 2019 14:54:17 +0200
Subject: [PATCH 003/132] fix tests and dependency
---
.../kibana/public/home/components/add_data.test.js | 10 +++-------
.../kibana/public/home/components/home.test.js | 5 +++++
.../components/sample_data_view_data_button.test.js | 11 ++++-------
.../public/home/components/tutorial/tutorial.test.js | 6 ++++++
.../kibana/public/home/kibana_services.ts | 2 +-
5 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
index f0417a6131dfa..1860814f6e062 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
@@ -22,13 +22,9 @@ import { AddData } from './add_data';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { getBasePath } from '../kibana_services';
-jest.mock(
- '../kibana_services',
- () => ({
- getBasePath: jest.fn(() => 'path'),
- }),
- { virtual: true }
-);
+jest.mock('../kibana_services', () =>({
+ getBasePath: jest.fn(() => 'path'),
+}));
test('render', () => {
const component = shallowWithIntl(({
+ getBasePath: () => 'path',
+ getInjected: () => ''
+}));
+
describe('home', () => {
let defaultProps;
diff --git a/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.test.js b/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.test.js
index b0551341965fa..4a2528b133def 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.test.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.test.js
@@ -17,19 +17,16 @@
* under the License.
*/
-jest.mock('ui/chrome', () => {
- return {
- addBasePath: (path) => {
- return `root${path}`;
- },
- };
-});
import React from 'react';
import { shallow } from 'enzyme';
import { SampleDataViewDataButton } from './sample_data_view_data_button';
+jest.mock('../kibana_services', () =>({
+ addBasePath: path => `root${path}`
+}));
+
test('should render simple button when appLinks is empty', () => {
const component = shallow(({
+ getBasePath: jest.fn(() => 'path'),
+ chrome: {
+ setBreadcrumbs: () => {}
+ }
+}));
jest.mock('../../../../../kibana_react/public', () => {
return {
Markdown: () => ,
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index cafe61fe825a9..a44686999a120 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -45,7 +45,7 @@ export const uiSettings = npStart.core.uiSettings;
export const addBasePath = npStart.core.http.basePath.prepend;
export const getBasePath = npStart.core.http.basePath.get;
-export const indexPatternService = data.indexPatterns;
+export const indexPatternService = data.indexPatterns.indexPatterns;
export let shouldShowTelemetryOptIn: boolean;
export let telemetryOptInProvider: any;
export let featureCatalogueRegistryProvider: any;
From b42f417deda7a8e52ad4786219c2070ff3ac02cd Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Sat, 19 Oct 2019 11:07:45 +0200
Subject: [PATCH 004/132] bootstrap home via local application service
---
.../kibana/public/home/components/add_data.js | 4 +-
.../kibana/public/home/components/home.js | 3 +-
.../kibana/public/home/components/home_app.js | 78 +++++++-------
.../home/components/sample_data_set_cards.js | 3 +-
.../sample_data_view_data_button.js | 7 +-
.../home/components/tutorial_directory.js | 3 +-
.../kibana/public/home/components/welcome.tsx | 5 +-
.../core_plugins/kibana/public/home/index.js | 55 ----------
.../core_plugins/kibana/public/home/index.ts | 76 +++++++++++++
.../kibana/public/home/kibana_services.ts | 11 ++
.../kibana/public/home/load_tutorials.js | 3 +-
.../core_plugins/kibana/public/home/plugin.ts | 102 ++++++++++++++++++
.../kibana/public/home/render_app.tsx | 90 ++++++++++++++++
.../kibana/public/home/sample_data_client.js | 3 +-
.../core_plugins/kibana/public/kibana.js | 3 +
.../public/local_application_service/index.ts | 20 ++++
.../local_application_service.ts | 76 +++++++++++++
17 files changed, 440 insertions(+), 102 deletions(-)
delete mode 100644 src/legacy/core_plugins/kibana/public/home/index.js
create mode 100644 src/legacy/core_plugins/kibana/public/home/index.ts
create mode 100644 src/legacy/core_plugins/kibana/public/home/plugin.ts
create mode 100644 src/legacy/core_plugins/kibana/public/home/render_app.tsx
create mode 100644 src/legacy/core_plugins/kibana/public/local_application_service/index.ts
create mode 100644 src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
diff --git a/src/legacy/core_plugins/kibana/public/home/components/add_data.js b/src/legacy/core_plugins/kibana/public/home/components/add_data.js
index 2bb11a46968b5..3816380b1d9b7 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/add_data.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/add_data.js
@@ -21,7 +21,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
-import { getBasePath } from '../kibana_services';
+import { getDeps } from '../kibana_services';
import {
EuiButton,
@@ -38,9 +38,9 @@ import {
EuiFlexGrid,
} from '@elastic/eui';
-const basePath = getBasePath();
const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
+ const basePath = getDeps().getBasePath();
const renderCards = () => {
const apmData = {
title: intl.formatMessage({
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home.js b/src/legacy/core_plugins/kibana/public/home/components/home.js
index 4cce329846710..9ffa4c7e6c44b 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home.js
@@ -39,7 +39,8 @@ import {
import { Welcome } from './welcome';
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
-import { getInjected } from '../kibana_services';
+import { getDeps } from '../kibana_services';
+const { getInjected } = getDeps();
const KEY_ENABLE_WELCOME = 'home:welcome:show';
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home_app.js b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
index 998f4e4608da3..3ccee843cb9a4 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home_app.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
@@ -18,6 +18,7 @@
*/
import React from 'react';
+import { I18nProvider } from '@kbn/i18n/react';
import PropTypes from 'prop-types';
import { Home } from './home';
import { FeatureDirectory } from './feature_directory';
@@ -31,13 +32,16 @@ import {
import { getTutorial } from '../load_tutorials';
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
import {
+ getDeps
+} from '../kibana_services';
+const {
telemetryOptInProvider,
shouldShowTelemetryOptIn,
getInjected,
savedObjectsClient,
getBasePath,
addBasePath,
-} from '../kibana_services';
+} = getDeps();
export function HomeApp({ directories }) {
const isCloudEnabled = getInjected('isCloudEnabled', false);
@@ -68,43 +72,45 @@ export function HomeApp({ directories }) {
};
return (
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js b/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js
index 579a68641a9e2..c19a3f068ee60 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js
@@ -31,7 +31,8 @@ import {
UNINSTALLED_STATUS,
} from './sample_data_set_card';
-import { toastNotifications, uiSettings } from '../kibana_services';
+import { getDeps } from '../kibana_services';
+const { toastNotifications, uiSettings } = getDeps();
import {
listSampleDataSets,
diff --git a/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js b/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js
index a0f21c9b2dbf1..233a6d95c678a 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js
@@ -27,7 +27,12 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { addBasePath } from '../kibana_services';
+import {
+ getDeps
+} from '../kibana_services';
+const {
+ addBasePath,
+} = getDeps();
export class SampleDataViewDataButton extends React.Component {
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
index 06c194a3f7ca8..d3c170984d615 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
@@ -22,7 +22,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Synopsis } from './synopsis';
import { SampleDataSetCards } from './sample_data_set_cards';
-import { chrome } from '../kibana_services';
+import { getDeps } from '../kibana_services';
+const { chrome } = getDeps();
import {
EuiPage,
diff --git a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
index 089739e380f11..02b45a87b89ab 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
+++ b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
@@ -34,12 +34,11 @@ import {
EuiPortal,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { banners } from '../kibana_services';
+import { getDeps } from '../kibana_services';
import { SampleDataCard } from './sample_data';
import { TelemetryOptInCard } from './telemetry_opt_in';
-// @ts-ignore
-import { trackUiMetric, METRIC_TYPE, addBasePath } from '../kibana_services';
+const { trackUiMetric, METRIC_TYPE, addBasePath, banners } = getDeps();
interface Props {
urlBasePath: string;
diff --git a/src/legacy/core_plugins/kibana/public/home/index.js b/src/legacy/core_plugins/kibana/public/home/index.js
deleted file mode 100644
index 746cdfcfb4768..0000000000000
--- a/src/legacy/core_plugins/kibana/public/home/index.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { chrome, addBasePath, featureCatalogueRegistryProvider, wrapInI18nContext, uiRoutes, uiModules } from './kibana_services';
-import template from './home_ng_wrapper.html';
-import {
- HomeApp
-} from './components/home_app';
-import { i18n } from '@kbn/i18n';
-
-const app = uiModules.get('apps/home', []);
-app.directive('homeApp', function (reactDirective) {
- return reactDirective(wrapInI18nContext(HomeApp));
-});
-
-const homeTitle = i18n.translate('kbn.home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
-
-function getRoute() {
- return {
- template,
- controller($scope) {
- $scope.directories = featureCatalogueRegistryProvider.inTitleOrder;
- $scope.recentlyAccessed = chrome.recentlyAccessed.get().map(item => {
- item.link = addBasePath(item.link);
- return item;
- });
- },
- k7Breadcrumbs: () => [
- { text: homeTitle },
- ]
- };
-}
-
-// All routing will be handled inside HomeApp via react, we just need to make sure angular doesn't
-// redirect us to the default page by encountering a url it isn't marked as being able to handle.
-uiRoutes.when('/home', getRoute());
-uiRoutes.when('/home/feature_directory', getRoute());
-uiRoutes.when('/home/tutorial_directory/:tab?', getRoute());
-uiRoutes.when('/home/tutorial/:id', getRoute());
diff --git a/src/legacy/core_plugins/kibana/public/home/index.ts b/src/legacy/core_plugins/kibana/public/home/index.ts
new file mode 100644
index 0000000000000..b8c468820f201
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/home/index.ts
@@ -0,0 +1,76 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
+import { npSetup, npStart } from 'ui/new_platform';
+import chrome from 'ui/chrome';
+import { IPrivate } from 'ui/private';
+// @ts-ignore
+import { toastNotifications, banners } from 'ui/notify';
+import { kfetch } from 'ui/kfetch';
+import { HomePlugin, LegacyAngularInjectedDependencies } from './plugin';
+import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
+import { start as data } from '../../../data/public/legacy';
+import { TelemetryOptInProvider } from '../../../telemetry/public/services';
+import { localApplicationService } from '../local_application_service';
+
+export const uiStatsReporter = createUiStatsReporter('Kibana_home');
+
+/**
+ * Get dependencies relying on the global angular context.
+ * They also have to get resolved together with the legacy imports above
+ */
+async function getAngularInjectedDependencies(): Promise {
+ const injector = await chrome.dangerouslyGetActiveInjector();
+
+ const Private = injector.get('Private');
+
+ const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
+ const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
+ const telemetryOptInProvider = Private(TelemetryOptInProvider);
+
+ return {
+ telemetryOptInProvider,
+ shouldShowTelemetryOptIn:
+ telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn(),
+ featureCatalogueRegistryProvider: Private(FeatureCatalogueRegistryProvider as any),
+ };
+}
+
+(async () => {
+ const instance = new HomePlugin();
+ instance.setup(npSetup.core, {
+ __LEGACY: {
+ uiStatsReporter,
+ toastNotifications,
+ banners,
+ kfetch,
+ metadata: npStart.core.injectedMetadata.getLegacyMetadata(),
+ METRIC_TYPE,
+ },
+ localApplicationService,
+ });
+ instance.start(npStart.core, {
+ data,
+ npData: npStart.plugins.data,
+ __LEGACY: {
+ angularDependencies: await getAngularInjectedDependencies(),
+ },
+ });
+})();
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index a44686999a120..78aa60a6946fa 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -17,6 +17,16 @@
* under the License.
*/
+let deps: any = {};
+
+export function setDeps(newDeps: any) {
+ deps = newDeps;
+}
+
+export function getDeps() {
+ return deps;
+}
+/*
// @ts-ignore
import { uiModules as modules } from 'ui/modules';
import routes from 'ui/routes';
@@ -62,3 +72,4 @@ modules.get('kibana').run((Private: IPrivate) => {
telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn();
featureCatalogueRegistryProvider = Private(FeatureCatalogueRegistryProvider as any);
});
+*/
diff --git a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
index f8336a8b5d412..13e03061613ac 100644
--- a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
+++ b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
@@ -18,7 +18,8 @@
*/
import _ from 'lodash';
-import { addBasePath, toastNotifications } from './kibana_services';
+import { getDeps } from './kibana_services';
+const { addBasePath, toastNotifications } = getDeps();
import { i18n } from '@kbn/i18n';
const baseUrl = addBasePath('/api/kibana/home/tutorials');
diff --git a/src/legacy/core_plugins/kibana/public/home/plugin.ts b/src/legacy/core_plugins/kibana/public/home/plugin.ts
new file mode 100644
index 0000000000000..9e0a85b2b7f72
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/home/plugin.ts
@@ -0,0 +1,102 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
+import { Plugin as DataPlugin } from 'src/plugins/data/public';
+
+import { DataStart } from '../../../data/public';
+import { LocalApplicationService } from '../local_application_service';
+
+export interface LegacyAngularInjectedDependencies {
+ featureCatalogueRegistryProvider: any;
+ telemetryOptInProvider: any;
+ shouldShowTelemetryOptIn: boolean;
+}
+
+export interface HomePluginStartDependencies {
+ data: DataStart;
+ npData: ReturnType;
+ __LEGACY: {
+ angularDependencies: LegacyAngularInjectedDependencies;
+ };
+}
+
+export interface HomePluginSetupDependencies {
+ __LEGACY: {
+ uiStatsReporter: any;
+ toastNotifications: any;
+ banners: any;
+ kfetch: any;
+ metadata: any;
+ METRIC_TYPE: any;
+ };
+ localApplicationService: LocalApplicationService;
+}
+
+export class HomePlugin implements Plugin {
+ private dataStart: DataStart | null = null;
+ private npDataStart: ReturnType | null = null;
+ private angularDependencies: LegacyAngularInjectedDependencies | null = null;
+ private savedObjectsClient: any = null;
+
+ setup(
+ core: CoreSetup,
+ {
+ __LEGACY: { uiStatsReporter, toastNotifications, banners, kfetch, metadata, METRIC_TYPE },
+ localApplicationService,
+ }: HomePluginSetupDependencies
+ ) {
+ localApplicationService.register({
+ id: 'home',
+ title: 'Home',
+ mount: async (context, params) => {
+ const { renderApp } = await import('./render_app');
+ return renderApp(
+ context,
+ {
+ ...params,
+ uiStatsReporter,
+ toastNotifications,
+ banners,
+ kfetch,
+ savedObjectsClient: this.savedObjectsClient,
+ metadata,
+ METRIC_TYPE,
+ data: this.dataStart!,
+ npData: this.npDataStart!,
+ },
+ this.angularDependencies!
+ );
+ },
+ });
+ }
+
+ start(
+ core: CoreStart,
+ { data, npData, __LEGACY: { angularDependencies } }: HomePluginStartDependencies
+ ) {
+ // TODO is this really the right way? I though the app context would give us those
+ this.dataStart = data;
+ this.npDataStart = npData;
+ this.angularDependencies = angularDependencies;
+ this.savedObjectsClient = core.savedObjects.client;
+ }
+
+ stop() {}
+}
diff --git a/src/legacy/core_plugins/kibana/public/home/render_app.tsx b/src/legacy/core_plugins/kibana/public/home/render_app.tsx
new file mode 100644
index 0000000000000..f81f4cd0f1ba4
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/home/render_app.tsx
@@ -0,0 +1,90 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import { DataStart } from 'src/legacy/core_plugins/data/public';
+import { AppMountContext } from 'kibana/public';
+import { Plugin as DataPlugin } from 'src/plugins/data/public';
+import { render, unmountComponentAtNode } from 'react-dom';
+import { i18n } from '@kbn/i18n';
+import { LegacyAngularInjectedDependencies } from './plugin';
+import { setDeps } from './kibana_services';
+
+/**
+ * These are dependencies of the Graph app besides the base dependencies
+ * provided by the application service. Some of those still rely on non-shimmed
+ * plugins in LP-world, but if they are migrated only the import path in the plugin
+ * itself changes
+ */
+export interface HomeDependencies {
+ element: HTMLElement;
+ appBasePath: string;
+ data: DataStart;
+ npData: ReturnType;
+ uiStatsReporter: any;
+ toastNotifications: any;
+ banners: any;
+ kfetch: any;
+ metadata: any;
+ savedObjectsClient: any;
+ METRIC_TYPE: any;
+}
+
+export const renderApp = (
+ { core }: AppMountContext,
+ {
+ element,
+ appBasePath,
+ data,
+ npData,
+ uiStatsReporter,
+ toastNotifications,
+ banners,
+ kfetch,
+ metadata,
+ savedObjectsClient,
+ }: HomeDependencies,
+ angularDeps: LegacyAngularInjectedDependencies
+) => {
+ const deps = {
+ getInjected: core.injectedMetadata.getInjectedVar,
+ metadata,
+ docLinks: core.docLinks,
+ savedObjectsClient,
+ chrome: core.chrome,
+ uiSettings: core.uiSettings,
+ addBasePath: core.http.basePath.prepend,
+ getBasePath: core.http.basePath.get,
+ indexPatternService: data.indexPatterns.indexPatterns,
+ toastNotifications,
+ banners,
+ kfetch,
+ ...angularDeps,
+ };
+ setDeps(deps);
+
+ const homeTitle = i18n.translate('kbn.home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
+ const directories = angularDeps.featureCatalogueRegistryProvider.inTitleOrder;
+ core.chrome.setBreadcrumbs([{ text: homeTitle }]);
+
+ const HomeApp = require('./components/home_app').HomeApp;
+ render(, element);
+
+ return () => unmountComponentAtNode(element);
+};
diff --git a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
index b7f7b92eced51..6afed700ab7a3 100644
--- a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
+++ b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
@@ -17,7 +17,8 @@
* under the License.
*/
-import { indexPatternService, uiSettings, kfetch } from './kibana_services';
+import { getDeps } from './kibana_services';
+const { indexPatternService, uiSettings, kfetch, } = getDeps();
const sampleDataUrl = '/api/sample_data';
diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js
index 6c809e84c8c84..f9b0980dcb7c9 100644
--- a/src/legacy/core_plugins/kibana/public/kibana.js
+++ b/src/legacy/core_plugins/kibana/public/kibana.js
@@ -58,6 +58,9 @@ import 'ui/agg_response';
import 'ui/agg_types';
import { showAppRedirectNotification } from 'ui/notify';
import 'leaflet';
+import { localApplicationService } from './local_application_service';
+
+localApplicationService.registerWithAngularRouter(routes);
routes.enable();
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/index.ts b/src/legacy/core_plugins/kibana/public/local_application_service/index.ts
new file mode 100644
index 0000000000000..2128355ca906a
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export * from './local_application_service';
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
new file mode 100644
index 0000000000000..0432c56edc508
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
@@ -0,0 +1,76 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { ApplicationSetup, App } from 'kibana/public';
+import { UIRoutes } from 'ui/routes';
+import { IScope } from 'angular';
+import { npStart } from 'ui/new_platform';
+import { htmlIdGenerator } from '@elastic/eui';
+
+/**
+ * To be able to migrate and shim parts of the Kibana app plugin
+ * while still running some parts of it in the legacy world, this
+ * service emulates the core application service while using the global
+ * angular router to switch between apps without page reload.
+ *
+ * The id of the apps is used as prefix of the route - when switching between
+ * to apps, the current application is torn down.
+ *
+ * This service becomes unnecessary once the platform provides a central
+ * router that handles switching between applications without page reload.
+ */
+export interface LocalApplicationService {
+ register: ApplicationSetup['register'];
+ registerWithAngularRouter: (routeManager: UIRoutes) => void;
+}
+
+const apps: App[] = [];
+const idGenerator = htmlIdGenerator('kibanaAppLocalApp');
+
+export const localApplicationService: LocalApplicationService = {
+ register(app) {
+ apps.push(app);
+ },
+ registerWithAngularRouter(angularRouteManager: UIRoutes) {
+ apps.forEach(app => {
+ const wrapperElementId = idGenerator();
+ const routeConfig = {
+ // marker for stuff operating on the route data.
+ // This can be used to not execute some operations because
+ // the route is not actually doing something besides serving
+ // as a wrapper for the actual inner-angular routes
+ outerAngularWrapperRoute: true,
+ reloadOnSearch: false,
+ reloadOnUrl: false,
+ template: ``,
+ controller($scope: IScope) {
+ const element = document.getElementById(wrapperElementId)!;
+ // controller itself is not allowed to be async, use inner IIFE
+ (async () => {
+ const onUnmount = await app.mount({ core: npStart.core }, { element, appBasePath: '' });
+ $scope.$on('$destroy', () => {
+ onUnmount();
+ });
+ })();
+ },
+ };
+ angularRouteManager.when(`/${app.id}/:tail*?`, routeConfig);
+ });
+ },
+};
From 0d2521e94f63a0cebdf8790a49e8d9b0ee5f5877 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Sat, 19 Oct 2019 11:27:30 +0200
Subject: [PATCH 005/132] fix routing for home app
---
.../kibana/public/home/components/home_app.js | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home_app.js b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
index 3ccee843cb9a4..d05210b07fdc7 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home_app.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
@@ -28,6 +28,7 @@ import {
HashRouter as Router,
Switch,
Route,
+ Redirect,
} from 'react-router-dom';
import { getTutorial } from '../load_tutorials';
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
@@ -47,6 +48,7 @@ export function HomeApp({ directories }) {
const isCloudEnabled = getInjected('isCloudEnabled', false);
const apmUiEnabled = getInjected('apmUiEnabled', true);
const mlEnabled = getInjected('mlEnabled', false);
+ const defaultAppId = getInjected('kbnDefaultAppId', 'discover');
const renderTutorialDirectory = (props) => {
return (
@@ -76,14 +78,17 @@ export function HomeApp({ directories }) {
+
+
+
From af3ad7f0d7b895d26421dbc78189e12828f04bf7 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Mon, 21 Oct 2019 14:44:18 +0200
Subject: [PATCH 006/132] switch to dependency getter instead of direct exports
---
.../kibana/public/home/components/add_data.js | 4 +-
.../public/home/components/add_data.test.js | 14 ++---
.../kibana/public/home/components/home.js | 7 ++-
.../public/home/components/home.test.js | 6 ++-
.../kibana/public/home/components/home_app.js | 16 +++---
.../home/components/sample_data_set_cards.js | 20 +++----
.../sample_data_view_data_button.js | 7 +--
.../tutorial/replace_template_strings.js | 5 +-
.../home/components/tutorial/tutorial.js | 4 +-
.../home/components/tutorial/tutorial.test.js | 10 ++--
.../home/components/tutorial_directory.js | 4 +-
.../kibana/public/home/components/welcome.tsx | 22 ++++----
.../core_plugins/kibana/public/home/index.js | 5 +-
.../kibana/public/home/kibana_services.ts | 54 ++++++++++++-------
.../kibana/public/home/load_tutorials.js | 6 +--
.../kibana/public/home/sample_data_client.js | 16 +++---
16 files changed, 120 insertions(+), 80 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/home/components/add_data.js b/src/legacy/core_plugins/kibana/public/home/components/add_data.js
index 2bb11a46968b5..0a3adfa430a45 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/add_data.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/add_data.js
@@ -21,7 +21,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
-import { getBasePath } from '../kibana_services';
+import { getServices } from '../kibana_services';
import {
EuiButton,
@@ -38,9 +38,9 @@ import {
EuiFlexGrid,
} from '@elastic/eui';
-const basePath = getBasePath();
const AddDataUi = ({ apmUiEnabled, isNewKibanaInstance, intl, mlEnabled }) => {
+ const basePath = getServices().getBasePath();
const renderCards = () => {
const apmData = {
title: intl.formatMessage({
diff --git a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
index 1860814f6e062..81e3d6aaf63ad 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
@@ -20,10 +20,12 @@
import React from 'react';
import { AddData } from './add_data';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
-import { getBasePath } from '../kibana_services';
+import { getServices } from '../kibana_services';
jest.mock('../kibana_services', () =>({
- getBasePath: jest.fn(() => 'path'),
+ getServices: () => ({
+ getBasePath: jest.fn(() => 'path'),
+ }),
}));
test('render', () => {
@@ -33,7 +35,7 @@ test('render', () => {
isNewKibanaInstance={false}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(getBasePath).toHaveBeenCalledTimes(1);
+ expect(getServices().getBasePath).toHaveBeenCalledTimes(1);
});
test('mlEnabled', () => {
@@ -43,7 +45,7 @@ test('mlEnabled', () => {
isNewKibanaInstance={false}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(getBasePath).toHaveBeenCalledTimes(1);
+ expect(getServices().getBasePath).toHaveBeenCalledTimes(1);
});
test('apmUiEnabled', () => {
@@ -53,7 +55,7 @@ test('apmUiEnabled', () => {
isNewKibanaInstance={false}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(getBasePath).toHaveBeenCalledTimes(1);
+ expect(getServices().getBasePath).toHaveBeenCalledTimes(1);
});
test('isNewKibanaInstance', () => {
@@ -63,5 +65,5 @@ test('isNewKibanaInstance', () => {
isNewKibanaInstance={true}
/>);
expect(component).toMatchSnapshot(); // eslint-disable-line
- expect(getBasePath).toHaveBeenCalledTimes(1);
+ expect(getServices().getBasePath).toHaveBeenCalledTimes(1);
});
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home.js b/src/legacy/core_plugins/kibana/public/home/components/home.js
index 4cce329846710..e4c7de9b495a0 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home.js
@@ -39,7 +39,7 @@ import {
import { Welcome } from './welcome';
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
-import { getInjected } from '../kibana_services';
+import { getServices } from '../kibana_services';
const KEY_ENABLE_WELCOME = 'home:welcome:show';
@@ -47,7 +47,10 @@ export class Home extends Component {
constructor(props) {
super(props);
- const isWelcomeEnabled = !(getInjected('disableWelcomeScreen') || props.localStorage.getItem(KEY_ENABLE_WELCOME) === 'false');
+ const isWelcomeEnabled = !(
+ getServices().getInjected('disableWelcomeScreen') ||
+ props.localStorage.getItem(KEY_ENABLE_WELCOME) === 'false'
+ );
this.state = {
// If welcome is enabled, we wait for loading to complete
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home.test.js b/src/legacy/core_plugins/kibana/public/home/components/home.test.js
index 768b79906e13f..c21c6fa3d98a5 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home.test.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home.test.js
@@ -26,8 +26,10 @@ import { Home } from './home';
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
jest.mock('../kibana_services', () =>({
- getBasePath: () => 'path',
- getInjected: () => ''
+ getServices: () => ({
+ getBasePath: () => 'path',
+ getInjected: () => ''
+ })
}));
describe('home', () => {
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home_app.js b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
index 998f4e4608da3..005d4bdb0a99e 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home_app.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
@@ -31,15 +31,19 @@ import {
import { getTutorial } from '../load_tutorials';
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
import {
- telemetryOptInProvider,
- shouldShowTelemetryOptIn,
- getInjected,
- savedObjectsClient,
- getBasePath,
- addBasePath,
+ getServices
} from '../kibana_services';
export function HomeApp({ directories }) {
+ const {
+ telemetryOptInProvider,
+ shouldShowTelemetryOptIn,
+ getInjected,
+ savedObjectsClient,
+ getBasePath,
+ addBasePath,
+ } = getServices();
+
const isCloudEnabled = getInjected('isCloudEnabled', false);
const apmUiEnabled = getInjected('apmUiEnabled', true);
const mlEnabled = getInjected('mlEnabled', false);
diff --git a/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js b/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js
index 579a68641a9e2..53d922c4e0a26 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/sample_data_set_cards.js
@@ -31,7 +31,7 @@ import {
UNINSTALLED_STATUS,
} from './sample_data_set_card';
-import { toastNotifications, uiSettings } from '../kibana_services';
+import { getServices } from '../kibana_services';
import {
listSampleDataSets,
@@ -41,13 +41,13 @@ import {
import { i18n } from '@kbn/i18n';
-const IS_DARK_THEME = uiSettings.get('theme:darkMode');
-
export class SampleDataSetCards extends React.Component {
constructor(props) {
super(props);
+ this.toastNotifications = getServices().toastNotifications;
+
this.state = {
sampleDataSets: [],
processingStatus: {},
@@ -69,7 +69,7 @@ export class SampleDataSetCards extends React.Component {
try {
sampleDataSets = await listSampleDataSets();
} catch (fetchError) {
- toastNotifications.addDanger({
+ this.toastNotifications.addDanger({
title: i18n.translate('kbn.home.sampleDataSet.unableToLoadListErrorMessage', {
defaultMessage: 'Unable to load sample data sets list' }
),
@@ -108,7 +108,7 @@ export class SampleDataSetCards extends React.Component {
processingStatus: { ...prevState.processingStatus, [id]: false }
}));
}
- toastNotifications.addDanger({
+ this.toastNotifications.addDanger({
title: i18n.translate('kbn.home.sampleDataSet.unableToInstallErrorMessage', {
defaultMessage: 'Unable to install sample data set: {name}', values: { name: targetSampleDataSet.name } }
),
@@ -129,7 +129,7 @@ export class SampleDataSetCards extends React.Component {
}));
}
- toastNotifications.addSuccess({
+ this.toastNotifications.addSuccess({
title: i18n.translate('kbn.home.sampleDataSet.installedLabel', {
defaultMessage: '{name} installed', values: { name: targetSampleDataSet.name } }
),
@@ -154,7 +154,7 @@ export class SampleDataSetCards extends React.Component {
processingStatus: { ...prevState.processingStatus, [id]: false }
}));
}
- toastNotifications.addDanger({
+ this.toastNotifications.addDanger({
title: i18n.translate('kbn.home.sampleDataSet.unableToUninstallErrorMessage', {
defaultMessage: 'Unable to uninstall sample data set: {name}', values: { name: targetSampleDataSet.name } }
),
@@ -175,7 +175,7 @@ export class SampleDataSetCards extends React.Component {
}));
}
- toastNotifications.addSuccess({
+ this.toastNotifications.addSuccess({
title: i18n.translate('kbn.home.sampleDataSet.uninstalledLabel', {
defaultMessage: '{name} uninstalled', values: { name: targetSampleDataSet.name } }
),
@@ -184,7 +184,9 @@ export class SampleDataSetCards extends React.Component {
}
lightOrDarkImage = (sampleDataSet) => {
- return IS_DARK_THEME && sampleDataSet.darkPreviewImagePath ? sampleDataSet.darkPreviewImagePath : sampleDataSet.previewImagePath;
+ return getServices().uiSettings.get('theme:darkMode') && sampleDataSet.darkPreviewImagePath
+ ? sampleDataSet.darkPreviewImagePath
+ : sampleDataSet.previewImagePath;
}
render() {
diff --git a/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js b/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js
index a0f21c9b2dbf1..89d4909b0c66f 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/sample_data_view_data_button.js
@@ -27,9 +27,10 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import { addBasePath } from '../kibana_services';
+import { getServices } from '../kibana_services';
export class SampleDataViewDataButton extends React.Component {
+ addBasePath = getServices().addBasePath;
state = {
isPopoverOpen: false
@@ -56,7 +57,7 @@ export class SampleDataViewDataButton extends React.Component {
datasetName: this.props.name,
},
});
- const dashboardPath = addBasePath(`/app/kibana#/dashboard/${this.props.overviewDashboard}`);
+ const dashboardPath = this.addBasePath(`/app/kibana#/dashboard/${this.props.overviewDashboard}`);
if (this.props.appLinks.length === 0) {
return (
@@ -79,7 +80,7 @@ export class SampleDataViewDataButton extends React.Component {
size="m"
/>
),
- href: addBasePath(path)
+ href: this.addBasePath(path)
};
});
const panels = [
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js
index cdbafadb228a4..e68307b58cdaf 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial/replace_template_strings.js
@@ -18,7 +18,8 @@
*/
import { Writer } from 'mustache';
-import { getInjected, metadata, docLinks } from '../../kibana_services';
+import { getServices } from '../../kibana_services';
+
const TEMPLATE_TAGS = ['{', '}'];
@@ -33,6 +34,8 @@ mustacheWriter.escapedValue = function escapedValue(token, context) {
};
export function replaceTemplateStrings(text, params = {}) {
+ const { getInjected, metadata, docLinks } = getServices();
+
const variables = {
// '{' and '}' can not be used in template since they are used as template tags.
// Must use '{curlyOpen}'' and '{curlyClose}'
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js
index 211801643a7a9..086fa5a059121 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.js
@@ -37,7 +37,7 @@ import {
import * as StatusCheckStates from './status_check_states';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
-import { chrome } from '../../kibana_services';
+import { getServices } from '../../kibana_services';
const INSTRUCTIONS_TYPE = {
ELASTIC_CLOUD: 'elasticCloud',
@@ -94,7 +94,7 @@ class TutorialUi extends React.Component {
});
}
- chrome.setBreadcrumbs([
+ getServices().chrome.setBreadcrumbs([
{
text: homeTitle,
href: '#/home'
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js
index 157b7fa5dfecd..150ab4451e46d 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial/tutorial.test.js
@@ -26,10 +26,12 @@ import {
jest.mock('../../kibana_services', () =>({
- getBasePath: jest.fn(() => 'path'),
- chrome: {
- setBreadcrumbs: () => {}
- }
+ getServices: () =>({
+ getBasePath: jest.fn(() => 'path'),
+ chrome: {
+ setBreadcrumbs: () => {}
+ }
+ })
}));
jest.mock('../../../../../kibana_react/public', () => {
return {
diff --git a/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js b/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
index 06c194a3f7ca8..0c537c8e9ae8a 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/tutorial_directory.js
@@ -22,7 +22,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Synopsis } from './synopsis';
import { SampleDataSetCards } from './sample_data_set_cards';
-import { chrome } from '../kibana_services';
+import { getServices } from '../kibana_services';
import {
EuiPage,
@@ -112,7 +112,7 @@ class TutorialDirectoryUi extends React.Component {
async componentDidMount() {
this._isMounted = true;
- chrome.setBreadcrumbs([
+ getServices().chrome.setBreadcrumbs([
{
text: homeTitle,
href: '#/home',
diff --git a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
index 089739e380f11..afe43a23e18cb 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
+++ b/src/legacy/core_plugins/kibana/public/home/components/welcome.tsx
@@ -34,12 +34,10 @@ import {
EuiPortal,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { banners } from '../kibana_services';
+import { getServices } from '../kibana_services';
import { SampleDataCard } from './sample_data';
import { TelemetryOptInCard } from './telemetry_opt_in';
-// @ts-ignore
-import { trackUiMetric, METRIC_TYPE, addBasePath } from '../kibana_services';
interface Props {
urlBasePath: string;
@@ -58,6 +56,7 @@ interface State {
* Shows a full-screen welcome page that gives helpful quick links to beginners.
*/
export class Welcome extends React.PureComponent {
+ private services = getServices();
public readonly state: State = {
step: 0,
};
@@ -69,32 +68,35 @@ export class Welcome extends React.PureComponent {
};
private redirecToSampleData() {
- const path = addBasePath('#/home/tutorial_directory/sampleData');
+ const path = this.services.addBasePath('#/home/tutorial_directory/sampleData');
window.location.href = path;
}
private async handleTelemetrySelection(confirm: boolean) {
const metricName = `telemetryOptIn${confirm ? 'Confirm' : 'Decline'}`;
- trackUiMetric(METRIC_TYPE.CLICK, metricName);
+ this.services.trackUiMetric(this.services.METRIC_TYPE.CLICK, metricName);
await this.props.setOptIn(confirm);
const bannerId = this.props.getTelemetryBannerId();
- banners.remove(bannerId);
+ this.services.banners.remove(bannerId);
this.setState(() => ({ step: 1 }));
}
private onSampleDataDecline = () => {
- trackUiMetric(METRIC_TYPE.CLICK, 'sampleDataDecline');
+ this.services.trackUiMetric(this.services.METRIC_TYPE.CLICK, 'sampleDataDecline');
this.props.onSkip();
};
private onSampleDataConfirm = () => {
- trackUiMetric(METRIC_TYPE.CLICK, 'sampleDataConfirm');
+ this.services.trackUiMetric(this.services.METRIC_TYPE.CLICK, 'sampleDataConfirm');
this.redirecToSampleData();
};
componentDidMount() {
- trackUiMetric(METRIC_TYPE.LOADED, 'welcomeScreenMount');
+ this.services.trackUiMetric(this.services.METRIC_TYPE.LOADED, 'welcomeScreenMount');
if (this.props.shouldShowTelemetryOptIn) {
- trackUiMetric(METRIC_TYPE.COUNT, 'welcomeScreenWithTelemetryOptIn');
+ this.services.trackUiMetric(
+ this.services.METRIC_TYPE.COUNT,
+ 'welcomeScreenWithTelemetryOptIn'
+ );
}
document.addEventListener('keydown', this.hideOnEsc);
}
diff --git a/src/legacy/core_plugins/kibana/public/home/index.js b/src/legacy/core_plugins/kibana/public/home/index.js
index 746cdfcfb4768..8ef5972d36683 100644
--- a/src/legacy/core_plugins/kibana/public/home/index.js
+++ b/src/legacy/core_plugins/kibana/public/home/index.js
@@ -17,13 +17,15 @@
* under the License.
*/
-import { chrome, addBasePath, featureCatalogueRegistryProvider, wrapInI18nContext, uiRoutes, uiModules } from './kibana_services';
+import { getServices } from './kibana_services';
import template from './home_ng_wrapper.html';
import {
HomeApp
} from './components/home_app';
import { i18n } from '@kbn/i18n';
+const { wrapInI18nContext, uiRoutes, uiModules } = getServices();
+
const app = uiModules.get('apps/home', []);
app.directive('homeApp', function (reactDirective) {
return reactDirective(wrapInI18nContext(HomeApp));
@@ -35,6 +37,7 @@ function getRoute() {
return {
template,
controller($scope) {
+ const { chrome, addBasePath, featureCatalogueRegistryProvider } = getServices();
$scope.directories = featureCatalogueRegistryProvider.inTitleOrder;
$scope.recentlyAccessed = chrome.recentlyAccessed.get().map(item => {
item.link = addBasePath(item.link);
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index a44686999a120..868e977a4601c 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -17,6 +17,12 @@
* under the License.
*/
+// @ts-ignore
+import { toastNotifications, banners } from 'ui/notify';
+import { kfetch } from 'ui/kfetch';
+
+import { wrapInI18nContext } from 'ui/i18n';
+
// @ts-ignore
import { uiModules as modules } from 'ui/modules';
import routes from 'ui/routes';
@@ -26,32 +32,40 @@ import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue'
import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
import { TelemetryOptInProvider } from '../../../telemetry/public/services';
import { start as data } from '../../../data/public/legacy';
-// @ts-ignore
-export { toastNotifications, banners } from 'ui/notify';
-export { kfetch } from 'ui/kfetch';
-export { wrapInI18nContext } from 'ui/i18n';
-export const getInjected = npStart.core.injectedMetadata.getInjectedVar;
-export const metadata = npStart.core.injectedMetadata.getLegacyMetadata();
+let shouldShowTelemetryOptIn: boolean;
+let telemetryOptInProvider: any;
+let featureCatalogueRegistryProvider: any;
+
+export function getServices() {
+ return {
+ getInjected: npStart.core.injectedMetadata.getInjectedVar,
+ metadata: npStart.core.injectedMetadata.getLegacyMetadata(),
+ docLinks: npStart.core.docLinks,
-export const docLinks = npStart.core.docLinks;
+ uiRoutes: routes,
+ uiModules: modules,
-export const uiRoutes = routes;
-export const uiModules = modules;
+ savedObjectsClient: npStart.core.savedObjects.client,
+ chrome: npStart.core.chrome,
+ uiSettings: npStart.core.uiSettings,
+ addBasePath: npStart.core.http.basePath.prepend,
+ getBasePath: npStart.core.http.basePath.get,
-export const savedObjectsClient = npStart.core.savedObjects.client;
-export const chrome = npStart.core.chrome;
-export const uiSettings = npStart.core.uiSettings;
-export const addBasePath = npStart.core.http.basePath.prepend;
-export const getBasePath = npStart.core.http.basePath.get;
+ indexPatternService: data.indexPatterns.indexPatterns,
+ shouldShowTelemetryOptIn,
+ telemetryOptInProvider,
+ featureCatalogueRegistryProvider,
-export const indexPatternService = data.indexPatterns.indexPatterns;
-export let shouldShowTelemetryOptIn: boolean;
-export let telemetryOptInProvider: any;
-export let featureCatalogueRegistryProvider: any;
+ trackUiMetric: createUiStatsReporter('Kibana_home'),
+ METRIC_TYPE,
-export const trackUiMetric = createUiStatsReporter('Kibana_home');
-export { METRIC_TYPE };
+ toastNotifications,
+ banners,
+ kfetch,
+ wrapInI18nContext,
+ };
+}
modules.get('kibana').run((Private: IPrivate) => {
const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
diff --git a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
index f8336a8b5d412..a6f19bc166dc7 100644
--- a/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
+++ b/src/legacy/core_plugins/kibana/public/home/load_tutorials.js
@@ -18,10 +18,10 @@
*/
import _ from 'lodash';
-import { addBasePath, toastNotifications } from './kibana_services';
+import { getServices } from './kibana_services';
import { i18n } from '@kbn/i18n';
-const baseUrl = addBasePath('/api/kibana/home/tutorials');
+const baseUrl = getServices().addBasePath('/api/kibana/home/tutorials');
const headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/json');
@@ -46,7 +46,7 @@ async function loadTutorials() {
tutorials = await response.json();
tutorialsLoaded = true;
} catch(err) {
- toastNotifications.addDanger({
+ getServices().toastNotifications.addDanger({
title: i18n.translate('kbn.home.loadTutorials.unableToLoadErrorMessage', {
defaultMessage: 'Unable to load tutorials' }
),
diff --git a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
index b7f7b92eced51..9411373004c25 100644
--- a/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
+++ b/src/legacy/core_plugins/kibana/public/home/sample_data_client.js
@@ -17,30 +17,32 @@
* under the License.
*/
-import { indexPatternService, uiSettings, kfetch } from './kibana_services';
+import { getServices } from './kibana_services';
const sampleDataUrl = '/api/sample_data';
function clearIndexPatternsCache() {
- indexPatternService.clearCache();
+ getServices().indexPatternService.clearCache();
}
export async function listSampleDataSets() {
- return await kfetch({ method: 'GET', pathname: sampleDataUrl });
+ return await getServices().kfetch({ method: 'GET', pathname: sampleDataUrl });
}
export async function installSampleDataSet(id, sampleDataDefaultIndex) {
- await kfetch({ method: 'POST', pathname: `${sampleDataUrl}/${id}` });
+ await getServices().kfetch({ method: 'POST', pathname: `${sampleDataUrl}/${id}` });
- if (uiSettings.isDefault('defaultIndex')) {
- uiSettings.set('defaultIndex', sampleDataDefaultIndex);
+ if (getServices().uiSettings.isDefault('defaultIndex')) {
+ getServices().uiSettings.set('defaultIndex', sampleDataDefaultIndex);
}
clearIndexPatternsCache();
}
export async function uninstallSampleDataSet(id, sampleDataDefaultIndex) {
- await kfetch({ method: 'DELETE', pathname: `${sampleDataUrl}/${id}` });
+ await getServices().kfetch({ method: 'DELETE', pathname: `${sampleDataUrl}/${id}` });
+
+ const uiSettings = getServices().uiSettings;
if (!uiSettings.isDefault('defaultIndex')
&& uiSettings.get('defaultIndex') === sampleDataDefaultIndex) {
From a1295d3140f46d3db7d2039e14c2cabefcf441a2 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Mon, 21 Oct 2019 15:49:42 +0200
Subject: [PATCH 007/132] clean up
---
.../core_plugins/kibana/public/home/index.ts | 7 +-
.../kibana/public/home/kibana_services.ts | 106 ++++++++----------
.../core_plugins/kibana/public/home/plugin.ts | 74 ++++++------
.../kibana/public/home/render_app.tsx | 67 ++---------
.../local_application_service.ts | 38 +++----
.../ui/public/routes/route_manager.d.ts | 2 +
6 files changed, 110 insertions(+), 184 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/home/index.ts b/src/legacy/core_plugins/kibana/public/home/index.ts
index b8c468820f201..42abbec798592 100644
--- a/src/legacy/core_plugins/kibana/public/home/index.ts
+++ b/src/legacy/core_plugins/kibana/public/home/index.ts
@@ -30,7 +30,7 @@ import { start as data } from '../../../data/public/legacy';
import { TelemetryOptInProvider } from '../../../telemetry/public/services';
import { localApplicationService } from '../local_application_service';
-export const uiStatsReporter = createUiStatsReporter('Kibana_home');
+export const trackUiMetric = createUiStatsReporter('Kibana_home');
/**
* Get dependencies relying on the global angular context.
@@ -57,18 +57,17 @@ async function getAngularInjectedDependencies(): Promise unknown;
+ chrome: ChromeStart;
+ telemetryOptInProvider: any;
+ uiSettings: UiSettingsClientContract;
+ kfetch: (options: KFetchOptions, kfetchOptions?: KFetchKibanaOptions) => Promise;
+ savedObjectsClient: SavedObjectsClientContract;
+ toastNotifications: ToastNotifications;
+ banners: any;
+ METRIC_TYPE: any;
+ trackUiMetric: (type: UiStatsMetricType, eventNames: string | string[], count?: number) => void;
+ getBasePath: () => string;
+ shouldShowTelemetryOptIn: boolean;
+ docLinks: DocLinksStart;
+ addBasePath: (url: string) => string;
+}
let services: HomeKibanaServices | null = null;
@@ -38,64 +81,3 @@ export function getServices() {
}
return services;
}
-/*
-// @ts-ignore
-import { toastNotifications, banners } from 'ui/notify';
-import { kfetch } from 'ui/kfetch';
-
-import { wrapInI18nContext } from 'ui/i18n';
-
-// @ts-ignore
-import { uiModules as modules } from 'ui/modules';
-import routes from 'ui/routes';
-import { npStart } from 'ui/new_platform';
-import { IPrivate } from 'ui/private';
-import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
-import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
-import { TelemetryOptInProvider } from '../../../telemetry/public/services';
-import { start as data } from '../../../data/public/legacy';
-
-let shouldShowTelemetryOptIn: boolean;
-let telemetryOptInProvider: any;
-let featureCatalogueRegistryProvider: any;
-
-export function getServices() {
- return {
- getInjected: npStart.core.injectedMetadata.getInjectedVar,
- metadata: npStart.core.injectedMetadata.getLegacyMetadata(),
- docLinks: npStart.core.docLinks,
-
- uiRoutes: routes,
- uiModules: modules,
-
- savedObjectsClient: npStart.core.savedObjects.client,
- chrome: npStart.core.chrome,
- uiSettings: npStart.core.uiSettings,
- addBasePath: npStart.core.http.basePath.prepend,
- getBasePath: npStart.core.http.basePath.get,
-
- indexPatternService: data.indexPatterns.indexPatterns,
- shouldShowTelemetryOptIn,
- telemetryOptInProvider,
- featureCatalogueRegistryProvider,
-
- trackUiMetric: createUiStatsReporter('Kibana_home'),
- METRIC_TYPE,
-
- toastNotifications,
- banners,
- kfetch,
- wrapInI18nContext,
- };
-}
-
-modules.get('kibana').run((Private: IPrivate) => {
- const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
- const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
-
- telemetryOptInProvider = Private(TelemetryOptInProvider);
- shouldShowTelemetryOptIn =
- telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn();
- featureCatalogueRegistryProvider = Private(FeatureCatalogueRegistryProvider as any);
-});
-*/
diff --git a/src/legacy/core_plugins/kibana/public/home/plugin.ts b/src/legacy/core_plugins/kibana/public/home/plugin.ts
index 9e0a85b2b7f72..b2d528fbc0950 100644
--- a/src/legacy/core_plugins/kibana/public/home/plugin.ts
+++ b/src/legacy/core_plugins/kibana/public/home/plugin.ts
@@ -17,11 +17,15 @@
* under the License.
*/
-import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
-import { Plugin as DataPlugin } from 'src/plugins/data/public';
+import { CoreSetup, CoreStart, LegacyNavLink, Plugin, UiSettingsState } from 'kibana/public';
+import { UiStatsMetricType } from '@kbn/analytics';
+import { ToastNotifications } from 'ui/notify/toasts/toast_notifications';
+import { KFetchOptions } from 'ui/kfetch';
+import { KFetchKibanaOptions } from 'ui/kfetch/kfetch';
import { DataStart } from '../../../data/public';
import { LocalApplicationService } from '../local_application_service';
+import { setServices } from './kibana_services';
export interface LegacyAngularInjectedDependencies {
featureCatalogueRegistryProvider: any;
@@ -31,7 +35,6 @@ export interface LegacyAngularInjectedDependencies {
export interface HomePluginStartDependencies {
data: DataStart;
- npData: ReturnType;
__LEGACY: {
angularDependencies: LegacyAngularInjectedDependencies;
};
@@ -39,61 +42,62 @@ export interface HomePluginStartDependencies {
export interface HomePluginSetupDependencies {
__LEGACY: {
- uiStatsReporter: any;
- toastNotifications: any;
+ trackUiMetric: (type: UiStatsMetricType, eventNames: string | string[], count?: number) => void;
+ toastNotifications: ToastNotifications;
banners: any;
- kfetch: any;
- metadata: any;
METRIC_TYPE: any;
+ kfetch: (options: KFetchOptions, kfetchOptions?: KFetchKibanaOptions) => Promise;
+ metadata: {
+ app: unknown;
+ bundleId: string;
+ nav: LegacyNavLink[];
+ version: string;
+ branch: string;
+ buildNum: number;
+ buildSha: string;
+ basePath: string;
+ serverName: string;
+ devMode: boolean;
+ uiSettings: { defaults: UiSettingsState; user?: UiSettingsState | undefined };
+ };
+ localApplicationService: LocalApplicationService;
};
- localApplicationService: LocalApplicationService;
}
export class HomePlugin implements Plugin {
private dataStart: DataStart | null = null;
- private npDataStart: ReturnType | null = null;
private angularDependencies: LegacyAngularInjectedDependencies | null = null;
private savedObjectsClient: any = null;
setup(
core: CoreSetup,
- {
- __LEGACY: { uiStatsReporter, toastNotifications, banners, kfetch, metadata, METRIC_TYPE },
- localApplicationService,
- }: HomePluginSetupDependencies
+ { __LEGACY: { localApplicationService, ...legacyServices } }: HomePluginSetupDependencies
) {
localApplicationService.register({
id: 'home',
title: 'Home',
- mount: async (context, params) => {
+ mount: async ({ core: contextCore }, params) => {
+ setServices({
+ ...legacyServices,
+ getInjected: core.injectedMetadata.getInjectedVar,
+ docLinks: contextCore.docLinks,
+ savedObjectsClient: this.savedObjectsClient!,
+ chrome: contextCore.chrome,
+ uiSettings: core.uiSettings,
+ addBasePath: core.http.basePath.prepend,
+ getBasePath: core.http.basePath.get,
+ indexPatternService: this.dataStart!.indexPatterns.indexPatterns,
+ ...this.angularDependencies!,
+ });
const { renderApp } = await import('./render_app');
- return renderApp(
- context,
- {
- ...params,
- uiStatsReporter,
- toastNotifications,
- banners,
- kfetch,
- savedObjectsClient: this.savedObjectsClient,
- metadata,
- METRIC_TYPE,
- data: this.dataStart!,
- npData: this.npDataStart!,
- },
- this.angularDependencies!
- );
+ return renderApp(params.element);
},
});
}
- start(
- core: CoreStart,
- { data, npData, __LEGACY: { angularDependencies } }: HomePluginStartDependencies
- ) {
+ start(core: CoreStart, { data, __LEGACY: { angularDependencies } }: HomePluginStartDependencies) {
// TODO is this really the right way? I though the app context would give us those
this.dataStart = data;
- this.npDataStart = npData;
this.angularDependencies = angularDependencies;
this.savedObjectsClient = core.savedObjects.client;
}
diff --git a/src/legacy/core_plugins/kibana/public/home/render_app.tsx b/src/legacy/core_plugins/kibana/public/home/render_app.tsx
index 01ea450d8d4d9..2e2db616756ee 100644
--- a/src/legacy/core_plugins/kibana/public/home/render_app.tsx
+++ b/src/legacy/core_plugins/kibana/public/home/render_app.tsx
@@ -18,71 +18,18 @@
*/
import React from 'react';
-import { DataStart } from 'src/legacy/core_plugins/data/public';
-import { AppMountContext } from 'kibana/public';
-import { Plugin as DataPlugin } from 'src/plugins/data/public';
import { render, unmountComponentAtNode } from 'react-dom';
import { i18n } from '@kbn/i18n';
-import { LegacyAngularInjectedDependencies } from './plugin';
-
-/**
- * These are dependencies of the Graph app besides the base dependencies
- * provided by the application service. Some of those still rely on non-shimmed
- * plugins in LP-world, but if they are migrated only the import path in the plugin
- * itself changes
- */
-export interface HomeDependencies {
- element: HTMLElement;
- appBasePath: string;
- data: DataStart;
- npData: ReturnType;
- uiStatsReporter: any;
- toastNotifications: any;
- banners: any;
- kfetch: any;
- metadata: any;
- savedObjectsClient: any;
- METRIC_TYPE: any;
-}
-
-export const renderApp = (
- { core }: AppMountContext,
- {
- element,
- appBasePath,
- data,
- npData,
- uiStatsReporter,
- toastNotifications,
- banners,
- kfetch,
- metadata,
- savedObjectsClient,
- }: HomeDependencies,
- angularDeps: LegacyAngularInjectedDependencies
-) => {
- const deps = {
- getInjected: core.injectedMetadata.getInjectedVar,
- metadata,
- docLinks: core.docLinks,
- savedObjectsClient,
- chrome: core.chrome,
- uiSettings: core.uiSettings,
- addBasePath: core.http.basePath.prepend,
- getBasePath: core.http.basePath.get,
- indexPatternService: data.indexPatterns.indexPatterns,
- toastNotifications,
- banners,
- kfetch,
- ...angularDeps,
- };
- setDeps(deps);
+// @ts-ignore
+import { HomeApp } from './components/home_app';
+import { getServices } from './kibana_services';
+export const renderApp = (element: HTMLElement) => {
const homeTitle = i18n.translate('kbn.home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
- const directories = angularDeps.featureCatalogueRegistryProvider.inTitleOrder;
- core.chrome.setBreadcrumbs([{ text: homeTitle }]);
+ const { featureCatalogueRegistryProvider, chrome } = getServices();
+ const directories = featureCatalogueRegistryProvider.inTitleOrder;
+ chrome.setBreadcrumbs([{ text: homeTitle }]);
- const HomeApp = require('./components/home_app').HomeApp;
render(, element);
return () => unmountComponentAtNode(element);
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
index 0432c56edc508..845ac72544973 100644
--- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { ApplicationSetup, App } from 'kibana/public';
+import { App } from 'kibana/public';
import { UIRoutes } from 'ui/routes';
import { IScope } from 'angular';
import { npStart } from 'ui/new_platform';
@@ -35,33 +35,24 @@ import { htmlIdGenerator } from '@elastic/eui';
* This service becomes unnecessary once the platform provides a central
* router that handles switching between applications without page reload.
*/
-export interface LocalApplicationService {
- register: ApplicationSetup['register'];
- registerWithAngularRouter: (routeManager: UIRoutes) => void;
-}
+export class LocalApplicationService {
+ private apps: App[] = [];
+ private idGenerator = htmlIdGenerator('kibanaAppLocalApp');
-const apps: App[] = [];
-const idGenerator = htmlIdGenerator('kibanaAppLocalApp');
+ register(app: App) {
+ this.apps.push(app);
+ }
-export const localApplicationService: LocalApplicationService = {
- register(app) {
- apps.push(app);
- },
registerWithAngularRouter(angularRouteManager: UIRoutes) {
- apps.forEach(app => {
- const wrapperElementId = idGenerator();
- const routeConfig = {
- // marker for stuff operating on the route data.
- // This can be used to not execute some operations because
- // the route is not actually doing something besides serving
- // as a wrapper for the actual inner-angular routes
+ this.apps.forEach(app => {
+ const wrapperElementId = this.idGenerator();
+ angularRouteManager.when(`/${app.id}/:tail*?`, {
outerAngularWrapperRoute: true,
reloadOnSearch: false,
reloadOnUrl: false,
template: ``,
controller($scope: IScope) {
const element = document.getElementById(wrapperElementId)!;
- // controller itself is not allowed to be async, use inner IIFE
(async () => {
const onUnmount = await app.mount({ core: npStart.core }, { element, appBasePath: '' });
$scope.$on('$destroy', () => {
@@ -69,8 +60,9 @@ export const localApplicationService: LocalApplicationService = {
});
})();
},
- };
- angularRouteManager.when(`/${app.id}/:tail*?`, routeConfig);
+ });
});
- },
-};
+ }
+}
+
+export const localApplicationService = new LocalApplicationService();
diff --git a/src/legacy/ui/public/routes/route_manager.d.ts b/src/legacy/ui/public/routes/route_manager.d.ts
index 3471d7e954862..d5f19e7a970ce 100644
--- a/src/legacy/ui/public/routes/route_manager.d.ts
+++ b/src/legacy/ui/public/routes/route_manager.d.ts
@@ -27,10 +27,12 @@ interface RouteConfiguration {
controller?: string | ((...args: any[]) => void);
redirectTo?: string;
reloadOnSearch?: boolean;
+ reloadOnUrl?: boolean;
resolve?: object;
template?: string;
k7Breadcrumbs?: (...args: any[]) => ChromeBreadcrumb[];
requireUICapability?: string;
+ outerAngularWrapperRoute?: boolean;
}
interface RouteManager {
From 082748a8225a946e93df53cf587fcca617e42732 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Mon, 21 Oct 2019 16:03:09 +0200
Subject: [PATCH 008/132] add redirect functionality to local application
service
---
.../core_plugins/kibana/public/kibana.js | 2 +-
.../local_application_service.ts | 20 ++++++++++++++++++-
.../ui/public/routes/route_manager.d.ts | 2 +-
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js
index f9b0980dcb7c9..af7c9131caf45 100644
--- a/src/legacy/core_plugins/kibana/public/kibana.js
+++ b/src/legacy/core_plugins/kibana/public/kibana.js
@@ -60,7 +60,7 @@ import { showAppRedirectNotification } from 'ui/notify';
import 'leaflet';
import { localApplicationService } from './local_application_service';
-localApplicationService.registerWithAngularRouter(routes);
+localApplicationService.apply(routes);
routes.enable();
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
index 845ac72544973..c2963d1ba7095 100644
--- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
@@ -37,13 +37,22 @@ import { htmlIdGenerator } from '@elastic/eui';
*/
export class LocalApplicationService {
private apps: App[] = [];
+ private forwards: Array<{ legacyAppId: string; newAppId: string; keepPrefix: boolean }> = [];
private idGenerator = htmlIdGenerator('kibanaAppLocalApp');
register(app: App) {
this.apps.push(app);
}
- registerWithAngularRouter(angularRouteManager: UIRoutes) {
+ forwardApp(
+ legacyAppId: string,
+ newAppId: string,
+ options: { keepPrefix: boolean } = { keepPrefix: false }
+ ) {
+ this.forwards.push({ legacyAppId, newAppId, ...options });
+ }
+
+ apply(angularRouteManager: UIRoutes) {
this.apps.forEach(app => {
const wrapperElementId = this.idGenerator();
angularRouteManager.when(`/${app.id}/:tail*?`, {
@@ -62,6 +71,15 @@ export class LocalApplicationService {
},
});
});
+
+ this.forwards.forEach(({ legacyAppId, newAppId, keepPrefix }) => {
+ angularRouteManager.when(`/${legacyAppId}:tail*?`, {
+ redirectTo: (_params: unknown, path: string, search: string) => {
+ const newPath = `/${newAppId}${keepPrefix ? path : path.replace(legacyAppId, '')}`;
+ return `${newPath}?${search}`;
+ },
+ });
+ });
}
}
diff --git a/src/legacy/ui/public/routes/route_manager.d.ts b/src/legacy/ui/public/routes/route_manager.d.ts
index d5f19e7a970ce..6187dfa71f856 100644
--- a/src/legacy/ui/public/routes/route_manager.d.ts
+++ b/src/legacy/ui/public/routes/route_manager.d.ts
@@ -25,7 +25,7 @@ import { ChromeBreadcrumb } from '../../../../core/public';
interface RouteConfiguration {
controller?: string | ((...args: any[]) => void);
- redirectTo?: string;
+ redirectTo?: string | ((...args: any[]) => string);
reloadOnSearch?: boolean;
reloadOnUrl?: boolean;
resolve?: object;
From 2bf3bf6c18a7320fabc69312069dfc5180293564 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Mon, 21 Oct 2019 16:39:10 +0200
Subject: [PATCH 009/132] return early from route change handlers on dummy
wrapper route
---
.../public/legacy_compat/angular_config.tsx | 22 ++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/legacy/ui/public/legacy_compat/angular_config.tsx b/src/legacy/ui/public/legacy_compat/angular_config.tsx
index 8eac31e24530c..86ca9f911a578 100644
--- a/src/legacy/ui/public/legacy_compat/angular_config.tsx
+++ b/src/legacy/ui/public/legacy_compat/angular_config.tsx
@@ -160,6 +160,12 @@ const capture$httpLoadingCount = (newPlatform: CoreStart) => (
);
};
+function isDummyWrapperRoute($route: any) {
+ return (
+ $route.current && $route.current.$$route && $route.current.$$route.outerAngularWrapperRoute
+ );
+}
+
/**
* internal angular run function that will be called when angular bootstraps and
* lets us integrate with the angular router so that we can automatically clear
@@ -187,6 +193,9 @@ const $setupBreadcrumbsAutoClear = (newPlatform: CoreStart) => (
});
$rootScope.$on('$routeChangeSuccess', () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
const current = $route.current || {};
if (breadcrumbSetSinceRouteChange || (current.$$route && current.$$route.redirectTo)) {
@@ -226,6 +235,9 @@ const $setupBadgeAutoClear = (newPlatform: CoreStart) => (
});
$rootScope.$on('$routeChangeSuccess', () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
const current = $route.current || {};
if (badgeSetSinceRouteChange || (current.$$route && current.$$route.redirectTo)) {
@@ -274,6 +286,9 @@ const $setupHelpExtensionAutoClear = (newPlatform: CoreStart) => (
});
$rootScope.$on('$routeChangeSuccess', () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
const current = $route.current || {};
if (helpExtensionSetSinceRouteChange || (current.$$route && current.$$route.redirectTo)) {
@@ -288,10 +303,15 @@ const $setupUrlOverflowHandling = (newPlatform: CoreStart) => (
$location: ILocationService,
$rootScope: IRootScopeService,
Private: any,
- config: any
+ config: any,
+ $injector: any
) => {
+ const $route = $injector.has('$route') ? $injector.get('$route') : {};
const urlOverflow = new UrlOverflowService();
const check = () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
// disable long url checks when storing state in session storage
if (config.get('state:storeInSessionStorage')) {
return;
From 398299c0b218cc1fe6415dfa6c80750240af5b19 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Mon, 21 Oct 2019 16:53:15 +0200
Subject: [PATCH 010/132] fix jest tests
---
.../public/home/components/add_data.test.js | 15 +++++++++++----
.../sample_data_view_data_button.test.js | 4 +++-
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
index 81e3d6aaf63ad..07f415cfcb1c9 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/add_data.test.js
@@ -22,11 +22,18 @@ import { AddData } from './add_data';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { getServices } from '../kibana_services';
-jest.mock('../kibana_services', () =>({
- getServices: () => ({
+jest.mock('../kibana_services', () =>{
+ const mock = {
getBasePath: jest.fn(() => 'path'),
- }),
-}));
+ };
+ return {
+ getServices: () => mock,
+ };
+});
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
test('render', () => {
const component = shallowWithIntl(({
- addBasePath: path => `root${path}`
+ getServices: () =>({
+ addBasePath: path => `root${path}`
+ })
}));
test('should render simple button when appLinks is empty', () => {
From 44bcd46b811db7ff356e3d8b74d0f7a6749b63e4 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Mon, 21 Oct 2019 18:47:00 +0200
Subject: [PATCH 011/132] Start shimming dashboard
---
.../kibana/public/dashboard/app.js | 228 ++++++++++++++++++
.../kibana/public/dashboard/dashboard_app.tsx | 102 ++++----
.../dashboard/dashboard_app_controller.tsx | 18 +-
.../kibana/public/dashboard/index.js | 207 ----------------
.../kibana/public/dashboard/index.ts | 75 ++++++
.../kibana/public/dashboard/plugin.ts | 30 +++
.../kibana/public/dashboard/render_app.ts | 203 ++++++++++++++++
src/legacy/ui/public/modals/confirm_modal.js | 24 +-
8 files changed, 605 insertions(+), 282 deletions(-)
create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/app.js
delete mode 100644 src/legacy/core_plugins/kibana/public/dashboard/index.js
create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/index.ts
create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
create mode 100644 src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
new file mode 100644
index 0000000000000..89ec519d656bb
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -0,0 +1,228 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { i18n } from '@kbn/i18n';
+import './saved_dashboard/saved_dashboards';
+import './dashboard_config';
+import uiRoutes from 'ui/routes';
+import { wrapInI18nContext } from 'ui/i18n';
+
+import dashboardTemplate from './dashboard_app.html';
+import dashboardListingTemplate from './listing/dashboard_listing_ng_wrapper.html';
+
+import { initDashboardAppDirective } from './dashboard_app';
+import { DashboardConstants, createDashboardEditUrl } from './dashboard_constants';
+import {
+ InvalidJSONProperty,
+ SavedObjectNotFound,
+} from '../../../../../plugins/kibana_utils/public';
+import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
+import { SavedObjectsClientProvider } from 'ui/saved_objects';
+import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
+import { DashboardListing, EMPTY_FILTER } from './listing/dashboard_listing';
+import 'ui/capabilities/route_setup';
+import { addHelpMenuToAppChrome } from './help_menu/help_menu_util';
+
+// load directives
+import '../../../data/public';
+
+export function initDashboardApp(app, deps) {
+ initDashboardAppDirective(app, deps);
+
+ app.directive('dashboardListing', function(reactDirective) {
+ return reactDirective(wrapInI18nContext(DashboardListing));
+ });
+
+ function createNewDashboardCtrl($scope) {
+ $scope.visitVisualizeAppLinkText = i18n.translate('kbn.dashboard.visitVisualizeAppLinkText', {
+ defaultMessage: 'visit the Visualize app',
+ });
+ addHelpMenuToAppChrome(deps.chrome);
+ }
+
+ app.config(function ($routeProvider) {
+ const defaults = {
+ requireDefaultIndex: true,
+ requireUICapability: 'dashboard.show',
+ badge: () => {
+ if (deps.dashboardCapabilities.showWriteControls) {
+ return undefined;
+ }
+
+ return {
+ text: i18n.translate('kbn.dashboard.badge.readOnly.text', {
+ defaultMessage: 'Read only',
+ }),
+ tooltip: i18n.translate('kbn.dashboard.badge.readOnly.tooltip', {
+ defaultMessage: 'Unable to save dashboards',
+ }),
+ iconType: 'glasses',
+ };
+ },
+ };
+ $routeProvider
+ .when(DashboardConstants.LANDING_PAGE_PATH, {
+ ...defaults,
+ template: dashboardListingTemplate,
+ controller($injector, $location, $scope) {
+ const services = deps.savedObjectRegistry.byLoaderPropertiesName;
+ const kbnUrl = $injector.get('kbnUrl');
+ const dashboardConfig = deps.dashboardConfig;
+
+ $scope.listingLimit = deps.uiSettings.get('savedObjects:listingLimit');
+ $scope.create = () => {
+ kbnUrl.redirect(DashboardConstants.CREATE_NEW_DASHBOARD_URL);
+ };
+ $scope.find = search => {
+ return services.dashboards.find(search, $scope.listingLimit);
+ };
+ $scope.editItem = ({ id }) => {
+ kbnUrl.redirect(`${createDashboardEditUrl(id)}?_a=(viewMode:edit)`);
+ };
+ $scope.getViewUrl = ({ id }) => {
+ return deps.addBasePath(`#${createDashboardEditUrl(id)}`);
+ };
+ $scope.delete = dashboards => {
+ return services.dashboards.delete(dashboards.map(d => d.id));
+ };
+ $scope.hideWriteControls = dashboardConfig.getHideWriteControls();
+ $scope.initialFilter = $location.search().filter || EMPTY_FILTER;
+ deps.chrome.setBreadcrumbs([
+ {
+ text: i18n.translate('kbn.dashboard.dashboardBreadcrumbsTitle', {
+ defaultMessage: 'Dashboards',
+ }),
+ },
+ ]);
+ addHelpMenuToAppChrome(deps.chrome);
+ },
+ resolve: {
+ dash: function ($route, redirectWhenMissing, kbnUrl) {
+ const savedObjectsClient = deps.savedObjectsClient;
+ const title = $route.current.params.title;
+ if (title) {
+ return savedObjectsClient
+ .find({
+ search: `"${title}"`,
+ search_fields: 'title',
+ type: 'dashboard',
+ })
+ .then(results => {
+ // The search isn't an exact match, lets see if we can find a single exact match to use
+ const matchingDashboards = results.savedObjects.filter(
+ dashboard => dashboard.attributes.title.toLowerCase() === title.toLowerCase()
+ );
+ if (matchingDashboards.length === 1) {
+ kbnUrl.redirect(createDashboardEditUrl(matchingDashboards[0].id));
+ } else {
+ kbnUrl.redirect(`${DashboardConstants.LANDING_PAGE_PATH}?filter="${title}"`);
+ }
+ throw uiRoutes.WAIT_FOR_URL_CHANGE_TOKEN;
+ })
+ .catch(
+ redirectWhenMissing({
+ dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ })
+ );
+ }
+ },
+ },
+ })
+ .when(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {
+ ...defaults,
+ template: dashboardTemplate,
+ controller: createNewDashboardCtrl,
+ requireUICapability: 'dashboard.createNew',
+ resolve: {
+ dash: function (savedDashboards, redirectWhenMissing) {
+ return savedDashboards.get().catch(
+ redirectWhenMissing({
+ dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ })
+ );
+ },
+ },
+ })
+ .when(createDashboardEditUrl(':id'), {
+ ...defaults,
+ template: dashboardTemplate,
+ controller: createNewDashboardCtrl,
+ resolve: {
+ dash: function ($route, redirectWhenMissing, kbnUrl, AppState) {
+ const id = $route.current.params.id;
+
+ return deps.savedDashboards
+ .get(id)
+ .then(savedDashboard => {
+ deps.chrome.recentlyAccessed.add(
+ savedDashboard.getFullPath(),
+ savedDashboard.title,
+ id
+ );
+ return savedDashboard;
+ })
+ .catch(error => {
+ // A corrupt dashboard was detected (e.g. with invalid JSON properties)
+ if (error instanceof InvalidJSONProperty) {
+ deps.toastNotifications.addDanger(error.message);
+ kbnUrl.redirect(DashboardConstants.LANDING_PAGE_PATH);
+ return;
+ }
+
+ // Preserve BWC of v5.3.0 links for new, unsaved dashboards.
+ // See https://github.com/elastic/kibana/issues/10951 for more context.
+ if (error instanceof SavedObjectNotFound && id === 'create') {
+ // Note "new AppState" is necessary so the state in the url is preserved through the redirect.
+ kbnUrl.redirect(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {}, new AppState());
+ deps.toastNotifications.addWarning(
+ i18n.translate('kbn.dashboard.urlWasRemovedInSixZeroWarningMessage', {
+ defaultMessage:
+ 'The url "dashboard/create" was removed in 6.0. Please update your bookmarks.',
+ })
+ );
+ } else {
+ throw error;
+ }
+ })
+ .catch(
+ redirectWhenMissing({
+ dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ })
+ );
+ },
+ },
+ });
+ });
+
+ deps.featureCatalogueRegistryProvider.register(() => {
+ return {
+ id: 'dashboard',
+ title: i18n.translate('kbn.dashboard.featureCatalogue.dashboardTitle', {
+ defaultMessage: 'Dashboard',
+ }),
+ description: i18n.translate('kbn.dashboard.featureCatalogue.dashboardDescription', {
+ defaultMessage: 'Display and share a collection of visualizations and saved searches.',
+ }),
+ icon: 'dashboardApp',
+ path: `/app/kibana#${DashboardConstants.LANDING_PAGE_PATH}`,
+ showOnHomePage: true,
+ category: FeatureCatalogueCategory.DATA,
+ };
+ });
+}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
index 7a0398e86a60d..77a59c3d57f94 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
@@ -17,18 +17,8 @@
* under the License.
*/
-import _ from 'lodash';
-
-// @ts-ignore
-import { uiModules } from 'ui/modules';
import { IInjector } from 'ui/chrome';
-// @ts-ignore
-import * as filterActions from 'plugins/kibana/discover/doc_table/actions/filter';
-
-// @ts-ignore
-import { getFilterGenerator } from 'ui/filter_manager';
-
import {
AppStateClass as TAppStateClass,
AppState as TAppState,
@@ -37,7 +27,6 @@ import {
import { KbnUrl } from 'ui/url/kbn_url';
import { Filter } from '@kbn/es-query';
import { TimeRange } from 'src/plugins/data/public';
-import { IndexPattern } from 'ui/index_patterns';
import { IPrivate } from 'ui/private';
import { StaticIndexPattern, Query, SavedQuery } from 'plugins/data';
import moment from 'moment';
@@ -48,6 +37,7 @@ import { SavedObjectDashboard } from './saved_dashboard/saved_dashboard';
import { DashboardAppState, SavedDashboardPanel, ConfirmModalFn } from './types';
import { DashboardAppController } from './dashboard_app_controller';
+import { RenderDeps } from './render_app';
export interface DashboardAppScope extends ng.IScope {
dash: SavedObjectDashboard;
@@ -96,52 +86,48 @@ export interface DashboardAppScope extends ng.IScope {
timefilterSubscriptions$: Subscription;
}
-const app = uiModules.get('app/dashboard', ['elasticsearch', 'ngRoute', 'react', 'kibana/config']);
-
-app.directive('dashboardApp', function($injector: IInjector) {
- const AppState = $injector.get>('AppState');
- const kbnUrl = $injector.get('kbnUrl');
- const confirmModal = $injector.get('confirmModal');
- const config = $injector.get('config');
+export function initDashboardAppDirective(app: any, deps: RenderDeps) {
+ app.directive('dashboardApp', function($injector: IInjector) {
+ const AppState = $injector.get>('AppState');
+ const kbnUrl = $injector.get('kbnUrl');
+ const confirmModal = $injector.get('confirmModal');
+ const config = deps.uiSettings;
- const Private = $injector.get('Private');
+ const Private = $injector.get('Private');
- const indexPatterns = $injector.get<{
- getDefault: () => Promise;
- }>('indexPatterns');
-
- return {
- restrict: 'E',
- controllerAs: 'dashboardApp',
- controller: (
- $scope: DashboardAppScope,
- $route: any,
- $routeParams: {
- id?: string;
- },
- getAppState: {
- previouslyStored: () => TAppState | undefined;
- },
- dashboardConfig: {
- getHideWriteControls: () => boolean;
- },
- localStorage: {
- get: (prop: string) => unknown;
- }
- ) =>
- new DashboardAppController({
- $route,
- $scope,
- $routeParams,
- getAppState,
- dashboardConfig,
- localStorage,
- Private,
- kbnUrl,
- AppStateClass: AppState,
- indexPatterns,
- config,
- confirmModal,
- }),
- };
-});
+ return {
+ restrict: 'E',
+ controllerAs: 'dashboardApp',
+ controller: (
+ $scope: DashboardAppScope,
+ $route: any,
+ $routeParams: {
+ id?: string;
+ },
+ getAppState: {
+ previouslyStored: () => TAppState | undefined;
+ },
+ dashboardConfig: {
+ getHideWriteControls: () => boolean;
+ },
+ localStorage: {
+ get: (prop: string) => unknown;
+ }
+ ) =>
+ new DashboardAppController({
+ $route,
+ $scope,
+ $routeParams,
+ getAppState,
+ dashboardConfig,
+ localStorage,
+ Private,
+ kbnUrl,
+ AppStateClass: AppState,
+ config,
+ confirmModal,
+ ...deps,
+ }),
+ };
+ });
+}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
index abf7b22a6e48c..e212d1cf83d7d 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
@@ -58,7 +58,6 @@ import { Subscription } from 'rxjs';
import { npStart } from 'ui/new_platform';
import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
import { extractTimeFilter, changeTimeFilter } from '../../../data/public';
-import { start as data } from '../../../data/public/legacy';
import {
DashboardContainer,
@@ -88,8 +87,8 @@ import { getDashboardTitle } from './dashboard_strings';
import { DashboardAppScope } from './dashboard_app';
import { VISUALIZE_EMBEDDABLE_TYPE } from '../visualize/embeddable';
import { convertSavedDashboardPanelToPanelState } from './lib/embeddable_saved_object_converters';
+import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
-const { savedQueryService } = data.search.services;
export class DashboardAppController {
// Part of the exposed plugin API - do not remove without careful consideration.
@@ -104,12 +103,15 @@ export class DashboardAppController {
getAppState,
dashboardConfig,
localStorage,
- Private,
kbnUrl,
AppStateClass,
indexPatterns,
config,
confirmModal,
+ queryFilter,
+ getUnhashableStates,
+ shareContextMenuExtensions,
+ savedQueryService,
}: {
$scope: DashboardAppScope;
$route: any;
@@ -129,10 +131,14 @@ export class DashboardAppController {
AppStateClass: TAppStateClass;
config: any;
confirmModal: ConfirmModalFn;
+ queryFilter: any;
+ getUnhashableStates: any;
+ shareContextMenuExtensions: any;
+ savedQueryService: SavedQueryService;
}) {
- const queryFilter = Private(FilterBarQueryFilterProvider);
- const getUnhashableStates = Private(getUnhashableStatesProvider);
- const shareContextMenuExtensions = Private(ShareContextMenuExtensionsRegistryProvider);
+ // const queryFilter = Private(FilterBarQueryFilterProvider);
+ // const getUnhashableStates = Private(getUnhashableStatesProvider);
+ // const shareContextMenuExtensions = Private(ShareContextMenuExtensionsRegistryProvider);
let lastReloadRequestTime = 0;
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/index.js b/src/legacy/core_plugins/kibana/public/dashboard/index.js
deleted file mode 100644
index 712e05c92e5e8..0000000000000
--- a/src/legacy/core_plugins/kibana/public/dashboard/index.js
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import './dashboard_app';
-import { i18n } from '@kbn/i18n';
-import './saved_dashboard/saved_dashboards';
-import './dashboard_config';
-import uiRoutes from 'ui/routes';
-import chrome from 'ui/chrome';
-import { wrapInI18nContext } from 'ui/i18n';
-import { toastNotifications } from 'ui/notify';
-
-import dashboardTemplate from './dashboard_app.html';
-import dashboardListingTemplate from './listing/dashboard_listing_ng_wrapper.html';
-
-import { DashboardConstants, createDashboardEditUrl } from './dashboard_constants';
-import { InvalidJSONProperty, SavedObjectNotFound } from '../../../../../plugins/kibana_utils/public';
-import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
-import { SavedObjectsClientProvider } from 'ui/saved_objects';
-import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
-import { DashboardListing, EMPTY_FILTER } from './listing/dashboard_listing';
-import { uiModules } from 'ui/modules';
-import 'ui/capabilities/route_setup';
-import { addHelpMenuToAppChrome } from './help_menu/help_menu_util';
-
-import { npStart } from 'ui/new_platform';
-
-// load directives
-import '../../../data/public';
-
-const app = uiModules.get('app/dashboard', [
- 'ngRoute',
- 'react',
-]);
-
-app.directive('dashboardListing', function (reactDirective) {
- return reactDirective(wrapInI18nContext(DashboardListing));
-});
-
-function createNewDashboardCtrl($scope) {
- $scope.visitVisualizeAppLinkText = i18n.translate('kbn.dashboard.visitVisualizeAppLinkText', {
- defaultMessage: 'visit the Visualize app',
- });
- addHelpMenuToAppChrome(chrome);
-}
-
-uiRoutes
- .defaults(/dashboard/, {
- requireDefaultIndex: true,
- requireUICapability: 'dashboard.show',
- badge: uiCapabilities => {
- if (uiCapabilities.dashboard.showWriteControls) {
- return undefined;
- }
-
- return {
- text: i18n.translate('kbn.dashboard.badge.readOnly.text', {
- defaultMessage: 'Read only',
- }),
- tooltip: i18n.translate('kbn.dashboard.badge.readOnly.tooltip', {
- defaultMessage: 'Unable to save dashboards',
- }),
- iconType: 'glasses'
- };
- }
- })
- .when(DashboardConstants.LANDING_PAGE_PATH, {
- template: dashboardListingTemplate,
- controller($injector, $location, $scope, Private, config) {
- const services = Private(SavedObjectRegistryProvider).byLoaderPropertiesName;
- const kbnUrl = $injector.get('kbnUrl');
- const dashboardConfig = $injector.get('dashboardConfig');
-
- $scope.listingLimit = config.get('savedObjects:listingLimit');
- $scope.create = () => {
- kbnUrl.redirect(DashboardConstants.CREATE_NEW_DASHBOARD_URL);
- };
- $scope.find = (search) => {
- return services.dashboards.find(search, $scope.listingLimit);
- };
- $scope.editItem = ({ id }) => {
- kbnUrl.redirect(`${createDashboardEditUrl(id)}?_a=(viewMode:edit)`);
- };
- $scope.getViewUrl = ({ id }) => {
- return chrome.addBasePath(`#${createDashboardEditUrl(id)}`);
- };
- $scope.delete = (dashboards) => {
- return services.dashboards.delete(dashboards.map(d => d.id));
- };
- $scope.hideWriteControls = dashboardConfig.getHideWriteControls();
- $scope.initialFilter = ($location.search()).filter || EMPTY_FILTER;
- chrome.breadcrumbs.set([{
- text: i18n.translate('kbn.dashboard.dashboardBreadcrumbsTitle', {
- defaultMessage: 'Dashboards',
- }),
- }]);
- addHelpMenuToAppChrome(chrome);
- },
- resolve: {
- dash: function ($route, Private, redirectWhenMissing, kbnUrl) {
- const savedObjectsClient = Private(SavedObjectsClientProvider);
- const title = $route.current.params.title;
- if (title) {
- return savedObjectsClient.find({
- search: `"${title}"`,
- search_fields: 'title',
- type: 'dashboard',
- }).then(results => {
- // The search isn't an exact match, lets see if we can find a single exact match to use
- const matchingDashboards = results.savedObjects.filter(
- dashboard => dashboard.attributes.title.toLowerCase() === title.toLowerCase());
- if (matchingDashboards.length === 1) {
- kbnUrl.redirect(createDashboardEditUrl(matchingDashboards[0].id));
- } else {
- kbnUrl.redirect(`${DashboardConstants.LANDING_PAGE_PATH}?filter="${title}"`);
- }
- throw uiRoutes.WAIT_FOR_URL_CHANGE_TOKEN;
- }).catch(redirectWhenMissing({
- 'dashboard': DashboardConstants.LANDING_PAGE_PATH
- }));
- }
- }
- }
- })
- .when(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {
- template: dashboardTemplate,
- controller: createNewDashboardCtrl,
- requireUICapability: 'dashboard.createNew',
- resolve: {
- dash: function (savedDashboards, redirectWhenMissing) {
- return savedDashboards.get()
- .catch(redirectWhenMissing({
- 'dashboard': DashboardConstants.LANDING_PAGE_PATH
- }));
- }
- }
- })
- .when(createDashboardEditUrl(':id'), {
- template: dashboardTemplate,
- controller: createNewDashboardCtrl,
- resolve: {
- dash: function (savedDashboards, $route, redirectWhenMissing, kbnUrl, AppState) {
- const id = $route.current.params.id;
-
- return savedDashboards.get(id)
- .then((savedDashboard) => {
- npStart.core.chrome.recentlyAccessed.add(savedDashboard.getFullPath(), savedDashboard.title, id);
- return savedDashboard;
- })
- .catch((error) => {
- // A corrupt dashboard was detected (e.g. with invalid JSON properties)
- if (error instanceof InvalidJSONProperty) {
- toastNotifications.addDanger(error.message);
- kbnUrl.redirect(DashboardConstants.LANDING_PAGE_PATH);
- return;
- }
-
- // Preserve BWC of v5.3.0 links for new, unsaved dashboards.
- // See https://github.com/elastic/kibana/issues/10951 for more context.
- if (error instanceof SavedObjectNotFound && id === 'create') {
- // Note "new AppState" is necessary so the state in the url is preserved through the redirect.
- kbnUrl.redirect(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {}, new AppState());
- toastNotifications.addWarning(i18n.translate('kbn.dashboard.urlWasRemovedInSixZeroWarningMessage',
- { defaultMessage: 'The url "dashboard/create" was removed in 6.0. Please update your bookmarks.' }
- ));
- } else {
- throw error;
- }
- })
- .catch(redirectWhenMissing({
- 'dashboard': DashboardConstants.LANDING_PAGE_PATH
- }));
- }
- }
- });
-
-FeatureCatalogueRegistryProvider.register(() => {
- return {
- id: 'dashboard',
- title: i18n.translate('kbn.dashboard.featureCatalogue.dashboardTitle', {
- defaultMessage: 'Dashboard',
- }),
- description: i18n.translate('kbn.dashboard.featureCatalogue.dashboardDescription', {
- defaultMessage: 'Display and share a collection of visualizations and saved searches.',
- }),
- icon: 'dashboardApp',
- path: `/app/kibana#${DashboardConstants.LANDING_PAGE_PATH}`,
- showOnHomePage: true,
- category: FeatureCatalogueCategory.DATA
- };
-});
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/index.ts b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
new file mode 100644
index 0000000000000..42abbec798592
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
@@ -0,0 +1,75 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
+import { npSetup, npStart } from 'ui/new_platform';
+import chrome from 'ui/chrome';
+import { IPrivate } from 'ui/private';
+// @ts-ignore
+import { toastNotifications, banners } from 'ui/notify';
+import { kfetch } from 'ui/kfetch';
+import { HomePlugin, LegacyAngularInjectedDependencies } from './plugin';
+import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
+import { start as data } from '../../../data/public/legacy';
+import { TelemetryOptInProvider } from '../../../telemetry/public/services';
+import { localApplicationService } from '../local_application_service';
+
+export const trackUiMetric = createUiStatsReporter('Kibana_home');
+
+/**
+ * Get dependencies relying on the global angular context.
+ * They also have to get resolved together with the legacy imports above
+ */
+async function getAngularInjectedDependencies(): Promise {
+ const injector = await chrome.dangerouslyGetActiveInjector();
+
+ const Private = injector.get('Private');
+
+ const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
+ const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
+ const telemetryOptInProvider = Private(TelemetryOptInProvider);
+
+ return {
+ telemetryOptInProvider,
+ shouldShowTelemetryOptIn:
+ telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn(),
+ featureCatalogueRegistryProvider: Private(FeatureCatalogueRegistryProvider as any),
+ };
+}
+
+(async () => {
+ const instance = new HomePlugin();
+ instance.setup(npSetup.core, {
+ __LEGACY: {
+ trackUiMetric,
+ toastNotifications,
+ banners,
+ kfetch,
+ metadata: npStart.core.injectedMetadata.getLegacyMetadata(),
+ METRIC_TYPE,
+ localApplicationService,
+ },
+ });
+ instance.start(npStart.core, {
+ data,
+ __LEGACY: {
+ angularDependencies: await getAngularInjectedDependencies(),
+ },
+ });
+})();
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
new file mode 100644
index 0000000000000..decc002f765c3
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
+
+export class DashboardPlugin implements Plugin {
+ public setup(core: CoreSetup) {
+
+ }
+
+ public start(core: CoreStart) {
+
+ }
+}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
new file mode 100644
index 0000000000000..ebde291380302
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -0,0 +1,203 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { EuiConfirmModal } from '@elastic/eui';
+import angular from 'angular';
+import { IPrivate } from 'ui/private';
+import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/src/angular';
+// @ts-ignore
+import { GlobalStateProvider } from 'ui/state_management/global_state';
+// @ts-ignore
+import { StateManagementConfigProvider } from 'ui/state_management/config_provider';
+// @ts-ignore
+import { PrivateProvider } from 'ui/private/private';
+// @ts-ignore
+import { EventsProvider } from 'ui/events';
+// @ts-ignore
+import { PersistedState } from 'ui/persisted_state';
+// @ts-ignore
+import { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav';
+// @ts-ignore
+import { PromiseServiceCreator } from 'ui/promises/promises';
+// @ts-ignore
+import { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
+// @ts-ignore
+import { confirmModalFactory } from 'ui/modals/confirm_modal';
+
+import { AppMountContext, ChromeStart, SavedObjectsClientContract, UiSettingsClientContract } from 'kibana/public';
+import { configureAppAngularModule } from 'ui/legacy_compat';
+
+// @ts-ignore
+import { initDashboardApp } from './app';
+import { DataStart } from '../../../data/public';
+import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
+import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing/get_unhashable_states_provider';
+import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
+import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
+
+export interface RenderDeps {
+ core: AppMountContext['core'];
+ indexPatterns: DataStart['indexPatterns']['indexPatterns'];
+ queryFilter: any;
+ getUnhashableStates: any;
+ shareContextMenuExtensions: any;
+ savedObjectRegistry: any;
+ savedObjectsClient: SavedObjectsClientContract;
+ dashboardConfig: any;
+ uiSettings: UiSettingsClientContract;
+ savedDashboards: any;
+ chrome: ChromeStart;
+ addBasePath: (path: string) => string;
+ featureCatalogueRegistryProvider: any;
+ dashboardCapabilities: any;
+ savedQueryService: SavedQueryService;
+ emebeddables: EmbeddableStart;
+}
+
+export const renderApp = (element: HTMLElement, appBasePath: string, { core }: RenderDeps) => {
+ const dashboardAngularModule = createLocalAngularModule(core);
+ configureAppAngularModule(dashboardAngularModule);
+ initDashboardApp(dashboardAngularModule);
+ const $injector = mountDashboardApp(appBasePath, element);
+ return () => $injector.get('$rootScope').$destroy();
+};
+
+const mainTemplate = (basePath: string) => `
+`;
+
+const moduleName = 'app/dashboard';
+
+const thirdPartyAngularDependencies = ['ngSanitize', 'ngRoute', 'react'];
+
+function mountDashboardApp(appBasePath: string, element: HTMLElement) {
+ const mountpoint = document.createElement('div');
+ mountpoint.setAttribute('style', 'height: 100%');
+ // eslint-disable-next-line
+ mountpoint.innerHTML = mainTemplate(appBasePath);
+ // bootstrap angular into detached element and attach it later to
+ // make angular-within-angular possible
+ const $injector = angular.bootstrap(mountpoint, [moduleName]);
+ // initialize global state handler
+ $injector.get('globalState');
+ element.appendChild(mountpoint);
+ return $injector;
+}
+
+function createLocalAngularModule(core: AppMountContext['core']) {
+ createLocalI18nModule();
+ createLocalPrivateModule();
+ createLocalPromiseModule();
+ createLocalConfigModule(core);
+ createLocalKbnUrlModule();
+ createLocalPersistedStateModule();
+ createLocalTopNavModule();
+ createLocalGlobalStateModule();
+ createLocalConfirmModalModule();
+
+ const dashboardAngularModule = angular.module(moduleName, [
+ ...thirdPartyAngularDependencies,
+ 'dashboardConfig',
+ 'dashboardI18n',
+ 'dashboardPrivate',
+ 'dashboardPersistedState',
+ 'dashboardTopNav',
+ 'dashboardGlobalState',
+ 'dashboardConfirmModal',
+ ]);
+ return dashboardAngularModule;
+}
+
+function createLocalConfirmModalModule() {
+ angular
+ .module('dashboardConfirmModal', ['react'])
+ .factory('confirmModal', confirmModalFactory)
+ .directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal));
+}
+
+function createLocalGlobalStateModule() {
+ angular
+ .module('dashboardGlobalState', [
+ 'dashboardPrivate',
+ 'dashboardConfig',
+ 'dashboardKbnUrl',
+ 'dashboardPromise',
+ ])
+ .service('globalState', function(Private: any) {
+ return Private(GlobalStateProvider);
+ });
+}
+
+function createLocalPersistedStateModule() {
+ angular
+ .module('dashboardPersistedState', ['dashboardPrivate', 'dashboardPromise'])
+ .factory('PersistedState', (Private: IPrivate) => {
+ const Events = Private(EventsProvider);
+ return class AngularPersistedState extends PersistedState {
+ constructor(value: any, path: any) {
+ super(value, path, Events);
+ }
+ };
+ });
+}
+
+function createLocalKbnUrlModule() {
+ angular
+ .module('dashboardKbnUrl', ['dashboardPrivate', 'ngRoute'])
+ .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
+ .service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
+}
+
+function createLocalConfigModule(core: AppMountContext['core']) {
+ angular
+ .module('dashboardConfig', ['dashboardPrivate'])
+ .provider('stateManagementConfig', StateManagementConfigProvider)
+ .provider('config', () => {
+ return {
+ $get: () => ({
+ get: core.uiSettings.get.bind(core.uiSettings),
+ }),
+ };
+ });
+}
+
+function createLocalPromiseModule() {
+ angular.module('dashboardPromise', []).service('Promise', PromiseServiceCreator);
+}
+
+function createLocalPrivateModule() {
+ angular.module('dashboardPrivate', []).provider('Private', PrivateProvider);
+}
+
+function createLocalTopNavModule() {
+ angular
+ .module('dashboardTopNav', ['react'])
+ .directive('kbnTopNav', createTopNavDirective)
+ .directive('kbnTopNavHelper', createTopNavHelper);
+}
+
+function createLocalI18nModule() {
+ angular
+ .module('dashboardI18n', [])
+ .provider('i18n', I18nProvider)
+ .filter('i18n', i18nFilter)
+ .directive('i18nId', i18nDirective);
+}
diff --git a/src/legacy/ui/public/modals/confirm_modal.js b/src/legacy/ui/public/modals/confirm_modal.js
index 6d5abfca64aaf..9c3f46da4e927 100644
--- a/src/legacy/ui/public/modals/confirm_modal.js
+++ b/src/legacy/ui/public/modals/confirm_modal.js
@@ -36,16 +36,7 @@ export const ConfirmationButtonTypes = {
CANCEL: CANCEL_BUTTON
};
-/**
- * @typedef {Object} ConfirmModalOptions
- * @property {String} confirmButtonText
- * @property {String=} cancelButtonText
- * @property {function} onConfirm
- * @property {function=} onCancel
- * @property {String=} title - If given, shows a title on the confirm modal.
- */
-
-module.factory('confirmModal', function ($rootScope, $compile) {
+export function confirmModalFactory($rootScope, $compile) {
let modalPopover;
const confirmQueue = [];
@@ -114,4 +105,15 @@ module.factory('confirmModal', function ($rootScope, $compile) {
}
}
};
-});
+}
+
+/**
+ * @typedef {Object} ConfirmModalOptions
+ * @property {String} confirmButtonText
+ * @property {String=} cancelButtonText
+ * @property {function} onConfirm
+ * @property {function=} onCancel
+ * @property {String=} title - If given, shows a title on the confirm modal.
+ */
+
+module.factory('confirmModal', confirmModalFactory);
From 4ea2e631a6b12ef8501fbd4a81ae54605f217a77 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Tue, 22 Oct 2019 13:49:39 +0200
Subject: [PATCH 012/132] fix broken tests
---
src/legacy/core_plugins/kibana/public/home/index.js | 7 +++++--
.../core_plugins/kibana/public/home/kibana_services.ts | 9 ++++++---
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/home/index.js b/src/legacy/core_plugins/kibana/public/home/index.js
index 8ef5972d36683..829d1ef8f0ba4 100644
--- a/src/legacy/core_plugins/kibana/public/home/index.js
+++ b/src/legacy/core_plugins/kibana/public/home/index.js
@@ -37,8 +37,11 @@ function getRoute() {
return {
template,
controller($scope) {
- const { chrome, addBasePath, featureCatalogueRegistryProvider } = getServices();
- $scope.directories = featureCatalogueRegistryProvider.inTitleOrder;
+ const { chrome, addBasePath, getFeatureCatalogueRegistryProvider } = getServices();
+ getFeatureCatalogueRegistryProvider().then(catalogue => {
+ $scope.directories = catalogue.inTitleOrder;
+ $scope.$digest();
+ });
$scope.recentlyAccessed = chrome.recentlyAccessed.get().map(item => {
item.link = addBasePath(item.link);
return item;
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index 868e977a4601c..39067e2271f28 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -20,6 +20,7 @@
// @ts-ignore
import { toastNotifications, banners } from 'ui/notify';
import { kfetch } from 'ui/kfetch';
+import chrome from 'ui/chrome';
import { wrapInI18nContext } from 'ui/i18n';
@@ -35,7 +36,6 @@ import { start as data } from '../../../data/public/legacy';
let shouldShowTelemetryOptIn: boolean;
let telemetryOptInProvider: any;
-let featureCatalogueRegistryProvider: any;
export function getServices() {
return {
@@ -55,7 +55,11 @@ export function getServices() {
indexPatternService: data.indexPatterns.indexPatterns,
shouldShowTelemetryOptIn,
telemetryOptInProvider,
- featureCatalogueRegistryProvider,
+ getFeatureCatalogueRegistryProvider: async () => {
+ const injector = await chrome.dangerouslyGetActiveInjector();
+ const Private = injector.get('Private');
+ return Private(FeatureCatalogueRegistryProvider as any);
+ },
trackUiMetric: createUiStatsReporter('Kibana_home'),
METRIC_TYPE,
@@ -74,5 +78,4 @@ modules.get('kibana').run((Private: IPrivate) => {
telemetryOptInProvider = Private(TelemetryOptInProvider);
shouldShowTelemetryOptIn =
telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn();
- featureCatalogueRegistryProvider = Private(FeatureCatalogueRegistryProvider as any);
});
From 1bd6b3bbdd59471742af1b4a47a930e74a629c9d Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Tue, 22 Oct 2019 14:46:53 +0200
Subject: [PATCH 013/132] local application service
---
.../core_plugins/kibana/public/kibana.js | 3 +
.../public/local_application_service/index.ts | 20 +++
.../local_application_service.ts | 136 ++++++++++++++++++
.../public/legacy_compat/angular_config.tsx | 20 +++
.../ui/public/routes/route_manager.d.ts | 4 +-
5 files changed, 182 insertions(+), 1 deletion(-)
create mode 100644 src/legacy/core_plugins/kibana/public/local_application_service/index.ts
create mode 100644 src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js
index 6c809e84c8c84..af7c9131caf45 100644
--- a/src/legacy/core_plugins/kibana/public/kibana.js
+++ b/src/legacy/core_plugins/kibana/public/kibana.js
@@ -58,6 +58,9 @@ import 'ui/agg_response';
import 'ui/agg_types';
import { showAppRedirectNotification } from 'ui/notify';
import 'leaflet';
+import { localApplicationService } from './local_application_service';
+
+localApplicationService.apply(routes);
routes.enable();
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/index.ts b/src/legacy/core_plugins/kibana/public/local_application_service/index.ts
new file mode 100644
index 0000000000000..2128355ca906a
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export * from './local_application_service';
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
new file mode 100644
index 0000000000000..ba7e3921d3537
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
@@ -0,0 +1,136 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { App } from 'kibana/public';
+import { UIRoutes } from 'ui/routes';
+import { IScope } from 'angular';
+import { npStart } from 'ui/new_platform';
+import { htmlIdGenerator } from '@elastic/eui';
+
+interface ForwardDefinition {
+ legacyAppId: string;
+ newAppId: string;
+ keepPrefix: boolean;
+}
+
+const matchAllWithPrefix = (prefixOrApp: string | App) =>
+ `/${typeof prefixOrApp === 'string' ? prefixOrApp : prefixOrApp.id}:tail*?`;
+
+/**
+ * To be able to migrate and shim parts of the Kibana app plugin
+ * while still running some parts of it in the legacy world, this
+ * service emulates the core application service while using the global
+ * angular router to switch between apps without page reload.
+ *
+ * The id of the apps is used as prefix of the route - when switching between
+ * to apps, the current application is unmounted.
+ *
+ * This service becomes unnecessary once the platform provides a central
+ * router that handles switching between applications without page reload.
+ */
+export class LocalApplicationService {
+ private apps: App[] = [];
+ private forwards: ForwardDefinition[] = [];
+ private idGenerator = htmlIdGenerator('kibanaAppLocalApp');
+
+ /**
+ * Register an app to be managed by the application service.
+ * This method works exactly as `core.application.register`.
+ *
+ * When an app is mounted, it is responsible for routing. The app
+ * won't be mounted again if the route changes within the prefix
+ * of the app (its id). It is fine to use whatever means for handling
+ * routing within the app.
+ *
+ * When switching to a URL outside of the current prefix, the app router
+ * shouldn't do anything because it doesn't own the routing anymore -
+ * the local application service takes over routing again,
+ * unmounts the current app and mounts the next app.
+ *
+ * @param app The app descriptor
+ */
+ register(app: App) {
+ this.apps.push(app);
+ }
+
+ /**
+ * Forwards every URL starting with `legacyAppId` to the same URL starting
+ * with `newAppId` - e.g. `/legacy/my/legacy/path?q=123` gets forwarded to
+ * `/newApp/my/legacy/path?q=123`.
+ *
+ * When setting the `keepPrefix` option, the new app id is simply prepended.
+ * The example above would become `/newApp/legacy/my/legacy/path?q=123`.
+ *
+ * This method can be used to provide backwards compatibility for URLs when
+ * renaming or nesting plugins. For route changes after the prefix, please
+ * use the routing mechanism of your app.
+ *
+ * @param legacyAppId The name of the old app to forward URLs from
+ * @param newAppId The name of the new app that handles the URLs now
+ * @param options Whether the prefix of the old app is kept to nest the legacy
+ * path into the new path
+ */
+ forwardApp(
+ legacyAppId: string,
+ newAppId: string,
+ options: { keepPrefix: boolean } = { keepPrefix: false }
+ ) {
+ this.forwards.push({ legacyAppId, newAppId, ...options });
+ }
+
+ /**
+ * Wires up listeners to handle mounting and unmounting of apps to
+ * the legacy angular route manager. Once all apps within the Kibana
+ * plugin are using the local route manager, this implementation can
+ * be switched to a more lightweight implementation.
+ *
+ * @param angularRouteManager The current `ui/routes` instance
+ */
+ apply(angularRouteManager: UIRoutes) {
+ this.apps.forEach(app => {
+ const wrapperElementId = this.idGenerator();
+ angularRouteManager.when(matchAllWithPrefix(app), {
+ outerAngularWrapperRoute: true,
+ reloadOnSearch: false,
+ reloadOnUrl: false,
+ template: ``,
+ controller($scope: IScope) {
+ const element = document.getElementById(wrapperElementId)!;
+ (async () => {
+ const onUnmount = await app.mount({ core: npStart.core }, { element, appBasePath: '' });
+ $scope.$on('$destroy', () => {
+ onUnmount();
+ });
+ })();
+ },
+ });
+ });
+
+ this.forwards.forEach(({ legacyAppId, newAppId, keepPrefix }) => {
+ angularRouteManager.when(matchAllWithPrefix(legacyAppId), {
+ redirectTo: (_params: unknown, path: string, search: string) => {
+ const newPath = `/${newAppId}${keepPrefix ? path : path.replace(legacyAppId, '')}`;
+ return `${newPath}?${search}`;
+ },
+ });
+ });
+ }
+}
+
+export const localApplicationService = new LocalApplicationService();
diff --git a/src/legacy/ui/public/legacy_compat/angular_config.tsx b/src/legacy/ui/public/legacy_compat/angular_config.tsx
index 8eac31e24530c..6b69e8e5f14b3 100644
--- a/src/legacy/ui/public/legacy_compat/angular_config.tsx
+++ b/src/legacy/ui/public/legacy_compat/angular_config.tsx
@@ -48,6 +48,12 @@ import { isSystemApiRequest } from '../system_api';
const URL_LIMIT_WARN_WITHIN = 1000;
+function isDummyWrapperRoute($route: any) {
+ return (
+ $route.current && $route.current.$$route && $route.current.$$route.outerAngularWrapperRoute
+ );
+}
+
export const configureAppAngularModule = (angularModule: IModule) => {
const newPlatform = npStart.core;
const legacyMetadata = newPlatform.injectedMetadata.getLegacyMetadata();
@@ -187,6 +193,9 @@ const $setupBreadcrumbsAutoClear = (newPlatform: CoreStart) => (
});
$rootScope.$on('$routeChangeSuccess', () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
const current = $route.current || {};
if (breadcrumbSetSinceRouteChange || (current.$$route && current.$$route.redirectTo)) {
@@ -226,6 +235,9 @@ const $setupBadgeAutoClear = (newPlatform: CoreStart) => (
});
$rootScope.$on('$routeChangeSuccess', () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
const current = $route.current || {};
if (badgeSetSinceRouteChange || (current.$$route && current.$$route.redirectTo)) {
@@ -270,6 +282,9 @@ const $setupHelpExtensionAutoClear = (newPlatform: CoreStart) => (
const $route = $injector.has('$route') ? $injector.get('$route') : {};
$rootScope.$on('$routeChangeStart', () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
helpExtensionSetSinceRouteChange = false;
});
@@ -287,11 +302,16 @@ const $setupHelpExtensionAutoClear = (newPlatform: CoreStart) => (
const $setupUrlOverflowHandling = (newPlatform: CoreStart) => (
$location: ILocationService,
$rootScope: IRootScopeService,
+ $injector: any,
Private: any,
config: any
) => {
+ const $route = $injector.has('$route') ? $injector.get('$route') : {};
const urlOverflow = new UrlOverflowService();
const check = () => {
+ if (isDummyWrapperRoute($route)) {
+ return;
+ }
// disable long url checks when storing state in session storage
if (config.get('state:storeInSessionStorage')) {
return;
diff --git a/src/legacy/ui/public/routes/route_manager.d.ts b/src/legacy/ui/public/routes/route_manager.d.ts
index 3471d7e954862..3d1ba88918f55 100644
--- a/src/legacy/ui/public/routes/route_manager.d.ts
+++ b/src/legacy/ui/public/routes/route_manager.d.ts
@@ -25,8 +25,10 @@ import { ChromeBreadcrumb } from '../../../../core/public';
interface RouteConfiguration {
controller?: string | ((...args: any[]) => void);
- redirectTo?: string;
+ redirectTo?: string | ((params: object, path: string, search: string) => string);
reloadOnSearch?: boolean;
+ reloadOnUrl?: boolean;
+ outerAngularWrapperRoute?: boolean;
resolve?: object;
template?: string;
k7Breadcrumbs?: (...args: any[]) => ChromeBreadcrumb[];
From afafe109010d4cc6a54e56f27ec06bfc50b77c4c Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Tue, 22 Oct 2019 16:53:44 +0200
Subject: [PATCH 014/132] wip
---
.../kibana/public/dashboard/app.js | 2 +-
.../kibana/public/dashboard/dashboard_app.tsx | 3 -
.../dashboard/dashboard_app_controller.tsx | 74 +++++++++----------
.../kibana/public/dashboard/index.ts | 45 +++++------
.../kibana/public/dashboard/plugin.ts | 68 ++++++++++++++++-
.../kibana/public/dashboard/render_app.ts | 37 +++++-----
6 files changed, 137 insertions(+), 92 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index 89ec519d656bb..44d031c0f50d5 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -210,7 +210,7 @@ export function initDashboardApp(app, deps) {
});
});
- deps.featureCatalogueRegistryProvider.register(() => {
+ deps.getFeatureCatalogueRegistryProvider().register(() => {
return {
id: 'dashboard',
title: i18n.translate('kbn.dashboard.featureCatalogue.dashboardTitle', {
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
index 77a59c3d57f94..cd1a616c4f5af 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.tsx
@@ -93,8 +93,6 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) {
const confirmModal = $injector.get('confirmModal');
const config = deps.uiSettings;
- const Private = $injector.get('Private');
-
return {
restrict: 'E',
controllerAs: 'dashboardApp',
@@ -121,7 +119,6 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) {
getAppState,
dashboardConfig,
localStorage,
- Private,
kbnUrl,
AppStateClass: AppState,
config,
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
index e212d1cf83d7d..4e327d63928a8 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
@@ -50,12 +50,9 @@ import {
import { KbnUrl } from 'ui/url/kbn_url';
import { Filter } from '@kbn/es-query';
import { IndexPattern } from 'ui/index_patterns';
-import { IPrivate } from 'ui/private';
import { Query, SavedQuery } from 'src/legacy/core_plugins/data/public';
import { SaveOptions } from 'ui/saved_objects/saved_object';
-import { capabilities } from 'ui/capabilities';
import { Subscription } from 'rxjs';
-import { npStart } from 'ui/new_platform';
import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
import { extractTimeFilter, changeTimeFilter } from '../../../data/public';
@@ -72,7 +69,7 @@ import {
ViewMode,
openAddPanelFlyout,
} from '../../../embeddable_api/public/np_ready/public';
-import { start } from '../../../embeddable_api/public/np_ready/public/legacy';
+// import { start } from '../../../embeddable_api/public/np_ready/public/legacy';
import { DashboardAppState, NavAction, ConfirmModalFn, SavedDashboardPanel } from './types';
import { showOptionsPopover } from './top_nav/show_options_popover';
@@ -88,7 +85,28 @@ import { DashboardAppScope } from './dashboard_app';
import { VISUALIZE_EMBEDDABLE_TYPE } from '../visualize/embeddable';
import { convertSavedDashboardPanelToPanelState } from './lib/embeddable_saved_object_converters';
import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
-
+import { NotificationsStart, OverlayStart } from 'kibana/public';
+import { RenderDeps } from './render_app';
+
+export interface DashboardAppControllerDependencies extends RenderDeps {
+ $scope: DashboardAppScope;
+ $route: any;
+ $routeParams: any;
+ getAppState: {
+ previouslyStored: () => TAppState | undefined;
+ };
+ indexPatterns: {
+ getDefault: () => Promise;
+ };
+ dashboardConfig: any;
+ localStorage: {
+ get: (prop: string) => unknown;
+ };
+ kbnUrl: KbnUrl;
+ AppStateClass: TAppStateClass;
+ config: any;
+ confirmModal: ConfirmModalFn;
+}
export class DashboardAppController {
// Part of the exposed plugin API - do not remove without careful consideration.
@@ -112,34 +130,10 @@ export class DashboardAppController {
getUnhashableStates,
shareContextMenuExtensions,
savedQueryService,
- }: {
- $scope: DashboardAppScope;
- $route: any;
- $routeParams: any;
- getAppState: {
- previouslyStored: () => TAppState | undefined;
- };
- indexPatterns: {
- getDefault: () => Promise;
- };
- dashboardConfig: any;
- localStorage: {
- get: (prop: string) => unknown;
- };
- Private: IPrivate;
- kbnUrl: KbnUrl;
- AppStateClass: TAppStateClass;
- config: any;
- confirmModal: ConfirmModalFn;
- queryFilter: any;
- getUnhashableStates: any;
- shareContextMenuExtensions: any;
- savedQueryService: SavedQueryService;
- }) {
- // const queryFilter = Private(FilterBarQueryFilterProvider);
- // const getUnhashableStates = Private(getUnhashableStatesProvider);
- // const shareContextMenuExtensions = Private(ShareContextMenuExtensionsRegistryProvider);
-
+ embeddables,
+ dashboardCapabilities,
+ core: { notifications, overlays },
+ }: DashboardAppControllerDependencies) {
let lastReloadRequestTime = 0;
const dash = ($scope.dash = $route.current.locals.dash);
@@ -160,7 +154,7 @@ export class DashboardAppController {
if (dashboardStateManager.getIsTimeSavedWithDashboard() && !getAppState.previouslyStored()) {
dashboardStateManager.syncTimefilterWithDashboard(timefilter);
}
- $scope.showSaveQuery = capabilities.get().dashboard.saveQuery as boolean;
+ $scope.showSaveQuery = dashboardCapabilities.saveQuery as boolean;
const updateIndexPatterns = (container?: DashboardContainer) => {
if (!container || isErrorEmbeddable(container)) {
@@ -247,7 +241,7 @@ export class DashboardAppController {
let outputSubscription: Subscription | undefined;
const dashboardDom = document.getElementById('dashboardViewport');
- const dashboardFactory = start.getEmbeddableFactory(
+ const dashboardFactory = embeddables.getEmbeddableFactory(
DASHBOARD_CONTAINER_TYPE
) as DashboardContainerFactory;
dashboardFactory
@@ -534,7 +528,7 @@ export class DashboardAppController {
});
$scope.$watch(
- () => capabilities.get().dashboard.saveQuery,
+ () => dashboardCapabilities.saveQuery,
newCapability => {
$scope.showSaveQuery = newCapability as boolean;
}
@@ -773,10 +767,10 @@ export class DashboardAppController {
if (dashboardContainer && !isErrorEmbeddable(dashboardContainer)) {
openAddPanelFlyout({
embeddable: dashboardContainer,
- getAllFactories: start.getEmbeddableFactories,
- getFactory: start.getEmbeddableFactory,
- notifications: npStart.core.notifications,
- overlays: npStart.core.overlays,
+ getAllFactories: embeddables.getEmbeddableFactories,
+ getFactory: embeddables.getEmbeddableFactory,
+ notifications,
+ overlays,
SavedObjectFinder,
});
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/index.ts b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
index 42abbec798592..04685de94fe06 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/index.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
@@ -21,55 +21,48 @@ import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue'
import { npSetup, npStart } from 'ui/new_platform';
import chrome from 'ui/chrome';
import { IPrivate } from 'ui/private';
-// @ts-ignore
-import { toastNotifications, banners } from 'ui/notify';
-import { kfetch } from 'ui/kfetch';
-import { HomePlugin, LegacyAngularInjectedDependencies } from './plugin';
-import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
+import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
+import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing/get_unhashable_states_provider';
+import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
+import { DashboardPlugin, LegacyAngularInjectedDependencies } from './plugin';
import { start as data } from '../../../data/public/legacy';
-import { TelemetryOptInProvider } from '../../../telemetry/public/services';
import { localApplicationService } from '../local_application_service';
-
-export const trackUiMetric = createUiStatsReporter('Kibana_home');
+import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy';
/**
* Get dependencies relying on the global angular context.
* They also have to get resolved together with the legacy imports above
*/
-async function getAngularInjectedDependencies(): Promise {
+async function getAngularDependencies(): Promise {
const injector = await chrome.dangerouslyGetActiveInjector();
const Private = injector.get('Private');
- const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
- const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
- const telemetryOptInProvider = Private(TelemetryOptInProvider);
+ const queryFilter = Private(FilterBarQueryFilterProvider);
+ const getUnhashableStates = Private(getUnhashableStatesProvider);
+ const shareContextMenuExtensions = Private(ShareContextMenuExtensionsRegistryProvider);
return {
- telemetryOptInProvider,
- shouldShowTelemetryOptIn:
- telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn(),
- featureCatalogueRegistryProvider: Private(FeatureCatalogueRegistryProvider as any),
+ queryFilter,
+ getUnhashableStates,
+ shareContextMenuExtensions,
+ getFeatureCatalogueRegistryProvider: () => {
+ return Private(FeatureCatalogueRegistryProvider as any);
+ },
+ dashboardConfig: injector.get('dashboardConfig'),
};
}
(async () => {
- const instance = new HomePlugin();
+ const instance = new DashboardPlugin();
instance.setup(npSetup.core, {
__LEGACY: {
- trackUiMetric,
- toastNotifications,
- banners,
- kfetch,
- metadata: npStart.core.injectedMetadata.getLegacyMetadata(),
- METRIC_TYPE,
localApplicationService,
+ getAngularDependencies,
},
});
instance.start(npStart.core, {
data,
- __LEGACY: {
- angularDependencies: await getAngularInjectedDependencies(),
- },
+ embeddables,
});
})();
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
index decc002f765c3..5a69c33bc55aa 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
@@ -17,14 +17,74 @@
* under the License.
*/
-import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
+import { CoreSetup, CoreStart, Plugin, SavedObjectsClientContract } from 'kibana/public';
+import { RenderDeps } from './render_app';
+import { LocalApplicationService } from '../local_application_service';
+import { DataStart } from '../../../data/public';
+import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
+import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public';
+
+export interface LegacyAngularInjectedDependencies {
+ queryFilter: any;
+ getUnhashableStates: any;
+ shareContextMenuExtensions: any;
+ getFeatureCatalogueRegistryProvider: () => Promise;
+ dashboardConfig: any;
+}
+
+export interface DashboardPluginStartDependencies {
+ data: DataStart;
+ embeddables: ReturnType;
+}
+
+export interface DashboardPluginSetupDependencies {
+ __LEGACY: {
+ getAngularDependencies: () => Promise;
+ localApplicationService: LocalApplicationService;
+ };
+}
export class DashboardPlugin implements Plugin {
- public setup(core: CoreSetup) {
+ private dataStart: DataStart | null = null;
+ private savedObjectsClient: SavedObjectsClientContract | null = null;
+ private savedQueryService: SavedQueryService | null = null;
+ private embeddables: ReturnType | null = null;
+ public setup(
+ core: CoreSetup,
+ {
+ __LEGACY: { localApplicationService, getAngularDependencies, ...legacyServices },
+ }: DashboardPluginSetupDependencies
+ ) {
+ localApplicationService.register({
+ id: 'home',
+ title: 'Home',
+ mount: async ({ core: contextCore }, params) => {
+ const angularDependencies = await getAngularDependencies();
+ const deps: RenderDeps = {
+ core: contextCore,
+ ...legacyServices,
+ ...angularDependencies,
+ indexPatterns: this.dataStart!.indexPatterns.indexPatterns,
+ savedObjectsClient: this.savedObjectsClient!,
+ chrome: contextCore.chrome,
+ addBasePath: contextCore.http.basePath.prepend,
+ uiSettings: contextCore.uiSettings,
+ savedQueryService: this.savedQueryService!,
+ embeddables: this.embeddables!,
+ dashboardCapabilities: contextCore.application.capabilities.dashboard,
+ };
+ const { renderApp } = await import('./render_app');
+ return renderApp(params.element, params.appBasePath, deps);
+ },
+ });
}
- public start(core: CoreStart) {
-
+ start(core: CoreStart, { data, embeddables }: DashboardPluginStartDependencies) {
+ // TODO is this really the right way? I though the app context would give us those
+ this.dataStart = data;
+ this.savedObjectsClient = core.savedObjects.client;
+ this.savedQueryService = data.search.services.savedQueryService;
+ this.embeddables = embeddables;
}
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index ebde291380302..473130af81a65 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -50,30 +50,31 @@ import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing/get_unhashable_states_provider';
import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
+import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public';
export interface RenderDeps {
- core: AppMountContext['core'];
- indexPatterns: DataStart['indexPatterns']['indexPatterns'];
- queryFilter: any;
- getUnhashableStates: any;
- shareContextMenuExtensions: any;
+ core: AppMountContext['core']; //x
+ indexPatterns: DataStart['indexPatterns']['indexPatterns']; //x
+ queryFilter: any; //x
+ getUnhashableStates: any; //x
+ shareContextMenuExtensions: any; //x
+ savedObjectsClient: SavedObjectsClientContract; //x
savedObjectRegistry: any;
- savedObjectsClient: SavedObjectsClientContract;
- dashboardConfig: any;
- uiSettings: UiSettingsClientContract;
- savedDashboards: any;
- chrome: ChromeStart;
- addBasePath: (path: string) => string;
- featureCatalogueRegistryProvider: any;
- dashboardCapabilities: any;
- savedQueryService: SavedQueryService;
- emebeddables: EmbeddableStart;
+ dashboardConfig: any; //x
+ savedDashboards: any
+ dashboardCapabilities: any; //x
+ uiSettings: UiSettingsClientContract; //x
+ chrome: ChromeStart; //x
+ addBasePath: (path: string) => string; //x
+ getFeatureCatalogueRegistryProvider: () => any; //x
+ savedQueryService: SavedQueryService; //x
+ embeddables: ReturnType; //x
}
-export const renderApp = (element: HTMLElement, appBasePath: string, { core }: RenderDeps) => {
- const dashboardAngularModule = createLocalAngularModule(core);
+export const renderApp = (element: HTMLElement, appBasePath: string, deps: RenderDeps) => {
+ const dashboardAngularModule = createLocalAngularModule(deps.core);
configureAppAngularModule(dashboardAngularModule);
- initDashboardApp(dashboardAngularModule);
+ initDashboardApp(dashboardAngularModule, deps);
const $injector = mountDashboardApp(appBasePath, element);
return () => $injector.get('$rootScope').$destroy();
};
From a7f2826dad084a964c4337525f9e57282a285979 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Tue, 22 Oct 2019 17:19:16 +0200
Subject: [PATCH 015/132] wip
---
.../kibana/public/dashboard/app.js | 4 +-
.../dashboard/dashboard_app_controller.tsx | 6 +--
.../kibana/public/dashboard/index.ts | 4 ++
.../kibana/public/dashboard/plugin.ts | 6 ++-
.../kibana/public/dashboard/render_app.ts | 40 ++++++++++---------
5 files changed, 32 insertions(+), 28 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index 44d031c0f50d5..0cf02da8b2e6a 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -150,8 +150,8 @@ export function initDashboardApp(app, deps) {
controller: createNewDashboardCtrl,
requireUICapability: 'dashboard.createNew',
resolve: {
- dash: function (savedDashboards, redirectWhenMissing) {
- return savedDashboards.get().catch(
+ dash: function (redirectWhenMissing) {
+ return deps.savedDashboards.get().catch(
redirectWhenMissing({
dashboard: DashboardConstants.LANDING_PAGE_PATH,
})
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
index 4e327d63928a8..1abf03a9d6d78 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
@@ -29,18 +29,16 @@ import { toastNotifications } from 'ui/notify';
// @ts-ignore
import { ConfirmationButtonTypes } from 'ui/modals/confirm_modal';
-import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
import { docTitle } from 'ui/doc_title/doc_title';
import { showSaveModal, SaveResult } from 'ui/saved_objects/show_saved_object_save_modal';
-import { showShareContextMenu, ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
+import { showShareContextMenu } from 'ui/share';
import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
import { timefilter } from 'ui/timefilter';
-import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing/get_unhashable_states_provider';
import {
AppStateClass as TAppStateClass,
@@ -84,8 +82,6 @@ import { getDashboardTitle } from './dashboard_strings';
import { DashboardAppScope } from './dashboard_app';
import { VISUALIZE_EMBEDDABLE_TYPE } from '../visualize/embeddable';
import { convertSavedDashboardPanelToPanelState } from './lib/embeddable_saved_object_converters';
-import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
-import { NotificationsStart, OverlayStart } from 'kibana/public';
import { RenderDeps } from './render_app';
export interface DashboardAppControllerDependencies extends RenderDeps {
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/index.ts b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
index 04685de94fe06..1508492e538c9 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/index.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
@@ -28,6 +28,7 @@ import { DashboardPlugin, LegacyAngularInjectedDependencies } from './plugin';
import { start as data } from '../../../data/public/legacy';
import { localApplicationService } from '../local_application_service';
import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy';
+import { SavedObjectRegistryProvider } from 'ui/saved_objects';
/**
* Get dependencies relying on the global angular context.
@@ -41,6 +42,7 @@ async function getAngularDependencies(): Promise Promise;
dashboardConfig: any;
+ savedObjectRegistry: any;
+ savedDashboards: any;
}
export interface DashboardPluginStartDependencies {
@@ -57,8 +59,8 @@ export class DashboardPlugin implements Plugin {
}: DashboardPluginSetupDependencies
) {
localApplicationService.register({
- id: 'home',
- title: 'Home',
+ id: 'discover',
+ title: 'Discover',
mount: async ({ core: contextCore }, params) => {
const angularDependencies = await getAngularDependencies();
const deps: RenderDeps = {
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index 473130af81a65..c57b309fee2e1 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -40,35 +40,37 @@ import { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
// @ts-ignore
import { confirmModalFactory } from 'ui/modals/confirm_modal';
-import { AppMountContext, ChromeStart, SavedObjectsClientContract, UiSettingsClientContract } from 'kibana/public';
+import {
+ AppMountContext,
+ ChromeStart,
+ SavedObjectsClientContract,
+ UiSettingsClientContract,
+} from 'kibana/public';
import { configureAppAngularModule } from 'ui/legacy_compat';
// @ts-ignore
import { initDashboardApp } from './app';
import { DataStart } from '../../../data/public';
-import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
-import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing/get_unhashable_states_provider';
-import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public';
export interface RenderDeps {
- core: AppMountContext['core']; //x
- indexPatterns: DataStart['indexPatterns']['indexPatterns']; //x
- queryFilter: any; //x
- getUnhashableStates: any; //x
- shareContextMenuExtensions: any; //x
- savedObjectsClient: SavedObjectsClientContract; //x
+ core: AppMountContext['core'];
+ indexPatterns: DataStart['indexPatterns']['indexPatterns'];
+ queryFilter: any;
+ getUnhashableStates: any;
+ shareContextMenuExtensions: any;
+ savedObjectsClient: SavedObjectsClientContract;
savedObjectRegistry: any;
- dashboardConfig: any; //x
- savedDashboards: any
- dashboardCapabilities: any; //x
- uiSettings: UiSettingsClientContract; //x
- chrome: ChromeStart; //x
- addBasePath: (path: string) => string; //x
- getFeatureCatalogueRegistryProvider: () => any; //x
- savedQueryService: SavedQueryService; //x
- embeddables: ReturnType; //x
+ dashboardConfig: any;
+ savedDashboards: any;
+ dashboardCapabilities: any;
+ uiSettings: UiSettingsClientContract;
+ chrome: ChromeStart;
+ addBasePath: (path: string) => string;
+ getFeatureCatalogueRegistryProvider: () => any;
+ savedQueryService: SavedQueryService;
+ embeddables: ReturnType;
}
export const renderApp = (element: HTMLElement, appBasePath: string, deps: RenderDeps) => {
From c4170606077740fbc07d0fd8c41be66759c696a1 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Tue, 22 Oct 2019 17:25:21 +0200
Subject: [PATCH 016/132] fix mounting home several times
---
.../core_plugins/kibana/public/home/kibana_services.ts | 4 ++++
src/legacy/core_plugins/kibana/public/home/render_app.tsx | 7 +++++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index 11f1f94d11b6f..ebc99df9d4e5e 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -81,3 +81,7 @@ export function getServices() {
}
return services;
}
+
+export function clearServices() {
+ services = null;
+}
diff --git a/src/legacy/core_plugins/kibana/public/home/render_app.tsx b/src/legacy/core_plugins/kibana/public/home/render_app.tsx
index 5d2881ea5edcf..50041410d3c6f 100644
--- a/src/legacy/core_plugins/kibana/public/home/render_app.tsx
+++ b/src/legacy/core_plugins/kibana/public/home/render_app.tsx
@@ -22,7 +22,7 @@ import { render, unmountComponentAtNode } from 'react-dom';
import { i18n } from '@kbn/i18n';
// @ts-ignore
import { HomeApp } from './components/home_app';
-import { getServices } from './kibana_services';
+import { clearServices, getServices } from './kibana_services';
export const renderApp = async (element: HTMLElement) => {
const homeTitle = i18n.translate('kbn.home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
@@ -32,5 +32,8 @@ export const renderApp = async (element: HTMLElement) => {
render(, element);
- return () => unmountComponentAtNode(element);
+ return () => {
+ unmountComponentAtNode(element);
+ clearServices();
+ };
};
From 03fd207650a9bf427fb25a708f35fc3a1a225417 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Tue, 22 Oct 2019 19:06:09 +0200
Subject: [PATCH 017/132] wip
---
.../kibana/public/dashboard/app.js | 6 +-
.../dashboard/help_menu/help_menu_util.js | 2 +-
.../kibana/public/dashboard/index.ts | 8 +-
.../kibana/public/dashboard/plugin.ts | 7 +-
.../kibana/public/dashboard/render_app.ts | 2 +-
.../local_application_service.ts | 4 +-
.../ui/public/kbn_top_nav/kbn_top_nav.js | 12 +-
src/legacy/ui/public/private/private.js | 146 +++++++++---------
.../state_management/config_provider.js | 32 ++--
9 files changed, 114 insertions(+), 105 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index 0cf02da8b2e6a..f219da072c87b 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -18,8 +18,6 @@
*/
import { i18n } from '@kbn/i18n';
-import './saved_dashboard/saved_dashboards';
-import './dashboard_config';
import uiRoutes from 'ui/routes';
import { wrapInI18nContext } from 'ui/i18n';
@@ -113,7 +111,7 @@ export function initDashboardApp(app, deps) {
addHelpMenuToAppChrome(deps.chrome);
},
resolve: {
- dash: function ($route, redirectWhenMissing, kbnUrl) {
+ dash: function ($route/*, redirectWhenMissing, kbnUrl*/) {
const savedObjectsClient = deps.savedObjectsClient;
const title = $route.current.params.title;
if (title) {
@@ -210,7 +208,7 @@ export function initDashboardApp(app, deps) {
});
});
- deps.getFeatureCatalogueRegistryProvider().register(() => {
+ deps.FeatureCatalogueRegistryProvider.register(() => {
return {
id: 'dashboard',
title: i18n.translate('kbn.dashboard.featureCatalogue.dashboardTitle', {
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js b/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js
index aeabff2d97007..58a92193de63e 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js
@@ -22,7 +22,7 @@ import { render, unmountComponentAtNode } from 'react-dom';
import { HelpMenu } from './help_menu';
export function addHelpMenuToAppChrome(chrome) {
- chrome.helpExtension.set(domElement => {
+ chrome.setHelpExtension(domElement => {
render(, domElement);
return () => {
unmountComponentAtNode(domElement);
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/index.ts b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
index 1508492e538c9..4b63970daa461 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/index.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
@@ -19,6 +19,7 @@
import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
import { npSetup, npStart } from 'ui/new_platform';
+import { SavedObjectRegistryProvider } from 'ui/saved_objects';
import chrome from 'ui/chrome';
import { IPrivate } from 'ui/private';
import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
@@ -28,7 +29,8 @@ import { DashboardPlugin, LegacyAngularInjectedDependencies } from './plugin';
import { start as data } from '../../../data/public/legacy';
import { localApplicationService } from '../local_application_service';
import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy';
-import { SavedObjectRegistryProvider } from 'ui/saved_objects';
+import './saved_dashboard/saved_dashboards';
+import './dashboard_config';
/**
* Get dependencies relying on the global angular context.
@@ -48,9 +50,6 @@ async function getAngularDependencies(): Promise {
- return Private(FeatureCatalogueRegistryProvider as any);
- },
dashboardConfig: injector.get('dashboardConfig'),
savedObjectRegistry,
savedDashboards: injector.get('savedDashboards'),
@@ -63,6 +62,7 @@ async function getAngularDependencies(): Promise Promise;
dashboardConfig: any;
savedObjectRegistry: any;
savedDashboards: any;
@@ -43,6 +42,7 @@ export interface DashboardPluginSetupDependencies {
__LEGACY: {
getAngularDependencies: () => Promise;
localApplicationService: LocalApplicationService;
+ FeatureCatalogueRegistryProvider: any;
};
}
@@ -58,9 +58,10 @@ export class DashboardPlugin implements Plugin {
__LEGACY: { localApplicationService, getAngularDependencies, ...legacyServices },
}: DashboardPluginSetupDependencies
) {
+ localApplicationService.forwardApp('dashboard', 'dashboards');
localApplicationService.register({
- id: 'discover',
- title: 'Discover',
+ id: 'dashboards',
+ title: 'Dashboards',
mount: async ({ core: contextCore }, params) => {
const angularDependencies = await getAngularDependencies();
const deps: RenderDeps = {
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index c57b309fee2e1..25f86a6d25c6e 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -100,7 +100,7 @@ function mountDashboardApp(appBasePath: string, element: HTMLElement) {
// make angular-within-angular possible
const $injector = angular.bootstrap(mountpoint, [moduleName]);
// initialize global state handler
- $injector.get('globalState');
+ // $injector.get('globalState');
element.appendChild(mountpoint);
return $injector;
}
diff --git a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
index c2963d1ba7095..5e9b9e5fd7ef7 100644
--- a/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
+++ b/src/legacy/core_plugins/kibana/public/local_application_service/local_application_service.ts
@@ -75,7 +75,9 @@ export class LocalApplicationService {
this.forwards.forEach(({ legacyAppId, newAppId, keepPrefix }) => {
angularRouteManager.when(`/${legacyAppId}:tail*?`, {
redirectTo: (_params: unknown, path: string, search: string) => {
- const newPath = `/${newAppId}${keepPrefix ? path : path.replace(legacyAppId, '')}`;
+ const newPath = `/${newAppId}${
+ keepPrefix ? path : path.replace(new RegExp(`${legacyAppId}/?`), '')
+ }`;
return `${newPath}?${search}`;
},
});
diff --git a/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js b/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js
index 79365eb5cf1cc..dd235bc62473e 100644
--- a/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js
+++ b/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js
@@ -24,7 +24,7 @@ import { TopNavMenu } from '../../../core_plugins/kibana_react/public';
const module = uiModules.get('kibana');
-module.directive('kbnTopNav', () => {
+export const createTopNavDirective = () => {
return {
restrict: 'E',
template: '',
@@ -71,9 +71,11 @@ module.directive('kbnTopNav', () => {
return linkFn;
}
};
-});
+};
-module.directive('kbnTopNavHelper', (reactDirective) => {
+module.directive('kbnTopNav', createTopNavDirective);
+
+export const createTopNavHelper = (reactDirective) => {
return reactDirective(
wrapInI18nContext(TopNavMenu),
[
@@ -113,4 +115,6 @@ module.directive('kbnTopNavHelper', (reactDirective) => {
'showAutoRefreshOnly',
],
);
-});
+};
+
+module.directive('kbnTopNavHelper', createTopNavHelper);
diff --git a/src/legacy/ui/public/private/private.js b/src/legacy/ui/public/private/private.js
index ef5c59c21dd7a..74d3785a4238a 100644
--- a/src/legacy/ui/public/private/private.js
+++ b/src/legacy/ui/public/private/private.js
@@ -108,98 +108,100 @@ function name(fn) {
return fn.name || fn.toString().split('\n').shift();
}
-uiModules.get('kibana/private')
- .provider('Private', function () {
- const provider = this;
-
- // one cache/swaps per Provider
- const cache = {};
- const swaps = {};
+export function PrivateProvider() {
+ const provider = this;
- // return the uniq id for this function
- function identify(fn) {
- if (typeof fn !== 'function') {
- throw new TypeError('Expected private module "' + fn + '" to be a function');
- }
+ // one cache/swaps per Provider
+ const cache = {};
+ const swaps = {};
- if (fn.$$id) return fn.$$id;
- else return (fn.$$id = nextId());
+ // return the uniq id for this function
+ function identify(fn) {
+ if (typeof fn !== 'function') {
+ throw new TypeError('Expected private module "' + fn + '" to be a function');
}
- provider.stub = function (fn, instance) {
- cache[identify(fn)] = instance;
- return instance;
- };
+ if (fn.$$id) return fn.$$id;
+ else return (fn.$$id = nextId());
+ }
- provider.swap = function (fn, prov) {
- const id = identify(fn);
- swaps[id] = prov;
- };
+ provider.stub = function (fn, instance) {
+ cache[identify(fn)] = instance;
+ return instance;
+ };
+
+ provider.swap = function (fn, prov) {
+ const id = identify(fn);
+ swaps[id] = prov;
+ };
- provider.$get = ['$injector', function PrivateFactory($injector) {
+ provider.$get = ['$injector', function PrivateFactory($injector) {
- // prevent circular deps by tracking where we came from
- const privPath = [];
- const pathToString = function () {
- return privPath.map(name).join(' -> ');
- };
+ // prevent circular deps by tracking where we came from
+ const privPath = [];
+ const pathToString = function () {
+ return privPath.map(name).join(' -> ');
+ };
- // call a private provider and return the instance it creates
- function instantiate(prov, locals) {
- if (~privPath.indexOf(prov)) {
- throw new Error(
- 'Circular reference to "' + name(prov) + '"' +
+ // call a private provider and return the instance it creates
+ function instantiate(prov, locals) {
+ if (~privPath.indexOf(prov)) {
+ throw new Error(
+ 'Circular reference to "' + name(prov) + '"' +
' found while resolving private deps: ' + pathToString()
- );
- }
+ );
+ }
- privPath.push(prov);
+ privPath.push(prov);
- const context = {};
- let instance = $injector.invoke(prov, context, locals);
- if (!_.isObject(instance)) instance = context;
+ const context = {};
+ let instance = $injector.invoke(prov, context, locals);
+ if (!_.isObject(instance)) instance = context;
- privPath.pop();
- return instance;
- }
-
- // retrieve an instance from cache or create and store on
- function get(id, prov, $delegateId, $delegateProv) {
- if (cache[id]) return cache[id];
+ privPath.pop();
+ return instance;
+ }
- let instance;
+ // retrieve an instance from cache or create and store on
+ function get(id, prov, $delegateId, $delegateProv) {
+ if (cache[id]) return cache[id];
- if ($delegateId != null && $delegateProv != null) {
- instance = instantiate(prov, {
- $decorate: _.partial(get, $delegateId, $delegateProv)
- });
- } else {
- instance = instantiate(prov);
- }
+ let instance;
- return (cache[id] = instance);
+ if ($delegateId != null && $delegateProv != null) {
+ instance = instantiate(prov, {
+ $decorate: _.partial(get, $delegateId, $delegateProv)
+ });
+ } else {
+ instance = instantiate(prov);
}
- // main api, get the appropriate instance for a provider
- function Private(prov) {
- let id = identify(prov);
- let $delegateId;
- let $delegateProv;
+ return (cache[id] = instance);
+ }
- if (swaps[id]) {
- $delegateId = id;
- $delegateProv = prov;
+ // main api, get the appropriate instance for a provider
+ function Private(prov) {
+ let id = identify(prov);
+ let $delegateId;
+ let $delegateProv;
- prov = swaps[$delegateId];
- id = identify(prov);
- }
+ if (swaps[id]) {
+ $delegateId = id;
+ $delegateProv = prov;
- return get(id, prov, $delegateId, $delegateProv);
+ prov = swaps[$delegateId];
+ id = identify(prov);
}
- Private.stub = provider.stub;
- Private.swap = provider.swap;
+ return get(id, prov, $delegateId, $delegateProv);
+ }
- return Private;
- }];
- });
+ Private.stub = provider.stub;
+ Private.swap = provider.swap;
+
+ return Private;
+ }];
+}
+
+uiModules.get('kibana/private')
+ .provider('Private', PrivateProvider);
diff --git a/src/legacy/ui/public/state_management/config_provider.js b/src/legacy/ui/public/state_management/config_provider.js
index 090210cc8723e..ec770e7fef6ca 100644
--- a/src/legacy/ui/public/state_management/config_provider.js
+++ b/src/legacy/ui/public/state_management/config_provider.js
@@ -25,21 +25,23 @@
import { uiModules } from '../modules';
-uiModules.get('kibana/state_management')
- .provider('stateManagementConfig', class StateManagementConfigProvider {
- _enabled = true
+export class StateManagementConfigProvider {
+ _enabled = true
+
+ $get(/* inject stuff */) {
+ return {
+ enabled: this._enabled,
+ };
+ }
- $get(/* inject stuff */) {
- return {
- enabled: this._enabled,
- };
- }
+ disable() {
+ this._enabled = false;
+ }
- disable() {
- this._enabled = false;
- }
+ enable() {
+ this._enabled = true;
+ }
+}
- enable() {
- this._enabled = true;
- }
- });
+uiModules.get('kibana/state_management')
+ .provider('stateManagementConfig', StateManagementConfigProvider);
From 160fe52741e7652431b724f642a244ae9a10e3e6 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Wed, 23 Oct 2019 18:19:07 +0300
Subject: [PATCH 018/132] Centralize dependencies for Visualize plugin
---
.../visualize/embeddable/get_index_pattern.ts | 9 +--
.../visualize_embeddable_factory.tsx | 6 +-
.../public/visualize/help_menu/help_menu.js | 7 +-
.../visualize/help_menu/help_menu_util.js | 2 +-
.../kibana/public/visualize/index.js | 7 +-
.../public/visualize/kibana_services.ts | 71 +++++++++++++++++++
.../visualize/listing/visualize_listing.js | 27 ++++---
.../listing/visualize_listing_table.js | 9 ++-
.../kibana/public/visualize/types.d.ts | 2 +-
.../public/visualize/wizard/new_vis_modal.tsx | 10 +--
.../wizard/type_selection/new_vis_help.tsx | 5 +-
11 files changed, 123 insertions(+), 32 deletions(-)
create mode 100644 src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
index 699fa68b4528b..97db9e1efea8c 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
@@ -17,10 +17,13 @@
* under the License.
*/
-import chrome from 'ui/chrome';
import { StaticIndexPattern, getFromSavedObject } from 'ui/index_patterns';
import { VisSavedObject } from 'ui/visualize/loader/types';
+import { getServices } from '../kibana_services';
+
+const { uiSettings, savedObjectsClient } = getServices();
+
export async function getIndexPattern(
savedVis: VisSavedObject
): Promise {
@@ -28,9 +31,7 @@ export async function getIndexPattern(
return savedVis.vis.indexPattern;
}
- const config = chrome.getUiSettingsClient();
- const savedObjectsClient = chrome.getSavedObjectsClient();
- const defaultIndex = config.get('defaultIndex');
+ const defaultIndex = uiSettings.get('defaultIndex');
if (savedVis.vis.params.index_pattern) {
const indexPatternObjects = await savedObjectsClient.find({
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index 8448b65e0994e..5c4768cd63dad 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -61,6 +61,10 @@ import { VisualizeEmbeddable, VisualizeInput, VisualizeOutput } from './visualiz
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
+import { getServices } from '../kibana_services';
+
+const { addBasePath } = getServices();
+
interface VisualizationAttributes extends SavedObjectAttributes {
visState: string;
}
@@ -142,7 +146,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
try {
const visId = savedObjectId;
- const editUrl = chrome.addBasePath(`/app/kibana${savedVisualizations.urlFor(visId)}`);
+ const editUrl = addBasePath(`/app/kibana${savedVisualizations.urlFor(visId)}`);
const loader = await getVisualizeLoader();
const savedObject = await savedVisualizations.get(visId);
const isLabsEnabled = config.get('visualize:enableLabs');
diff --git a/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu.js b/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu.js
index d95f7ea85c5db..40a1b79ea3520 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu.js
@@ -20,7 +20,10 @@
import React, { Fragment, PureComponent } from 'react';
import { EuiButton, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links';
+
+import { getServices } from '../kibana_services';
+
+const { docLinks } = getServices();
export class HelpMenu extends PureComponent {
render() {
@@ -31,7 +34,7 @@ export class HelpMenu extends PureComponent {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js b/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js
index aeabff2d97007..58a92193de63e 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/help_menu/help_menu_util.js
@@ -22,7 +22,7 @@ import { render, unmountComponentAtNode } from 'react-dom';
import { HelpMenu } from './help_menu';
export function addHelpMenuToAppChrome(chrome) {
- chrome.helpExtension.set(domElement => {
+ chrome.setHelpExtension(domElement => {
render(, domElement);
return () => {
unmountComponentAtNode(domElement);
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.js b/src/legacy/core_plugins/kibana/public/visualize/index.js
index b3c16fb94d7fb..e53a3479f0ffa 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/index.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/index.js
@@ -21,17 +21,18 @@ import './editor/editor';
import { i18n } from '@kbn/i18n';
import './saved_visualizations/_saved_vis';
import './saved_visualizations/saved_visualizations';
-import uiRoutes from 'ui/routes';
-import 'ui/capabilities/route_setup';
import visualizeListingTemplate from './listing/visualize_listing.html';
import { VisualizeListingController } from './listing/visualize_listing';
import { VisualizeConstants } from './visualize_constants';
-import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { getLandingBreadcrumbs, getWizardStep1Breadcrumbs } from './breadcrumbs';
+import { getServices, FeatureCatalogueCategory } from './kibana_services';
+
// load directives
import '../../../data/public';
+const { uiRoutes, FeatureCatalogueRegistryProvider } = getServices();
+
uiRoutes
.defaults(/visualize/, {
requireDefaultIndex: true,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
new file mode 100644
index 0000000000000..dd0234d6ed490
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -0,0 +1,71 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import 'ui/directives/kbn_href';
+
+import { npStart } from 'ui/new_platform';
+import chromeLegacy from 'ui/chrome';
+import angular from 'angular';
+
+import uiRoutes from 'ui/routes';
+import { wrapInI18nContext } from 'ui/i18n';
+
+// @ts-ignore
+import { uiModules } from 'ui/modules';
+import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
+
+// Filters
+import { timefilter } from 'ui/timefilter';
+
+// Saved objects
+import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
+import { SavedObjectsClientProvider } from 'ui/saved_objects';
+// @ts-ignore
+import { SavedObjectProvider } from 'ui/saved_objects/saved_object';
+
+const services = {
+ // new platform
+ capabilities: npStart.core.application.capabilities,
+ chrome: npStart.core.chrome,
+ docLinks: npStart.core.docLinks,
+ toastNotifications: npStart.core.notifications.toasts,
+ uiSettings: npStart.core.uiSettings,
+ savedObjectsClient: npStart.core.savedObjects.client,
+ addBasePath: npStart.core.http.basePath.prepend,
+
+ // legacy
+ angular,
+ uiRoutes,
+ uiModules,
+ FeatureCatalogueRegistryProvider,
+ SavedObjectRegistryProvider,
+ SavedObjectsClientProvider,
+ SavedObjectProvider,
+ timefilter,
+ wrapInI18nContext,
+};
+export function getServices() {
+ return services;
+}
+
+// export types
+export { VisSavedObject } from 'ui/visualize/loader/types';
+
+// const
+export { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index bb05ce34413db..aeee3c91cbfa7 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -17,21 +17,26 @@
* under the License.
*/
-import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
-import 'ui/directives/kbn_href';
-import { uiModules } from 'ui/modules';
-import { timefilter } from 'ui/timefilter';
-import chrome from 'ui/chrome';
-import { wrapInI18nContext } from 'ui/i18n';
-import { toastNotifications } from 'ui/notify';
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
-import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { VisualizeListingTable } from './visualize_listing_table';
import { NewVisModal } from '../wizard/new_vis_modal';
import { VisualizeConstants } from '../visualize_constants';
import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { i18n } from '@kbn/i18n';
+import { getServices } from '../kibana_services';
+
+const {
+ uiModules,
+ SavedObjectRegistryProvider,
+ timefilter,
+ chrome,
+ toastNotifications,
+ wrapInI18nContext,
+ SavedObjectsClientProvider,
+ addBasePath
+} = getServices();
+
const app = uiModules.get('app/visualize', ['ngRoute', 'react']);
app.directive('visualizeListingTable', reactDirective =>
reactDirective(wrapInI18nContext(VisualizeListingTable))
@@ -55,11 +60,11 @@ export function VisualizeListingController($injector, createNewVis) {
this.editItem = ({ editUrl }) => {
// for visualizations the edit and view URLs are the same
- window.location = chrome.addBasePath(editUrl);
+ window.location = addBasePath(editUrl);
};
this.getViewUrl = ({ editUrl }) => {
- return chrome.addBasePath(editUrl);
+ return addBasePath(editUrl);
};
this.closeNewVisModal = () => {
@@ -112,7 +117,7 @@ export function VisualizeListingController($injector, createNewVis) {
});
};
- chrome.breadcrumbs.set([
+ chrome.setBreadcrumbs([
{
text: i18n.translate('kbn.visualize.visualizeListingBreadcrumbsTitle', {
defaultMessage: 'Visualize',
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
index c909b6003516f..67fc70899410b 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
@@ -21,7 +21,6 @@ import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
-import { capabilities } from 'ui/capabilities';
import { TableListView } from './../../table_list_view';
import {
@@ -32,6 +31,10 @@ import {
EuiEmptyPrompt,
} from '@elastic/eui';
+import { getServices } from '../kibana_services';
+
+const { capabilities } = getServices();
+
class VisualizeListingTableUi extends Component {
constructor(props) {
@@ -46,8 +49,8 @@ class VisualizeListingTableUi extends Component {
// for data exploration purposes
createItem={this.props.createItem}
findItems={this.props.findItems}
- deleteItems={capabilities.get().visualize.delete ? this.props.deleteItems : null}
- editItem={capabilities.get().visualize.save ? this.props.editItem : null}
+ deleteItems={capabilities.visualize.delete ? this.props.deleteItems : null}
+ editItem={capabilities.visualize.save ? this.props.editItem : null}
tableColumns={this.getTableColumns()}
listingLimit={this.props.listingLimit}
selectable={item => item.canDelete}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/types.d.ts b/src/legacy/core_plugins/kibana/public/visualize/types.d.ts
index b321e5563eb60..c83f7f5a5da8b 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/types.d.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/types.d.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { VisSavedObject } from 'ui/visualize/loader/types';
+import { VisSavedObject } from './kibana_services';
export interface SavedVisualizations {
urlFor: (id: string) => string;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
index 31ddafb4ec719..7231d7e947408 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
@@ -22,14 +22,16 @@ import React from 'react';
import { EuiModal, EuiOverlayMask } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import chrome from 'ui/chrome';
-import { VisType } from 'ui/vis';
import { VisualizeConstants } from '../visualize_constants';
import { createUiStatsReporter, METRIC_TYPE } from '../../../../ui_metric/public';
import { SearchSelection } from './search_selection';
import { TypeSelection } from './type_selection';
import { TypesStart, VisTypeAlias } from '../../../../visualizations/public/np_ready/public/types';
+import { getServices, VisType } from '../kibana_services';
+
+const { addBasePath, uiSettings } = getServices();
+
interface TypeSelectionProps {
isOpen: boolean;
onClose: () => void;
@@ -54,7 +56,7 @@ class NewVisModal extends React.Component{t.promotion!.description}
Date: Thu, 24 Oct 2019 12:29:54 +0200
Subject: [PATCH 019/132] move handlers from addSetupWork into legacy_compat
---
.../console/np_ready/public/legacy.ts | 1 -
src/legacy/core_plugins/data/public/index.ts | 11 ++
.../data/public/shim/legacy_module.ts | 185 ++++++++++--------
.../kibana/public/dashboard/app.js | 15 +-
.../public/dashboard/dashboard_app.html | 6 +-
.../kibana/public/dashboard/dashboard_app.tsx | 10 +-
.../dashboard/dashboard_app_controller.tsx | 14 +-
.../public/dashboard/dashboard_constants.ts | 4 +-
.../kibana/public/dashboard/plugin.ts | 4 +-
.../kibana/public/dashboard/render_app.ts | 78 +++++---
.../public/discover/angular/discover.js | 1 -
.../kibana/public/management/index.js | 8 -
.../management/route_setup/load_default.js | 110 -----------
.../kibana/public/visualize/index.js | 1 -
.../ui/public/capabilities/route_setup.ts | 38 ----
.../public/legacy_compat/angular_config.tsx | 127 +++++++++++-
src/legacy/ui/public/promises/promises.js | 10 +-
.../ui/public/routes/route_manager.d.ts | 3 +-
.../grokdebugger/grokdebugger_route.js | 1 -
.../plugins/searchprofiler/public/app.js | 1 -
20 files changed, 318 insertions(+), 310 deletions(-)
delete mode 100644 src/legacy/core_plugins/kibana/public/management/route_setup/load_default.js
delete mode 100644 src/legacy/ui/public/capabilities/route_setup.ts
diff --git a/src/legacy/core_plugins/console/np_ready/public/legacy.ts b/src/legacy/core_plugins/console/np_ready/public/legacy.ts
index af9803c97749e..b5ac3866c3a51 100644
--- a/src/legacy/core_plugins/console/np_ready/public/legacy.ts
+++ b/src/legacy/core_plugins/console/np_ready/public/legacy.ts
@@ -31,7 +31,6 @@ import { DOC_LINK_VERSION } from 'ui/documentation_links';
import { I18nContext } from 'ui/i18n';
import { ResizeChecker } from 'ui/resize_checker';
import 'ui/autoload/styles';
-import 'ui/capabilities/route_setup';
/* eslint-enable @kbn/eslint/no-restricted-paths */
import template from '../../public/quarantined/index.html';
diff --git a/src/legacy/core_plugins/data/public/index.ts b/src/legacy/core_plugins/data/public/index.ts
index cb3869ff57711..b7d3cfb79a463 100644
--- a/src/legacy/core_plugins/data/public/index.ts
+++ b/src/legacy/core_plugins/data/public/index.ts
@@ -69,4 +69,15 @@ export {
mockIndexPattern,
} from './index_patterns';
+/**
+ * These functions can be used to register the angular wrappers for react components
+ * in a separate module to use them without relying on the uiModules module tree.
+ * */
+export {
+ createFilterBarHelper,
+ createFilterBarDirective,
+ createApplyFiltersPopoverDirective,
+ createApplyFiltersPopoverHelper,
+} from './shim/legacy_module';
+
export { TimeHistoryContract, TimefilterContract, getTime, InputTimeRange } from './timefilter';
diff --git a/src/legacy/core_plugins/data/public/shim/legacy_module.ts b/src/legacy/core_plugins/data/public/shim/legacy_module.ts
index 0b5ca72599208..37b3112aa4c06 100644
--- a/src/legacy/core_plugins/data/public/shim/legacy_module.ts
+++ b/src/legacy/core_plugins/data/public/shim/legacy_module.ts
@@ -30,97 +30,108 @@ import { FilterBar, ApplyFiltersPopover } from '../filter';
import { mapAndFlattenFilters } from '../filter/filter_manager/lib/map_and_flatten_filters';
import { IndexPatterns } from '../index_patterns/index_patterns';
+/** @internal */
+export const createFilterBarDirective = () => {
+ return {
+ restrict: 'E',
+ template: '',
+ compile: (elem: any) => {
+ const child = document.createElement('filter-bar-helper');
+
+ // Copy attributes to the child directive
+ for (const attr of elem[0].attributes) {
+ child.setAttribute(attr.name, attr.value);
+ }
+
+ child.setAttribute('ui-settings', 'uiSettings');
+ child.setAttribute('doc-links', 'docLinks');
+ child.setAttribute('plugin-data-start', 'pluginDataStart');
+
+ // Append helper directive
+ elem.append(child);
+
+ const linkFn = ($scope: any) => {
+ $scope.uiSettings = npStart.core.uiSettings;
+ $scope.docLinks = npStart.core.docLinks;
+ $scope.pluginDataStart = npStart.plugins.data;
+ };
+
+ return linkFn;
+ },
+ };
+};
+
+/** @internal */
+export const createFilterBarHelper = (reactDirective: any) => {
+ return reactDirective(wrapInI18nContext(FilterBar), [
+ ['uiSettings', { watchDepth: 'reference' }],
+ ['docLinks', { watchDepth: 'reference' }],
+ ['onFiltersUpdated', { watchDepth: 'reference' }],
+ ['indexPatterns', { watchDepth: 'collection' }],
+ ['filters', { watchDepth: 'collection' }],
+ ['className', { watchDepth: 'reference' }],
+ ['pluginDataStart', { watchDepth: 'reference' }],
+ ]);
+};
+
+/** @internal */
+export const createApplyFiltersPopoverDirective = () => {
+ return {
+ restrict: 'E',
+ template: '',
+ compile: (elem: any) => {
+ const child = document.createElement('apply-filters-popover-helper');
+
+ // Copy attributes to the child directive
+ for (const attr of elem[0].attributes) {
+ child.setAttribute(attr.name, attr.value);
+ }
+
+ // Add a key attribute that will force a full rerender every time that
+ // a filter changes.
+ child.setAttribute('key', 'key');
+
+ // Append helper directive
+ elem.append(child);
+
+ const linkFn = ($scope: any, _: any, $attr: any) => {
+ // Watch only for filter changes to update key.
+ $scope.$watch(
+ () => {
+ return $scope.$eval($attr.filters) || [];
+ },
+ (newVal: any) => {
+ $scope.key = Date.now();
+ },
+ true
+ );
+ };
+
+ return linkFn;
+ },
+ };
+};
+
+/** @internal */
+export const createApplyFiltersPopoverHelper = (reactDirective: any) =>
+ reactDirective(wrapInI18nContext(ApplyFiltersPopover), [
+ ['filters', { watchDepth: 'collection' }],
+ ['onCancel', { watchDepth: 'reference' }],
+ ['onSubmit', { watchDepth: 'reference' }],
+ ['indexPatterns', { watchDepth: 'collection' }],
+
+ // Key is needed to trigger a full rerender of the component
+ 'key',
+ ]);
+
/** @internal */
export const initLegacyModule = once((): void => {
uiModules
.get('app/kibana', ['react'])
- .directive('filterBar', () => {
- return {
- restrict: 'E',
- template: '',
- compile: (elem: any) => {
- const child = document.createElement('filter-bar-helper');
-
- // Copy attributes to the child directive
- for (const attr of elem[0].attributes) {
- child.setAttribute(attr.name, attr.value);
- }
-
- child.setAttribute('ui-settings', 'uiSettings');
- child.setAttribute('doc-links', 'docLinks');
- child.setAttribute('plugin-data-start', 'pluginDataStart');
-
- // Append helper directive
- elem.append(child);
-
- const linkFn = ($scope: any) => {
- $scope.uiSettings = npStart.core.uiSettings;
- $scope.docLinks = npStart.core.docLinks;
- $scope.pluginDataStart = npStart.plugins.data;
- };
-
- return linkFn;
- },
- };
- })
- .directive('filterBarHelper', (reactDirective: any) => {
- return reactDirective(wrapInI18nContext(FilterBar), [
- ['uiSettings', { watchDepth: 'reference' }],
- ['docLinks', { watchDepth: 'reference' }],
- ['onFiltersUpdated', { watchDepth: 'reference' }],
- ['indexPatterns', { watchDepth: 'collection' }],
- ['filters', { watchDepth: 'collection' }],
- ['className', { watchDepth: 'reference' }],
- ['pluginDataStart', { watchDepth: 'reference' }],
- ]);
- })
- .directive('applyFiltersPopover', () => {
- return {
- restrict: 'E',
- template: '',
- compile: (elem: any) => {
- const child = document.createElement('apply-filters-popover-helper');
-
- // Copy attributes to the child directive
- for (const attr of elem[0].attributes) {
- child.setAttribute(attr.name, attr.value);
- }
-
- // Add a key attribute that will force a full rerender every time that
- // a filter changes.
- child.setAttribute('key', 'key');
-
- // Append helper directive
- elem.append(child);
-
- const linkFn = ($scope: any, _: any, $attr: any) => {
- // Watch only for filter changes to update key.
- $scope.$watch(
- () => {
- return $scope.$eval($attr.filters) || [];
- },
- (newVal: any) => {
- $scope.key = Date.now();
- },
- true
- );
- };
-
- return linkFn;
- },
- };
- })
- .directive('applyFiltersPopoverHelper', (reactDirective: any) =>
- reactDirective(wrapInI18nContext(ApplyFiltersPopover), [
- ['filters', { watchDepth: 'collection' }],
- ['onCancel', { watchDepth: 'reference' }],
- ['onSubmit', { watchDepth: 'reference' }],
- ['indexPatterns', { watchDepth: 'collection' }],
-
- // Key is needed to trigger a full rerender of the component
- 'key',
- ])
- );
+ .directive('filterBar', createFilterBarDirective)
+ .directive('filterBarHelper', createFilterBarHelper)
+ .directive('applyFiltersPopover', createApplyFiltersPopoverDirective)
+ .directive('applyFiltersPopoverHelper', createApplyFiltersPopoverHelper);
const module = uiModules.get('kibana/index_patterns');
let _service: any;
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index f219da072c87b..c57aeec9acabb 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -31,19 +31,13 @@ import {
SavedObjectNotFound,
} from '../../../../../plugins/kibana_utils/public';
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
-import { SavedObjectsClientProvider } from 'ui/saved_objects';
-import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
import { DashboardListing, EMPTY_FILTER } from './listing/dashboard_listing';
-import 'ui/capabilities/route_setup';
import { addHelpMenuToAppChrome } from './help_menu/help_menu_util';
-// load directives
-import '../../../data/public';
-
export function initDashboardApp(app, deps) {
initDashboardAppDirective(app, deps);
- app.directive('dashboardListing', function(reactDirective) {
+ app.directive('dashboardListing', function (reactDirective) {
return reactDirective(wrapInI18nContext(DashboardListing));
});
@@ -56,6 +50,7 @@ export function initDashboardApp(app, deps) {
app.config(function ($routeProvider) {
const defaults = {
+ reloadOnSearch: false,
requireDefaultIndex: true,
requireUICapability: 'dashboard.show',
badge: () => {
@@ -74,7 +69,11 @@ export function initDashboardApp(app, deps) {
};
},
};
+
$routeProvider
+ // migrate old URLs
+ .when('/dashboards/dashboard', { redirectTo: (_params, _path, query) => `/dashboards/create?${query}` })
+ .when('/dashboards/dashboard/:id', { redirectTo: (params, _path, query) => `/dashboards/edit/${params.id}?${query}` })
.when(DashboardConstants.LANDING_PAGE_PATH, {
...defaults,
template: dashboardListingTemplate,
@@ -111,7 +110,7 @@ export function initDashboardApp(app, deps) {
addHelpMenuToAppChrome(deps.chrome);
},
resolve: {
- dash: function ($route/*, redirectWhenMissing, kbnUrl*/) {
+ dash: function ($route, redirectWhenMissing, kbnUrl) {
const savedObjectsClient = deps.savedObjectsClient;
const title = $route.current.params.title;
if (title) {
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
index 68c8131fa1a7b..d51b7e394f339 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app.html
@@ -4,11 +4,11 @@
>
void;
timefilterSubscriptions$: Subscription;
+ isVisible: boolean;
}
export function initDashboardAppDirective(app: any, deps: RenderDeps) {
@@ -104,12 +104,6 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) {
},
getAppState: {
previouslyStored: () => TAppState | undefined;
- },
- dashboardConfig: {
- getHideWriteControls: () => boolean;
- },
- localStorage: {
- get: (prop: string) => unknown;
}
) =>
new DashboardAppController({
@@ -117,8 +111,6 @@ export function initDashboardAppDirective(app: any, deps: RenderDeps) {
$scope,
$routeParams,
getAppState,
- dashboardConfig,
- localStorage,
kbnUrl,
AppStateClass: AppState,
config,
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
index 1abf03a9d6d78..af6b8f086a921 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
@@ -23,7 +23,6 @@ import React from 'react';
import angular from 'angular';
import { uniq } from 'lodash';
-import chrome from 'ui/chrome';
import { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
import { toastNotifications } from 'ui/notify';
@@ -39,7 +38,6 @@ import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
import { timefilter } from 'ui/timefilter';
-
import {
AppStateClass as TAppStateClass,
AppState as TAppState,
@@ -95,9 +93,6 @@ export interface DashboardAppControllerDependencies extends RenderDeps {
getDefault: () => Promise;
};
dashboardConfig: any;
- localStorage: {
- get: (prop: string) => unknown;
- };
kbnUrl: KbnUrl;
AppStateClass: TAppStateClass;
config: any;
@@ -128,7 +123,7 @@ export class DashboardAppController {
savedQueryService,
embeddables,
dashboardCapabilities,
- core: { notifications, overlays },
+ core: { notifications, overlays, chrome },
}: DashboardAppControllerDependencies) {
let lastReloadRequestTime = 0;
@@ -332,7 +327,7 @@ export class DashboardAppController {
// Push breadcrumbs to new header navigation
const updateBreadcrumbs = () => {
- chrome.breadcrumbs.set([
+ chrome.setBreadcrumbs([
{
text: i18n.translate('kbn.dashboard.dashboardAppBreadcrumbsTitle', {
defaultMessage: 'Dashboard',
@@ -814,8 +809,13 @@ export class DashboardAppController {
},
});
+ const visibleSubscription = chrome.getIsVisible$().subscribe(isVisible => {
+ $scope.isVisible = isVisible;
+ });
+
$scope.$on('$destroy', () => {
updateSubscription.unsubscribe();
+ visibleSubscription.unsubscribe();
$scope.timefilterSubscriptions$.unsubscribe();
dashboardStateManager.destroy();
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts
index b76b3f309874a..f3e4414477b86 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts
@@ -21,9 +21,9 @@ export const DashboardConstants = {
ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM: 'addToDashboard',
NEW_VISUALIZATION_ID_PARAM: 'addVisualization',
LANDING_PAGE_PATH: '/dashboards',
- CREATE_NEW_DASHBOARD_URL: '/dashboard',
+ CREATE_NEW_DASHBOARD_URL: '/dashboards/create',
};
export function createDashboardEditUrl(id: string) {
- return `/dashboard/${id}`;
+ return `/dashboards/view/${id}`;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
index 29e5f3e5f15a0..cbdc0663bfd77 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
@@ -18,6 +18,7 @@
*/
import { CoreSetup, CoreStart, Plugin, SavedObjectsClientContract } from 'kibana/public';
+import { Storage } from 'ui/storage';
import { RenderDeps } from './render_app';
import { LocalApplicationService } from '../local_application_service';
import { DataStart } from '../../../data/public';
@@ -58,7 +59,7 @@ export class DashboardPlugin implements Plugin {
__LEGACY: { localApplicationService, getAngularDependencies, ...legacyServices },
}: DashboardPluginSetupDependencies
) {
- localApplicationService.forwardApp('dashboard', 'dashboards');
+ localApplicationService.forwardApp('dashboard', 'dashboards', { keepPrefix: true });
localApplicationService.register({
id: 'dashboards',
title: 'Dashboards',
@@ -76,6 +77,7 @@ export class DashboardPlugin implements Plugin {
savedQueryService: this.savedQueryService!,
embeddables: this.embeddables!,
dashboardCapabilities: contextCore.application.capabilities.dashboard,
+ localStorage: new Storage(localStorage),
};
const { renderApp } = await import('./render_app');
return renderApp(params.element, params.appBasePath, deps);
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index 25f86a6d25c6e..82e38d9944370 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -20,12 +20,15 @@
import { EuiConfirmModal } from '@elastic/eui';
import angular from 'angular';
import { IPrivate } from 'ui/private';
+import { Storage } from 'ui/storage';
import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/src/angular';
// @ts-ignore
import { GlobalStateProvider } from 'ui/state_management/global_state';
// @ts-ignore
import { StateManagementConfigProvider } from 'ui/state_management/config_provider';
// @ts-ignore
+import { AppStateProvider } from 'ui/state_management/app_state';
+// @ts-ignore
import { PrivateProvider } from 'ui/private/private';
// @ts-ignore
import { EventsProvider } from 'ui/events';
@@ -50,7 +53,13 @@ import { configureAppAngularModule } from 'ui/legacy_compat';
// @ts-ignore
import { initDashboardApp } from './app';
-import { DataStart } from '../../../data/public';
+import {
+ createApplyFiltersPopoverDirective,
+ createApplyFiltersPopoverHelper,
+ createFilterBarDirective,
+ createFilterBarHelper,
+ DataStart,
+} from '../../../data/public';
import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public';
@@ -68,14 +77,17 @@ export interface RenderDeps {
uiSettings: UiSettingsClientContract;
chrome: ChromeStart;
addBasePath: (path: string) => string;
- getFeatureCatalogueRegistryProvider: () => any;
+ FeatureCatalogueRegistryProvider: any;
savedQueryService: SavedQueryService;
embeddables: ReturnType;
+ localStorage: Storage;
}
export const renderApp = (element: HTMLElement, appBasePath: string, deps: RenderDeps) => {
const dashboardAngularModule = createLocalAngularModule(deps.core);
+ // global routing stuff
configureAppAngularModule(dashboardAngularModule);
+ // custom routing stuff
initDashboardApp(dashboardAngularModule, deps);
const $injector = mountDashboardApp(appBasePath, element);
return () => $injector.get('$rootScope').$destroy();
@@ -111,39 +123,48 @@ function createLocalAngularModule(core: AppMountContext['core']) {
createLocalPromiseModule();
createLocalConfigModule(core);
createLocalKbnUrlModule();
+ createLocalStateModule();
createLocalPersistedStateModule();
createLocalTopNavModule();
- createLocalGlobalStateModule();
createLocalConfirmModalModule();
+ createLocalFilterBarModule();
const dashboardAngularModule = angular.module(moduleName, [
...thirdPartyAngularDependencies,
- 'dashboardConfig',
- 'dashboardI18n',
- 'dashboardPrivate',
- 'dashboardPersistedState',
- 'dashboardTopNav',
- 'dashboardGlobalState',
- 'dashboardConfirmModal',
+ 'app/dashboard/Config',
+ 'app/dashboard/I18n',
+ 'app/dashboard/Private',
+ 'app/dashboard/PersistedState',
+ 'app/dashboard/TopNav',
+ 'app/dashboard/State',
+ 'app/dashboard/ConfirmModal',
+ 'app/dashboard/FilterBar',
]);
return dashboardAngularModule;
}
function createLocalConfirmModalModule() {
angular
- .module('dashboardConfirmModal', ['react'])
+ .module('app/dashboard/ConfirmModal', ['react'])
.factory('confirmModal', confirmModalFactory)
.directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal));
}
-function createLocalGlobalStateModule() {
+function createLocalStateModule() {
angular
- .module('dashboardGlobalState', [
- 'dashboardPrivate',
- 'dashboardConfig',
- 'dashboardKbnUrl',
- 'dashboardPromise',
+ .module('app/dashboard/State', [
+ 'app/dashboard/Private',
+ 'app/dashboard/Config',
+ 'app/dashboard/KbnUrl',
+ 'app/dashboard/Promise',
+ 'app/dashboard/PersistedState',
])
+ .factory('AppState', function(Private: any) {
+ return Private(AppStateProvider);
+ })
+ .service('getAppState', function(Private: any) {
+ return Private(AppStateProvider).getAppState;
+ })
.service('globalState', function(Private: any) {
return Private(GlobalStateProvider);
});
@@ -151,7 +172,7 @@ function createLocalGlobalStateModule() {
function createLocalPersistedStateModule() {
angular
- .module('dashboardPersistedState', ['dashboardPrivate', 'dashboardPromise'])
+ .module('app/dashboard/PersistedState', ['app/dashboard/Private', 'app/dashboard/Promise'])
.factory('PersistedState', (Private: IPrivate) => {
const Events = Private(EventsProvider);
return class AngularPersistedState extends PersistedState {
@@ -164,14 +185,14 @@ function createLocalPersistedStateModule() {
function createLocalKbnUrlModule() {
angular
- .module('dashboardKbnUrl', ['dashboardPrivate', 'ngRoute'])
+ .module('app/dashboard/KbnUrl', ['app/dashboard/Private', 'ngRoute'])
.service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
.service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
}
function createLocalConfigModule(core: AppMountContext['core']) {
angular
- .module('dashboardConfig', ['dashboardPrivate'])
+ .module('app/dashboard/Config', ['app/dashboard/Private'])
.provider('stateManagementConfig', StateManagementConfigProvider)
.provider('config', () => {
return {
@@ -183,23 +204,32 @@ function createLocalConfigModule(core: AppMountContext['core']) {
}
function createLocalPromiseModule() {
- angular.module('dashboardPromise', []).service('Promise', PromiseServiceCreator);
+ angular.module('app/dashboard/Promise', []).service('Promise', PromiseServiceCreator);
}
function createLocalPrivateModule() {
- angular.module('dashboardPrivate', []).provider('Private', PrivateProvider);
+ angular.module('app/dashboard/Private', []).provider('Private', PrivateProvider);
}
function createLocalTopNavModule() {
angular
- .module('dashboardTopNav', ['react'])
+ .module('app/dashboard/TopNav', ['react'])
.directive('kbnTopNav', createTopNavDirective)
.directive('kbnTopNavHelper', createTopNavHelper);
}
+function createLocalFilterBarModule() {
+ angular
+ .module('app/dashboard/FilterBar', ['react'])
+ .directive('filterBar', createFilterBarDirective)
+ .directive('filterBarHelper', createFilterBarHelper)
+ .directive('applyFiltersPopover', createApplyFiltersPopoverDirective)
+ .directive('applyFiltersPopoverHelper', createApplyFiltersPopoverHelper);
+}
+
function createLocalI18nModule() {
angular
- .module('dashboardI18n', [])
+ .module('app/dashboard/I18n', [])
.provider('i18n', I18nProvider)
.filter('i18n', i18nFilter)
.directive('i18nId', i18nDirective);
diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
index 840152fc40ced..1a6c6aad363ba 100644
--- a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
+++ b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
@@ -69,7 +69,6 @@ import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../breadcrumbs';
import { buildVislibDimensions } from 'ui/visualize/loader/pipeline_helpers/build_pipeline';
-import 'ui/capabilities/route_setup';
import { addHelpMenuToAppChrome } from '../components/help_menu/help_menu_util';
import { extractTimeFilter, changeTimeFilter } from '../../../../data/public';
diff --git a/src/legacy/core_plugins/kibana/public/management/index.js b/src/legacy/core_plugins/kibana/public/management/index.js
index c0949318e9253..83fc8e4db9b55 100644
--- a/src/legacy/core_plugins/kibana/public/management/index.js
+++ b/src/legacy/core_plugins/kibana/public/management/index.js
@@ -28,7 +28,6 @@ import { I18nContext } from 'ui/i18n';
import { uiModules } from 'ui/modules';
import appTemplate from './app.html';
import landingTemplate from './landing.html';
-import { capabilities } from 'ui/capabilities';
import { management, SidebarNav, MANAGEMENT_BREADCRUMB } from 'ui/management';
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { timefilter } from 'ui/timefilter';
@@ -50,13 +49,6 @@ uiRoutes
redirectTo: '/management'
});
-require('./route_setup/load_default')({
- whenMissingRedirectTo: () => {
- const canManageIndexPatterns = capabilities.get().management.kibana.index_patterns;
- return canManageIndexPatterns ? '/management/kibana/index_pattern' : '/home';
- }
-});
-
export function updateLandingPage(version) {
const node = document.getElementById(LANDING_ID);
if (!node) {
diff --git a/src/legacy/core_plugins/kibana/public/management/route_setup/load_default.js b/src/legacy/core_plugins/kibana/public/management/route_setup/load_default.js
deleted file mode 100644
index f797acbe8888e..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/route_setup/load_default.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import _ from 'lodash';
-import React from 'react';
-import { banners } from 'ui/notify';
-import { NoDefaultIndexPattern } from 'ui/index_patterns';
-import uiRoutes from 'ui/routes';
-import {
- EuiCallOut,
-} from '@elastic/eui';
-import { clearTimeout } from 'timers';
-import { i18n } from '@kbn/i18n';
-
-let bannerId;
-let timeoutId;
-
-function displayBanner() {
- clearTimeout(timeoutId);
-
- // Avoid being hostile to new users who don't have an index pattern setup yet
- // give them a friendly info message instead of a terse error message
- bannerId = banners.set({
- id: bannerId, // initially undefined, but reused after first set
- component: (
-
- )
- });
-
- // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
- timeoutId = setTimeout(() => {
- banners.remove(bannerId);
- timeoutId = undefined;
- }, 15000);
-}
-
-// eslint-disable-next-line import/no-default-export
-export default function (opts) {
- opts = opts || {};
- const whenMissingRedirectTo = opts.whenMissingRedirectTo || null;
-
- uiRoutes
- .addSetupWork(function loadDefaultIndexPattern(Promise, $route, config, indexPatterns) {
- const route = _.get($route, 'current.$$route');
-
- if (!route.requireDefaultIndex) {
- return;
- }
-
- return indexPatterns.getIds()
- .then(function (patterns) {
- let defaultId = config.get('defaultIndex');
- let defined = !!defaultId;
- const exists = _.contains(patterns, defaultId);
-
- if (defined && !exists) {
- config.remove('defaultIndex');
- defaultId = defined = false;
- }
-
- if (!defined) {
- // If there is any index pattern created, set the first as default
- if (patterns.length >= 1) {
- defaultId = patterns[0];
- config.set('defaultIndex', defaultId);
- } else {
- throw new NoDefaultIndexPattern();
- }
- }
- });
- })
- .afterWork(
- // success
- null,
-
- // failure
- function (err, kbnUrl) {
- const hasDefault = !(err instanceof NoDefaultIndexPattern);
- if (hasDefault || !whenMissingRedirectTo) throw err; // rethrow
-
- kbnUrl.change(whenMissingRedirectTo());
-
- displayBanner();
- }
- );
-}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.js b/src/legacy/core_plugins/kibana/public/visualize/index.js
index b3c16fb94d7fb..7afb98709fae0 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/index.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/index.js
@@ -22,7 +22,6 @@ import { i18n } from '@kbn/i18n';
import './saved_visualizations/_saved_vis';
import './saved_visualizations/saved_visualizations';
import uiRoutes from 'ui/routes';
-import 'ui/capabilities/route_setup';
import visualizeListingTemplate from './listing/visualize_listing.html';
import { VisualizeListingController } from './listing/visualize_listing';
import { VisualizeConstants } from './visualize_constants';
diff --git a/src/legacy/ui/public/capabilities/route_setup.ts b/src/legacy/ui/public/capabilities/route_setup.ts
deleted file mode 100644
index c7817b8cc5748..0000000000000
--- a/src/legacy/ui/public/capabilities/route_setup.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { get } from 'lodash';
-import chrome from 'ui/chrome';
-import uiRoutes from 'ui/routes';
-import { UICapabilities } from '.';
-
-uiRoutes.addSetupWork(
- (uiCapabilities: UICapabilities, kbnBaseUrl: string, $route: any, kbnUrl: any) => {
- const route = get($route, 'current.$$route') as any;
- if (!route.requireUICapability) {
- return;
- }
-
- if (!get(uiCapabilities, route.requireUICapability)) {
- const url = chrome.addBasePath(`${kbnBaseUrl}#/home`);
- kbnUrl.redirect(url);
- throw uiRoutes.WAIT_FOR_URL_CHANGE_TOKEN;
- }
- }
-);
diff --git a/src/legacy/ui/public/legacy_compat/angular_config.tsx b/src/legacy/ui/public/legacy_compat/angular_config.tsx
index 86ca9f911a578..d0cf8dd6e0da5 100644
--- a/src/legacy/ui/public/legacy_compat/angular_config.tsx
+++ b/src/legacy/ui/public/legacy_compat/angular_config.tsx
@@ -26,17 +26,20 @@ import {
IModule,
IRootScopeService,
} from 'angular';
+import { EuiCallOut } from '@elastic/eui';
+import ReactDOM from 'react-dom';
import $ from 'jquery';
-import { cloneDeep, forOwn, set } from 'lodash';
+import _, { cloneDeep, forOwn, get, set } from 'lodash';
import React, { Fragment } from 'react';
import * as Rx from 'rxjs';
import { i18n } from '@kbn/i18n';
-import { FormattedMessage } from '@kbn/i18n/react';
+import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
import { CoreStart, LegacyCoreStart } from 'kibana/public';
import { fatalError } from 'ui/notify';
import { capabilities } from 'ui/capabilities';
+import { RouteConfiguration } from 'ui/routes/route_manager';
// @ts-ignore
import { modifyUrl } from 'ui/url';
// @ts-ignore
@@ -45,6 +48,8 @@ import { npStart } from '../new_platform';
import { toastNotifications } from '../notify';
// @ts-ignore
import { isSystemApiRequest } from '../system_api';
+import { DataStart } from '../../../core_plugins/data/public';
+import { start as dataStart } from '../../../core_plugins/data/public/legacy';
const URL_LIMIT_WARN_WITHIN = 1000;
@@ -73,7 +78,9 @@ export const configureAppAngularModule = (angularModule: IModule) => {
.run($setupBreadcrumbsAutoClear(newPlatform))
.run($setupBadgeAutoClear(newPlatform))
.run($setupHelpExtensionAutoClear(newPlatform))
- .run($setupUrlOverflowHandling(newPlatform));
+ .run($setupUrlOverflowHandling(newPlatform))
+ .run($setupUICapabilityRedirect(newPlatform))
+ .run($setupDefaultIndexRedirect(newPlatform, dataStart));
};
const getEsUrl = (newPlatform: CoreStart) => {
@@ -166,6 +173,120 @@ function isDummyWrapperRoute($route: any) {
);
}
+/**
+ * integrates with angular to automatically redirect to home if required
+ * capability is not met
+ */
+const $setupUICapabilityRedirect = (newPlatform: CoreStart) => (
+ $rootScope: IRootScopeService,
+ $injector: any
+) => {
+ const isKibanaAppRoute = window.location.pathname.endsWith('/app/kibana');
+ // this feature only works within kibana app for now after everything is
+ // switched to the application service, this can be changed to handle all
+ // apps.
+ if (!isKibanaAppRoute) {
+ return;
+ }
+ $rootScope.$on(
+ '$routeChangeStart',
+ (event, { $$route: route }: { $$route?: RouteConfiguration } = {}) => {
+ if (!route || !route.requireUICapability) {
+ return;
+ }
+
+ if (!get(newPlatform.application.capabilities, route.requireUICapability)) {
+ $injector.get('kbnUrl').change('/home');
+ event.preventDefault();
+ }
+ }
+ );
+};
+
+let bannerId: string;
+let timeoutId: NodeJS.Timeout | undefined;
+
+/**
+ * integrates with angular to automatically redirect to management if no default
+ * index pattern is configured when a route flag is set.
+ */
+const $setupDefaultIndexRedirect = (newPlatform: CoreStart, data: DataStart) => (
+ $rootScope: IRootScopeService,
+ $injector: any
+) => {
+ const isKibanaAppRoute = window.location.pathname.endsWith('/app/kibana');
+ // this feature only works within kibana app for now after everything is
+ // switched to the application service, this can be changed to handle all
+ // apps.
+ if (!isKibanaAppRoute) {
+ return;
+ }
+
+ $rootScope.$on(
+ '$routeChangeStart',
+ (event, { $$route: route }: { $$route?: RouteConfiguration } = {}) => {
+ if (!route || !route.requireDefaultIndex) {
+ return;
+ }
+
+ return data.indexPatterns.indexPatterns.getIds().then(function(patterns: string[]) {
+ let defaultId = newPlatform.uiSettings.get('defaultIndex');
+ let defined = !!defaultId;
+ const exists = _.contains(patterns, defaultId);
+
+ if (defined && !exists) {
+ newPlatform.uiSettings.remove('defaultIndex');
+ defaultId = defined = false;
+ }
+
+ if (!defined) {
+ // If there is any index pattern created, set the first as default
+ if (patterns.length >= 1) {
+ defaultId = patterns[0];
+ newPlatform.uiSettings.set('defaultIndex', defaultId);
+ } else {
+ const canManageIndexPatterns = capabilities.get().management.kibana.index_patterns;
+ const redirectTarget = canManageIndexPatterns
+ ? '/management/kibana/index_pattern'
+ : '/home';
+
+ $injector.get('kbnUrl').change(redirectTarget);
+ $rootScope.$digest();
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+
+ // Avoid being hostile to new users who don't have an index pattern setup yet
+ // give them a friendly info message instead of a terse error message
+ bannerId = newPlatform.overlays.banners.replace(bannerId, (element: HTMLElement) => {
+ ReactDOM.render(
+
+
+ ,
+ element
+ );
+ return () => ReactDOM.unmountComponentAtNode(element);
+ });
+
+ // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
+ timeoutId = setTimeout(() => {
+ newPlatform.overlays.banners.remove(bannerId);
+ timeoutId = undefined;
+ }, 15000);
+ }
+ }
+ });
+ }
+ );
+};
+
/**
* internal angular run function that will be called when angular bootstraps and
* lets us integrate with the angular router so that we can automatically clear
diff --git a/src/legacy/ui/public/promises/promises.js b/src/legacy/ui/public/promises/promises.js
index 99c9a11be7431..af8a5081e0c55 100644
--- a/src/legacy/ui/public/promises/promises.js
+++ b/src/legacy/ui/public/promises/promises.js
@@ -22,9 +22,7 @@ import { uiModules } from '../modules';
const module = uiModules.get('kibana');
-// Provides a tiny subset of the excellent API from
-// bluebird, reimplemented using the $q service
-module.service('Promise', function ($q, $timeout) {
+export function PromiseServiceCreator($q, $timeout) {
function Promise(fn) {
if (typeof this === 'undefined') throw new Error('Promise constructor must be called with "new"');
@@ -122,4 +120,8 @@ module.service('Promise', function ($q, $timeout) {
};
return Promise;
-});
+}
+
+// Provides a tiny subset of the excellent API from
+// bluebird, reimplemented using the $q service
+module.service('Promise', PromiseServiceCreator);
diff --git a/src/legacy/ui/public/routes/route_manager.d.ts b/src/legacy/ui/public/routes/route_manager.d.ts
index 6187dfa71f856..c47a31eb7be76 100644
--- a/src/legacy/ui/public/routes/route_manager.d.ts
+++ b/src/legacy/ui/public/routes/route_manager.d.ts
@@ -23,7 +23,7 @@
import { ChromeBreadcrumb } from '../../../../core/public';
-interface RouteConfiguration {
+export interface RouteConfiguration {
controller?: string | ((...args: any[]) => void);
redirectTo?: string | ((...args: any[]) => string);
reloadOnSearch?: boolean;
@@ -32,6 +32,7 @@ interface RouteConfiguration {
template?: string;
k7Breadcrumbs?: (...args: any[]) => ChromeBreadcrumb[];
requireUICapability?: string;
+ requireDefaultIndex?: boolean;
outerAngularWrapperRoute?: boolean;
}
diff --git a/x-pack/legacy/plugins/grokdebugger/public/sections/grokdebugger/grokdebugger_route.js b/x-pack/legacy/plugins/grokdebugger/public/sections/grokdebugger/grokdebugger_route.js
index 9f588bbe510ae..d63d669b0375e 100644
--- a/x-pack/legacy/plugins/grokdebugger/public/sections/grokdebugger/grokdebugger_route.js
+++ b/x-pack/legacy/plugins/grokdebugger/public/sections/grokdebugger/grokdebugger_route.js
@@ -5,7 +5,6 @@
*/
import routes from 'ui/routes';
-import 'ui/capabilities/route_setup';
import { toastNotifications } from 'ui/notify';
import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
import template from './grokdebugger_route.html';
diff --git a/x-pack/legacy/plugins/searchprofiler/public/app.js b/x-pack/legacy/plugins/searchprofiler/public/app.js
index 1c7598ab982bc..b385832b1c554 100644
--- a/x-pack/legacy/plugins/searchprofiler/public/app.js
+++ b/x-pack/legacy/plugins/searchprofiler/public/app.js
@@ -9,7 +9,6 @@
import { uiModules } from 'ui/modules';
import { i18n } from '@kbn/i18n';
import uiRoutes from 'ui/routes';
-import 'ui/capabilities/route_setup';
import { toastNotifications } from 'ui/notify';
import { formatAngularHttpError } from 'ui/notify/lib';
From 4f0c5b24e00d05f10b73393127ec84faebb689d5 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Thu, 24 Oct 2019 15:08:29 +0200
Subject: [PATCH 020/132] pass dependencies into angular configurator
---
.../kibana/public/dashboard/render_app.ts | 4 +++-
src/legacy/ui/public/chrome/api/angular.js | 4 +++-
.../ui/public/legacy_compat/angular_config.tsx | 18 +++++++++---------
3 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index 82e38d9944370..030b6dd387ff1 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -46,6 +46,7 @@ import { confirmModalFactory } from 'ui/modals/confirm_modal';
import {
AppMountContext,
ChromeStart,
+ LegacyCoreStart,
SavedObjectsClientContract,
UiSettingsClientContract,
} from 'kibana/public';
@@ -66,6 +67,7 @@ import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public
export interface RenderDeps {
core: AppMountContext['core'];
indexPatterns: DataStart['indexPatterns']['indexPatterns'];
+ dataStart: DataStart;
queryFilter: any;
getUnhashableStates: any;
shareContextMenuExtensions: any;
@@ -86,7 +88,7 @@ export interface RenderDeps {
export const renderApp = (element: HTMLElement, appBasePath: string, deps: RenderDeps) => {
const dashboardAngularModule = createLocalAngularModule(deps.core);
// global routing stuff
- configureAppAngularModule(dashboardAngularModule);
+ configureAppAngularModule(dashboardAngularModule, deps.core as LegacyCoreStart, deps.dataStart);
// custom routing stuff
initDashboardApp(dashboardAngularModule, deps);
const $injector = mountDashboardApp(appBasePath, element);
diff --git a/src/legacy/ui/public/chrome/api/angular.js b/src/legacy/ui/public/chrome/api/angular.js
index e6457fec93633..512229cca6126 100644
--- a/src/legacy/ui/public/chrome/api/angular.js
+++ b/src/legacy/ui/public/chrome/api/angular.js
@@ -21,13 +21,15 @@ import { uiModules } from '../../modules';
import { directivesProvider } from '../directives';
import { registerSubUrlHooks } from './sub_url_hooks';
+import { start as data } from '../../../../core_plugins/data/public/legacy';
import { configureAppAngularModule } from 'ui/legacy_compat';
+import { npStart } from '../../new_platform/new_platform';
export function initAngularApi(chrome, internals) {
chrome.setupAngular = function () {
const kibana = uiModules.get('kibana');
- configureAppAngularModule(kibana);
+ configureAppAngularModule(kibana, npStart.core, data);
kibana.value('chrome', chrome);
diff --git a/src/legacy/ui/public/legacy_compat/angular_config.tsx b/src/legacy/ui/public/legacy_compat/angular_config.tsx
index d0cf8dd6e0da5..f62ce41291e1a 100644
--- a/src/legacy/ui/public/legacy_compat/angular_config.tsx
+++ b/src/legacy/ui/public/legacy_compat/angular_config.tsx
@@ -38,23 +38,22 @@ import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
import { CoreStart, LegacyCoreStart } from 'kibana/public';
import { fatalError } from 'ui/notify';
-import { capabilities } from 'ui/capabilities';
import { RouteConfiguration } from 'ui/routes/route_manager';
// @ts-ignore
import { modifyUrl } from 'ui/url';
// @ts-ignore
import { UrlOverflowService } from '../error_url_overflow';
-import { npStart } from '../new_platform';
-import { toastNotifications } from '../notify';
// @ts-ignore
import { isSystemApiRequest } from '../system_api';
import { DataStart } from '../../../core_plugins/data/public';
-import { start as dataStart } from '../../../core_plugins/data/public/legacy';
const URL_LIMIT_WARN_WITHIN = 1000;
-export const configureAppAngularModule = (angularModule: IModule) => {
- const newPlatform = npStart.core;
+export const configureAppAngularModule = (
+ angularModule: IModule,
+ newPlatform: LegacyCoreStart,
+ dataStart: DataStart
+) => {
const legacyMetadata = newPlatform.injectedMetadata.getLegacyMetadata();
forOwn(newPlatform.injectedMetadata.getInjectedVars(), (val, name) => {
@@ -70,7 +69,7 @@ export const configureAppAngularModule = (angularModule: IModule) => {
.value('buildSha', legacyMetadata.buildSha)
.value('serverName', legacyMetadata.serverName)
.value('esUrl', getEsUrl(newPlatform))
- .value('uiCapabilities', capabilities.get())
+ .value('uiCapabilities', newPlatform.application.capabilities)
.config(setupCompileProvider(newPlatform))
.config(setupLocationProvider(newPlatform))
.config($setupXsrfRequestInterceptor(newPlatform))
@@ -245,7 +244,8 @@ const $setupDefaultIndexRedirect = (newPlatform: CoreStart, data: DataStart) =>
defaultId = patterns[0];
newPlatform.uiSettings.set('defaultIndex', defaultId);
} else {
- const canManageIndexPatterns = capabilities.get().management.kibana.index_patterns;
+ const canManageIndexPatterns =
+ newPlatform.application.capabilities.management.kibana.index_patterns;
const redirectTarget = canManageIndexPatterns
? '/management/kibana/index_pattern'
: '/home';
@@ -444,7 +444,7 @@ const $setupUrlOverflowHandling = (newPlatform: CoreStart) => (
try {
if (urlOverflow.check($location.absUrl()) <= URL_LIMIT_WARN_WITHIN) {
- toastNotifications.addWarning({
+ newPlatform.notifications.toasts.addWarning({
title: i18n.translate('common.ui.chrome.bigUrlWarningNotificationTitle', {
defaultMessage: 'The URL is big and Kibana might stop working',
}),
From f1ff38875d133eec06d1e672baa1805ffcc8f80a Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Thu, 24 Oct 2019 16:24:19 +0200
Subject: [PATCH 021/132] centralize dependencies and clean up shim
---
.../kibana/public/dashboard/app.js | 17 +++----
.../dashboard/dashboard_app_controller.tsx | 17 +++----
.../dashboard/dashboard_state_manager.ts | 9 +++-
.../public/dashboard/help_menu/help_menu.js | 34 +++++++------
.../dashboard/help_menu/help_menu_util.js | 4 +-
.../kibana/public/dashboard/index.ts | 2 +
.../lib/embeddable_saved_object_converters.ts | 6 +--
.../public/dashboard/lib/migrate_app_state.ts | 8 +--
.../kibana/public/dashboard/plugin.ts | 49 ++++++++++++-------
.../kibana/public/dashboard/render_app.ts | 3 +-
10 files changed, 86 insertions(+), 63 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index c57aeec9acabb..65a933b5335d5 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -18,7 +18,6 @@
*/
import { i18n } from '@kbn/i18n';
-import uiRoutes from 'ui/routes';
import { wrapInI18nContext } from 'ui/i18n';
import dashboardTemplate from './dashboard_app.html';
@@ -45,7 +44,7 @@ export function initDashboardApp(app, deps) {
$scope.visitVisualizeAppLinkText = i18n.translate('kbn.dashboard.visitVisualizeAppLinkText', {
defaultMessage: 'visit the Visualize app',
});
- addHelpMenuToAppChrome(deps.chrome);
+ addHelpMenuToAppChrome(deps.chrome, deps.core.docLinks);
}
app.config(function ($routeProvider) {
@@ -107,10 +106,10 @@ export function initDashboardApp(app, deps) {
}),
},
]);
- addHelpMenuToAppChrome(deps.chrome);
+ addHelpMenuToAppChrome(deps.chrome, deps.core.docLinks);
},
resolve: {
- dash: function ($route, redirectWhenMissing, kbnUrl) {
+ dash: function ($rootScope, $route, redirectWhenMissing, kbnUrl, Promise) {
const savedObjectsClient = deps.savedObjectsClient;
const title = $route.current.params.title;
if (title) {
@@ -130,13 +129,9 @@ export function initDashboardApp(app, deps) {
} else {
kbnUrl.redirect(`${DashboardConstants.LANDING_PAGE_PATH}?filter="${title}"`);
}
- throw uiRoutes.WAIT_FOR_URL_CHANGE_TOKEN;
- })
- .catch(
- redirectWhenMissing({
- dashboard: DashboardConstants.LANDING_PAGE_PATH,
- })
- );
+ $rootScope.$digest();
+ return Promise.halt();
+ });
}
},
},
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
index af6b8f086a921..8a5cee4ff61c7 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_app_controller.tsx
@@ -24,20 +24,15 @@ import angular from 'angular';
import { uniq } from 'lodash';
import { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
-import { toastNotifications } from 'ui/notify';
// @ts-ignore
import { ConfirmationButtonTypes } from 'ui/modals/confirm_modal';
-import { docTitle } from 'ui/doc_title/doc_title';
-
import { showSaveModal, SaveResult } from 'ui/saved_objects/show_saved_object_save_modal';
import { showShareContextMenu } from 'ui/share';
import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
-import { timefilter } from 'ui/timefilter';
-
import {
AppStateClass as TAppStateClass,
AppState as TAppState,
@@ -65,7 +60,6 @@ import {
ViewMode,
openAddPanelFlyout,
} from '../../../embeddable_api/public/np_ready/public';
-// import { start } from '../../../embeddable_api/public/np_ready/public/legacy';
import { DashboardAppState, NavAction, ConfirmModalFn, SavedDashboardPanel } from './types';
import { showOptionsPopover } from './top_nav/show_options_popover';
@@ -123,7 +117,11 @@ export class DashboardAppController {
savedQueryService,
embeddables,
dashboardCapabilities,
- core: { notifications, overlays, chrome },
+ docTitle,
+ dataStart: {
+ timefilter: { timefilter },
+ },
+ core: { notifications, overlays, chrome, injectedMetadata, docLinks },
}: DashboardAppControllerDependencies) {
let lastReloadRequestTime = 0;
@@ -136,6 +134,7 @@ export class DashboardAppController {
savedDashboard: dash,
AppStateClass,
hideWriteControls: dashboardConfig.getHideWriteControls(),
+ kibanaVersion: injectedMetadata.getKibanaVersion(),
});
$scope.appState = dashboardStateManager.getAppState();
@@ -619,7 +618,7 @@ export class DashboardAppController {
return saveDashboard(angular.toJson, timefilter, dashboardStateManager, saveOptions)
.then(function(id) {
if (id) {
- toastNotifications.addSuccess({
+ notifications.toasts.addSuccess({
title: i18n.translate('kbn.dashboard.dashboardWasSavedSuccessMessage', {
defaultMessage: `Dashboard '{dashTitle}' was saved`,
values: { dashTitle: dash.title },
@@ -637,7 +636,7 @@ export class DashboardAppController {
return { id };
})
.catch(error => {
- toastNotifications.addDanger({
+ notifications.toasts.addDanger({
title: i18n.translate('kbn.dashboard.dashboardWasNotSavedDangerMessage', {
defaultMessage: `Dashboard '{dashTitle}' was not saved. Error: {errorMessage}`,
values: {
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts
index 7c1fc771de349..ecaf1cafe5f14 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_state_manager.ts
@@ -55,6 +55,7 @@ export class DashboardStateManager {
};
private stateDefaults: DashboardAppStateDefaults;
private hideWriteControls: boolean;
+ private kibanaVersion: string;
public isDirty: boolean;
private changeListeners: Array<(status: { dirty: boolean }) => void>;
private stateMonitor: StateMonitor;
@@ -69,11 +70,14 @@ export class DashboardStateManager {
savedDashboard,
AppStateClass,
hideWriteControls,
+ kibanaVersion,
}: {
savedDashboard: SavedObjectDashboard;
AppStateClass: TAppStateClass;
hideWriteControls: boolean;
+ kibanaVersion: string;
}) {
+ this.kibanaVersion = kibanaVersion;
this.savedDashboard = savedDashboard;
this.hideWriteControls = hideWriteControls;
@@ -85,7 +89,7 @@ export class DashboardStateManager {
// appState based on the URL (the url trumps the defaults). This means if we update the state format at all and
// want to handle BWC, we must not only migrate the data stored with saved Dashboard, but also any old state in the
// url.
- migrateAppState(this.appState);
+ migrateAppState(this.appState, kibanaVersion);
this.isDirty = false;
@@ -147,7 +151,8 @@ export class DashboardStateManager {
}
convertedPanelStateMap[panelState.explicitInput.id] = convertPanelStateToSavedDashboardPanel(
- panelState
+ panelState,
+ this.kibanaVersion
);
if (
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu.js b/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu.js
index 56b2bd253381c..1b1a7f84c8131 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu.js
@@ -17,26 +17,30 @@
* under the License.
*/
-import React, { Fragment, PureComponent } from 'react';
+import React, { PureComponent } from 'react';
import { EuiButton, EuiHorizontalRule, EuiSpacer } from '@elastic/eui';
-import { FormattedMessage } from '@kbn/i18n/react';
-import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links';
+import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
export class HelpMenu extends PureComponent {
render() {
return (
-
-
-
-
-
-
-
+
+ <>
+
+
+
+
+
+ >
+
);
}
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js b/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js
index 58a92193de63e..2dc8ce523a7da 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/help_menu/help_menu_util.js
@@ -21,9 +21,9 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { HelpMenu } from './help_menu';
-export function addHelpMenuToAppChrome(chrome) {
+export function addHelpMenuToAppChrome(chrome, docLinks) {
chrome.setHelpExtension(domElement => {
- render(, domElement);
+ render(, domElement);
return () => {
unmountComponentAtNode(domElement);
};
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/index.ts b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
index 4b63970daa461..7c9954359464a 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/index.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
@@ -20,6 +20,7 @@
import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
import { npSetup, npStart } from 'ui/new_platform';
import { SavedObjectRegistryProvider } from 'ui/saved_objects';
+import { docTitle } from 'ui/doc_title/doc_title';
import chrome from 'ui/chrome';
import { IPrivate } from 'ui/private';
import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
@@ -63,6 +64,7 @@ async function getAngularDependencies(): Promise,
- chrome.getKibanaVersion(),
+ kibanaVersion,
appState.useMargins,
appState.uiState
);
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
index cbdc0663bfd77..8ece51a06e33f 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
@@ -17,12 +17,17 @@
* under the License.
*/
-import { CoreSetup, CoreStart, Plugin, SavedObjectsClientContract } from 'kibana/public';
+import {
+ CoreSetup,
+ CoreStart,
+ LegacyCoreStart,
+ Plugin,
+ SavedObjectsClientContract,
+} from 'kibana/public';
import { Storage } from 'ui/storage';
import { RenderDeps } from './render_app';
import { LocalApplicationService } from '../local_application_service';
import { DataStart } from '../../../data/public';
-import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public';
export interface LegacyAngularInjectedDependencies {
@@ -44,14 +49,16 @@ export interface DashboardPluginSetupDependencies {
getAngularDependencies: () => Promise;
localApplicationService: LocalApplicationService;
FeatureCatalogueRegistryProvider: any;
+ docTitle: any;
};
}
export class DashboardPlugin implements Plugin {
- private dataStart: DataStart | null = null;
- private savedObjectsClient: SavedObjectsClientContract | null = null;
- private savedQueryService: SavedQueryService | null = null;
- private embeddables: ReturnType | null = null;
+ private startDependencies: {
+ dataStart: DataStart;
+ savedObjectsClient: SavedObjectsClientContract;
+ embeddables: ReturnType;
+ } | null = null;
public setup(
core: CoreSetup,
@@ -64,18 +71,23 @@ export class DashboardPlugin implements Plugin {
id: 'dashboards',
title: 'Dashboards',
mount: async ({ core: contextCore }, params) => {
+ if (this.startDependencies === null) {
+ throw new Error('not started yet');
+ }
+ const { dataStart, savedObjectsClient, embeddables } = this.startDependencies;
const angularDependencies = await getAngularDependencies();
const deps: RenderDeps = {
- core: contextCore,
+ core: contextCore as LegacyCoreStart,
...legacyServices,
...angularDependencies,
- indexPatterns: this.dataStart!.indexPatterns.indexPatterns,
- savedObjectsClient: this.savedObjectsClient!,
+ dataStart,
+ indexPatterns: dataStart.indexPatterns.indexPatterns,
+ savedObjectsClient,
chrome: contextCore.chrome,
addBasePath: contextCore.http.basePath.prepend,
uiSettings: contextCore.uiSettings,
- savedQueryService: this.savedQueryService!,
- embeddables: this.embeddables!,
+ savedQueryService: dataStart.search.services.savedQueryService,
+ embeddables,
dashboardCapabilities: contextCore.application.capabilities.dashboard,
localStorage: new Storage(localStorage),
};
@@ -85,11 +97,14 @@ export class DashboardPlugin implements Plugin {
});
}
- start(core: CoreStart, { data, embeddables }: DashboardPluginStartDependencies) {
- // TODO is this really the right way? I though the app context would give us those
- this.dataStart = data;
- this.savedObjectsClient = core.savedObjects.client;
- this.savedQueryService = data.search.services.savedQueryService;
- this.embeddables = embeddables;
+ start(
+ { savedObjects: { client: savedObjectsClient } }: CoreStart,
+ { data: dataStart, embeddables }: DashboardPluginStartDependencies
+ ) {
+ this.startDependencies = {
+ dataStart,
+ savedObjectsClient,
+ embeddables,
+ };
}
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index 030b6dd387ff1..dfb18ddf231bb 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -65,7 +65,7 @@ import { SavedQueryService } from '../../../data/public/search/search_bar/lib/sa
import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public';
export interface RenderDeps {
- core: AppMountContext['core'];
+ core: LegacyCoreStart;
indexPatterns: DataStart['indexPatterns']['indexPatterns'];
dataStart: DataStart;
queryFilter: any;
@@ -76,6 +76,7 @@ export interface RenderDeps {
dashboardConfig: any;
savedDashboards: any;
dashboardCapabilities: any;
+ docTitle: any;
uiSettings: UiSettingsClientContract;
chrome: ChromeStart;
addBasePath: (path: string) => string;
From 0b595a0edb72ebd7b84541ffe9f225bd3ba9aa35 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Fri, 25 Oct 2019 10:24:30 +0300
Subject: [PATCH 022/132] Centralizing dependencies in editor and embeddable
---
.../kibana/public/visualize/editor/editor.js | 66 +++++++++++--------
.../visualize/editor/visualization_editor.js | 6 +-
.../visualize/embeddable/get_index_pattern.ts | 12 ++--
.../embeddable/visualize_embeddable.ts | 19 +++---
.../visualize_embeddable_factory.tsx | 11 +---
.../kibana/public/visualize/index.js | 2 +-
.../public/visualize/kibana_services.ts | 53 +++++++++++----
.../visualize/listing/visualize_listing.js | 8 +--
8 files changed, 107 insertions(+), 70 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
index dac0880e6fec4..d140d8b29ad92 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
@@ -26,39 +26,47 @@ import 'ui/vis/editors/default/sidebar';
import 'ui/visualize';
import 'ui/collapsible_sidebar';
-import { capabilities } from 'ui/capabilities';
-import chrome from 'ui/chrome';
import React from 'react';
-import angular from 'angular';
import { FormattedMessage } from '@kbn/i18n/react';
-import { toastNotifications } from 'ui/notify';
-import { docTitle } from 'ui/doc_title';
-import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
-import { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
import { migrateAppState } from './lib';
-import uiRoutes from 'ui/routes';
-import { uiModules } from 'ui/modules';
import editorTemplate from './editor.html';
import { DashboardConstants } from '../../dashboard/dashboard_constants';
import { VisualizeConstants } from '../visualize_constants';
-import { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
-import { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
-import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
-import { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
-import { timefilter } from 'ui/timefilter';
-import { getVisualizeLoader } from '../../../../../ui/public/visualize/loader';
-import { showShareContextMenu, ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
-import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing';
-import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
-import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
-import { npStart } from 'ui/new_platform';
import { extractTimeFilter, changeTimeFilter } from '../../../../data/public';
import { start as data } from '../../../../data/public/legacy';
import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
+import {
+ getServices,
+ absoluteToParsedUrl,
+ getUnhashableStatesProvider,
+ getVisualizeLoader,
+ KibanaParsedUrl,
+ migrateLegacyQuery,
+ SavedObjectSaveModal,
+ showShareContextMenu,
+ showSaveModal,
+ stateMonitorFactory,
+ subscribeWithScope,
+} from '../kibana_services';
+
+const {
+ angular,
+ capabilities,
+ chrome,
+ docTitle,
+ FilterBarQueryFilterProvider,
+ getBasePath,
+ ShareContextMenuExtensionsRegistryProvider,
+ toastNotifications,
+ timefilter,
+ uiModules,
+ uiRoutes,
+} = getServices();
+
const { savedQueryService } = data.search.services;
uiRoutes
@@ -100,7 +108,7 @@ uiRoutes
savedVis: function (savedVisualizations, redirectWhenMissing, $route) {
return savedVisualizations.get($route.current.params.id)
.then((savedVis) => {
- npStart.core.chrome.recentlyAccessed.add(
+ chrome.recentlyAccessed.add(
savedVis.getFullPath(),
savedVis.title,
savedVis.id);
@@ -167,7 +175,7 @@ function VisEditor(
dirty: !savedVis.id
};
- $scope.topNavMenu = [...(capabilities.get().visualize.save ? [{
+ $scope.topNavMenu = [...(capabilities.visualize.save ? [{
id: 'save',
label: i18n.translate('kbn.topNavMenu.saveVisualizationButtonLabel', { defaultMessage: 'save' }),
description: i18n.translate('kbn.visualize.topNavMenu.saveVisualizationButtonAriaLabel', {
@@ -236,7 +244,7 @@ function VisEditor(
showShareContextMenu({
anchorElement,
allowEmbed: true,
- allowShortUrl: capabilities.get().visualize.createShortUrl,
+ allowShortUrl: capabilities.visualize.createShortUrl,
getUnhashableStates,
objectId: savedVis.id,
objectType: 'visualization',
@@ -353,9 +361,9 @@ function VisEditor(
}
});
- $scope.showSaveQuery = capabilities.get().visualize.saveQuery;
+ $scope.showSaveQuery = capabilities.visualize.saveQuery;
- $scope.$watch(() => capabilities.get().visualize.saveQuery, (newCapability) => {
+ $scope.$watch(() => capabilities.visualize.saveQuery, (newCapability) => {
$scope.showSaveQuery = newCapability;
});
@@ -582,7 +590,7 @@ function VisEditor(
if ($scope.isAddToDashMode()) {
const savedVisualizationParsedUrl = new KibanaParsedUrl({
- basePath: chrome.getBasePath(),
+ basePath: getBasePath(),
appId: kbnBaseUrl.slice('/app/'.length),
appPath: kbnUrl.eval(`${VisualizeConstants.EDIT_PATH}/{{id}}`, { id: savedVis.id }),
});
@@ -593,13 +601,13 @@ function VisEditor(
// url, not the unsaved one.
chrome.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl);
- const lastDashboardAbsoluteUrl = npStart.core.chrome.navLinks.get('kibana:dashboard').url;
- const dashboardParsedUrl = absoluteToParsedUrl(lastDashboardAbsoluteUrl, chrome.getBasePath());
+ const lastDashboardAbsoluteUrl = chrome.navLinks.get('kibana:dashboard').url;
+ const dashboardParsedUrl = absoluteToParsedUrl(lastDashboardAbsoluteUrl, getBasePath());
dashboardParsedUrl.addQueryParameter(DashboardConstants.NEW_VISUALIZATION_ID_PARAM, savedVis.id);
kbnUrl.change(dashboardParsedUrl.appPath);
} else if (savedVis.id === $route.current.params.id) {
docTitle.change(savedVis.lastSavedTitle);
- chrome.breadcrumbs.set($injector.invoke(getEditBreadcrumbs));
+ chrome.setBreadcrumbs($injector.invoke(getEditBreadcrumbs));
} else {
kbnUrl.change(`${VisualizeConstants.EDIT_PATH}/{{id}}`, { id: savedVis.id });
}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
index a2ed44df2f5b0..63dcd395ef918 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
@@ -18,9 +18,11 @@
*/
import { debounce } from 'lodash';
-import { uiModules } from 'ui/modules';
import 'angular-sanitize';
-import { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
+
+import { getServices, VisEditorTypesRegistryProvider } from '../kibana_services';
+
+const { uiModules } = getServices();
uiModules
.get('kibana/directive', ['ngSanitize'])
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
index 97db9e1efea8c..b6d5adcd98bd0 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/get_index_pattern.ts
@@ -17,12 +17,14 @@
* under the License.
*/
-import { StaticIndexPattern, getFromSavedObject } from 'ui/index_patterns';
-import { VisSavedObject } from 'ui/visualize/loader/types';
+import {
+ getServices,
+ getFromSavedObject,
+ StaticIndexPattern,
+ VisSavedObject,
+} from '../kibana_services';
-import { getServices } from '../kibana_services';
-
-const { uiSettings, savedObjectsClient } = getServices();
+const { savedObjectsClient, uiSettings } = getServices();
export async function getIndexPattern(
savedVis: VisSavedObject
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
index b9febc3af54ea..3b5d68de3f8a0 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
@@ -18,15 +18,6 @@
*/
import _ from 'lodash';
-import { StaticIndexPattern } from 'ui/index_patterns';
-import { PersistedState } from 'ui/persisted_state';
-import { VisualizeLoader } from 'ui/visualize/loader';
-import { EmbeddedVisualizeHandler } from 'ui/visualize/loader/embedded_visualize_handler';
-import {
- VisSavedObject,
- VisualizeLoaderParams,
- VisualizeUpdateParams,
-} from 'ui/visualize/loader/types';
import { Subscription } from 'rxjs';
import * as Rx from 'rxjs';
import { Filter } from '@kbn/es-query';
@@ -40,6 +31,16 @@ import {
import { Query, onlyDisabledFiltersChanged } from '../../../../data/public';
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
+import {
+ EmbeddedVisualizeHandler,
+ PersistedState,
+ StaticIndexPattern,
+ VisSavedObject,
+ VisualizeLoader,
+ VisualizeLoaderParams,
+ VisualizeUpdateParams,
+} from '../kibana_services';
+
const getKeys = (o: T): Array => Object.keys(o) as Array;
export interface VisualizeEmbeddableConfiguration {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index 5c4768cd63dad..a8e0fee804a72 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -37,11 +37,6 @@ import 'uiExports/visualize';
import { i18n } from '@kbn/i18n';
-import { capabilities } from 'ui/capabilities';
-
-import chrome from 'ui/chrome';
-import { getVisualizeLoader } from 'ui/visualize/loader';
-
import { Legacy } from 'kibana';
import { SavedObjectAttributes } from 'kibana/server';
@@ -61,9 +56,9 @@ import { VisualizeEmbeddable, VisualizeInput, VisualizeOutput } from './visualiz
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
-import { getServices } from '../kibana_services';
+import { getServices, getVisualizeLoader } from '../kibana_services';
-const { addBasePath } = getServices();
+const { addBasePath, capabilities, chrome, uiSettings } = getServices();
interface VisualizationAttributes extends SavedObjectAttributes {
visState: string;
@@ -113,7 +108,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
if (!visType) {
return false;
}
- if (chrome.getUiSettingsClient().get('visualize:enableLabs')) {
+ if (uiSettings.get('visualize:enableLabs')) {
return true;
}
return visType.stage !== 'experimental';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.js b/src/legacy/core_plugins/kibana/public/visualize/index.js
index e53a3479f0ffa..74dd17a18a9bc 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/index.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/index.js
@@ -31,7 +31,7 @@ import { getServices, FeatureCatalogueCategory } from './kibana_services';
// load directives
import '../../../data/public';
-const { uiRoutes, FeatureCatalogueRegistryProvider } = getServices();
+const { FeatureCatalogueRegistryProvider, uiRoutes } = getServices();
uiRoutes
.defaults(/visualize/, {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index dd0234d6ed490..2a7591dd7fa48 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -20,52 +20,81 @@
import 'ui/directives/kbn_href';
import { npStart } from 'ui/new_platform';
-import chromeLegacy from 'ui/chrome';
import angular from 'angular';
import uiRoutes from 'ui/routes';
-import { wrapInI18nContext } from 'ui/i18n';
+// @ts-ignore
+import { docTitle } from 'ui/doc_title';
+import { FilterBarQueryFilterProvider } from 'ui/filter_manager/query_filter';
+import { wrapInI18nContext } from 'ui/i18n';
// @ts-ignore
import { uiModules } from 'ui/modules';
import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
-
-// Filters
+import { ShareContextMenuExtensionsRegistryProvider } from 'ui/share';
import { timefilter } from 'ui/timefilter';
// Saved objects
-import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
import { SavedObjectsClientProvider } from 'ui/saved_objects';
// @ts-ignore
import { SavedObjectProvider } from 'ui/saved_objects/saved_object';
+import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
const services = {
// new platform
+ addBasePath: npStart.core.http.basePath.prepend,
capabilities: npStart.core.application.capabilities,
chrome: npStart.core.chrome,
docLinks: npStart.core.docLinks,
+ savedObjectsClient: npStart.core.savedObjects.client,
toastNotifications: npStart.core.notifications.toasts,
uiSettings: npStart.core.uiSettings,
- savedObjectsClient: npStart.core.savedObjects.client,
- addBasePath: npStart.core.http.basePath.prepend,
// legacy
angular,
- uiRoutes,
- uiModules,
+ docTitle,
FeatureCatalogueRegistryProvider,
+ FilterBarQueryFilterProvider,
+ SavedObjectProvider,
SavedObjectRegistryProvider,
SavedObjectsClientProvider,
- SavedObjectProvider,
+ ShareContextMenuExtensionsRegistryProvider,
timefilter,
+ uiModules,
+ uiRoutes,
wrapInI18nContext,
};
+
export function getServices() {
return services;
}
+// export legacy static dependencies
+export { getFromSavedObject } from 'ui/index_patterns';
+export { PersistedState } from 'ui/persisted_state';
+// @ts-ignore
+export { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
+// @ts-ignore
+export { getUnhashableStatesProvider } from 'ui/state_management/state_hashing';
+export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
+export { showShareContextMenu } from 'ui/share';
+export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
+export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
+export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
+export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
+export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
+export { getVisualizeLoader } from 'ui/visualize/loader';
+export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
+
// export types
-export { VisSavedObject } from 'ui/visualize/loader/types';
+export { StaticIndexPattern } from 'ui/index_patterns';
+export { VisualizeLoader } from 'ui/visualize/loader';
+export {
+ VisSavedObject,
+ VisualizeLoaderParams,
+ VisualizeUpdateParams,
+} from 'ui/visualize/loader/types';
+export { EmbeddedVisualizeHandler } from 'ui/visualize/loader/embedded_visualize_handler';
-// const
+// export const
export { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index aeee3c91cbfa7..42c4556041197 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -27,14 +27,14 @@ import { i18n } from '@kbn/i18n';
import { getServices } from '../kibana_services';
const {
- uiModules,
+ addBasePath,
+ chrome,
SavedObjectRegistryProvider,
+ SavedObjectsClientProvider,
timefilter,
- chrome,
toastNotifications,
+ uiModules,
wrapInI18nContext,
- SavedObjectsClientProvider,
- addBasePath
} = getServices();
const app = uiModules.get('app/visualize', ['ngRoute', 'react']);
From 46ba3db2eeb649d41c846f9bba43ddfe45b8d1f4 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Fri, 25 Oct 2019 12:30:04 +0300
Subject: [PATCH 023/132] Remove unused deps, move imports
---
.../kibana/public/visualize/editor/editor.js | 7 ++---
.../visualize/editor/visualization_editor.js | 1 -
.../embeddable/visualize_embeddable.ts | 2 +-
.../visualize_embeddable_factory.tsx | 27 ++-----------------
.../public/visualize/kibana_services.ts | 18 ++++++++++---
.../visualize/listing/visualize_listing.js | 2 +-
.../public/visualize/wizard/new_vis_modal.tsx | 5 ++--
7 files changed, 22 insertions(+), 40 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
index fa59084e345da..5930c96b09273 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
@@ -22,9 +22,6 @@ import { Subscription } from 'rxjs';
import { i18n } from '@kbn/i18n';
import '../saved_visualizations/saved_visualizations';
import './visualization_editor';
-import 'ui/vis/editors/default/sidebar';
-import 'ui/visualize';
-import 'ui/collapsible_sidebar';
import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
@@ -35,12 +32,12 @@ import { VisualizeConstants } from '../visualize_constants';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
import { extractTimeFilter, changeTimeFilter } from '../../../../data/public';
import { start as data } from '../../../../data/public/legacy';
-import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
import {
getServices,
+ angular,
absoluteToParsedUrl,
getUnhashableStatesProvider,
getVisualizeLoader,
@@ -54,7 +51,6 @@ import {
} from '../kibana_services';
const {
- angular,
capabilities,
chrome,
docTitle,
@@ -65,6 +61,7 @@ const {
timefilter,
uiModules,
uiRoutes,
+ visualizations,
} = getServices();
const { savedQueryService } = data.search.services;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
index 63dcd395ef918..9c96d8ca506a8 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/visualization_editor.js
@@ -18,7 +18,6 @@
*/
import { debounce } from 'lodash';
-import 'angular-sanitize';
import { getServices, VisEditorTypesRegistryProvider } from '../kibana_services';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
index 3b5d68de3f8a0..d95264abdd559 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
@@ -18,6 +18,7 @@
*/
import _ from 'lodash';
+import { EmbeddedVisualizeHandler } from 'ui/visualize/loader/embedded_visualize_handler';
import { Subscription } from 'rxjs';
import * as Rx from 'rxjs';
import { Filter } from '@kbn/es-query';
@@ -32,7 +33,6 @@ import { Query, onlyDisabledFiltersChanged } from '../../../../data/public';
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
import {
- EmbeddedVisualizeHandler,
PersistedState,
StaticIndexPattern,
VisSavedObject,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index a8e0fee804a72..a0a1182ea3c55 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -17,37 +17,17 @@
* under the License.
*/
-import 'ui/registry/field_formats';
-import 'uiExports/contextMenuActions';
-import 'uiExports/devTools';
-import 'uiExports/docViews';
-import 'uiExports/embeddableFactories';
-import 'uiExports/embeddableActions';
-import 'uiExports/fieldFormatEditors';
-import 'uiExports/fieldFormats';
-import 'uiExports/home';
-import 'uiExports/indexManagement';
-import 'uiExports/inspectorViews';
-import 'uiExports/savedObjectTypes';
-import 'uiExports/search';
-import 'uiExports/shareContextMenuExtensions';
-import 'uiExports/visEditorTypes';
-import 'uiExports/visTypes';
-import 'uiExports/visualize';
-
import { i18n } from '@kbn/i18n';
import { Legacy } from 'kibana';
import { SavedObjectAttributes } from 'kibana/server';
-import { npSetup } from 'ui/new_platform';
import {
EmbeddableFactory,
ErrorEmbeddable,
Container,
EmbeddableOutput,
} from '../../../../../../plugins/embeddable/public';
-import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { showNewVisModal } from '../wizard';
import { SavedVisualizations } from '../types';
import { DisabledLabEmbeddable } from './disabled_lab_embeddable';
@@ -58,7 +38,7 @@ import { TypesStart } from '../../../../visualizations/public/np_ready/public/ty
import { getServices, getVisualizeLoader } from '../kibana_services';
-const { addBasePath, capabilities, chrome, uiSettings } = getServices();
+const { addBasePath, capabilities, chrome, embeddable, uiSettings, visualizations } = getServices();
interface VisualizationAttributes extends SavedObjectAttributes {
visState: string;
@@ -182,8 +162,5 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
}
VisualizeEmbeddableFactory.createVisualizeEmbeddableFactory().then(embeddableFactory => {
- npSetup.plugins.embeddable.registerEmbeddableFactory(
- VISUALIZE_EMBEDDABLE_TYPE,
- embeddableFactory
- );
+ embeddable.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory);
});
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index 2a7591dd7fa48..2b8fcb02dcb5b 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -17,10 +17,11 @@
* under the License.
*/
-import 'ui/directives/kbn_href';
+import 'angular-sanitize'; // used in visualization_editor.js
+import 'ui/collapsible_sidebar'; // used in default editor
import { npStart } from 'ui/new_platform';
-import angular from 'angular';
+import angular from 'angular'; // just used in editor.js
import uiRoutes from 'ui/routes';
@@ -40,18 +41,23 @@ import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { SavedObjectProvider } from 'ui/saved_objects/saved_object';
import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
+import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
+import { start as visualizations } from '../../../visualizations/public/np_ready/public/legacy';
+
const services = {
// new platform
addBasePath: npStart.core.http.basePath.prepend,
capabilities: npStart.core.application.capabilities,
chrome: npStart.core.chrome,
docLinks: npStart.core.docLinks,
+ embeddable: npStart.plugins.embeddable,
savedObjectsClient: npStart.core.savedObjects.client,
toastNotifications: npStart.core.notifications.toasts,
uiSettings: npStart.core.uiSettings,
+ visualizations,
+
// legacy
- angular,
docTitle,
FeatureCatalogueRegistryProvider,
FilterBarQueryFilterProvider,
@@ -63,6 +69,8 @@ const services = {
uiModules,
uiRoutes,
wrapInI18nContext,
+
+ createUiStatsReporter,
};
export function getServices() {
@@ -70,6 +78,7 @@ export function getServices() {
}
// export legacy static dependencies
+export { angular };
export { getFromSavedObject } from 'ui/index_patterns';
export { PersistedState } from 'ui/persisted_state';
// @ts-ignore
@@ -87,14 +96,15 @@ export { getVisualizeLoader } from 'ui/visualize/loader';
export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
// export types
+export { METRIC_TYPE };
export { StaticIndexPattern } from 'ui/index_patterns';
+export { VisType } from 'ui/vis';
export { VisualizeLoader } from 'ui/visualize/loader';
export {
VisSavedObject,
VisualizeLoaderParams,
VisualizeUpdateParams,
} from 'ui/visualize/loader/types';
-export { EmbeddedVisualizeHandler } from 'ui/visualize/loader/embedded_visualize_handler';
// export const
export { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index 42c4556041197..7a0ff15f13511 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -21,7 +21,6 @@ import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
import { VisualizeListingTable } from './visualize_listing_table';
import { NewVisModal } from '../wizard/new_vis_modal';
import { VisualizeConstants } from '../visualize_constants';
-import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { i18n } from '@kbn/i18n';
import { getServices } from '../kibana_services';
@@ -35,6 +34,7 @@ const {
toastNotifications,
uiModules,
wrapInI18nContext,
+ visualizations,
} = getServices();
const app = uiModules.get('app/visualize', ['ngRoute', 'react']);
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
index 7231d7e947408..2b36c9af705c2 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
@@ -23,14 +23,13 @@ import { EuiModal, EuiOverlayMask } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { VisualizeConstants } from '../visualize_constants';
-import { createUiStatsReporter, METRIC_TYPE } from '../../../../ui_metric/public';
import { SearchSelection } from './search_selection';
import { TypeSelection } from './type_selection';
import { TypesStart, VisTypeAlias } from '../../../../visualizations/public/np_ready/public/types';
-import { getServices, VisType } from '../kibana_services';
+import { getServices, METRIC_TYPE, VisType } from '../kibana_services';
-const { addBasePath, uiSettings } = getServices();
+const { addBasePath, createUiStatsReporter, uiSettings } = getServices();
interface TypeSelectionProps {
isOpen: boolean;
From 36ec4e1e8929ac73e400801bd8b7ebf2f7e492d5 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Fri, 25 Oct 2019 12:50:03 +0300
Subject: [PATCH 024/132] Fix dangerouslyGetActiveInjector
---
.../embeddable/visualize_embeddable_factory.tsx | 14 +++++++++++---
.../kibana/public/visualize/kibana_services.ts | 5 +++++
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index a0a1182ea3c55..c69bd25966451 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -38,7 +38,15 @@ import { TypesStart } from '../../../../visualizations/public/np_ready/public/ty
import { getServices, getVisualizeLoader } from '../kibana_services';
-const { addBasePath, capabilities, chrome, embeddable, uiSettings, visualizations } = getServices();
+const {
+ addBasePath,
+ capabilities,
+ chrome,
+ embeddable,
+ getInjector,
+ uiSettings,
+ visualizations,
+} = getServices();
interface VisualizationAttributes extends SavedObjectAttributes {
visState: string;
@@ -100,7 +108,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
}
public isEditable() {
- return capabilities.get().visualize.save as boolean;
+ return capabilities.visualize.save as boolean;
}
public getDisplayName() {
@@ -114,7 +122,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
input: Partial & { id: string },
parent?: Container
): Promise {
- const $injector = await chrome.dangerouslyGetActiveInjector();
+ const $injector = await getInjector();
const config = $injector.get('config');
const savedVisualizations = $injector.get('savedVisualizations');
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index 2b8fcb02dcb5b..8ffd1d19e447a 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -19,9 +19,11 @@
import 'angular-sanitize'; // used in visualization_editor.js
import 'ui/collapsible_sidebar'; // used in default editor
+import 'ui/vis/editors/default/sidebar';
import { npStart } from 'ui/new_platform';
import angular from 'angular'; // just used in editor.js
+import chromeLegacy from 'ui/chrome';
import uiRoutes from 'ui/routes';
@@ -61,6 +63,9 @@ const services = {
docTitle,
FeatureCatalogueRegistryProvider,
FilterBarQueryFilterProvider,
+ getInjector: () => {
+ return chromeLegacy.dangerouslyGetActiveInjector();
+ },
SavedObjectProvider,
SavedObjectRegistryProvider,
SavedObjectsClientProvider,
From abfdc2aa48fc31067d5345ab030101115bc58955 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Fri, 25 Oct 2019 12:58:06 +0300
Subject: [PATCH 025/132] Move loading directive to kibana_services.ts
---
src/legacy/core_plugins/kibana/public/visualize/index.js | 3 ---
.../core_plugins/kibana/public/visualize/kibana_services.ts | 2 ++
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.js b/src/legacy/core_plugins/kibana/public/visualize/index.js
index 74dd17a18a9bc..592a355a71b0d 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/index.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/index.js
@@ -28,9 +28,6 @@ import { getLandingBreadcrumbs, getWizardStep1Breadcrumbs } from './breadcrumbs'
import { getServices, FeatureCatalogueCategory } from './kibana_services';
-// load directives
-import '../../../data/public';
-
const { FeatureCatalogueRegistryProvider, uiRoutes } = getServices();
uiRoutes
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index 8ffd1d19e447a..69333e0768229 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -20,6 +20,8 @@
import 'angular-sanitize'; // used in visualization_editor.js
import 'ui/collapsible_sidebar'; // used in default editor
import 'ui/vis/editors/default/sidebar';
+// load directives
+import '../../../data/public';
import { npStart } from 'ui/new_platform';
import angular from 'angular'; // just used in editor.js
From d1700d22c0f53da0bc3df0d3f1b3973e653249d8 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Fri, 25 Oct 2019 12:26:37 +0200
Subject: [PATCH 026/132] remove requireDefaultIndex and provide helper
function
---
.../kibana/public/dashboard/app.js | 79 +++++++-------
.../public/dashboard/dashboard_constants.ts | 4 +-
.../kibana/public/dashboard/plugin.ts | 10 +-
.../kibana/public/dashboard/render_app.ts | 2 +-
.../public/discover/angular/discover.js | 93 ++++++++--------
.../kibana/public/visualize/editor/editor.js | 34 +++---
.../kibana/public/visualize/index.js | 6 +-
.../public/legacy_compat/angular_config.tsx | 99 +----------------
src/legacy/ui/public/legacy_compat/utils.tsx | 100 ++++++++++++++++++
.../public/routes/__tests__/_route_manager.js | 12 ---
.../ui/public/routes/route_manager.d.ts | 1 -
src/legacy/ui/public/routes/route_manager.js | 4 -
12 files changed, 228 insertions(+), 216 deletions(-)
create mode 100644 src/legacy/ui/public/legacy_compat/utils.tsx
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index 65a933b5335d5..c8fab451242ba 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -32,6 +32,8 @@ import {
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { DashboardListing, EMPTY_FILTER } from './listing/dashboard_listing';
import { addHelpMenuToAppChrome } from './help_menu/help_menu_util';
+import { ensureDefaultIndexPattern } from '../../../../ui/public/legacy_compat/utils';
+import { start as data } from '../../../data/public/legacy';
export function initDashboardApp(app, deps) {
initDashboardAppDirective(app, deps);
@@ -50,7 +52,6 @@ export function initDashboardApp(app, deps) {
app.config(function ($routeProvider) {
const defaults = {
reloadOnSearch: false,
- requireDefaultIndex: true,
requireUICapability: 'dashboard.show',
badge: () => {
if (deps.dashboardCapabilities.showWriteControls) {
@@ -70,9 +71,6 @@ export function initDashboardApp(app, deps) {
};
$routeProvider
- // migrate old URLs
- .when('/dashboards/dashboard', { redirectTo: (_params, _path, query) => `/dashboards/create?${query}` })
- .when('/dashboards/dashboard/:id', { redirectTo: (params, _path, query) => `/dashboards/edit/${params.id}?${query}` })
.when(DashboardConstants.LANDING_PAGE_PATH, {
...defaults,
template: dashboardListingTemplate,
@@ -109,30 +107,32 @@ export function initDashboardApp(app, deps) {
addHelpMenuToAppChrome(deps.chrome, deps.core.docLinks);
},
resolve: {
- dash: function ($rootScope, $route, redirectWhenMissing, kbnUrl, Promise) {
- const savedObjectsClient = deps.savedObjectsClient;
- const title = $route.current.params.title;
- if (title) {
- return savedObjectsClient
- .find({
- search: `"${title}"`,
- search_fields: 'title',
- type: 'dashboard',
- })
- .then(results => {
- // The search isn't an exact match, lets see if we can find a single exact match to use
- const matchingDashboards = results.savedObjects.filter(
- dashboard => dashboard.attributes.title.toLowerCase() === title.toLowerCase()
- );
- if (matchingDashboards.length === 1) {
- kbnUrl.redirect(createDashboardEditUrl(matchingDashboards[0].id));
- } else {
- kbnUrl.redirect(`${DashboardConstants.LANDING_PAGE_PATH}?filter="${title}"`);
- }
- $rootScope.$digest();
- return Promise.halt();
- });
- }
+ dash: function ($rootScope, $route, redirectWhenMissing, kbnUrl) {
+ return ensureDefaultIndexPattern(deps.core, data, $rootScope, kbnUrl).then(() => {
+ const savedObjectsClient = deps.savedObjectsClient;
+ const title = $route.current.params.title;
+ if (title) {
+ return savedObjectsClient
+ .find({
+ search: `"${title}"`,
+ search_fields: 'title',
+ type: 'dashboard',
+ })
+ .then(results => {
+ // The search isn't an exact match, lets see if we can find a single exact match to use
+ const matchingDashboards = results.savedObjects.filter(
+ dashboard => dashboard.attributes.title.toLowerCase() === title.toLowerCase()
+ );
+ if (matchingDashboards.length === 1) {
+ kbnUrl.redirect(createDashboardEditUrl(matchingDashboards[0].id));
+ } else {
+ kbnUrl.redirect(`${DashboardConstants.LANDING_PAGE_PATH}?filter="${title}"`);
+ }
+ $rootScope.$digest();
+ return new Promise(() => {});
+ });
+ }
+ });
},
},
})
@@ -142,12 +142,16 @@ export function initDashboardApp(app, deps) {
controller: createNewDashboardCtrl,
requireUICapability: 'dashboard.createNew',
resolve: {
- dash: function (redirectWhenMissing) {
- return deps.savedDashboards.get().catch(
- redirectWhenMissing({
- dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ dash: function (redirectWhenMissing, $rootScope, kbnUrl) {
+ return ensureDefaultIndexPattern(deps.core, data, $rootScope, kbnUrl)
+ .then(() => {
+ return deps.savedDashboards.get();
})
- );
+ .catch(
+ redirectWhenMissing({
+ dashboard: DashboardConstants.LANDING_PAGE_PATH,
+ })
+ );
},
},
})
@@ -156,11 +160,13 @@ export function initDashboardApp(app, deps) {
template: dashboardTemplate,
controller: createNewDashboardCtrl,
resolve: {
- dash: function ($route, redirectWhenMissing, kbnUrl, AppState) {
+ dash: function ($rootScope, $route, redirectWhenMissing, kbnUrl, AppState) {
const id = $route.current.params.id;
- return deps.savedDashboards
- .get(id)
+ return ensureDefaultIndexPattern(deps.core, data, $rootScope, kbnUrl)
+ .then(() => {
+ return deps.savedDashboards.get(id);
+ })
.then(savedDashboard => {
deps.chrome.recentlyAccessed.add(
savedDashboard.getFullPath(),
@@ -188,6 +194,7 @@ export function initDashboardApp(app, deps) {
'The url "dashboard/create" was removed in 6.0. Please update your bookmarks.',
})
);
+ return new Promise(() => {});
} else {
throw error;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts
index f3e4414477b86..b76b3f309874a 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/dashboard_constants.ts
@@ -21,9 +21,9 @@ export const DashboardConstants = {
ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM: 'addToDashboard',
NEW_VISUALIZATION_ID_PARAM: 'addVisualization',
LANDING_PAGE_PATH: '/dashboards',
- CREATE_NEW_DASHBOARD_URL: '/dashboards/create',
+ CREATE_NEW_DASHBOARD_URL: '/dashboard',
};
export function createDashboardEditUrl(id: string) {
- return `/dashboards/view/${id}`;
+ return `/dashboard/${id}`;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
index 8ece51a06e33f..e3358546a5c75 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/plugin.ts
@@ -18,6 +18,7 @@
*/
import {
+ App,
CoreSetup,
CoreStart,
LegacyCoreStart,
@@ -66,9 +67,8 @@ export class DashboardPlugin implements Plugin {
__LEGACY: { localApplicationService, getAngularDependencies, ...legacyServices },
}: DashboardPluginSetupDependencies
) {
- localApplicationService.forwardApp('dashboard', 'dashboards', { keepPrefix: true });
- localApplicationService.register({
- id: 'dashboards',
+ const app: App = {
+ id: '',
title: 'Dashboards',
mount: async ({ core: contextCore }, params) => {
if (this.startDependencies === null) {
@@ -94,7 +94,9 @@ export class DashboardPlugin implements Plugin {
const { renderApp } = await import('./render_app');
return renderApp(params.element, params.appBasePath, deps);
},
- });
+ };
+ localApplicationService.register({ ...app, id: 'dashboard' });
+ localApplicationService.register({ ...app, id: 'dashboards' });
}
start(
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index dfb18ddf231bb..be77a7f273138 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -89,7 +89,7 @@ export interface RenderDeps {
export const renderApp = (element: HTMLElement, appBasePath: string, deps: RenderDeps) => {
const dashboardAngularModule = createLocalAngularModule(deps.core);
// global routing stuff
- configureAppAngularModule(dashboardAngularModule, deps.core as LegacyCoreStart, deps.dataStart);
+ configureAppAngularModule(dashboardAngularModule, deps.core as LegacyCoreStart);
// custom routing stuff
initDashboardApp(dashboardAngularModule, deps);
const $injector = mountDashboardApp(appBasePath, element);
diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
index 1a6c6aad363ba..e9ad486d70db7 100644
--- a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
+++ b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
@@ -74,6 +74,7 @@ import { addHelpMenuToAppChrome } from '../components/help_menu/help_menu_util';
import { extractTimeFilter, changeTimeFilter } from '../../../../data/public';
import { start as data } from '../../../../data/public/legacy';
import { npStart } from 'ui/new_platform';
+import { ensureDefaultIndexPattern } from '../../../../../ui/public/legacy_compat/utils';
const { savedQueryService } = data.search.services;
@@ -90,7 +91,6 @@ const app = uiModules.get('apps/discover', [
uiRoutes
.defaults(/^\/discover(\/|$)/, {
- requireDefaultIndex: true,
requireUICapability: 'discover.show',
k7Breadcrumbs: ($route, $injector) =>
$injector.invoke(
@@ -118,50 +118,53 @@ uiRoutes
template: indexTemplate,
reloadOnSearch: false,
resolve: {
- ip: function (Promise, indexPatterns, config, Private) {
+ savedObjects: function (Promise, indexPatterns, config, Private, $rootScope, kbnUrl, redirectWhenMissing, savedSearches, $route) {
const State = Private(StateProvider);
- return indexPatterns.getCache().then((savedObjects)=> {
- /**
- * In making the indexPattern modifiable it was placed in appState. Unfortunately,
- * the load order of AppState conflicts with the load order of many other things
- * so in order to get the name of the index we should use, and to switch to the
- * default if necessary, we parse the appState with a temporary State object and
- * then destroy it immediatly after we're done
- *
- * @type {State}
- */
- const state = new State('_a', {});
-
- const specified = !!state.index;
- const exists = _.findIndex(savedObjects, o => o.id === state.index) > -1;
- const id = exists ? state.index : config.get('defaultIndex');
- state.destroy();
+ const savedSearchId = $route.current.params.id;
+ return ensureDefaultIndexPattern(npStart.core, data, $rootScope, kbnUrl).then(() => {
return Promise.props({
- list: savedObjects,
- loaded: indexPatterns.get(id),
- stateVal: state.index,
- stateValFound: specified && exists
+ ip: indexPatterns.getCache().then((savedObjects) => {
+ /**
+ * In making the indexPattern modifiable it was placed in appState. Unfortunately,
+ * the load order of AppState conflicts with the load order of many other things
+ * so in order to get the name of the index we should use, and to switch to the
+ * default if necessary, we parse the appState with a temporary State object and
+ * then destroy it immediatly after we're done
+ *
+ * @type {State}
+ */
+ const state = new State('_a', {});
+
+ const specified = !!state.index;
+ const exists = _.findIndex(savedObjects, o => o.id === state.index) > -1;
+ const id = exists ? state.index : config.get('defaultIndex');
+ state.destroy();
+
+ return Promise.props({
+ list: savedObjects,
+ loaded: indexPatterns.get(id),
+ stateVal: state.index,
+ stateValFound: specified && exists
+ });
+ }),
+ savedSearch: savedSearches.get(savedSearchId)
+ .then((savedSearch) => {
+ if (savedSearchId) {
+ npStart.core.chrome.recentlyAccessed.add(
+ savedSearch.getFullPath(),
+ savedSearch.title,
+ savedSearchId);
+ }
+ return savedSearch;
+ })
+ .catch(redirectWhenMissing({
+ 'search': '/discover',
+ 'index-pattern': '/management/kibana/objects/savedSearches/' + $route.current.params.id
+ }))
});
});
},
- savedSearch: function (redirectWhenMissing, savedSearches, $route) {
- const savedSearchId = $route.current.params.id;
- return savedSearches.get(savedSearchId)
- .then((savedSearch) => {
- if (savedSearchId) {
- npStart.core.chrome.recentlyAccessed.add(
- savedSearch.getFullPath(),
- savedSearch.title,
- savedSearchId);
- }
- return savedSearch;
- })
- .catch(redirectWhenMissing({
- 'search': '/discover',
- 'index-pattern': '/management/kibana/objects/savedSearches/' + $route.current.params.id
- }));
- }
}
});
@@ -228,7 +231,7 @@ function discoverController(
};
// the saved savedSearch
- const savedSearch = $route.current.locals.savedSearch;
+ const savedSearch = $route.current.locals.savedObjects.savedSearch;
let abortController;
$scope.$on('$destroy', () => {
@@ -544,7 +547,7 @@ function discoverController(
sampleSize: config.get('discover:sampleSize'),
timefield: isDefaultTypeIndexPattern($scope.indexPattern) && $scope.indexPattern.timeFieldName,
savedSearch: savedSearch,
- indexPatternList: $route.current.locals.ip.list,
+ indexPatternList: $route.current.locals.savedObjects.ip.list,
};
const shouldSearchOnPageLoad = () => {
@@ -1059,7 +1062,7 @@ function discoverController(
loaded: loadedIndexPattern,
stateVal,
stateValFound,
- } = $route.current.locals.ip;
+ } = $route.current.locals.savedObjects.ip;
const ownIndexPattern = $scope.searchSource.getOwnField('index');
@@ -1107,12 +1110,12 @@ function discoverController(
// Block the UI from loading if the user has loaded a rollup index pattern but it isn't
// supported.
$scope.isUnsupportedIndexPattern = (
- !isDefaultTypeIndexPattern($route.current.locals.ip.loaded)
- && !hasSearchStategyForIndexPattern($route.current.locals.ip.loaded)
+ !isDefaultTypeIndexPattern($route.current.locals.savedObjects.ip.loaded)
+ && !hasSearchStategyForIndexPattern($route.current.locals.savedObjects.ip.loaded)
);
if ($scope.isUnsupportedIndexPattern) {
- $scope.unsupportedIndexPatternType = $route.current.locals.ip.loaded.type;
+ $scope.unsupportedIndexPatternType = $route.current.locals.savedObjects.ip.loaded.type;
return;
}
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
index dac0880e6fec4..146a02720a3e1 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
@@ -58,6 +58,7 @@ import { start as data } from '../../../../data/public/legacy';
import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
+import { ensureDefaultIndexPattern } from '../../../../../ui/public/legacy_compat/utils';
const { savedQueryService } = data.search.services;
@@ -66,7 +67,7 @@ uiRoutes
template: editorTemplate,
k7Breadcrumbs: getCreateBreadcrumbs,
resolve: {
- savedVis: function (savedVisualizations, redirectWhenMissing, $route) {
+ savedVis: function (savedVisualizations, redirectWhenMissing, $route, $rootScope, kbnUrl) {
const visTypes = visualizations.types.all();
const visType = _.find(visTypes, { name: $route.current.params.type });
const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection;
@@ -79,7 +80,7 @@ uiRoutes
);
}
- return savedVisualizations.get($route.current.params)
+ return ensureDefaultIndexPattern(npStart.core, data, $rootScope, kbnUrl).then(() => savedVisualizations.get($route.current.params))
.then(savedVis => {
if (savedVis.vis.type.setup) {
return savedVis.vis.type.setup(savedVis)
@@ -97,28 +98,33 @@ uiRoutes
template: editorTemplate,
k7Breadcrumbs: getEditBreadcrumbs,
resolve: {
- savedVis: function (savedVisualizations, redirectWhenMissing, $route) {
- return savedVisualizations.get($route.current.params.id)
- .then((savedVis) => {
+ savedVis: function (savedVisualizations, redirectWhenMissing, $route, $rootScope, kbnUrl) {
+ return ensureDefaultIndexPattern(npStart.core, data, $rootScope, kbnUrl)
+ .then(() => savedVisualizations.get($route.current.params.id))
+ .then(savedVis => {
npStart.core.chrome.recentlyAccessed.add(
savedVis.getFullPath(),
savedVis.title,
- savedVis.id);
+ savedVis.id
+ );
return savedVis;
})
.then(savedVis => {
if (savedVis.vis.type.setup) {
- return savedVis.vis.type.setup(savedVis)
- .catch(() => savedVis);
+ return savedVis.vis.type.setup(savedVis).catch(() => savedVis);
}
return savedVis;
})
- .catch(redirectWhenMissing({
- 'visualization': '/visualize',
- 'search': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
- 'index-pattern': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
- 'index-pattern-field': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id
- }));
+ .catch(
+ redirectWhenMissing({
+ visualization: '/visualize',
+ search: '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ 'index-pattern':
+ '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ 'index-pattern-field':
+ '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
+ })
+ );
}
}
});
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.js b/src/legacy/core_plugins/kibana/public/visualize/index.js
index 7afb98709fae0..be39ed6c2be38 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/index.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/index.js
@@ -30,10 +30,12 @@ import { getLandingBreadcrumbs, getWizardStep1Breadcrumbs } from './breadcrumbs'
// load directives
import '../../../data/public';
+import { ensureDefaultIndexPattern } from '../../../../ui/public/legacy_compat/utils';
+import { npStart } from '../../../../ui/public/new_platform';
+import { start as data } from '../../../data/public/legacy';
uiRoutes
.defaults(/visualize/, {
- requireDefaultIndex: true,
requireUICapability: 'visualize.show',
badge: uiCapabilities => {
if (uiCapabilities.visualize.save) {
@@ -58,6 +60,7 @@ uiRoutes
controllerAs: 'listingController',
resolve: {
createNewVis: () => false,
+ hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(npStart.core, data, $rootScope, kbnUrl)
},
})
.when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
@@ -67,6 +70,7 @@ uiRoutes
controllerAs: 'listingController',
resolve: {
createNewVis: () => true,
+ hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(npStart.core, data, $rootScope, kbnUrl)
},
});
diff --git a/src/legacy/ui/public/legacy_compat/angular_config.tsx b/src/legacy/ui/public/legacy_compat/angular_config.tsx
index f62ce41291e1a..14828bbce8558 100644
--- a/src/legacy/ui/public/legacy_compat/angular_config.tsx
+++ b/src/legacy/ui/public/legacy_compat/angular_config.tsx
@@ -26,15 +26,13 @@ import {
IModule,
IRootScopeService,
} from 'angular';
-import { EuiCallOut } from '@elastic/eui';
-import ReactDOM from 'react-dom';
import $ from 'jquery';
import _, { cloneDeep, forOwn, get, set } from 'lodash';
import React, { Fragment } from 'react';
import * as Rx from 'rxjs';
import { i18n } from '@kbn/i18n';
-import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
+import { FormattedMessage } from '@kbn/i18n/react';
import { CoreStart, LegacyCoreStart } from 'kibana/public';
import { fatalError } from 'ui/notify';
@@ -45,15 +43,10 @@ import { modifyUrl } from 'ui/url';
import { UrlOverflowService } from '../error_url_overflow';
// @ts-ignore
import { isSystemApiRequest } from '../system_api';
-import { DataStart } from '../../../core_plugins/data/public';
const URL_LIMIT_WARN_WITHIN = 1000;
-export const configureAppAngularModule = (
- angularModule: IModule,
- newPlatform: LegacyCoreStart,
- dataStart: DataStart
-) => {
+export const configureAppAngularModule = (angularModule: IModule, newPlatform: LegacyCoreStart) => {
const legacyMetadata = newPlatform.injectedMetadata.getLegacyMetadata();
forOwn(newPlatform.injectedMetadata.getInjectedVars(), (val, name) => {
@@ -78,8 +71,7 @@ export const configureAppAngularModule = (
.run($setupBadgeAutoClear(newPlatform))
.run($setupHelpExtensionAutoClear(newPlatform))
.run($setupUrlOverflowHandling(newPlatform))
- .run($setupUICapabilityRedirect(newPlatform))
- .run($setupDefaultIndexRedirect(newPlatform, dataStart));
+ .run($setupUICapabilityRedirect(newPlatform));
};
const getEsUrl = (newPlatform: CoreStart) => {
@@ -202,91 +194,6 @@ const $setupUICapabilityRedirect = (newPlatform: CoreStart) => (
);
};
-let bannerId: string;
-let timeoutId: NodeJS.Timeout | undefined;
-
-/**
- * integrates with angular to automatically redirect to management if no default
- * index pattern is configured when a route flag is set.
- */
-const $setupDefaultIndexRedirect = (newPlatform: CoreStart, data: DataStart) => (
- $rootScope: IRootScopeService,
- $injector: any
-) => {
- const isKibanaAppRoute = window.location.pathname.endsWith('/app/kibana');
- // this feature only works within kibana app for now after everything is
- // switched to the application service, this can be changed to handle all
- // apps.
- if (!isKibanaAppRoute) {
- return;
- }
-
- $rootScope.$on(
- '$routeChangeStart',
- (event, { $$route: route }: { $$route?: RouteConfiguration } = {}) => {
- if (!route || !route.requireDefaultIndex) {
- return;
- }
-
- return data.indexPatterns.indexPatterns.getIds().then(function(patterns: string[]) {
- let defaultId = newPlatform.uiSettings.get('defaultIndex');
- let defined = !!defaultId;
- const exists = _.contains(patterns, defaultId);
-
- if (defined && !exists) {
- newPlatform.uiSettings.remove('defaultIndex');
- defaultId = defined = false;
- }
-
- if (!defined) {
- // If there is any index pattern created, set the first as default
- if (patterns.length >= 1) {
- defaultId = patterns[0];
- newPlatform.uiSettings.set('defaultIndex', defaultId);
- } else {
- const canManageIndexPatterns =
- newPlatform.application.capabilities.management.kibana.index_patterns;
- const redirectTarget = canManageIndexPatterns
- ? '/management/kibana/index_pattern'
- : '/home';
-
- $injector.get('kbnUrl').change(redirectTarget);
- $rootScope.$digest();
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
-
- // Avoid being hostile to new users who don't have an index pattern setup yet
- // give them a friendly info message instead of a terse error message
- bannerId = newPlatform.overlays.banners.replace(bannerId, (element: HTMLElement) => {
- ReactDOM.render(
-
-
- ,
- element
- );
- return () => ReactDOM.unmountComponentAtNode(element);
- });
-
- // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
- timeoutId = setTimeout(() => {
- newPlatform.overlays.banners.remove(bannerId);
- timeoutId = undefined;
- }, 15000);
- }
- }
- });
- }
- );
-};
-
/**
* internal angular run function that will be called when angular bootstraps and
* lets us integrate with the angular router so that we can automatically clear
diff --git a/src/legacy/ui/public/legacy_compat/utils.tsx b/src/legacy/ui/public/legacy_compat/utils.tsx
new file mode 100644
index 0000000000000..c1f83035bff4c
--- /dev/null
+++ b/src/legacy/ui/public/legacy_compat/utils.tsx
@@ -0,0 +1,100 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { contains } from 'lodash';
+import { IRootScopeService } from 'angular';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { i18n } from '@kbn/i18n';
+import { I18nProvider } from '@kbn/i18n/react';
+import { EuiCallOut } from '@elastic/eui';
+import { CoreStart } from 'kibana/public';
+import { DataStart } from '../../../core_plugins/data/public';
+
+let bannerId: string;
+let timeoutId: NodeJS.Timeout | undefined;
+
+/**
+ * Makes sure a default index pattern is set and defines one otherwise.
+ * if there are no index patterns, redirect to management page and show
+ * banner.
+ */
+export async function ensureDefaultIndexPattern(
+ newPlatform: CoreStart,
+ data: DataStart,
+ $rootScope: IRootScopeService,
+ kbnUrl: any
+) {
+ const patterns = await data.indexPatterns.indexPatterns.getIds();
+ let defaultId = newPlatform.uiSettings.get('defaultIndex');
+ let defined = !!defaultId;
+ const exists = contains(patterns, defaultId);
+
+ if (defined && !exists) {
+ newPlatform.uiSettings.remove('defaultIndex');
+ defaultId = defined = false;
+ }
+
+ if (!defined) {
+ // If there is any index pattern created, set the first as default
+ if (patterns.length >= 1) {
+ defaultId = patterns[0];
+ newPlatform.uiSettings.set('defaultIndex', defaultId);
+ } else {
+ const canManageIndexPatterns =
+ newPlatform.application.capabilities.management.kibana.index_patterns;
+ const redirectTarget = canManageIndexPatterns ? '/management/kibana/index_pattern' : '/home';
+
+ if (timeoutId) {
+ clearTimeout(timeoutId);
+ }
+
+ // Avoid being hostile to new users who don't have an index pattern setup yet
+ // give them a friendly info message instead of a terse error message
+ bannerId = newPlatform.overlays.banners.replace(bannerId, (element: HTMLElement) => {
+ ReactDOM.render(
+
+
+ ,
+ element
+ );
+ return () => ReactDOM.unmountComponentAtNode(element);
+ });
+
+ // hide the message after the user has had a chance to acknowledge it -- so it doesn't permanently stick around
+ timeoutId = setTimeout(() => {
+ newPlatform.overlays.banners.remove(bannerId);
+ timeoutId = undefined;
+ }, 15000);
+
+ kbnUrl.change(redirectTarget);
+ $rootScope.$digest();
+
+ // return never-resolving promise to stop resolving and wait for the url change
+ return new Promise(() => {});
+ }
+ }
+}
diff --git a/src/legacy/ui/public/routes/__tests__/_route_manager.js b/src/legacy/ui/public/routes/__tests__/_route_manager.js
index d6d4c869b4b7e..450bb51f0b0c6 100644
--- a/src/legacy/ui/public/routes/__tests__/_route_manager.js
+++ b/src/legacy/ui/public/routes/__tests__/_route_manager.js
@@ -119,18 +119,6 @@ describe('routes/route_manager', function () {
expect($rp.when.secondCall.args[1]).to.have.property('reloadOnSearch', false);
expect($rp.when.lastCall.args[1]).to.have.property('reloadOnSearch', true);
});
-
- it('sets route.requireDefaultIndex to false by default', function () {
- routes.when('/nothing-set');
- routes.when('/no-index-required', { requireDefaultIndex: false });
- routes.when('/index-required', { requireDefaultIndex: true });
- routes.config($rp);
-
- expect($rp.when.callCount).to.be(3);
- expect($rp.when.firstCall.args[1]).to.have.property('requireDefaultIndex', false);
- expect($rp.when.secondCall.args[1]).to.have.property('requireDefaultIndex', false);
- expect($rp.when.lastCall.args[1]).to.have.property('requireDefaultIndex', true);
- });
});
describe('#defaults()', () => {
diff --git a/src/legacy/ui/public/routes/route_manager.d.ts b/src/legacy/ui/public/routes/route_manager.d.ts
index c47a31eb7be76..749a5b9ee4d96 100644
--- a/src/legacy/ui/public/routes/route_manager.d.ts
+++ b/src/legacy/ui/public/routes/route_manager.d.ts
@@ -32,7 +32,6 @@ export interface RouteConfiguration {
template?: string;
k7Breadcrumbs?: (...args: any[]) => ChromeBreadcrumb[];
requireUICapability?: string;
- requireDefaultIndex?: boolean;
outerAngularWrapperRoute?: boolean;
}
diff --git a/src/legacy/ui/public/routes/route_manager.js b/src/legacy/ui/public/routes/route_manager.js
index ba48984bb45b9..6444ef66fbe47 100644
--- a/src/legacy/ui/public/routes/route_manager.js
+++ b/src/legacy/ui/public/routes/route_manager.js
@@ -46,10 +46,6 @@ export default function RouteManager() {
route.reloadOnSearch = false;
}
- if (route.requireDefaultIndex == null) {
- route.requireDefaultIndex = false;
- }
-
wrapRouteWithPrep(route, setup);
$routeProvider.when(path, route);
});
From 0dd5d3a5ef00800abf20bd958a4640cf0e9bbacd Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Fri, 25 Oct 2019 12:33:29 +0200
Subject: [PATCH 027/132] rename function and improve documentation
---
src/legacy/core_plugins/kibana/public/dashboard/app.js | 2 +-
.../kibana/public/discover/angular/discover.js | 2 +-
.../kibana/public/visualize/editor/editor.js | 2 +-
src/legacy/core_plugins/kibana/public/visualize/index.js | 2 +-
.../{utils.tsx => ensure_default_index_pattern.tsx} | 9 ++++++---
src/legacy/ui/public/legacy_compat/index.ts | 1 +
6 files changed, 11 insertions(+), 7 deletions(-)
rename src/legacy/ui/public/legacy_compat/{utils.tsx => ensure_default_index_pattern.tsx} (92%)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index c8fab451242ba..85eb6da196d07 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -19,6 +19,7 @@
import { i18n } from '@kbn/i18n';
import { wrapInI18nContext } from 'ui/i18n';
+import { ensureDefaultIndexPattern } from 'ui/legacy_compat';
import dashboardTemplate from './dashboard_app.html';
import dashboardListingTemplate from './listing/dashboard_listing_ng_wrapper.html';
@@ -32,7 +33,6 @@ import {
import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { DashboardListing, EMPTY_FILTER } from './listing/dashboard_listing';
import { addHelpMenuToAppChrome } from './help_menu/help_menu_util';
-import { ensureDefaultIndexPattern } from '../../../../ui/public/legacy_compat/utils';
import { start as data } from '../../../data/public/legacy';
export function initDashboardApp(app, deps) {
diff --git a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
index e9ad486d70db7..e0d7843d978f1 100644
--- a/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
+++ b/src/legacy/core_plugins/kibana/public/discover/angular/discover.js
@@ -54,6 +54,7 @@ import { StateProvider } from 'ui/state_management/state';
import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
import { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
import { getFilterGenerator } from 'ui/filter_manager';
+import { ensureDefaultIndexPattern } from 'ui/legacy_compat';
import { getDocLink } from 'ui/documentation_links';
import '../components/fetch_error';
@@ -74,7 +75,6 @@ import { addHelpMenuToAppChrome } from '../components/help_menu/help_menu_util';
import { extractTimeFilter, changeTimeFilter } from '../../../../data/public';
import { start as data } from '../../../../data/public/legacy';
import { npStart } from 'ui/new_platform';
-import { ensureDefaultIndexPattern } from '../../../../../ui/public/legacy_compat/utils';
const { savedQueryService } = data.search.services;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
index 146a02720a3e1..5b6b953ff5631 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
@@ -26,6 +26,7 @@ import 'ui/vis/editors/default/sidebar';
import 'ui/visualize';
import 'ui/collapsible_sidebar';
+import { ensureDefaultIndexPattern } from 'ui/legacy_compat';
import { capabilities } from 'ui/capabilities';
import chrome from 'ui/chrome';
import React from 'react';
@@ -58,7 +59,6 @@ import { start as data } from '../../../../data/public/legacy';
import { start as visualizations } from '../../../../visualizations/public/np_ready/public/legacy';
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
-import { ensureDefaultIndexPattern } from '../../../../../ui/public/legacy_compat/utils';
const { savedQueryService } = data.search.services;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/index.js b/src/legacy/core_plugins/kibana/public/visualize/index.js
index be39ed6c2be38..64505bb852be8 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/index.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/index.js
@@ -17,6 +17,7 @@
* under the License.
*/
+import { ensureDefaultIndexPattern } from 'ui/legacy_compat';
import './editor/editor';
import { i18n } from '@kbn/i18n';
import './saved_visualizations/_saved_vis';
@@ -30,7 +31,6 @@ import { getLandingBreadcrumbs, getWizardStep1Breadcrumbs } from './breadcrumbs'
// load directives
import '../../../data/public';
-import { ensureDefaultIndexPattern } from '../../../../ui/public/legacy_compat/utils';
import { npStart } from '../../../../ui/public/new_platform';
import { start as data } from '../../../data/public/legacy';
diff --git a/src/legacy/ui/public/legacy_compat/utils.tsx b/src/legacy/ui/public/legacy_compat/ensure_default_index_pattern.tsx
similarity index 92%
rename from src/legacy/ui/public/legacy_compat/utils.tsx
rename to src/legacy/ui/public/legacy_compat/ensure_default_index_pattern.tsx
index c1f83035bff4c..daedd9f329ed0 100644
--- a/src/legacy/ui/public/legacy_compat/utils.tsx
+++ b/src/legacy/ui/public/legacy_compat/ensure_default_index_pattern.tsx
@@ -31,9 +31,12 @@ let bannerId: string;
let timeoutId: NodeJS.Timeout | undefined;
/**
- * Makes sure a default index pattern is set and defines one otherwise.
- * if there are no index patterns, redirect to management page and show
- * banner.
+ * Checks whether a default index pattern is set and exists and defines
+ * one otherwise.
+ *
+ * If there are no index patterns, redirect to management page and show
+ * banner. In this case the promise returned from this function will never
+ * resolve to wait for the URL change to happen.
*/
export async function ensureDefaultIndexPattern(
newPlatform: CoreStart,
diff --git a/src/legacy/ui/public/legacy_compat/index.ts b/src/legacy/ui/public/legacy_compat/index.ts
index b29056954051b..ea8932114118e 100644
--- a/src/legacy/ui/public/legacy_compat/index.ts
+++ b/src/legacy/ui/public/legacy_compat/index.ts
@@ -18,3 +18,4 @@
*/
export { configureAppAngularModule } from './angular_config';
+export { ensureDefaultIndexPattern } from './ensure_default_index_pattern';
From 1dc18c7a84fa0b7a2f1708e72d99c81dc09a0280 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Fri, 25 Oct 2019 14:35:39 +0300
Subject: [PATCH 028/132] Fix exceptions
---
.../visualize/embeddable/visualize_embeddable_factory.tsx | 1 -
.../core_plugins/kibana/public/visualize/kibana_services.ts | 1 +
.../kibana/public/visualize/listing/visualize_listing.js | 2 +-
.../kibana/public/visualize/wizard/new_vis_modal.tsx | 2 +-
4 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index c69bd25966451..b3ccd55110373 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -41,7 +41,6 @@ import { getServices, getVisualizeLoader } from '../kibana_services';
const {
addBasePath,
capabilities,
- chrome,
embeddable,
getInjector,
uiSettings,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index 69333e0768229..a39cbc231bd4f 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -55,6 +55,7 @@ const services = {
chrome: npStart.core.chrome,
docLinks: npStart.core.docLinks,
embeddable: npStart.plugins.embeddable,
+ getBasePath: npStart.core.http.basePath.get,
savedObjectsClient: npStart.core.savedObjects.client,
toastNotifications: npStart.core.notifications.toasts,
uiSettings: npStart.core.uiSettings,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index 7a0ff15f13511..81f8c0fe5a2b9 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -60,7 +60,7 @@ export function VisualizeListingController($injector, createNewVis) {
this.editItem = ({ editUrl }) => {
// for visualizations the edit and view URLs are the same
- window.location = addBasePath(editUrl);
+ window.location.href = addBasePath(editUrl);
};
this.getViewUrl = ({ editUrl }) => {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
index 2b36c9af705c2..420f0e5198056 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.tsx
@@ -124,7 +124,7 @@ class NewVisModal extends React.Component
Date: Fri, 25 Oct 2019 15:05:22 +0300
Subject: [PATCH 029/132] Get rid of injectI18n; fix chrome method invocation
---
.../kibana/public/visualize/editor/editor.js | 3 +-
.../public/visualize/kibana_services.ts | 1 +
.../listing/no_visualizations_prompt.js | 12 +-
.../visualize/listing/visualize_listing.js | 3 +-
.../listing/visualize_listing_table.js | 129 +++++++-----------
5 files changed, 61 insertions(+), 87 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
index 5930c96b09273..b0909d16974b6 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
@@ -53,6 +53,7 @@ import {
const {
capabilities,
chrome,
+ chromeLegacy,
docTitle,
FilterBarQueryFilterProvider,
getBasePath,
@@ -596,7 +597,7 @@ function VisEditor(
// Since we aren't reloading the page, only inserting a new browser history item, we need to manually update
// the last url for this app, so directly clicking on the Visualize tab will also bring the user to the saved
// url, not the unsaved one.
- chrome.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl);
+ chromeLegacy.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl);
const lastDashboardAbsoluteUrl = chrome.navLinks.get('kibana:dashboard').url;
const dashboardParsedUrl = absoluteToParsedUrl(lastDashboardAbsoluteUrl, getBasePath());
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index a39cbc231bd4f..f85b602583335 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -63,6 +63,7 @@ const services = {
visualizations,
// legacy
+ chromeLegacy,
docTitle,
FeatureCatalogueRegistryProvider,
FilterBarQueryFilterProvider,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/no_visualizations_prompt.js b/src/legacy/core_plugins/kibana/public/visualize/listing/no_visualizations_prompt.js
index 54a6048a22daf..34b662838880e 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/no_visualizations_prompt.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/no_visualizations_prompt.js
@@ -18,7 +18,8 @@
*/
import React from 'react';
-import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
import {
KuiEmptyTablePrompt,
@@ -27,7 +28,7 @@ import {
KuiButtonIcon,
} from '@kbn/ui-framework/components';
-function NoVisualizationsPromptUi({ onCreateVis, intl }) {
+function NoVisualizationsPrompt({ onCreateVis }) {
return (
}
+ icon={}
>
}
- message={intl.formatMessage({
- id: 'kbn.visualize.listing.noVisualizationsText',
+ message={i18n.translate('kbn.visualize.listing.noVisualizationsText', {
defaultMessage: `Looks like you don't have any visualizations. Let's create some!`,
})}
/>
@@ -52,4 +52,4 @@ function NoVisualizationsPromptUi({ onCreateVis, intl }) {
);
}
-export const NoVisualizationsPrompt = injectI18n(NoVisualizationsPromptUi);
+export { NoVisualizationsPrompt };
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
index 81f8c0fe5a2b9..f9e3a1a90115a 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing.js
@@ -28,6 +28,7 @@ import { getServices } from '../kibana_services';
const {
addBasePath,
chrome,
+ chromeLegacy,
SavedObjectRegistryProvider,
SavedObjectsClientProvider,
timefilter,
@@ -106,7 +107,7 @@ export function VisualizeListingController($injector, createNewVis) {
})
)
.then(() => {
- chrome.untrackNavLinksForDeletedSavedObjects(selectedItems.map(item => item.id));
+ chromeLegacy.untrackNavLinksForDeletedSavedObjects(selectedItems.map(item => item.id));
})
.catch(error => {
toastNotifications.addError(error, {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
index 67fc70899410b..fbd70a0d8c0f7 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/listing/visualize_listing_table.js
@@ -19,30 +19,22 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
-import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
+import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { TableListView } from './../../table_list_view';
-import {
- EuiIcon,
- EuiBetaBadge,
- EuiLink,
- EuiButton,
- EuiEmptyPrompt,
-} from '@elastic/eui';
+import { EuiIcon, EuiBetaBadge, EuiLink, EuiButton, EuiEmptyPrompt } from '@elastic/eui';
import { getServices } from '../kibana_services';
const { capabilities } = getServices();
-class VisualizeListingTableUi extends Component {
-
+class VisualizeListingTable extends Component {
constructor(props) {
super(props);
}
render() {
- const { intl } = this.props;
return (
item.canDelete}
initialFilter={''}
noItemsFragment={this.getNoItemsMessage()}
- entityName={
- intl.formatMessage({
- id: 'kbn.visualize.listing.table.entityName',
- defaultMessage: 'visualization',
- })
- }
- entityNamePlural={
- intl.formatMessage({
- id: 'kbn.visualize.listing.table.entityNamePlural',
- defaultMessage: 'visualizations',
- })
- }
- tableListTitle={
- intl.formatMessage({
- id: 'kbn.visualize.listing.table.listTitle',
- defaultMessage: 'Visualizations',
- })
- }
+ entityName={i18n.translate('kbn.visualize.listing.table.entityName', {
+ defaultMessage: 'visualization',
+ })}
+ entityNamePlural={i18n.translate('kbn.visualize.listing.table.entityNamePlural', {
+ defaultMessage: 'visualizations',
+ })}
+ tableListTitle={i18n.translate('kbn.visualize.listing.table.listTitle', {
+ defaultMessage: 'Visualizations',
+ })}
/>
);
}
getTableColumns() {
- const { intl } = this.props;
const tableColumns = [
{
field: 'title',
- name: intl.formatMessage({
- id: 'kbn.visualize.listing.table.titleColumnName',
+ name: i18n.translate('kbn.visualize.listing.table.titleColumnName', {
defaultMessage: 'Title',
}),
sortable: true,
@@ -95,35 +76,29 @@ class VisualizeListingTableUi extends Component {
>
{field}
- )
+ ),
},
{
field: 'typeTitle',
- name: intl.formatMessage({
- id: 'kbn.visualize.listing.table.typeColumnName',
+ name: i18n.translate('kbn.visualize.listing.table.typeColumnName', {
defaultMessage: 'Type',
}),
sortable: true,
- render: (field, record) => (
+ render: (field, record) => (
{this.renderItemTypeIcon(record)}
{record.typeTitle}
{this.getBadge(record)}
- )
+ ),
},
{
field: 'description',
- name: intl.formatMessage({
- id: 'kbn.dashboard.listing.table.descriptionColumnName',
+ name: i18n.translate('kbn.dashboard.listing.table.descriptionColumnName', {
defaultMessage: 'Description',
}),
sortable: true,
- render: (field, record) => (
-
- {record.description}
-
- )
+ render: (field, record) => {record.description},
},
];
@@ -187,19 +162,13 @@ class VisualizeListingTableUi extends Component {
/>
);
-
}
renderItemTypeIcon(item) {
let icon;
if (item.image) {
icon = (
-
+
);
} else {
icon = (
@@ -217,38 +186,40 @@ class VisualizeListingTableUi extends Component {
getBadge(item) {
if (item.stage === 'beta') {
- return ();
+ return (
+
+ );
} else if (item.stage === 'experimental') {
- return ();
+ return (
+
+ );
}
}
}
-VisualizeListingTableUi.propTypes = {
+VisualizeListingTable.propTypes = {
deleteItems: PropTypes.func.isRequired,
findItems: PropTypes.func.isRequired,
createItem: PropTypes.func.isRequired,
@@ -257,4 +228,4 @@ VisualizeListingTableUi.propTypes = {
listingLimit: PropTypes.number.isRequired,
};
-export const VisualizeListingTable = injectI18n(VisualizeListingTableUi);
+export { VisualizeListingTable };
From 72fd4acfd20349febc5c154a12ae045085d4f467 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Fri, 25 Oct 2019 17:23:56 +0300
Subject: [PATCH 030/132] Update unit tests
---
.../wizard/new_vis_modal.test.mocks.ts | 26 -------------------
.../visualize/wizard/new_vis_modal.test.tsx | 26 ++++++++++++++++---
.../type_selection/new_vis_help.test.tsx | 14 ++++++++--
3 files changed, 34 insertions(+), 32 deletions(-)
delete mode 100644 src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.mocks.ts
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.mocks.ts b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.mocks.ts
deleted file mode 100644
index 04c99a1547ba9..0000000000000
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.mocks.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-export const settingsGet = jest.fn();
-
-jest.doMock('ui/chrome', () => ({
- getUiSettingsClient: () => ({
- get: settingsGet,
- }),
-}));
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
index 6b2f51c3dcf2b..a69c4e4b5d3d1 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
@@ -20,14 +20,32 @@
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { settingsGet } from './new_vis_modal.test.mocks';
-
import { NewVisModal } from './new_vis_modal';
-
-import { VisType } from 'ui/vis';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
+jest.mock('../kibana_services', () => {
+ const mock = {
+ addBasePath: jest.fn(path => `root${path}`),
+ uiSettings: { get: jest.fn() },
+ createUiStatsReporter: () => jest.fn(),
+ };
+
+ return {
+ getServices: () => mock,
+ VisType: {},
+ METRIC_TYPE: 'metricType',
+ };
+});
+
+import { getServices } from '../kibana_services';
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
+
describe('NewVisModal', () => {
+ const settingsGet = getServices().uiSettings.get;
+
const defaultVisTypeParams = {
hidden: false,
visualization: class Controller {
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
index 7fd1df85cee06..5980430d0f259 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
@@ -22,7 +22,17 @@ import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { NewVisHelp } from './new_vis_help';
import chrome from 'ui/chrome';
-jest.doMock('ui/chrome');
+jest.mock('../../kibana_services', () => {
+ return {
+ getServices: () => ({
+ addBasePath: jest.fn(url => `testbasepath${url}`),
+ }),
+ };
+});
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
describe('NewVisHelp', () => {
it('should render as expected', () => {
@@ -36,7 +46,7 @@ describe('NewVisHelp', () => {
aliasUrl: '/my/fancy/new/thing',
description: 'Some desc',
highlighted: false,
- icon: 'wahtever',
+ icon: 'whatever',
name: 'whatever',
promotion: {
buttonText: 'Do it now!',
From 105af0a1f211f9dc18bdae726d87ec0c38d599c8 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Mon, 28 Oct 2019 12:14:50 +0100
Subject: [PATCH 031/132] redirect unknown urls to default app
---
src/legacy/core_plugins/kibana/public/dashboard/app.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/app.js b/src/legacy/core_plugins/kibana/public/dashboard/app.js
index 85eb6da196d07..85e73cc7db24d 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/app.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/app.js
@@ -206,7 +206,9 @@ export function initDashboardApp(app, deps) {
);
},
},
- });
+ })
+ .when(`dashboard/:tail*?`, { redirectTo: `/${deps.core.injectedMetadata.getInjectedVar('kbnDefaultAppId')}` })
+ .when(`dashboards/:tail*?`, { redirectTo: `/${deps.core.injectedMetadata.getInjectedVar('kbnDefaultAppId')}` });
});
deps.FeatureCatalogueRegistryProvider.register(() => {
From 65ef3d063aab523b9795430596471217f739b58e Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Mon, 28 Oct 2019 16:29:32 +0300
Subject: [PATCH 032/132] Fix TS
---
.../kibana/public/visualize/wizard/new_vis_modal.test.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
index a69c4e4b5d3d1..99d9590e750fd 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/new_vis_modal.test.tsx
@@ -21,6 +21,7 @@ import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { NewVisModal } from './new_vis_modal';
+import { VisType } from '../kibana_services';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
jest.mock('../kibana_services', () => {
@@ -44,7 +45,7 @@ beforeEach(() => {
});
describe('NewVisModal', () => {
- const settingsGet = getServices().uiSettings.get;
+ const settingsGet = getServices().uiSettings.get as jest.Mock;
const defaultVisTypeParams = {
hidden: false,
From d66b1adc46bb15a925f3c4b16d21a01044b67b1f Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Tue, 29 Oct 2019 09:25:40 +0300
Subject: [PATCH 033/132] Move data and Embeddable import
---
.../kibana/public/visualize/editor/editor.js | 2 +-
.../embeddable/disabled_lab_embeddable.tsx | 3 ++-
.../visualize/embeddable/visualize_embeddable.ts | 10 ++++------
.../embeddable/visualize_embeddable_factory.tsx | 15 ++++++++-------
.../kibana/public/visualize/kibana_services.ts | 10 ++++++++++
.../wizard/search_selection/search_selection.tsx | 4 ++--
.../wizard/type_selection/new_vis_help.test.tsx | 5 +----
.../wizard/type_selection/type_selection.tsx | 2 +-
8 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
index b0909d16974b6..a617e184c3dc7 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
+++ b/src/legacy/core_plugins/kibana/public/visualize/editor/editor.js
@@ -31,7 +31,6 @@ import { DashboardConstants } from '../../dashboard/dashboard_constants';
import { VisualizeConstants } from '../visualize_constants';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
import { extractTimeFilter, changeTimeFilter } from '../../../../data/public';
-import { start as data } from '../../../../data/public/legacy';
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
@@ -54,6 +53,7 @@ const {
capabilities,
chrome,
chromeLegacy,
+ data,
docTitle,
FilterBarQueryFilterProvider,
getBasePath,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx
index 92bd0fa345fa0..065feae045597 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/disabled_lab_embeddable.tsx
@@ -19,7 +19,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
-import { Embeddable, EmbeddableOutput } from '../../../../../../plugins/embeddable/public';
+
+import { Embeddable, EmbeddableOutput } from '../kibana_services';
import { DisabledLabVisualization } from './disabled_lab_visualization';
import { VisualizeInput } from './visualize_embeddable';
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
index d95264abdd559..caf37fd907e60 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
@@ -23,16 +23,14 @@ import { Subscription } from 'rxjs';
import * as Rx from 'rxjs';
import { Filter } from '@kbn/es-query';
import { TimeRange } from '../../../../../../plugins/data/public';
-import {
- EmbeddableInput,
- EmbeddableOutput,
- Embeddable,
- Container,
-} from '../../../../../../plugins/embeddable/public';
import { Query, onlyDisabledFiltersChanged } from '../../../../data/public';
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
import {
+ Container,
+ Embeddable,
+ EmbeddableInput,
+ EmbeddableOutput,
PersistedState,
StaticIndexPattern,
VisSavedObject,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
index b3ccd55110373..ff55b02082040 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable_factory.tsx
@@ -22,12 +22,6 @@ import { i18n } from '@kbn/i18n';
import { Legacy } from 'kibana';
import { SavedObjectAttributes } from 'kibana/server';
-import {
- EmbeddableFactory,
- ErrorEmbeddable,
- Container,
- EmbeddableOutput,
-} from '../../../../../../plugins/embeddable/public';
import { showNewVisModal } from '../wizard';
import { SavedVisualizations } from '../types';
import { DisabledLabEmbeddable } from './disabled_lab_embeddable';
@@ -36,7 +30,14 @@ import { VisualizeEmbeddable, VisualizeInput, VisualizeOutput } from './visualiz
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
-import { getServices, getVisualizeLoader } from '../kibana_services';
+import {
+ getServices,
+ Container,
+ EmbeddableFactory,
+ EmbeddableOutput,
+ ErrorEmbeddable,
+ getVisualizeLoader,
+} from '../kibana_services';
const {
addBasePath,
diff --git a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
index f85b602583335..29d18c28392f0 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/kibana_services.ts
@@ -47,6 +47,7 @@ import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_regis
import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
import { start as visualizations } from '../../../visualizations/public/np_ready/public/legacy';
+import { start as data } from '../../../data/public/legacy';
const services = {
// new platform
@@ -60,6 +61,7 @@ const services = {
toastNotifications: npStart.core.notifications.toasts,
uiSettings: npStart.core.uiSettings,
+ data,
visualizations,
// legacy
@@ -103,6 +105,14 @@ export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
export { getVisualizeLoader } from 'ui/visualize/loader';
export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
+export {
+ Container,
+ Embeddable,
+ EmbeddableFactory,
+ EmbeddableInput,
+ EmbeddableOutput,
+ ErrorEmbeddable,
+} from '../../../../../plugins/embeddable/public';
// export types
export { METRIC_TYPE };
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/search_selection/search_selection.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/search_selection/search_selection.tsx
index 34c95b43991e8..88dbbb8de7df9 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/search_selection/search_selection.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/search_selection/search_selection.tsx
@@ -22,10 +22,10 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
-import { VisType } from 'ui/vis';
-
import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
+import { VisType } from '../../kibana_services';
+
interface SearchSelectionProps {
onSearchSelected: (searchId: string, searchType: string) => void;
visType: VisType;
diff --git a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
index 5980430d0f259..382f475669f5d 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
+++ b/src/legacy/core_plugins/kibana/public/visualize/wizard/type_selection/new_vis_help.test.tsx
@@ -20,12 +20,11 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { NewVisHelp } from './new_vis_help';
-import chrome from 'ui/chrome';
jest.mock('../../kibana_services', () => {
return {
getServices: () => ({
- addBasePath: jest.fn(url => `testbasepath${url}`),
+ addBasePath: jest.fn((url: string) => `testbasepath${url}`),
}),
};
});
@@ -36,8 +35,6 @@ beforeEach(() => {
describe('NewVisHelp', () => {
it('should render as expected', () => {
- (chrome.addBasePath as unknown) = (url: string) => `testbasepath${url}`;
-
expect(
shallowWithIntl(
Date: Tue, 29 Oct 2019 10:49:42 +0300
Subject: [PATCH 034/132] Import VISUALIZE_EMBEDDABLE_TYPE directly
---
.../canvas_plugin_src/expression_types/embeddable_types.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts
index 6efe6bc96dbba..546e8967a7439 100644
--- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts
+++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/expression_types/embeddable_types.ts
@@ -6,7 +6,7 @@
// @ts-ignore
import { MAP_SAVED_OBJECT_TYPE } from '../../../maps/common/constants';
-import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/kibana/public/visualize/embeddable';
+import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/kibana/public/visualize/embeddable/constants';
import { SEARCH_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/kibana/public/discover/embeddable/constants';
export const EmbeddableTypes = {
From 8dd28f785f4b0f7cfc686671466b789258f36b84 Mon Sep 17 00:00:00 2001
From: maryia-lapata
Date: Tue, 29 Oct 2019 16:02:52 +0300
Subject: [PATCH 035/132] Fix deps
---
.../public/visualize/embeddable/visualize_embeddable.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
index 246e16b50efa6..ef9c9a00f980b 100644
--- a/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
+++ b/src/legacy/core_plugins/kibana/public/visualize/embeddable/visualize_embeddable.ts
@@ -22,8 +22,8 @@ import { EmbeddedVisualizeHandler } from 'ui/visualize/loader/embedded_visualize
import { Subscription } from 'rxjs';
import * as Rx from 'rxjs';
import { Filter } from '@kbn/es-query';
-import { TimeRange } from '../../../../../../plugins/data/public';
-import { Query, onlyDisabledFiltersChanged } from '../../../../data/public';
+import { TimeRange, onlyDisabledFiltersChanged } from '../../../../../../plugins/data/public';
+import { Query } from '../../../../data/public';
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
import {
From f9b47f1675f404f93d30077f65c8561c256ef32e Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Tue, 29 Oct 2019 16:19:54 +0100
Subject: [PATCH 036/132] only wire up local angular once
---
.../kibana/public/dashboard/render_app.ts | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index 9376d4d87ddb0..fdbe3d44c35a1 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -18,7 +18,7 @@
*/
import { EuiConfirmModal } from '@elastic/eui';
-import angular from 'angular';
+import angular, { IModule } from 'angular';
import { IPrivate } from 'ui/private';
import { Storage } from 'ui/storage';
import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/src/angular';
@@ -86,12 +86,16 @@ export interface RenderDeps {
localStorage: Storage;
}
+let angularModuleInstance: IModule | null = null;
+
export const renderApp = (element: HTMLElement, appBasePath: string, deps: RenderDeps) => {
- const dashboardAngularModule = createLocalAngularModule(deps.core, deps.dataStart);
- // global routing stuff
- configureAppAngularModule(dashboardAngularModule, deps.core as LegacyCoreStart);
- // custom routing stuff
- initDashboardApp(dashboardAngularModule, deps);
+ if (!angularModuleInstance) {
+ angularModuleInstance = createLocalAngularModule(deps.core, deps.dataStart);
+ // global routing stuff
+ configureAppAngularModule(angularModuleInstance, deps.core as LegacyCoreStart);
+ // custom routing stuff
+ initDashboardApp(angularModuleInstance, deps);
+ }
const $injector = mountDashboardApp(appBasePath, element);
return () => $injector.get('$rootScope').$destroy();
};
From 1246675763dc9ac013832d067dab13dcbb76a0c6 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Wed, 30 Oct 2019 17:49:41 +0100
Subject: [PATCH 037/132] fix top nav and dashboard only mode
---
.../kibana/public/dashboard/index.ts | 2 ++
.../kibana/public/dashboard/plugin.ts | 11 ++++++++---
.../kibana/public/dashboard/render_app.ts | 17 +++++++++--------
.../dashboard_mode/public/dashboard_viewer.js | 4 ++++
4 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/index.ts b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
index 7c9954359464a..ea9f98016227e 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/index.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/index.ts
@@ -30,6 +30,7 @@ import { DashboardPlugin, LegacyAngularInjectedDependencies } from './plugin';
import { start as data } from '../../../data/public/legacy';
import { localApplicationService } from '../local_application_service';
import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy';
+import { start as navigation } from '../../../navigation/public/legacy';
import './saved_dashboard/saved_dashboards';
import './dashboard_config';
@@ -70,5 +71,6 @@ async function getAngularDependencies(): Promise;
+ navigation: NavigationStart;
}
export interface DashboardPluginSetupDependencies {
@@ -59,6 +61,7 @@ export class DashboardPlugin implements Plugin {
dataStart: DataStart;
savedObjectsClient: SavedObjectsClientContract;
embeddables: ReturnType;
+ navigation: NavigationStart;
} | null = null;
public setup(
@@ -74,12 +77,13 @@ export class DashboardPlugin implements Plugin {
if (this.startDependencies === null) {
throw new Error('not started yet');
}
- const { dataStart, savedObjectsClient, embeddables } = this.startDependencies;
+ const { dataStart, savedObjectsClient, embeddables, navigation } = this.startDependencies;
const angularDependencies = await getAngularDependencies();
const deps: RenderDeps = {
core: contextCore as LegacyCoreStart,
...legacyServices,
...angularDependencies,
+ navigation,
dataStart,
indexPatterns: dataStart.indexPatterns.indexPatterns,
savedObjectsClient,
@@ -101,12 +105,13 @@ export class DashboardPlugin implements Plugin {
start(
{ savedObjects: { client: savedObjectsClient } }: CoreStart,
- { data: dataStart, embeddables }: DashboardPluginStartDependencies
+ { data: dataStart, embeddables, navigation }: DashboardPluginStartDependencies
) {
this.startDependencies = {
dataStart,
savedObjectsClient,
embeddables,
+ navigation,
};
}
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
index fdbe3d44c35a1..20c4b9ca23e0b 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/render_app.ts
@@ -20,7 +20,6 @@
import { EuiConfirmModal } from '@elastic/eui';
import angular, { IModule } from 'angular';
import { IPrivate } from 'ui/private';
-import { Storage } from 'ui/storage';
import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/src/angular';
// @ts-ignore
import { GlobalStateProvider } from 'ui/state_management/global_state';
@@ -42,7 +41,6 @@ import { PromiseServiceCreator } from 'ui/promises/promises';
import { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
// @ts-ignore
import { confirmModalFactory } from 'ui/modals/confirm_modal';
-
import {
AppMountContext,
ChromeStart,
@@ -51,6 +49,7 @@ import {
UiSettingsClientContract,
} from 'kibana/public';
import { configureAppAngularModule } from 'ui/legacy_compat';
+import { Storage } from '../../../../../plugins/kibana_utils/public';
// @ts-ignore
import { initDashboardApp } from './app';
@@ -63,11 +62,13 @@ import {
} from '../../../data/public';
import { SavedQueryService } from '../../../data/public/search/search_bar/lib/saved_query_service';
import { EmbeddablePublicPlugin } from '../../../../../plugins/embeddable/public';
+import { NavigationStart } from '../../../navigation/public';
export interface RenderDeps {
core: LegacyCoreStart;
indexPatterns: DataStart['indexPatterns']['indexPatterns'];
dataStart: DataStart;
+ navigation: NavigationStart;
queryFilter: any;
getUnhashableStates: any;
shareContextMenuExtensions: any;
@@ -90,7 +91,7 @@ let angularModuleInstance: IModule | null = null;
export const renderApp = (element: HTMLElement, appBasePath: string, deps: RenderDeps) => {
if (!angularModuleInstance) {
- angularModuleInstance = createLocalAngularModule(deps.core, deps.dataStart);
+ angularModuleInstance = createLocalAngularModule(deps.core, deps.navigation);
// global routing stuff
configureAppAngularModule(angularModuleInstance, deps.core as LegacyCoreStart);
// custom routing stuff
@@ -102,7 +103,7 @@ export const renderApp = (element: HTMLElement, appBasePath: string, deps: Rende
const mainTemplate = (basePath: string) => `
`;
@@ -124,7 +125,7 @@ function mountDashboardApp(appBasePath: string, element: HTMLElement) {
return $injector;
}
-function createLocalAngularModule(core: AppMountContext['core'], data: DataStart) {
+function createLocalAngularModule(core: AppMountContext['core'], navigation: NavigationStart) {
createLocalI18nModule();
createLocalPrivateModule();
createLocalPromiseModule();
@@ -132,7 +133,7 @@ function createLocalAngularModule(core: AppMountContext['core'], data: DataStart
createLocalKbnUrlModule();
createLocalStateModule();
createLocalPersistedStateModule();
- createLocalTopNavModule(data);
+ createLocalTopNavModule(navigation);
createLocalConfirmModalModule();
createLocalFilterBarModule();
@@ -218,11 +219,11 @@ function createLocalPrivateModule() {
angular.module('app/dashboard/Private', []).provider('Private', PrivateProvider);
}
-function createLocalTopNavModule(data: DataStart) {
+function createLocalTopNavModule(navigation: NavigationStart) {
angular
.module('app/dashboard/TopNav', ['react'])
.directive('kbnTopNav', createTopNavDirective)
- .directive('kbnTopNavHelper', createTopNavHelper(data.ui));
+ .directive('kbnTopNavHelper', createTopNavHelper(navigation.ui));
}
function createLocalFilterBarModule() {
diff --git a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js
index d39d3fdaa84b8..02d61a86bf9e5 100644
--- a/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js
+++ b/x-pack/legacy/plugins/dashboard_mode/public/dashboard_viewer.js
@@ -37,6 +37,8 @@ import 'ui/agg_response';
import 'ui/agg_types';
import 'leaflet';
import { npStart } from 'ui/new_platform';
+import { localApplicationService } from 'plugins/kibana/local_application_service';
+
import { showAppRedirectNotification } from 'ui/notify';
import { DashboardConstants, createDashboardEditUrl } from 'plugins/kibana/dashboard/dashboard_constants';
@@ -44,6 +46,8 @@ import { DashboardConstants, createDashboardEditUrl } from 'plugins/kibana/dashb
uiModules.get('kibana')
.config(dashboardConfigProvider => dashboardConfigProvider.turnHideWriteControlsOn());
+localApplicationService.attachToAngular(routes);
+
routes.enable();
routes.otherwise({ redirectTo: defaultUrl() });
From a34dd9fc4ed7c66dfa04e486e5d558509705eee3 Mon Sep 17 00:00:00 2001
From: Joe Reuter
Date: Thu, 31 Oct 2019 09:54:49 +0100
Subject: [PATCH 038/132] decouple frome home shim PR
---
.../kibana/public/home/components/home_app.js | 82 +--
.../core_plugins/kibana/public/home/index.js | 61 ++
.../core_plugins/kibana/public/home/index.ts | 81 ---
.../kibana/public/home/kibana_services.ts | 116 +--
.../core_plugins/kibana/public/home/plugin.ts | 106 ---
.../kibana/public/home/render_app.tsx | 39 -
.../cockroachdb_metrics/screenshot.png | Bin 233000 -> 0 bytes
.../tutorial_resources/logos/cockroachdb.svg | 666 ------------------
8 files changed, 155 insertions(+), 996 deletions(-)
create mode 100644 src/legacy/core_plugins/kibana/public/home/index.js
delete mode 100644 src/legacy/core_plugins/kibana/public/home/index.ts
delete mode 100644 src/legacy/core_plugins/kibana/public/home/plugin.ts
delete mode 100644 src/legacy/core_plugins/kibana/public/home/render_app.tsx
delete mode 100644 src/legacy/core_plugins/kibana/public/home/tutorial_resources/cockroachdb_metrics/screenshot.png
delete mode 100644 src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/cockroachdb.svg
diff --git a/src/legacy/core_plugins/kibana/public/home/components/home_app.js b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
index 64eac2323b378..005d4bdb0a99e 100644
--- a/src/legacy/core_plugins/kibana/public/home/components/home_app.js
+++ b/src/legacy/core_plugins/kibana/public/home/components/home_app.js
@@ -18,7 +18,6 @@
*/
import React from 'react';
-import { I18nProvider } from '@kbn/i18n/react';
import PropTypes from 'prop-types';
import { Home } from './home';
import { FeatureDirectory } from './feature_directory';
@@ -28,7 +27,6 @@ import {
HashRouter as Router,
Switch,
Route,
- Redirect,
} from 'react-router-dom';
import { getTutorial } from '../load_tutorials';
import { replaceTemplateStrings } from './tutorial/replace_template_strings';
@@ -49,7 +47,6 @@ export function HomeApp({ directories }) {
const isCloudEnabled = getInjected('isCloudEnabled', false);
const apmUiEnabled = getInjected('apmUiEnabled', true);
const mlEnabled = getInjected('mlEnabled', false);
- const defaultAppId = getInjected('kbnDefaultAppId', 'discover');
const renderTutorialDirectory = (props) => {
return (
@@ -75,52 +72,43 @@ export function HomeApp({ directories }) {
};
return (
-
-
-
-
+
+
+
+
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
);
}
diff --git a/src/legacy/core_plugins/kibana/public/home/index.js b/src/legacy/core_plugins/kibana/public/home/index.js
new file mode 100644
index 0000000000000..01f94b8ee4368
--- /dev/null
+++ b/src/legacy/core_plugins/kibana/public/home/index.js
@@ -0,0 +1,61 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { getServices } from './kibana_services';
+import template from './home_ng_wrapper.html';
+import {
+ HomeApp
+} from './components/home_app';
+import { i18n } from '@kbn/i18n';
+
+const { wrapInI18nContext, uiRoutes, uiModules } = getServices();
+
+const app = uiModules.get('apps/home', []);
+app.directive('homeApp', function (reactDirective) {
+ return reactDirective(wrapInI18nContext(HomeApp));
+});
+
+const homeTitle = i18n.translate('kbn.home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
+
+function getRoute() {
+ return {
+ template,
+ resolve: {
+ directories: () => getServices().getFeatureCatalogueEntries()
+ },
+ controller($scope, $route) {
+ const { chrome, addBasePath } = getServices();
+ $scope.directories = $route.current.locals.directories;
+ $scope.recentlyAccessed = chrome.recentlyAccessed.get().map(item => {
+ item.link = addBasePath(item.link);
+ return item;
+ });
+ },
+ k7Breadcrumbs: () => [
+ { text: homeTitle },
+ ]
+ };
+}
+
+// All routing will be handled inside HomeApp via react, we just need to make sure angular doesn't
+// redirect us to the default page by encountering a url it isn't marked as being able to handle.
+uiRoutes.when('/home', getRoute());
+uiRoutes.when('/home/feature_directory', getRoute());
+uiRoutes.when('/home/tutorial_directory/:tab?', getRoute());
+uiRoutes.when('/home/tutorial/:id', getRoute());
diff --git a/src/legacy/core_plugins/kibana/public/home/index.ts b/src/legacy/core_plugins/kibana/public/home/index.ts
deleted file mode 100644
index db0b317e06ca1..0000000000000
--- a/src/legacy/core_plugins/kibana/public/home/index.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
-import { npSetup, npStart } from 'ui/new_platform';
-import chrome from 'ui/chrome';
-import { IPrivate } from 'ui/private';
-// @ts-ignore
-import { toastNotifications, banners } from 'ui/notify';
-import { kfetch } from 'ui/kfetch';
-import { HomePlugin, LegacyAngularInjectedDependencies } from './plugin';
-import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
-import { start as data } from '../../../data/public/legacy';
-import { TelemetryOptInProvider } from '../../../telemetry/public/services';
-import { localApplicationService } from '../local_application_service';
-
-export const trackUiMetric = createUiStatsReporter('Kibana_home');
-
-/**
- * Get dependencies relying on the global angular context.
- * They also have to get resolved together with the legacy imports above
- */
-async function getAngularDependencies(): Promise {
- const injector = await chrome.dangerouslyGetActiveInjector();
-
- const Private = injector.get('Private');
-
- const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
- const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
- const telemetryOptInProvider = Private(TelemetryOptInProvider);
-
- return {
- telemetryOptInProvider,
- shouldShowTelemetryOptIn:
- telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn(),
- };
-}
-
-(async () => {
- const instance = new HomePlugin();
- instance.setup(npSetup.core, {
- __LEGACY: {
- trackUiMetric,
- toastNotifications,
- banners,
- kfetch,
- metadata: npStart.core.injectedMetadata.getLegacyMetadata(),
- METRIC_TYPE,
- getFeatureCatalogueEntries: async () => {
- const injector = await chrome.dangerouslyGetActiveInjector();
- const Private = injector.get('Private');
- // Merge legacy registry with new registry
- (Private(FeatureCatalogueRegistryProvider as any) as any).inTitleOrder.map(
- npSetup.plugins.feature_catalogue.register
- );
- return npStart.plugins.feature_catalogue.get();
- },
- getAngularDependencies,
- localApplicationService,
- },
- });
- instance.start(npStart.core, {
- data,
- });
-})();
diff --git a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
index d094885526a5c..b9f2ae1cfa7e8 100644
--- a/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
+++ b/src/legacy/core_plugins/kibana/public/home/kibana_services.ts
@@ -17,67 +17,69 @@
* under the License.
*/
-import { ToastNotifications } from 'ui/notify/toasts/toast_notifications';
-import {
- ChromeStart,
- DocLinksStart,
- LegacyNavLink,
- SavedObjectsClientContract,
- UiSettingsClientContract,
- UiSettingsState,
-} from 'kibana/public';
-import { KFetchOptions } from 'ui/kfetch';
-import { KFetchKibanaOptions } from 'ui/kfetch/kfetch';
-import { UiStatsMetricType } from '@kbn/analytics';
-import { FeatureCatalogueEntry } from '../../../../../plugins/feature_catalogue/public';
+// @ts-ignore
+import { toastNotifications, banners } from 'ui/notify';
+import { kfetch } from 'ui/kfetch';
+import chrome from 'ui/chrome';
-export interface HomeKibanaServices {
- indexPatternService: any;
- getFeatureCatalogueEntries: () => Promise;
- metadata: {
- app: unknown;
- bundleId: string;
- nav: LegacyNavLink[];
- version: string;
- branch: string;
- buildNum: number;
- buildSha: string;
- basePath: string;
- serverName: string;
- devMode: boolean;
- uiSettings: { defaults: UiSettingsState; user?: UiSettingsState | undefined };
- };
- getInjected: (name: string, defaultValue?: any) => unknown;
- chrome: ChromeStart;
- telemetryOptInProvider: any;
- uiSettings: UiSettingsClientContract;
- kfetch: (options: KFetchOptions, kfetchOptions?: KFetchKibanaOptions) => Promise;
- savedObjectsClient: SavedObjectsClientContract;
- toastNotifications: ToastNotifications;
- banners: any;
- METRIC_TYPE: any;
- trackUiMetric: (type: UiStatsMetricType, eventNames: string | string[], count?: number) => void;
- getBasePath: () => string;
- shouldShowTelemetryOptIn: boolean;
- docLinks: DocLinksStart;
- addBasePath: (url: string) => string;
-}
+import { wrapInI18nContext } from 'ui/i18n';
-let services: HomeKibanaServices | null = null;
+// @ts-ignore
+import { uiModules as modules } from 'ui/modules';
+import routes from 'ui/routes';
+import { npSetup, npStart } from 'ui/new_platform';
+import { IPrivate } from 'ui/private';
+import { FeatureCatalogueRegistryProvider } from 'ui/registry/feature_catalogue';
+import { createUiStatsReporter, METRIC_TYPE } from '../../../ui_metric/public';
+import { TelemetryOptInProvider } from '../../../telemetry/public/services';
+import { start as data } from '../../../data/public/legacy';
-export function setServices(newServices: HomeKibanaServices) {
- services = newServices;
-}
+let shouldShowTelemetryOptIn: boolean;
+let telemetryOptInProvider: any;
export function getServices() {
- if (!services) {
- throw new Error(
- 'Kibana services not set - are you trying to import this module from outside of the home app?'
- );
- }
- return services;
-}
+ return {
+ getInjected: npStart.core.injectedMetadata.getInjectedVar,
+ metadata: npStart.core.injectedMetadata.getLegacyMetadata(),
+ docLinks: npStart.core.docLinks,
+
+ uiRoutes: routes,
+ uiModules: modules,
+
+ savedObjectsClient: npStart.core.savedObjects.client,
+ chrome: npStart.core.chrome,
+ uiSettings: npStart.core.uiSettings,
+ addBasePath: npStart.core.http.basePath.prepend,
+ getBasePath: npStart.core.http.basePath.get,
-export function clearServices() {
- services = null;
+ indexPatternService: data.indexPatterns.indexPatterns,
+ shouldShowTelemetryOptIn,
+ telemetryOptInProvider,
+ getFeatureCatalogueEntries: async () => {
+ const injector = await chrome.dangerouslyGetActiveInjector();
+ const Private = injector.get('Private');
+ // Merge legacy registry with new registry
+ (Private(FeatureCatalogueRegistryProvider as any) as any).inTitleOrder.map(
+ npSetup.plugins.feature_catalogue.register
+ );
+ return npStart.plugins.feature_catalogue.get();
+ },
+
+ trackUiMetric: createUiStatsReporter('Kibana_home'),
+ METRIC_TYPE,
+
+ toastNotifications,
+ banners,
+ kfetch,
+ wrapInI18nContext,
+ };
}
+
+modules.get('kibana').run((Private: IPrivate) => {
+ const telemetryEnabled = npStart.core.injectedMetadata.getInjectedVar('telemetryEnabled');
+ const telemetryBanner = npStart.core.injectedMetadata.getInjectedVar('telemetryBanner');
+
+ telemetryOptInProvider = Private(TelemetryOptInProvider);
+ shouldShowTelemetryOptIn =
+ telemetryEnabled && telemetryBanner && !telemetryOptInProvider.getOptIn();
+});
diff --git a/src/legacy/core_plugins/kibana/public/home/plugin.ts b/src/legacy/core_plugins/kibana/public/home/plugin.ts
deleted file mode 100644
index 916c6e05f61be..0000000000000
--- a/src/legacy/core_plugins/kibana/public/home/plugin.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { CoreSetup, CoreStart, LegacyNavLink, Plugin, UiSettingsState } from 'kibana/public';
-import { UiStatsMetricType } from '@kbn/analytics';
-import { ToastNotifications } from 'ui/notify/toasts/toast_notifications';
-import { KFetchOptions } from 'ui/kfetch';
-import { KFetchKibanaOptions } from 'ui/kfetch/kfetch';
-
-import { DataStart } from '../../../data/public';
-import { LocalApplicationService } from '../local_application_service';
-import { setServices } from './kibana_services';
-import { FeatureCatalogueEntry } from '../../../../../plugins/feature_catalogue/public';
-
-export interface LegacyAngularInjectedDependencies {
- telemetryOptInProvider: any;
- shouldShowTelemetryOptIn: boolean;
-}
-
-export interface HomePluginStartDependencies {
- data: DataStart;
-}
-
-export interface HomePluginSetupDependencies {
- __LEGACY: {
- trackUiMetric: (type: UiStatsMetricType, eventNames: string | string[], count?: number) => void;
- toastNotifications: ToastNotifications;
- banners: any;
- METRIC_TYPE: any;
- kfetch: (options: KFetchOptions, kfetchOptions?: KFetchKibanaOptions) => Promise;
- metadata: {
- app: unknown;
- bundleId: string;
- nav: LegacyNavLink[];
- version: string;
- branch: string;
- buildNum: number;
- buildSha: string;
- basePath: string;
- serverName: string;
- devMode: boolean;
- uiSettings: { defaults: UiSettingsState; user?: UiSettingsState | undefined };
- };
- getFeatureCatalogueEntries: () => Promise;
- getAngularDependencies: () => Promise;
- localApplicationService: LocalApplicationService;
- };
-}
-
-export class HomePlugin implements Plugin {
- private dataStart: DataStart | null = null;
- private savedObjectsClient: any = null;
-
- setup(
- core: CoreSetup,
- {
- __LEGACY: { localApplicationService, getAngularDependencies, ...legacyServices },
- }: HomePluginSetupDependencies
- ) {
- localApplicationService.register({
- id: 'home',
- title: 'Home',
- mount: async ({ core: contextCore }, params) => {
- const angularDependencies = await getAngularDependencies();
- setServices({
- ...legacyServices,
- getInjected: core.injectedMetadata.getInjectedVar,
- docLinks: contextCore.docLinks,
- savedObjectsClient: this.savedObjectsClient!,
- chrome: contextCore.chrome,
- uiSettings: core.uiSettings,
- addBasePath: core.http.basePath.prepend,
- getBasePath: core.http.basePath.get,
- indexPatternService: this.dataStart!.indexPatterns.indexPatterns,
- ...angularDependencies,
- });
- const { renderApp } = await import('./render_app');
- return await renderApp(params.element);
- },
- });
- }
-
- start(core: CoreStart, { data }: HomePluginStartDependencies) {
- // TODO is this really the right way? I though the app context would give us those
- this.dataStart = data;
- this.savedObjectsClient = core.savedObjects.client;
- }
-
- stop() {}
-}
diff --git a/src/legacy/core_plugins/kibana/public/home/render_app.tsx b/src/legacy/core_plugins/kibana/public/home/render_app.tsx
deleted file mode 100644
index 50041410d3c6f..0000000000000
--- a/src/legacy/core_plugins/kibana/public/home/render_app.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import React from 'react';
-import { render, unmountComponentAtNode } from 'react-dom';
-import { i18n } from '@kbn/i18n';
-// @ts-ignore
-import { HomeApp } from './components/home_app';
-import { clearServices, getServices } from './kibana_services';
-
-export const renderApp = async (element: HTMLElement) => {
- const homeTitle = i18n.translate('kbn.home.breadcrumbs.homeTitle', { defaultMessage: 'Home' });
- const { getFeatureCatalogueRegistryProvider, chrome } = getServices();
- const directories = (await getFeatureCatalogueRegistryProvider()).inTitleOrder;
- chrome.setBreadcrumbs([{ text: homeTitle }]);
-
- render(, element);
-
- return () => {
- unmountComponentAtNode(element);
- clearServices();
- };
-};
diff --git a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/cockroachdb_metrics/screenshot.png b/src/legacy/core_plugins/kibana/public/home/tutorial_resources/cockroachdb_metrics/screenshot.png
deleted file mode 100644
index 4b3020d91d57da293c2bd62dae6f5265ac726251..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 233000
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 |