Properly redirect legacy URLs (#68284)

This commit is contained in:
Joe Reuter 2020-06-24 11:26:19 +02:00 committed by GitHub
parent fc9df7244b
commit d1a6fa26b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
96 changed files with 473 additions and 642 deletions

View file

@ -73,7 +73,6 @@ module.exports = {
'rxjs',
'sinon',
'tinycolor2',
'./src/legacy/ui/public/styles/font_awesome.less',
'./src/legacy/ui/public/styles/bootstrap/bootstrap_light.less',
],
plugins: [

View file

@ -23,9 +23,6 @@ import { promisify } from 'util';
import { getUiSettingDefaults } from './server/ui_setting_defaults';
import { registerCspCollector } from './server/lib/csp_usage_collector';
import { injectVars } from './inject_vars';
import { kbnBaseUrl } from '../../../plugins/kibana_legacy/server';
const mkdirAsync = promisify(Fs.mkdir);
@ -43,35 +40,7 @@ export default function (kibana) {
},
uiExports: {
app: {
id: 'kibana',
title: 'Kibana',
listed: false,
main: 'plugins/kibana/kibana',
},
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
links: [],
injectDefaultVars(server, options) {
const mapConfig = server.config().get('map');
const tilemap = mapConfig.tilemap;
return {
kbnIndex: options.index,
kbnBaseUrl,
// required on all pages due to hacks that use these values
mapConfig,
tilemapsConfig: {
deprecated: {
// If url is set, old settings must be used for backward compatibility
isOverridden: typeof tilemap.url === 'string' && tilemap.url !== '',
config: tilemap,
},
},
};
},
uiSettingDefaults: getUiSettingDefaults(),
},
@ -90,7 +59,6 @@ export default function (kibana) {
init: async function (server) {
const { usageCollection } = server.newPlatform.setup.plugins;
registerCspCollector(usageCollection, server);
server.injectUiAppVars('kibana', () => injectVars(server));
},
});
}

View file

@ -35,4 +35,5 @@ const pluginInstance = new TableVisPlugin({} as PluginInitializerContext);
export const setup = pluginInstance.setup(npSetup.core, plugins);
export const start = pluginInstance.start(npStart.core, {
data: npStart.plugins.data,
kibanaLegacy: npStart.plugins.kibanaLegacy,
});

View file

@ -7,12 +7,3 @@
// Public UI styles
@import 'src/legacy/ui/public/index';
// Has to come after visualize because of some
// bad cascading in the Editor layout
@import '../../../../plugins/maps_legacy/public/index';
// Management styles
@import './management/index';
// Local application mount wrapper styles
@import 'local_application_service/index';

View file

@ -1,59 +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.
*/
// autoloading
// preloading (for faster webpack builds)
import routes from 'ui/routes';
import { npSetup } from 'ui/new_platform';
// import the uiExports that we want to "use"
import 'uiExports/savedObjectTypes';
import 'uiExports/fieldFormatEditors';
import 'uiExports/navbarExtensions';
import 'uiExports/contextMenuActions';
import 'uiExports/managementSections';
import 'uiExports/indexManagement';
import 'uiExports/embeddableFactories';
import 'uiExports/embeddableActions';
import 'uiExports/inspectorViews';
import 'uiExports/search';
import 'uiExports/shareContextMenuExtensions';
import 'uiExports/interpreter';
import 'ui/autoload/all';
import { localApplicationService } from './local_application_service';
npSetup.plugins.kibanaLegacy.registerLegacyAppAlias('doc', 'discover', { keepPrefix: true });
npSetup.plugins.kibanaLegacy.registerLegacyAppAlias('context', 'discover', { keepPrefix: true });
npSetup.plugins.kibanaLegacy.forwardApp('management', 'management', (path) => {
return path.replace('/management', '');
});
localApplicationService.attachToAngular(routes);
routes.enable();
const { config } = npSetup.plugins.kibanaLegacy;
routes.otherwise({
redirectTo: `/${config.defaultAppId || 'discover'}`,
});

View file

@ -1 +0,0 @@
@import 'local_application_service';

View file

@ -1,5 +0,0 @@
.kbnLocalApplicationWrapper {
display: flex;
flex-direction: column;
flex-grow: 1;
}

View file

@ -1,20 +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 * from './local_application_service';

View file

@ -1,134 +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 { App, AppUnmount, AppMountDeprecated } from 'kibana/public';
import { UIRoutes } from 'ui/routes';
import { ILocationService, IScope } from 'angular';
import { npStart } from 'ui/new_platform';
import { htmlIdGenerator } from '@elastic/eui';
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 idGenerator = htmlIdGenerator('kibanaAppLocalApp');
/**
* 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
*/
attachToAngular(angularRouteManager: UIRoutes) {
npStart.plugins.kibanaLegacy.getApps().forEach((app) => {
const wrapperElementId = this.idGenerator();
angularRouteManager.when(matchAllWithPrefix(app), {
outerAngularWrapperRoute: true,
reloadOnSearch: false,
reloadOnUrl: false,
template: `<div class="kbnLocalApplicationWrapper" id="${wrapperElementId}"></div>`,
controller($scope: IScope) {
const element = document.getElementById(wrapperElementId)!;
let unmountHandler: AppUnmount | null = null;
let isUnmounted = false;
$scope.$on('$destroy', () => {
if (unmountHandler) {
unmountHandler();
}
isUnmounted = true;
});
(async () => {
const params = {
element,
appBasePath: '',
onAppLeave: () => undefined,
// TODO: adapt to use Core's ScopedHistory
history: {} as any,
};
unmountHandler = isAppMountDeprecated(app.mount)
? await app.mount({ core: npStart.core }, params)
: await app.mount(params);
// immediately unmount app if scope got destroyed in the meantime
if (isUnmounted) {
unmountHandler();
}
})();
},
});
if (app.updater$) {
app.updater$.subscribe((updater) => {
const updatedFields = updater(app);
if (updatedFields && updatedFields.activeUrl) {
npStart.core.chrome.navLinks.update(app.navLinkId || app.id, {
url: updatedFields.activeUrl,
});
}
});
}
});
npStart.plugins.kibanaLegacy.getForwards().forEach((forwardDefinition) => {
angularRouteManager.when(matchAllWithPrefix(forwardDefinition.legacyAppId), {
outerAngularWrapperRoute: true,
reloadOnSearch: false,
reloadOnUrl: false,
template: '<span></span>',
controller($location: ILocationService) {
const newPath = forwardDefinition.rewritePath($location.url());
window.location.replace(
npStart.core.http.basePath.prepend(`/app/${forwardDefinition.newAppId}${newPath}`)
);
},
});
});
npStart.plugins.kibanaLegacy
.getLegacyAppAliases()
.forEach(({ legacyAppId, newAppId, keepPrefix }) => {
angularRouteManager.when(matchAllWithPrefix(legacyAppId), {
resolveRedirectTo: ($location: ILocationService) => {
const url = $location.url();
return `/${newAppId}${keepPrefix ? url : url.replace(legacyAppId, '')}`;
},
});
});
}
}
export const localApplicationService = new LocalApplicationService();
function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated {
// Mount functions with two arguments are assumed to expect deprecated `context` object.
return mount.length === 2;
}

View file

@ -1,13 +0,0 @@
// This file is imported into src/core_plugings/kibana/publix/index.scss
// Prefix all styles with "dsh" to avoid conflicts.
// Examples
// mgtChart
// mgtChart__legend
// mgtChart__legend--small
// mgtChart__legend-isLoading
// Core
@import '../../../../../plugins/advanced_settings/public/index';
@import 'sections/index_patterns/index';

View file

@ -1,25 +0,0 @@
#indexPatternListReact {
display: flex;
.indexPatternList__headerWrapper {
padding-bottom: $euiSizeS;
}
.euiButtonEmpty__content {
justify-content: left;
padding: 0;
span {
text-overflow: ellipsis;
overflow: hidden;
}
}
.indexPatternListPrompt__descList {
text-align: left;
}
}
.indexPatternList__badge {
margin-left: $euiSizeS;
}

View file

@ -18,7 +18,7 @@
*/
import { PluginInitializerContext } from 'kibana/public';
import { npSetup } from 'ui/new_platform';
import { npSetup, npStart } from 'ui/new_platform';
import { plugin } from '.';
import { TimelionPluginSetupDependencies } from './plugin';
import { LegacyDependenciesPlugin } from './shim';
@ -32,4 +32,4 @@ const setupPlugins: Readonly<TimelionPluginSetupDependencies> = {
const pluginInstance = plugin({} as PluginInitializerContext);
export const setup = pluginInstance.setup(npSetup.core, setupPlugins);
export const start = pluginInstance.start();
export const start = pluginInstance.start(npStart.core, npStart.plugins);

View file

@ -16,10 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
import { CoreSetup, Plugin, PluginInitializerContext, IUiSettingsClient } from 'kibana/public';
import {
CoreSetup,
Plugin,
PluginInitializerContext,
IUiSettingsClient,
CoreStart,
} from 'kibana/public';
import { getTimeChart } from './panels/timechart/timechart';
import { Panel } from './panels/panel';
import { LegacyDependenciesPlugin, LegacyDependenciesPluginSetup } from './shim';
import { KibanaLegacyStart } from '../../../../plugins/kibana_legacy/public';
/** @internal */
export interface TimelionVisualizationDependencies extends LegacyDependenciesPluginSetup {
@ -59,7 +66,9 @@ export class TimelionPlugin implements Plugin<Promise<void>, void> {
dependencies.timelionPanels.set(timeChartPanel.name, timeChartPanel);
}
public start() {}
public start(core: CoreStart, { kibanaLegacy }: { kibanaLegacy: KibanaLegacyStart }) {
kibanaLegacy.loadFontAwesome();
}
public stop(): void {}
}

View file

@ -20,4 +20,3 @@
import './accessibility';
import './modules';
import './settings';
import './styles';

View file

@ -1,20 +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 'ui/styles/font_awesome.less';

View file

@ -21,6 +21,7 @@ import expect from '@kbn/expect';
import ngMock from 'ng_mock';
import $ from 'jquery';
import '../input_focus';
import uiRoutes from 'ui/routes';
describe('Input focus directive', function () {
let $compile;
@ -32,6 +33,8 @@ describe('Input focus directive', function () {
let selectedText;
const inputValue = 'Input Text Value';
uiRoutes.enable();
beforeEach(ngMock.module('kibana'));
beforeEach(
ngMock.inject(function (_$compile_, _$rootScope_, _$timeout_) {

View file

@ -263,7 +263,6 @@ export const npSetup = {
},
kibanaLegacy: {
registerLegacyApp: () => {},
registerLegacyAppAlias: () => {},
forwardApp: () => {},
config: {
defaultAppId: 'home',
@ -379,9 +378,8 @@ export const npStart = {
registerType: sinon.fake(),
},
kibanaLegacy: {
getApps: () => [],
getForwards: () => [],
getLegacyAppAliases: () => [],
loadFontAwesome: () => {},
config: {
defaultAppId: 'home',
},

View file

@ -1,10 +0,0 @@
// Needs to remain a LESS file to point to the correct path for the fonts themeselves
@import "~font-awesome/less/font-awesome";
// new file icon
.@{fa-css-prefix}-file-new-o:before { content: @fa-var-file-o; }
.@{fa-css-prefix}-file-new-o:after { content: @fa-var-plus; position: relative; margin-left: -1.0em; font-size: 0.5em; }
// alias for alert types - allows class="fa fa-{{alertType}}"
.fa-success:before { content: @fa-var-check; }
.fa-danger:before { content: @fa-var-exclamation-circle; }

View file

@ -130,7 +130,6 @@ export function uiRenderMixin(kbnServer, server, config) {
`${basePath}/node_modules/@kbn/ui-framework/dist/kui_light.css`,
`${regularBundlePath}/light_theme.style.css`,
]),
`${regularBundlePath}/commons.style.css`,
...(isCore
? []
: [
@ -155,13 +154,7 @@ export function uiRenderMixin(kbnServer, server, config) {
(filename) => `${regularBundlePath}/kbn-ui-shared-deps/${filename}`
),
`${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.jsFilename}`,
...(isCore
? []
: [
`${dllBundlePath}/vendors_runtime.bundle.dll.js`,
...dllJsChunks,
`${regularBundlePath}/commons.bundle.js`,
]),
...(isCore ? [] : [`${dllBundlePath}/vendors_runtime.bundle.dll.js`, ...dllJsChunks]),
`${regularBundlePath}/core/core.entry.js`,
...kpPluginIds.map(

View file

@ -266,13 +266,6 @@ export default class BaseOptimizer {
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: (chunk) =>
chunk.canBeInitial() && chunk.name !== 'light_theme' && chunk.name !== 'dark_theme',
minChunks: 2,
reuseExistingChunk: true,
},
light_theme: {
name: 'light_theme',
test: (m) =>

View file

@ -29,6 +29,8 @@ import { AdvancedSettings } from './advanced_settings';
import { ManagementAppMountParams } from '../../../management/public';
import { ComponentRegistry } from '../types';
import './index.scss';
const title = i18n.translate('advancedSettings.advancedSettingsLabel', {
defaultMessage: 'Advanced Settings',
});

View file

@ -68,11 +68,12 @@ export interface RenderDeps {
embeddable: EmbeddableStart;
localStorage: Storage;
share?: SharePluginStart;
config: KibanaLegacyStart['config'];
usageCollection?: UsageCollectionSetup;
navigateToDefaultApp: KibanaLegacyStart['navigateToDefaultApp'];
navigateToLegacyKibanaUrl: KibanaLegacyStart['navigateToLegacyKibanaUrl'];
scopedHistory: () => ScopedHistory;
savedObjects: SavedObjectsStart;
restorePreviousUrl: () => void;
}
let angularModuleInstance: IModule | null = null;

View file

@ -242,9 +242,17 @@ export function initDashboardApp(app, deps) {
},
})
.otherwise({
template: '<span></span>',
controller: function () {
deps.navigateToDefaultApp();
resolveRedirectTo: function ($rootScope) {
const path = window.location.hash.substr(1);
deps.restorePreviousUrl();
$rootScope.$applyAsync(() => {
const { navigated } = deps.navigateToLegacyKibanaUrl(path);
if (!navigated) {
deps.navigateToDefaultApp();
}
});
// prevent angular from completing the navigation
return new Promise(() => {});
},
});
});

View file

@ -215,7 +215,13 @@ export class DashboardPlugin
const placeholderFactory = new PlaceholderEmbeddableFactory();
embeddable.registerEmbeddableFactory(placeholderFactory.type, placeholderFactory);
const { appMounted, appUnMounted, stop: stopUrlTracker, getActiveUrl } = createKbnUrlTracker({
const {
appMounted,
appUnMounted,
stop: stopUrlTracker,
getActiveUrl,
restorePreviousUrl,
} = createKbnUrlTracker({
baseUrl: core.http.basePath.prepend('/app/dashboards'),
defaultSubUrl: `#${DashboardConstants.LANDING_PAGE_PATH}`,
storageKey: `lastUrl:${core.http.basePath.get()}:dashboard`,
@ -260,7 +266,7 @@ export class DashboardPlugin
navigation,
share: shareStart,
data: dataStart,
kibanaLegacy: { dashboardConfig, navigateToDefaultApp },
kibanaLegacy: { dashboardConfig, navigateToDefaultApp, navigateToLegacyKibanaUrl },
savedObjects,
} = pluginsStart;
@ -269,6 +275,7 @@ export class DashboardPlugin
core: coreStart,
dashboardConfig,
navigateToDefaultApp,
navigateToLegacyKibanaUrl,
navigation,
share: shareStart,
data: dataStart,
@ -277,7 +284,6 @@ export class DashboardPlugin
chrome: coreStart.chrome,
addBasePath: coreStart.http.basePath.prepend,
uiSettings: coreStart.uiSettings,
config: kibanaLegacy.config,
savedQueryService: dataStart.query.savedQueries,
embeddable: embeddableStart,
dashboardCapabilities: coreStart.application.capabilities.dashboard,
@ -289,6 +295,7 @@ export class DashboardPlugin
usageCollection,
scopedHistory: () => this.currentHistory!,
savedObjects,
restorePreviousUrl,
};
// make sure the index pattern list is up to date
await dataStart.indexPatterns.clearCache();
@ -305,6 +312,15 @@ export class DashboardPlugin
initAngularBootstrap();
core.application.register(app);
kibanaLegacy.forwardApp(
DashboardConstants.DASHBOARDS_ID,
DashboardConstants.DASHBOARDS_ID,
(path) => {
const [, tail] = /(\?.*)/.exec(path) || [];
// carry over query if it exists
return `#/list${tail || ''}`;
}
);
kibanaLegacy.forwardApp(
DashboardConstants.DASHBOARD_ID,
DashboardConstants.DASHBOARDS_ID,
@ -322,15 +338,6 @@ export class DashboardPlugin
return `#/view/${id}${tail || ''}`;
}
);
kibanaLegacy.forwardApp(
DashboardConstants.DASHBOARDS_ID,
DashboardConstants.DASHBOARDS_ID,
(path) => {
const [, tail] = /(\?.*)/.exec(path) || [];
// carry over query if it exists
return `#/list${tail || ''}`;
}
);
if (home) {
home.featureCatalogue.register({

View file

@ -198,7 +198,7 @@ export class IndexPattern implements IIndexPattern {
private updateFromElasticSearch(response: any, forceFieldRefresh: boolean = false) {
if (!response.found) {
throw new SavedObjectNotFound(type, this.id, 'kibana#/management/kibana/indexPatterns');
throw new SavedObjectNotFound(type, this.id, 'management/kibana/indexPatterns');
}
_.forOwn(this.mapping, (fieldMapping: FieldMappingSpec, name: string | undefined) => {

View file

@ -36,7 +36,7 @@ export const searchSavedObjectType: SavedObjectsType = {
},
getInAppUrl(obj) {
return {
path: `/app/discover#/${encodeURIComponent(obj.id)}`,
path: `/app/discover#/view/${encodeURIComponent(obj.id)}`,
uiCapabilitiesPath: 'discover.show',
};
},

View file

@ -2,5 +2,3 @@
.tab-discover {
overflow: hidden;
}

View file

@ -114,7 +114,7 @@ app.config(($routeProvider) => {
};
},
};
$routeProvider.when('/:id?', {
const discoverRoute = {
...defaults,
template: indexTemplate,
reloadOnSearch: false,
@ -177,7 +177,10 @@ app.config(($routeProvider) => {
});
},
},
});
};
$routeProvider.when('/view/:id?', discoverRoute);
$routeProvider.when('/', discoverRoute);
});
app.directive('discoverApp', function () {
@ -415,7 +418,7 @@ function discoverController(
testId: 'discoverOpenButton',
run: () => {
showOpenSearchPanel({
makeUrl: (searchId) => `#/${encodeURIComponent(searchId)}`,
makeUrl: (searchId) => `#/view/${encodeURIComponent(searchId)}`,
I18nContext: core.i18n.Context,
});
},
@ -747,7 +750,7 @@ function discoverController(
});
if (savedSearch.id !== $route.current.params.id) {
history.push(`/${encodeURIComponent(savedSearch.id)}`);
history.push(`/view/${encodeURIComponent(savedSearch.id)}`);
} else {
// Update defaults so that "reload saved query" functions correctly
setAppState(getStateDefaults());
@ -926,7 +929,9 @@ function discoverController(
};
$scope.resetQuery = function () {
history.push(`/${encodeURIComponent($route.current.params.id)}`);
history.push(
$route.current.params.id ? `/view/${encodeURIComponent($route.current.params.id)}` : '/'
);
$route.reload();
};

View file

@ -144,8 +144,7 @@ export function createTableRowDirective($compile: ng.ICompileService, $httpParam
cellTemplate({
timefield: true,
formatted: _displayField(row, indexPattern.timeFieldName),
filterable:
mapping(indexPattern.timeFieldName).filterable && _.isFunction($scope.filter),
filterable: mapping(indexPattern.timeFieldName).filterable && $scope.filter,
column: indexPattern.timeFieldName,
})
);
@ -156,7 +155,7 @@ export function createTableRowDirective($compile: ng.ICompileService, $httpParam
$scope.flattenedRow[column] !== undefined &&
mapping(column) &&
mapping(column).filterable &&
_.isFunction($scope.filter);
$scope.filter;
newHtmls.push(
cellTemplate({

View file

@ -25,4 +25,5 @@ import './discover';
import './doc';
import './context';
import './doc_viewer';
import './redirect';
import './directives';

View file

@ -16,8 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/
import { getAngularModule, getServices, getUrlTracker } from '../../kibana_services';
export {
ProcessedImportResponse,
processImportResponse,
} from '../../../../plugins/saved_objects_management/public/lib'; // eslint-disable-line @kbn/eslint/no-restricted-paths
getAngularModule().config(($routeProvider: any) => {
$routeProvider.otherwise({
resolveRedirectTo: ($rootScope: any) => {
const path = window.location.hash.substr(1);
getUrlTracker().restorePreviousUrl();
$rootScope.$applyAsync(() => {
const { kibanaLegacy } = getServices();
const { navigated } = kibanaLegacy.navigateToLegacyKibanaUrl(path);
if (!navigated) {
kibanaLegacy.navigateToDefaultApp();
}
});
// prevent angular from completing the navigation
return new Promise(() => {});
},
});
});

View file

@ -19,11 +19,14 @@
import './index.scss';
import angular from 'angular';
import { getServices } from '../kibana_services';
/**
* Here's where Discover's inner angular is mounted and rendered
*/
export async function renderApp(moduleName: string, element: HTMLElement) {
// do not wait for fontawesome
getServices().kibanaLegacy.loadFontAwesome();
await import('./angular');
const $injector = mountDiscoverApp(moduleName, element);
return () => $injector.get('$rootScope').$destroy();

View file

@ -42,6 +42,7 @@ import { SavedObjectKibanaServices } from 'src/plugins/saved_objects/public';
import { DiscoverStartPlugins } from './plugin';
import { createSavedSearchesLoader, SavedSearch } from './saved_searches';
import { getHistory } from './kibana_services';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
export interface DiscoverServices {
addBasePath: (path: string) => string;
@ -57,6 +58,7 @@ export interface DiscoverServices {
inspector: InspectorPublicPluginStart;
metadata: { branch: string };
share?: SharePluginStart;
kibanaLegacy: KibanaLegacyStart;
timefilter: TimefilterContract;
toastNotifications: ToastsStart;
getSavedSearchById: (id: string) => Promise<SavedSearch>;
@ -97,6 +99,7 @@ export async function buildServices(
branch: context.env.packageInfo.branch,
},
share: plugins.share,
kibanaLegacy: plugins.kibanaLegacy,
timefilter: plugins.data.query.timefilter.timefilter,
toastNotifications: core.notifications.toasts,
uiSettings: core.uiSettings,

View file

@ -53,6 +53,7 @@ export function setServices(newServices: any) {
export const [getUrlTracker, setUrlTracker] = createGetterSetter<{
setTrackedUrl: (url: string) => void;
restorePreviousUrl: () => void;
}>('urlTracker');
export const [getDocViewsRegistry, setDocViewsRegistry] = createGetterSetter<DocViewsRegistry>(

View file

@ -36,7 +36,7 @@ import { ChartsPluginStart } from 'src/plugins/charts/public';
import { NavigationPublicPluginStart as NavigationStart } from 'src/plugins/navigation/public';
import { SharePluginStart, SharePluginSetup, UrlGeneratorContract } from 'src/plugins/share/public';
import { VisualizationsStart, VisualizationsSetup } from 'src/plugins/visualizations/public';
import { KibanaLegacySetup } from 'src/plugins/kibana_legacy/public';
import { KibanaLegacySetup, KibanaLegacyStart } from 'src/plugins/kibana_legacy/public';
import { HomePublicPluginSetup } from 'src/plugins/home/public';
import { Start as InspectorPublicPluginStart } from 'src/plugins/inspector/public';
import { DataPublicPluginStart, DataPublicPluginSetup, esFilters } from '../../data/public';
@ -55,6 +55,7 @@ import {
setServices,
setScopedHistory,
getScopedHistory,
getServices,
} from './kibana_services';
import { createSavedSearchesLoader } from './saved_searches';
import { registerFeature } from './register_feature';
@ -130,6 +131,7 @@ export interface DiscoverStartPlugins {
charts: ChartsPluginStart;
data: DataPublicPluginStart;
share?: SharePluginStart;
kibanaLegacy: KibanaLegacyStart;
inspector: InspectorPublicPluginStart;
visualizations: VisualizationsStart;
}
@ -195,6 +197,7 @@ export class DiscoverPlugin
appUnMounted,
stop: stopUrlTracker,
setActiveUrl: setTrackedUrl,
restorePreviousUrl,
} = createKbnUrlTracker({
// we pass getter here instead of plain `history`,
// so history is lazily created (when app is mounted)
@ -220,7 +223,7 @@ export class DiscoverPlugin
},
],
});
setUrlTracker({ setTrackedUrl });
setUrlTracker({ setTrackedUrl, restorePreviousUrl });
this.stopUrlTracking = () => {
stopUrlTracker();
};
@ -260,7 +263,19 @@ export class DiscoverPlugin
},
});
plugins.kibanaLegacy.forwardApp('discover', 'discover');
plugins.kibanaLegacy.forwardApp('doc', 'discover', (path) => {
return `#${path}`;
});
plugins.kibanaLegacy.forwardApp('context', 'discover', (path) => {
return `#${path}`;
});
plugins.kibanaLegacy.forwardApp('discover', 'discover', (path) => {
const [, id, tail] = /discover\/([^\?]+)(.*)/.exec(path) || [];
if (!id) {
return `#${path.replace('/discover', '') || '/'}`;
}
return `#/view/${id}${tail || ''}`;
});
if (plugins.home) {
registerFeature(plugins.home);
@ -356,6 +371,7 @@ export class DiscoverPlugin
throw Error('Discover plugin getEmbeddableInjector: initializeServices is undefined');
}
const { core, plugins } = await this.initializeServices();
getServices().kibanaLegacy.loadFontAwesome();
const { getInnerAngularModuleEmbeddable } = await import('./get_inner_angular');
getInnerAngularModuleEmbeddable(
embeddableAngularName,

View file

@ -66,7 +66,7 @@ export function createSavedSearchClass(services: SavedObjectKibanaServices) {
});
this.showInRecentlyAccessed = true;
this.id = id;
this.getFullPath = () => `/app/discover#/${String(id)}`;
this.getFullPath = () => `/app/discover#/view/${String(id)}`;
}
}

View file

@ -34,7 +34,7 @@ export function createSavedSearchesLoader(services: SavedObjectKibanaServices) {
nouns: 'saved searches',
};
savedSearchLoader.urlFor = (id: string) => `#/${encodeURIComponent(id)}`;
savedSearchLoader.urlFor = (id: string) => (id ? `#/view/${encodeURIComponent(id)}` : '#/');
return savedSearchLoader;
}

View file

@ -0,0 +1,23 @@
@font-face {
font-family: 'FontAwesome';
src: url('~font-awesome/fonts/fontawesome-webfont.eot?v=4.7.0');
src: url('~font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),
url('~font-awesome/fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),
url('~font-awesome/fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),
url('~font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),
url('~font-awesome/fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}
@import "font-awesome/scss/variables";
@import "font-awesome/scss/core";
@import "font-awesome/scss/icons";
// new file icon
.#{$fa-css-prefix}-file-new-o:before { content: $fa-var-file-o; }
.#{$fa-css-prefix}-file-new-o:after { content: $fa-var-plus; position: relative; margin-left: -1.0em; font-size: 0.5em; }
// alias for alert types - allows class="fa fa-{{alertType}}"
.fa-success:before { content: $fa-var-check; }
.fa-danger:before { content: $fa-var-exclamation-circle; }

View file

@ -17,4 +17,4 @@
* under the License.
*/
@import './management_app/index';
import './font_awesome.scss';

View file

@ -22,10 +22,8 @@ import { AppNavLinkStatus } from '../../../../core/public';
import { navigateToLegacyKibanaUrl } from './navigate_to_legacy_kibana_url';
import { ForwardDefinition } from '../plugin';
export const createLegacyUrlForwardApp = (
core: CoreSetup<{}, { getForwards: () => ForwardDefinition[] }>
): App => ({
id: 'url_migrate',
export const createLegacyUrlForwardApp = (core: CoreSetup, forwards: ForwardDefinition[]): App => ({
id: 'kibana',
chromeless: true,
title: 'Legacy URL migration',
navLinkStatus: AppNavLinkStatus.hidden,
@ -33,7 +31,7 @@ export const createLegacyUrlForwardApp = (
const hash = params.history.location.hash.substr(1);
if (!hash) {
throw new Error('Could not forward URL');
core.fatalErrors.add('Could not forward URL');
}
const [
@ -41,11 +39,13 @@ export const createLegacyUrlForwardApp = (
application,
http: { basePath },
},
,
{ getForwards },
] = await core.getStartServices();
navigateToLegacyKibanaUrl(hash, getForwards(), basePath, application, window.location);
const result = await navigateToLegacyKibanaUrl(hash, forwards, basePath, application);
if (!result.navigated) {
core.fatalErrors.add('Could not forward URL');
}
return () => {};
},

View file

@ -25,7 +25,6 @@ import { coreMock } from '../../../../core/public/mocks';
describe('migrate legacy kibana urls', () => {
let forwardDefinitions: ForwardDefinition[];
let coreStart: CoreStart;
let locationMock: Location;
beforeEach(() => {
coreStart = coreMock.createStart({ basePath: '/base/path' });
@ -36,34 +35,33 @@ describe('migrate legacy kibana urls', () => {
rewritePath: jest.fn(() => '/new/path'),
},
];
locationMock = { href: '' } as Location;
});
it('should redirect to kibana if no forward definition is found', () => {
navigateToLegacyKibanaUrl(
it('should do nothing if no forward definition is found', () => {
const result = navigateToLegacyKibanaUrl(
'/myOtherApp/deep/path',
forwardDefinitions,
coreStart.http.basePath,
coreStart.application,
locationMock
coreStart.application
);
expect(locationMock.href).toEqual('/base/path/app/kibana#/myOtherApp/deep/path');
expect(result).toEqual({ navigated: false });
expect(coreStart.application.navigateToApp).not.toHaveBeenCalled();
});
it('should call navigateToApp with migrated URL', () => {
navigateToLegacyKibanaUrl(
const result = navigateToLegacyKibanaUrl(
'/myApp/deep/path',
forwardDefinitions,
coreStart.http.basePath,
coreStart.application,
locationMock
coreStart.application
);
expect(coreStart.application.navigateToApp).toHaveBeenCalledWith('updatedApp', {
path: '/new/path',
replace: true,
});
expect(forwardDefinitions[0].rewritePath).toHaveBeenCalledWith('/myApp/deep/path');
expect(locationMock.href).toEqual('');
expect(result).toEqual({ navigated: true });
});
});

View file

@ -19,30 +19,26 @@
import { ApplicationStart, IBasePath } from 'kibana/public';
import { ForwardDefinition } from '../index';
import { normalizePath } from '../utils/normalize_path';
export const navigateToLegacyKibanaUrl = (
path: string,
forwards: ForwardDefinition[],
basePath: IBasePath,
application: ApplicationStart,
location: Location
) => {
// navigate to the respective path in the legacy kibana plugin by default (for unmigrated plugins)
let targetAppId = 'kibana';
let targetAppPath = path;
application: ApplicationStart
): { navigated: boolean } => {
const normalizedPath = normalizePath(path);
// try to find an existing redirect for the target path if possible
// this avoids having to load the legacy app just to get redirected to a core application again afterwards
const relevantForward = forwards.find((forward) => path.startsWith(`/${forward.legacyAppId}`));
if (relevantForward) {
targetAppPath = relevantForward.rewritePath(path);
targetAppId = relevantForward.newAppId;
}
if (targetAppId === 'kibana') {
// exception for kibana app because redirect won't work right otherwise
location.href = basePath.prepend(`/app/kibana#${targetAppPath}`);
} else {
application.navigateToApp(targetAppId, { path: targetAppPath });
const relevantForward = forwards.find((forward) =>
normalizedPath.startsWith(`/${forward.legacyAppId}`)
);
if (!relevantForward) {
return { navigated: false };
}
const targetAppPath = relevantForward.rewritePath(normalizedPath);
const targetAppId = relevantForward.newAppId;
application.navigateToApp(targetAppId, { path: targetAppPath, replace: true });
return { navigated: true };
};

View file

@ -17,7 +17,6 @@
* under the License.
*/
import { EnvironmentMode, PackageInfo } from 'kibana/server';
import { KibanaLegacyPlugin } from './plugin';
export type Setup = jest.Mocked<ReturnType<KibanaLegacyPlugin['setup']>>;
@ -25,20 +24,9 @@ export type Start = jest.Mocked<ReturnType<KibanaLegacyPlugin['start']>>;
const createSetupContract = (): Setup => ({
forwardApp: jest.fn(),
registerLegacyAppAlias: jest.fn(),
registerLegacyApp: jest.fn(),
config: {
defaultAppId: 'home',
},
env: {} as {
mode: Readonly<EnvironmentMode>;
packageInfo: Readonly<PackageInfo>;
},
});
const createStartContract = (): Start => ({
getApps: jest.fn(),
getLegacyAppAliases: jest.fn(),
getForwards: jest.fn(),
config: {
defaultAppId: 'home',
@ -48,6 +36,8 @@ const createStartContract = (): Start => ({
getHideWriteControls: jest.fn(),
},
navigateToDefaultApp: jest.fn(),
navigateToLegacyKibanaUrl: jest.fn(),
loadFontAwesome: jest.fn(),
});
export const kibanaLegacyPluginMock = {

View file

@ -43,12 +43,7 @@ export function navigateToDefaultApp(
// when the correct app is already loaded, just set the hash to the right value
// otherwise use navigateToApp (or setting href in case of kibana app)
if (currentAppId !== targetAppId) {
if (targetAppId === 'kibana') {
// exception for kibana app because redirect won't work right otherwise
window.location.href = basePath.prepend(`/app/kibana${targetAppPath}`);
} else {
application.navigateToApp(targetAppId, { path: targetAppPath });
}
application.navigateToApp(targetAppId, { path: targetAppPath, replace: true });
} else if (overwriteHash) {
window.location.hash = targetAppPath;
}

View file

@ -17,26 +17,14 @@
* under the License.
*/
import {
App,
AppBase,
PluginInitializerContext,
AppUpdatableFields,
CoreStart,
CoreSetup,
} from 'kibana/public';
import { Observable, Subscription } from 'rxjs';
import { PluginInitializerContext, CoreStart, CoreSetup } from 'kibana/public';
import { Subscription } from 'rxjs';
import { ConfigSchema } from '../config';
import { getDashboardConfig } from './dashboard_config';
import { navigateToDefaultApp } from './navigate_to_default_app';
import { createLegacyUrlForwardApp } from './forward_app';
import { injectHeaderStyle } from './utils/inject_header_style';
interface LegacyAppAliasDefinition {
legacyAppId: string;
newAppId: string;
keepPrefix: boolean;
}
import { navigateToLegacyKibanaUrl } from './forward_app/navigate_to_legacy_kibana_url';
export interface ForwardDefinition {
legacyAppId: string;
@ -44,27 +32,7 @@ export interface ForwardDefinition {
rewritePath: (legacyPath: string) => string;
}
export type AngularRenderedAppUpdater = (
app: AppBase
) => Partial<AppUpdatableFields & { activeUrl: string }> | undefined;
export interface AngularRenderedApp extends App {
/**
* Angular rendered apps are able to update the active url in the nav link (which is currently not
* possible for actual NP apps). When regular applications have the same functionality, this type
* override can be removed.
*/
updater$?: Observable<AngularRenderedAppUpdater>;
/**
* If the active url is updated via the updater$ subject, the app id is assumed to be identical with
* the nav link id. If this is not the case, it is possible to provide another nav link id here.
*/
navLinkId?: string;
}
export class KibanaLegacyPlugin {
private apps: AngularRenderedApp[] = [];
private legacyAppAliases: LegacyAppAliasDefinition[] = [];
private forwardDefinitions: ForwardDefinition[] = [];
private currentAppId: string | undefined;
private currentAppIdSubscription: Subscription | undefined;
@ -72,57 +40,8 @@ export class KibanaLegacyPlugin {
constructor(private readonly initializerContext: PluginInitializerContext<ConfigSchema>) {}
public setup(core: CoreSetup<{}, KibanaLegacyStart>) {
core.application.register(createLegacyUrlForwardApp(core));
core.application.register(createLegacyUrlForwardApp(core, this.forwardDefinitions));
return {
/**
* @deprecated
* 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
*/
registerLegacyApp: (app: AngularRenderedApp) => {
this.apps.push(app);
},
/**
* @deprecated
* 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.
*
* This method just redirects URLs within the legacy `kibana` 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
*/
registerLegacyAppAlias: (
legacyAppId: string,
newAppId: string,
options: { keepPrefix: boolean } = { keepPrefix: false }
) => {
this.legacyAppAliases.push({ legacyAppId, newAppId, ...options });
},
/**
* Forwards URLs within the legacy `kibana` app to a new platform application.
*
@ -164,18 +83,6 @@ export class KibanaLegacyPlugin {
rewritePath: rewritePath || ((path) => `#${path.replace(`/${legacyAppId}`, '') || '/'}`),
});
},
/**
* @deprecated
* The `defaultAppId` config key is temporarily exposed to be used in the legacy platform.
* As this setting is going away, no new code should depend on it.
*/
config: this.initializerContext.config.get(),
/**
* @deprecated
* Temporarily exposing the NP env to simulate initializer contexts in the LP.
*/
env: this.initializerContext.env,
};
}
@ -186,21 +93,9 @@ export class KibanaLegacyPlugin {
injectHeaderStyle(uiSettings);
return {
/**
* Used to power dashboard mode. Should be removed when dashboard mode is removed eventually.
* @deprecated
* Just exported for wiring up with legacy platform, should not be used.
*/
getApps: () => this.apps,
/**
* @deprecated
* Just exported for wiring up with legacy platform, should not be used.
*/
getLegacyAppAliases: () => this.legacyAppAliases,
/**
* @deprecated
* Just exported for wiring up with legacy platform, should not be used.
*/
getForwards: () => this.forwardDefinitions,
config: this.initializerContext.config.get(),
dashboardConfig: getDashboardConfig(!application.capabilities.dashboard.showWriteControls),
/**
* Navigates to the app defined as kibana.defaultAppId.
@ -218,6 +113,32 @@ export class KibanaLegacyPlugin {
overwriteHash
);
},
/**
* Resolves the provided hash using the registered forwards and navigates to the target app.
* If a navigation happened, `{ navigated: true }` will be returned.
* If no matching forward is found, `{ navigated: false }` will be returned.
* @param hash
*/
navigateToLegacyKibanaUrl: (hash: string) => {
return navigateToLegacyKibanaUrl(hash, this.forwardDefinitions, basePath, application);
},
/**
* Loads the font-awesome icon font. Should be removed once the last consumer has migrated to EUI
* @deprecated
*/
loadFontAwesome: async () => {
await import('./font_awesome');
},
/**
* @deprecated
* Just exported for wiring up with legacy platform, should not be used.
*/
getForwards: () => this.forwardDefinitions,
/**
* @deprecated
* Just exported for wiring up with dashboard mode, should not be used.
*/
config: this.initializerContext.config.get(),
};
}

View file

@ -19,6 +19,7 @@
export * from './migrate_legacy_query';
export * from './system_api';
export * from './normalize_path';
// @ts-ignore
export { KbnAccessibleClickProvider } from './kbn_accessible_click';
// @ts-ignore

View file

@ -17,11 +17,11 @@
* under the License.
*/
export function injectVars(server) {
const serverConfig = server.config();
import { normalize } from 'path';
return {
autocompleteTerminateAfter: serverConfig.get('kibana.autocompleteTerminateAfter'),
autocompleteTimeout: serverConfig.get('kibana.autocompleteTimeout'),
};
export function normalizePath(path: string) {
// resolve ../ within the path
const normalizedPath = normalize(path);
// strip any leading slashes and dots and replace with single leading slash
return normalizedPath.replace(/(\.?\.?\/?)*/, '/');
}

View file

@ -38,6 +38,10 @@ export interface KbnUrlTracker {
stop: () => void;
setActiveUrl: (newUrl: string) => void;
getActiveUrl: () => string;
/**
* Resets internal state to the last active url, discarding the most recent change
*/
restorePreviousUrl: () => void;
}
/**
@ -122,6 +126,8 @@ export function createKbnUrlTracker({
}): KbnUrlTracker {
const storageInstance = storage || sessionStorage;
// local state storing previous active url to make restore possible
let previousActiveUrl: string = '';
// local state storing current listeners and active url
let activeUrl: string = '';
let unsubscribeURLHistory: UnregisterCallback | undefined;
@ -157,6 +163,7 @@ export function createKbnUrlTracker({
toastNotifications.addDanger(e.message);
}
previousActiveUrl = activeUrl;
activeUrl = getActiveSubUrl(urlWithStates || urlWithHashes);
storageInstance.setItem(storageKey, activeUrl);
}
@ -183,6 +190,7 @@ export function createKbnUrlTracker({
{ useHash: false },
baseUrl + (activeUrl || defaultSubUrl)
);
previousActiveUrl = activeUrl;
// remove baseUrl prefix (just storing the sub url part)
activeUrl = getActiveSubUrl(updatedUrl);
storageInstance.setItem(storageKey, activeUrl);
@ -198,6 +206,7 @@ export function createKbnUrlTracker({
const storedUrl = storageInstance.getItem(storageKey);
if (storedUrl) {
activeUrl = storedUrl;
previousActiveUrl = storedUrl;
setNavLink(storedUrl);
}
@ -217,5 +226,8 @@ export function createKbnUrlTracker({
getActiveUrl() {
return activeUrl;
},
restorePreviousUrl() {
activeUrl = previousActiveUrl;
},
};
}

View file

@ -1 +0,0 @@
@import './map/index';

View file

@ -44,6 +44,8 @@ import {
// @ts-ignore
import { mapTooltipProvider } from './tooltip_provider';
import './map/index.scss';
export interface MapsLegacyConfigType {
regionmap: any;
emsTileLayerId: string;

View file

@ -9,6 +9,7 @@
"visualizations",
"expressions",
"mapsLegacy",
"kibanaLegacy",
"data"
]
}

View file

@ -20,6 +20,7 @@
import { NotificationsStart } from 'kibana/public';
import { createGetterSetter } from '../../kibana_utils/public';
import { DataPublicPluginStart } from '../../data/public';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
export const [getFormatService, setFormatService] = createGetterSetter<
DataPublicPluginStart['fieldFormats']
@ -28,3 +29,7 @@ export const [getFormatService, setFormatService] = createGetterSetter<
export const [getNotifications, setNotifications] = createGetterSetter<NotificationsStart>(
'Notifications'
);
export const [getKibanaLegacy, setKibanaLegacy] = createGetterSetter<KibanaLegacyStart>(
'KibanaLegacy'
);

View file

@ -31,10 +31,11 @@ import { createRegionMapFn } from './region_map_fn';
// @ts-ignore
import { createRegionMapTypeDefinition } from './region_map_type';
import { getBaseMapsVis, IServiceSettings, MapsLegacyPluginSetup } from '../../maps_legacy/public';
import { setFormatService, setNotifications } from './kibana_services';
import { setFormatService, setNotifications, setKibanaLegacy } from './kibana_services';
import { DataPublicPluginStart } from '../../data/public';
import { RegionMapsConfigType } from './index';
import { ConfigSchema } from '../../maps_legacy/config';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
/** @private */
interface RegionMapVisualizationDependencies {
@ -55,6 +56,7 @@ export interface RegionMapPluginSetupDependencies {
export interface RegionMapPluginStartDependencies {
data: DataPublicPluginStart;
notifications: NotificationsStart;
kibanaLegacy: KibanaLegacyStart;
}
/** @internal */
@ -107,8 +109,9 @@ export class RegionMapPlugin implements Plugin<RegionMapPluginSetup, RegionMapPl
}
// @ts-ignore
public start(core: CoreStart, { data }: RegionMapPluginStartDependencies) {
public start(core: CoreStart, { data, kibanaLegacy }: RegionMapPluginStartDependencies) {
setFormatService(data.fieldFormats);
setNotifications(core.notifications);
setKibanaLegacy(kibanaLegacy);
}
}

View file

@ -19,7 +19,7 @@
import { i18n } from '@kbn/i18n';
import ChoroplethLayer from './choropleth_layer';
import { getFormatService, getNotifications } from './kibana_services';
import { getFormatService, getNotifications, getKibanaLegacy } from './kibana_services';
import { truncatedColorMaps } from '../../charts/public';
import { tooltipFormatter } from './tooltip_formatter';
import { mapTooltipProvider } from '../../maps_legacy/public';
@ -38,6 +38,7 @@ export function createRegionMapVisualization({
}
async render(esResponse, visParams) {
getKibanaLegacy().loadFontAwesome();
await super.render(esResponse, visParams);
if (this._choroplethLayer) {
await this._choroplethLayer.whenDataLoaded();

View file

@ -29,6 +29,7 @@ export {
ISavedObjectsManagementServiceRegistry,
SavedObjectsManagementServiceRegistryEntry,
} from './services';
export { ProcessedImportResponse, processImportResponse } from './lib';
export { SavedObjectRelation, SavedObjectWithMetadata, SavedObjectMetadata } from './types';
export function plugin(initializerContext: PluginInitializerContext) {

View file

@ -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 { SavedObjectMigrationFn } from 'kibana/server';
/**
* To avoid loading the client twice for old short urls pointing to the /app/kibana app,
* this PR rewrites them to point to the new platform app url_migrate instead. This app will
* migrate the url on the fly and redirect the user to the actual new location of the short url
* without loading the page again.
* @param doc
*/
export const migrateLegacyKibanaAppShortUrls: SavedObjectMigrationFn<any, any> = (doc) => ({
...doc,
attributes: {
...doc.attributes,
url:
typeof doc.attributes.url === 'string' && doc.attributes.url.startsWith('/app/kibana')
? doc.attributes.url.replace('/app/kibana', '/app/url_migrate')
: doc.attributes.url,
},
});

View file

@ -16,9 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { SavedObjectMigrationFn, SavedObjectsType } from 'kibana/server';
import { flow } from 'lodash';
import { migrateLegacyKibanaAppShortUrls } from './kibana_app_migration';
import { SavedObjectsType } from 'kibana/server';
export const url: SavedObjectsType = {
name: 'url',
@ -32,9 +30,6 @@ export const url: SavedObjectsType = {
return `/goto/${encodeURIComponent(obj.id)}`;
},
},
migrations: {
'7.9.0': flow<SavedObjectMigrationFn>(migrateLegacyKibanaAppShortUrls),
},
mappings: {
properties: {
accessCount: {

View file

@ -9,6 +9,7 @@
"visualizations",
"expressions",
"mapsLegacy",
"kibanaLegacy",
"data"
]
}

View file

@ -35,6 +35,8 @@ import { createTileMapTypeDefinition } from './tile_map_type';
import { getBaseMapsVis, MapsLegacyPluginSetup } from '../../maps_legacy/public';
import { DataPublicPluginStart } from '../../data/public';
import { setFormatService, setQueryService } from './services';
import { setKibanaLegacy } from './services';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
export interface TileMapConfigType {
tilemap: any;
@ -58,6 +60,7 @@ export interface TileMapPluginSetupDependencies {
/** @internal */
export interface TileMapPluginStartDependencies {
data: DataPublicPluginStart;
kibanaLegacy: KibanaLegacyStart;
}
export interface TileMapPluginSetup {
@ -96,9 +99,10 @@ export class TileMapPlugin implements Plugin<TileMapPluginSetup, TileMapPluginSt
};
}
public start(core: CoreStart, { data }: TileMapPluginStartDependencies) {
public start(core: CoreStart, { data, kibanaLegacy }: TileMapPluginStartDependencies) {
setFormatService(data.fieldFormats);
setQueryService(data.query);
setKibanaLegacy(kibanaLegacy);
return {};
}
}

View file

@ -19,6 +19,7 @@
import { createGetterSetter } from '../../kibana_utils/public';
import { DataPublicPluginStart } from '../../data/public';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
export const [getFormatService, setFormatService] = createGetterSetter<
DataPublicPluginStart['fieldFormats']
@ -27,3 +28,7 @@ export const [getFormatService, setFormatService] = createGetterSetter<
export const [getQueryService, setQueryService] = createGetterSetter<
DataPublicPluginStart['query']
>('Query');
export const [getKibanaLegacy, setKibanaLegacy] = createGetterSetter<KibanaLegacyStart>(
'KibanaLegacy'
);

View file

@ -19,7 +19,7 @@
import { get } from 'lodash';
import { GeohashLayer } from './geohash_layer';
import { getFormatService, getQueryService } from './services';
import { getFormatService, getQueryService, getKibanaLegacy } from './services';
import { scaleBounds, geoContains, mapTooltipProvider } from '../../maps_legacy/public';
import { tooltipFormatter } from './tooltip_formatter';
@ -60,6 +60,11 @@ export const createTileMapVisualization = (dependencies) => {
this.vis.eventsSubject.next(updateVarsObject);
};
async render(esResponse, visParams) {
getKibanaLegacy().loadFontAwesome();
await super.render(esResponse, visParams);
}
async _makeKibanaMap() {
await super._makeKibanaMap();

View file

@ -6,6 +6,7 @@
"requiredPlugins": [
"expressions",
"visualizations",
"data"
"data",
"kibanaLegacy"
]
}

View file

@ -23,7 +23,8 @@ import { VisualizationsSetup } from '../../visualizations/public';
import { createTableVisFn } from './table_vis_fn';
import { getTableVisTypeDefinition } from './table_vis_type';
import { DataPublicPluginStart } from '../../data/public';
import { setFormatService } from './services';
import { setFormatService, setKibanaLegacy } from './services';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
/** @internal */
export interface TablePluginSetupDependencies {
@ -34,6 +35,7 @@ export interface TablePluginSetupDependencies {
/** @internal */
export interface TablePluginStartDependencies {
data: DataPublicPluginStart;
kibanaLegacy: KibanaLegacyStart;
}
/** @internal */
@ -55,7 +57,8 @@ export class TableVisPlugin implements Plugin<Promise<void>, void> {
);
}
public start(core: CoreStart, { data }: TablePluginStartDependencies) {
public start(core: CoreStart, { data, kibanaLegacy }: TablePluginStartDependencies) {
setFormatService(data.fieldFormats);
setKibanaLegacy(kibanaLegacy);
}
}

View file

@ -19,7 +19,12 @@
import { createGetterSetter } from '../../kibana_utils/public';
import { DataPublicPluginStart } from '../../data/public';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
export const [getFormatService, setFormatService] = createGetterSetter<
DataPublicPluginStart['fieldFormats']
>('table data.fieldFormats');
export const [getKibanaLegacy, setKibanaLegacy] = createGetterSetter<KibanaLegacyStart>(
'table kibanaLegacy'
);

View file

@ -22,6 +22,7 @@ import $ from 'jquery';
import { VisParams, ExprVis } from '../../visualizations/public';
import { getAngularModule } from './get_inner_angular';
import { getKibanaLegacy } from './services';
import { initTableVisLegacyModule } from './table_vis_legacy_module';
const innerAngularName = 'kibana/table_vis';
@ -64,6 +65,7 @@ export function getTableVisualizationControllerClass(
}
async render(esResponse: object, visParams: VisParams) {
getKibanaLegacy().loadFontAwesome();
await this.initLocalAngular();
return new Promise(async (resolve, reject) => {

View file

@ -3,6 +3,6 @@
"version": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["charts", "data", "expressions", "visualizations"],
"requiredPlugins": ["charts", "data", "expressions", "visualizations", "kibanaLegacy"],
"optionalPlugins": ["visTypeXy"]
}

View file

@ -44,7 +44,8 @@ import {
} from './vis_type_vislib_vis_types';
import { ChartsPluginSetup } from '../../charts/public';
import { DataPublicPluginStart } from '../../data/public';
import { setFormatService, setDataActions } from './services';
import { setFormatService, setDataActions, setKibanaLegacy } from './services';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
export interface VisTypeVislibDependencies {
uiSettings: IUiSettingsClient;
@ -62,6 +63,7 @@ export interface VisTypeVislibPluginSetupDependencies {
/** @internal */
export interface VisTypeVislibPluginStartDependencies {
data: DataPublicPluginStart;
kibanaLegacy: KibanaLegacyStart;
}
type VisTypeVislibCoreSetup = CoreSetup<VisTypeVislibPluginStartDependencies, void>;
@ -109,8 +111,9 @@ export class VisTypeVislibPlugin implements Plugin<void, void> {
);
}
public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) {
public start(core: CoreStart, { data, kibanaLegacy }: VisTypeVislibPluginStartDependencies) {
setFormatService(data.fieldFormats);
setDataActions(data.actions);
setKibanaLegacy(kibanaLegacy);
}
}

View file

@ -19,6 +19,7 @@
import { createGetterSetter } from '../../kibana_utils/public';
import { DataPublicPluginStart } from '../../data/public';
import { KibanaLegacyStart } from '../../kibana_legacy/public';
export const [getDataActions, setDataActions] = createGetterSetter<
DataPublicPluginStart['actions']
@ -27,3 +28,7 @@ export const [getDataActions, setDataActions] = createGetterSetter<
export const [getFormatService, setFormatService] = createGetterSetter<
DataPublicPluginStart['fieldFormats']
>('vislib data.fieldFormats');
export const [getKibanaLegacy, setKibanaLegacy] = createGetterSetter<KibanaLegacyStart>(
'vislib kibanalegacy'
);

View file

@ -27,6 +27,7 @@ import { VisTypeVislibDependencies } from './plugin';
import { mountReactNode } from '../../../core/public/utils';
import { VisLegend, CUSTOM_LEGEND_VIS_TYPES } from './vislib/components/legend';
import { VisParams, ExprVis } from '../../visualizations/public';
import { getKibanaLegacy } from './services';
const legendClassName = {
top: 'visLib--legend-top',
@ -72,6 +73,8 @@ export const createVislibVisController = (deps: VisTypeVislibDependencies) => {
this.destroy();
}
getKibanaLegacy().loadFontAwesome();
return new Promise(async (resolve) => {
if (this.el.clientWidth === 0 || this.el.clientHeight === 0) {
return resolve();

View file

@ -244,9 +244,17 @@ export function initVisualizeApp(app, deps) {
},
})
.otherwise({
template: '<span></span>',
controller: function () {
deps.kibanaLegacy.navigateToDefaultApp();
resolveRedirectTo: function ($rootScope) {
const path = window.location.hash.substr(1);
deps.restorePreviousUrl();
$rootScope.$applyAsync(() => {
const { navigated } = deps.kibanaLegacy.navigateToLegacyKibanaUrl(path);
if (!navigated) {
deps.kibanaLegacy.navigateToDefaultApp();
}
});
// prevent angular from completing the navigation
return new Promise(() => {});
},
});
});

View file

@ -55,6 +55,7 @@ export interface VisualizeKibanaServices {
embeddable: EmbeddableStart;
I18nContext: I18nStart['Context'];
setActiveUrl: (newUrl: string) => void;
restorePreviousUrl: () => void;
createVisEmbeddableFromObject: VisualizationsStart['__LEGACY']['createVisEmbeddableFromObject'];
scopedHistory: () => ScopedHistory;
savedObjects: SavedObjectsStart;

View file

@ -73,7 +73,13 @@ export class VisualizePlugin
core: CoreSetup<VisualizePluginStartDependencies>,
{ home, kibanaLegacy, data }: VisualizePluginSetupDependencies
) {
const { appMounted, appUnMounted, stop: stopUrlTracker, setActiveUrl } = createKbnUrlTracker({
const {
appMounted,
appUnMounted,
stop: stopUrlTracker,
setActiveUrl,
restorePreviousUrl,
} = createKbnUrlTracker({
baseUrl: core.http.basePath.prepend('/app/visualize'),
defaultSubUrl: '#/',
storageKey: `lastUrl:${core.http.basePath.get()}:visualize`,
@ -136,6 +142,7 @@ export class VisualizePlugin
pluginsStart.visualizations.__LEGACY.createVisEmbeddableFromObject,
scopedHistory: () => this.currentHistory!,
savedObjects: pluginsStart.savedObjects,
restorePreviousUrl,
};
setServices(deps);

View file

@ -221,7 +221,7 @@ export default function ({ getService }: FtrProviderContext) {
editUrl:
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
path: '/app/discover#/960372e0-3224-11e8-a572-ffca06da1357',
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'discover.show',
},
});

View file

@ -283,7 +283,7 @@ export default function ({ getService }: FtrProviderContext) {
editUrl:
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
path: '/app/discover#/960372e0-3224-11e8-a572-ffca06da1357',
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'discover.show',
},
},
@ -323,7 +323,7 @@ export default function ({ getService }: FtrProviderContext) {
editUrl:
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
path: '/app/discover#/960372e0-3224-11e8-a572-ffca06da1357',
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'discover.show',
},
},
@ -366,7 +366,7 @@ export default function ({ getService }: FtrProviderContext) {
editUrl:
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
path: '/app/discover#/960372e0-3224-11e8-a572-ffca06da1357',
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'discover.show',
},
},
@ -406,7 +406,7 @@ export default function ({ getService }: FtrProviderContext) {
editUrl:
'/management/kibana/objects/savedSearches/960372e0-3224-11e8-a572-ffca06da1357',
inAppUrl: {
path: '/app/discover#/960372e0-3224-11e8-a572-ffca06da1357',
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'discover.show',
},
},

View file

@ -65,7 +65,7 @@ export default function ({ getService }) {
it('returns gzip files when no brotli version exists', () =>
supertest
.get(`/${buildNum}/bundles/commons.style.css`) // legacy optimizer does not create brotli outputs
.get(`/${buildNum}/bundles/light_theme.style.css`) // legacy optimizer does not create brotli outputs
.set('Accept-Encoding', 'gzip, br')
.expect(200)
.expect('Content-Encoding', 'gzip'));

View file

@ -58,6 +58,7 @@ export default function ({ getService, loadTestFile }) {
loadTestFile(require.resolve('./embed_mode'));
loadTestFile(require.resolve('./dashboard_back_button'));
loadTestFile(require.resolve('./dashboard_error_handling'));
loadTestFile(require.resolve('./legacy_urls'));
// Note: This one must be last because it unloads some data for one of its tests!
// No, this isn't ideal, but loading/unloading takes so much time and these are all bunched

View file

@ -0,0 +1,111 @@
/*
* 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 { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects([
'dashboard',
'header',
'common',
'timePicker',
'visualize',
'visEditor',
]);
const pieChart = getService('pieChart');
const browser = getService('browser');
const find = getService('find');
const log = getService('log');
const dashboardAddPanel = getService('dashboardAddPanel');
const listingTable = getService('listingTable');
const esArchiver = getService('esArchiver');
let kibanaLegacyBaseUrl: string;
let kibanaVisualizeBaseUrl: string;
let testDashboardId: string;
describe('legacy urls', function describeIndexTests() {
before(async function () {
await esArchiver.load('dashboard/current/kibana');
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.clickNewDashboard();
await dashboardAddPanel.addVisualization('Rendering-Test:-animal-sounds-pie');
await PageObjects.dashboard.saveDashboard('legacyTest', { waitDialogIsClosed: true });
await PageObjects.header.waitUntilLoadingHasFinished();
const currentUrl = await browser.getCurrentUrl();
await log.debug(`Current url is ${currentUrl}`);
testDashboardId = /#\/view\/(.+)\?/.exec(currentUrl)![1];
kibanaLegacyBaseUrl =
currentUrl.substring(0, currentUrl.indexOf('/app/dashboards')) + '/app/kibana';
kibanaVisualizeBaseUrl =
currentUrl.substring(0, currentUrl.indexOf('/app/dashboards')) + '/app/visualize';
await log.debug(`id is ${testDashboardId}`);
});
after(async function () {
await PageObjects.dashboard.gotoDashboardLandingPage();
await listingTable.deleteItem('legacyTest', testDashboardId);
});
describe('kibana link redirect', () => {
it('redirects from old kibana app URL', async () => {
const url = `${kibanaLegacyBaseUrl}#/dashboard/${testDashboardId}`;
await browser.get(url, true);
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.timePicker.setDefaultDataRange();
await PageObjects.dashboard.waitForRenderComplete();
await pieChart.expectPieSliceCount(5);
});
it('redirects from legacy hash in wrong app', async () => {
const url = `${kibanaVisualizeBaseUrl}#/dashboard/${testDashboardId}`;
await browser.get(url, true);
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.timePicker.setDefaultDataRange();
await PageObjects.dashboard.waitForRenderComplete();
await pieChart.expectPieSliceCount(5);
});
it('resolves markdown link', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickMarkdownWidget();
await PageObjects.visEditor.setMarkdownTxt(`[abc](#/dashboard/${testDashboardId})`);
await PageObjects.visEditor.clickGo();
(await find.byLinkText('abc')).click();
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.timePicker.setDefaultDataRange();
await PageObjects.dashboard.waitForRenderComplete();
await pieChart.expectPieSliceCount(5);
});
it('back button works', async () => {
// back to default time range
await browser.goBack();
// back to last app
await browser.goBack();
await PageObjects.visEditor.expectMarkdownTextArea();
await browser.goForward();
});
});
});
}

View file

@ -109,7 +109,7 @@ export default function ({ getService, getPageObjects }) {
const expectedUrl =
baseUrl +
'/app/discover#' +
'/ab12e3c0-f231-11e6-9486-733b1ac9221a' +
'/view/ab12e3c0-f231-11e6-9486-733b1ac9221a' +
'?_g=(filters%3A!()%2CrefreshInterval%3A(pause%3A!t%2Cvalue%3A0)' +
"%2Ctime%3A(from%3A'2015-09-19T06%3A31%3A44.000Z'%2C" +
"to%3A'2015-09-23T18%3A31%3A44.000Z'))";

View file

@ -230,6 +230,10 @@ export function VisualizeEditorPageProvider({ getService, getPageObjects }: FtrP
await testSubjects.click('dropPartialBucketsCheckbox');
}
public async expectMarkdownTextArea() {
await testSubjects.existOrFail('markdownTextarea');
}
public async setMarkdownTxt(markdownTxt: string) {
const input = await testSubjects.find('markdownTextarea');
await input.clearValue();

View file

@ -4,7 +4,7 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["licensing", "data", "navigation", "savedObjects"],
"requiredPlugins": ["licensing", "data", "navigation", "savedObjects", "kibanaLegacy"],
"optionalPlugins": ["home", "features"],
"configPath": ["xpack", "graph"]
}

View file

@ -35,6 +35,7 @@ import {
configureAppAngularModule,
createTopNavDirective,
createTopNavHelper,
KibanaLegacyStart,
} from '../../../../src/plugins/kibana_legacy/public';
import './index.scss';
@ -67,9 +68,11 @@ export interface GraphDependencies {
graphSavePolicy: string;
overlays: OverlayStart;
savedObjects: SavedObjectsStart;
kibanaLegacy: KibanaLegacyStart;
}
export const renderApp = ({ appBasePath, element, ...deps }: GraphDependencies) => {
export const renderApp = ({ appBasePath, element, kibanaLegacy, ...deps }: GraphDependencies) => {
kibanaLegacy.loadFontAwesome();
const graphAngularModule = createLocalAngularModule(deps.navigation);
configureAppAngularModule(
graphAngularModule,

View file

@ -10,7 +10,10 @@ import { AppMountParameters, Plugin } from 'src/core/public';
import { PluginInitializerContext } from 'kibana/public';
import { Storage } from '../../../../src/plugins/kibana_utils/public';
import { initAngularBootstrap } from '../../../../src/plugins/kibana_legacy/public';
import {
initAngularBootstrap,
KibanaLegacyStart,
} from '../../../../src/plugins/kibana_legacy/public';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../src/plugins/navigation/public';
import { DataPublicPluginStart } from '../../../../src/plugins/data/public';
@ -34,6 +37,7 @@ export interface GraphPluginStartDependencies {
navigation: NavigationStart;
data: DataPublicPluginStart;
savedObjects: SavedObjectsStart;
kibanaLegacy: KibanaLegacyStart;
}
export class GraphPlugin
@ -85,6 +89,7 @@ export class GraphPlugin
core: coreStart,
navigation: pluginsStart.navigation,
data: pluginsStart.data,
kibanaLegacy: pluginsStart.kibanaLegacy,
savedObjectsClient: coreStart.savedObjects.client,
addBasePath: core.http.basePath.prepend,
getBasePath: core.http.basePath.get,

View file

@ -15,7 +15,8 @@
"usageCollection",
"share",
"embeddable",
"uiActions"
"uiActions",
"kibanaLegacy"
],
"optionalPlugins": [
"security",

View file

@ -78,6 +78,8 @@ export const renderApp = (
urlGenerators: deps.share.urlGenerators,
});
deps.kibanaLegacy.loadFontAwesome();
const mlLicense = setLicenseCache(deps.licensing);
appMountParams.onAppLeave((actions) => actions.default());

View file

@ -30,10 +30,12 @@ import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/public';
import { registerEmbeddables } from './embeddables';
import { UiActionsSetup } from '../../../../src/plugins/ui_actions/public';
import { registerMlUiActions } from './ui_actions';
import { KibanaLegacyStart } from '../../../../src/plugins/kibana_legacy/public';
export interface MlStartDependencies {
data: DataPublicPluginStart;
share: SharePluginStart;
kibanaLegacy: KibanaLegacyStart;
}
export interface MlSetupDependencies {
security?: SecurityPluginSetup;
@ -70,6 +72,7 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> {
{
data: pluginsStart.data,
share: pluginsStart.share,
kibanaLegacy: pluginsStart.kibanaLegacy,
security: pluginsSetup.security,
licensing: pluginsSetup.licensing,
management: pluginsSetup.management,

View file

@ -25,12 +25,22 @@ export class AngularApp {
isCloud,
pluginInitializerContext,
externalConfig,
kibanaLegacy,
} = deps;
const app: IModule = localAppModule(deps);
app.run(($injector: angular.auto.IInjectorService) => {
this.injector = $injector;
Legacy.init(
{ core, element, data, navigation, isCloud, pluginInitializerContext, externalConfig },
{
core,
element,
data,
navigation,
isCloud,
pluginInitializerContext,
externalConfig,
kibanaLegacy,
},
this.injector
);
});

View file

@ -70,6 +70,7 @@ export class MonitoringPlugin
const { AngularApp } = await import('./angular');
const deps: MonitoringPluginDependencies = {
navigation: pluginsStart.navigation,
kibanaLegacy: pluginsStart.kibanaLegacy,
element: params.element,
core: coreStart,
data: pluginsStart.data,
@ -78,6 +79,7 @@ export class MonitoringPlugin
externalConfig: this.getExternalConfig(),
};
pluginsStart.kibanaLegacy.loadFontAwesome();
this.setInitialTimefilter(deps);
this.overrideAlertingEmailDefaults(deps);

View file

@ -7,6 +7,7 @@
import { PluginInitializerContext, CoreStart } from 'kibana/public';
import { NavigationPublicPluginStart as NavigationStart } from '../../../../src/plugins/navigation/public';
import { DataPublicPluginStart } from '../../../../src/plugins/data/public';
import { KibanaLegacyStart } from '../../../../src/plugins/kibana_legacy/public';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
export { MonitoringConfig } from '../server';
@ -14,6 +15,7 @@ export { MonitoringConfig } from '../server';
export interface MonitoringPluginDependencies {
navigation: NavigationStart;
data: DataPublicPluginStart;
kibanaLegacy: KibanaLegacyStart;
element: HTMLElement;
core: CoreStart;
isCloud: boolean;

View file

@ -22,10 +22,6 @@ import { mapValues } from 'lodash';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { ToastsStart } from 'src/core/public';
import {
ProcessedImportResponse,
processImportResponse,
} from '../../../../../../src/legacy/core_plugins/kibana/public';
import { SavedObjectsManagementRecord } from '../../../../../../src/plugins/saved_objects_management/public';
import { Space } from '../../../common/model/space';
import { SpacesManager } from '../../spaces_manager';
@ -33,6 +29,10 @@ import { ProcessingCopyToSpace } from './processing_copy_to_space';
import { CopyToSpaceFlyoutFooter } from './copy_to_space_flyout_footer';
import { CopyToSpaceForm } from './copy_to_space_form';
import { CopyOptions, ImportRetry } from '../types';
import {
ProcessedImportResponse,
processImportResponse,
} from '../../../../../../src/plugins/saved_objects_management/public';
interface Props {
onClose: () => void;

View file

@ -8,8 +8,8 @@ import React, { Fragment } from 'react';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiStat, EuiHorizontalRule } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { ProcessedImportResponse } from '../../../../../../src/legacy/core_plugins/kibana/public';
import { ImportRetry } from '../types';
import { ProcessedImportResponse } from '../../../../../../src/plugins/saved_objects_management/public';
interface Props {
copyInProgress: boolean;

View file

@ -13,8 +13,10 @@ import {
EuiHorizontalRule,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { ProcessedImportResponse } from '../../../../../../src/legacy/core_plugins/kibana/public';
import { SavedObjectsManagementRecord } from '../../../../../../src/plugins/saved_objects_management/public';
import {
ProcessedImportResponse,
SavedObjectsManagementRecord,
} from 'src/plugins/saved_objects_management/public';
import { Space } from '../../../common/model/space';
import { CopyOptions, ImportRetry } from '../types';
import { SpaceResult } from './space_result';

View file

@ -5,7 +5,7 @@
*/
import { summarizeCopyResult } from './summarize_copy_result';
import { ProcessedImportResponse } from 'src/legacy/core_plugins/kibana/public';
import { ProcessedImportResponse } from 'src/plugins/saved_objects_management/public';
const createSavedObjectsManagementRecord = () => ({
type: 'dashboard',

View file

@ -4,8 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ProcessedImportResponse } from 'src/legacy/core_plugins/kibana/public';
import { SavedObjectsManagementRecord } from 'src/plugins/saved_objects_management/public';
import {
SavedObjectsManagementRecord,
ProcessedImportResponse,
} from 'src/plugins/saved_objects_management/public';
export interface SummarizedSavedObjectResult {
type: string;