mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Visualize] Shim with local application service (#49891)
* Add dashboard updates * Use I18nProvider instead of I18nContext * remove unused dependencies * Centralizing and cleaning up legacy imports * Fix merge conflict * fix merge bugs and rename main dynamic entrypoint * Rename app to legacy_app * Clear deps * fix jest tests * fix saved object finder bug * Fix unit tests * Ignore TS * revert using stateless component for this PR * fix types * Fix merge conflicts * Update deps * Revert filter bar export * Revert ts-ignore * Clean up * Refactoring * Fix test * Remove global_state_sync * Refactoring * Remove uiExports/embeddableFactories * Trigger digest cycle in local angular when vis is changed. * Fix TS * Revert back syncOnMount * Add missed import * Revert import 'uiExports/embeddableFactories' * Update app navigation func test * Update app navigation func test * Update app navigation func test * Remove 'kibana-install-dir' arg in pluginFunctionalTestsRelease * Fix review comments * Fix code review comments * Rename alias * Fix indexPatterns * Use IndexPatternsContract interface
This commit is contained in:
parent
23edb41739
commit
33989b0805
38 changed files with 1113 additions and 474 deletions
|
@ -62,6 +62,7 @@ export default function (kibana) {
|
|||
hacks: [
|
||||
'plugins/kibana/discover',
|
||||
'plugins/kibana/dev_tools',
|
||||
'plugins/kibana/visualize',
|
||||
],
|
||||
savedObjectTypes: [
|
||||
'plugins/kibana/visualize/saved_visualizations/saved_visualization_register',
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
-->
|
||||
<kbn-top-nav
|
||||
ng-if="showFilterBar() && !isVisible"
|
||||
|
||||
|
||||
app-name="'dashboard'"
|
||||
show-search-bar="true"
|
||||
show-filter-bar="true"
|
||||
|
|
|
@ -29,7 +29,6 @@ import { npSetup } from 'ui/new_platform';
|
|||
import 'uiExports/home';
|
||||
import 'uiExports/visTypes';
|
||||
|
||||
import 'uiExports/visEditorTypes';
|
||||
import 'uiExports/visualize';
|
||||
import 'uiExports/savedObjectTypes';
|
||||
import 'uiExports/fieldFormatEditors';
|
||||
|
|
193
src/legacy/core_plugins/kibana/public/visualize/application.ts
Normal file
193
src/legacy/core_plugins/kibana/public/visualize/application.ts
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* 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 angular, { IModule } from 'angular';
|
||||
import { EuiConfirmModal } from '@elastic/eui';
|
||||
import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular';
|
||||
|
||||
import { AppMountContext, LegacyCoreStart } from 'kibana/public';
|
||||
import {
|
||||
AppStateProvider,
|
||||
AppState,
|
||||
configureAppAngularModule,
|
||||
confirmModalFactory,
|
||||
createTopNavDirective,
|
||||
createTopNavHelper,
|
||||
EventsProvider,
|
||||
GlobalStateProvider,
|
||||
KbnUrlProvider,
|
||||
RedirectWhenMissingProvider,
|
||||
IPrivate,
|
||||
PersistedState,
|
||||
PrivateProvider,
|
||||
PromiseServiceCreator,
|
||||
StateManagementConfigProvider,
|
||||
} from './legacy_imports';
|
||||
import { NavigationStart } from '../../../navigation/public';
|
||||
|
||||
// @ts-ignore
|
||||
import { initVisualizeApp } from './legacy_app';
|
||||
import { VisualizeKibanaServices } from './kibana_services';
|
||||
|
||||
let angularModuleInstance: IModule | null = null;
|
||||
|
||||
export const renderApp = async (
|
||||
element: HTMLElement,
|
||||
appBasePath: string,
|
||||
deps: VisualizeKibanaServices
|
||||
) => {
|
||||
if (!angularModuleInstance) {
|
||||
angularModuleInstance = createLocalAngularModule(deps.core, deps.navigation);
|
||||
// global routing stuff
|
||||
configureAppAngularModule(angularModuleInstance, deps.core as LegacyCoreStart, true);
|
||||
// custom routing stuff
|
||||
initVisualizeApp(angularModuleInstance, deps);
|
||||
}
|
||||
const $injector = mountVisualizeApp(appBasePath, element);
|
||||
return () => $injector.get('$rootScope').$destroy();
|
||||
};
|
||||
|
||||
const mainTemplate = (basePath: string) => `<div style="height: 100%">
|
||||
<base href="${basePath}" />
|
||||
<div ng-view style="height: 100%;"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const moduleName = 'app/visualize';
|
||||
|
||||
const thirdPartyAngularDependencies = ['ngSanitize', 'ngRoute', 'react'];
|
||||
|
||||
function mountVisualizeApp(appBasePath: string, element: HTMLElement) {
|
||||
const mountpoint = document.createElement('div');
|
||||
mountpoint.setAttribute('style', 'height: 100%');
|
||||
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
|
||||
element.appendChild(mountpoint);
|
||||
return $injector;
|
||||
}
|
||||
|
||||
function createLocalAngularModule(core: AppMountContext['core'], navigation: NavigationStart) {
|
||||
createLocalI18nModule();
|
||||
createLocalPrivateModule();
|
||||
createLocalPromiseModule();
|
||||
createLocalConfigModule(core);
|
||||
createLocalKbnUrlModule();
|
||||
createLocalStateModule();
|
||||
createLocalPersistedStateModule();
|
||||
createLocalTopNavModule(navigation);
|
||||
createLocalConfirmModalModule();
|
||||
|
||||
const visualizeAngularModule: IModule = angular.module(moduleName, [
|
||||
...thirdPartyAngularDependencies,
|
||||
'app/visualize/Config',
|
||||
'app/visualize/I18n',
|
||||
'app/visualize/Private',
|
||||
'app/visualize/PersistedState',
|
||||
'app/visualize/TopNav',
|
||||
'app/visualize/State',
|
||||
'app/visualize/ConfirmModal',
|
||||
]);
|
||||
return visualizeAngularModule;
|
||||
}
|
||||
|
||||
function createLocalConfirmModalModule() {
|
||||
angular
|
||||
.module('app/visualize/ConfirmModal', ['react'])
|
||||
.factory('confirmModal', confirmModalFactory)
|
||||
.directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal));
|
||||
}
|
||||
|
||||
function createLocalStateModule() {
|
||||
angular
|
||||
.module('app/visualize/State', [
|
||||
'app/visualize/Private',
|
||||
'app/visualize/Config',
|
||||
'app/visualize/KbnUrl',
|
||||
'app/visualize/Promise',
|
||||
'app/visualize/PersistedState',
|
||||
])
|
||||
.factory('AppState', function(Private: IPrivate) {
|
||||
return Private(AppStateProvider);
|
||||
})
|
||||
.service('getAppState', function(Private: IPrivate) {
|
||||
return Private<AppState>(AppStateProvider).getAppState;
|
||||
})
|
||||
.service('globalState', function(Private: IPrivate) {
|
||||
return Private(GlobalStateProvider);
|
||||
});
|
||||
}
|
||||
|
||||
function createLocalPersistedStateModule() {
|
||||
angular
|
||||
.module('app/visualize/PersistedState', ['app/visualize/Private', 'app/visualize/Promise'])
|
||||
.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('app/visualize/KbnUrl', ['app/visualize/Private', 'ngRoute'])
|
||||
.service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider))
|
||||
.service('redirectWhenMissing', (Private: IPrivate) => Private(RedirectWhenMissingProvider));
|
||||
}
|
||||
|
||||
function createLocalConfigModule(core: AppMountContext['core']) {
|
||||
angular
|
||||
.module('app/visualize/Config', ['app/visualize/Private'])
|
||||
.provider('stateManagementConfig', StateManagementConfigProvider)
|
||||
.provider('config', () => {
|
||||
return {
|
||||
$get: () => ({
|
||||
get: core.uiSettings.get.bind(core.uiSettings),
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function createLocalPromiseModule() {
|
||||
angular.module('app/visualize/Promise', []).service('Promise', PromiseServiceCreator);
|
||||
}
|
||||
|
||||
function createLocalPrivateModule() {
|
||||
angular.module('app/visualize/Private', []).provider('Private', PrivateProvider);
|
||||
}
|
||||
|
||||
function createLocalTopNavModule(navigation: NavigationStart) {
|
||||
angular
|
||||
.module('app/visualize/TopNav', ['react'])
|
||||
.directive('kbnTopNav', createTopNavDirective)
|
||||
.directive('kbnTopNavHelper', createTopNavHelper(navigation.ui));
|
||||
}
|
||||
|
||||
function createLocalI18nModule() {
|
||||
angular
|
||||
.module('app/visualize/I18n', [])
|
||||
.provider('i18n', I18nProvider)
|
||||
.filter('i18n', i18nFilter)
|
||||
.directive('i18nId', i18nDirective);
|
||||
}
|
|
@ -39,7 +39,7 @@
|
|||
show-search-bar="true"
|
||||
show-query-bar="true"
|
||||
show-query-input="showQueryInput()"
|
||||
show-filter-bar="showFilterBar() && chrome.getVisible()"
|
||||
show-filter-bar="showFilterBar() && isVisible"
|
||||
show-date-picker="showQueryBarTimePicker()"
|
||||
show-auto-refresh-only="!showQueryBarTimePicker()"
|
||||
query="state.query"
|
||||
|
@ -67,7 +67,7 @@
|
|||
-->
|
||||
<kbn-top-nav
|
||||
ng-if="showFilterBar() && !isVisible"
|
||||
|
||||
|
||||
app-name="'visualize'"
|
||||
show-search-bar="true"
|
||||
show-filter-bar="true"
|
||||
|
@ -91,7 +91,7 @@
|
|||
</div>
|
||||
|
||||
<visualization-embedded
|
||||
ng-if="!chrome.getVisible()"
|
||||
ng-if="!isVisible"
|
||||
class="visualize"
|
||||
saved-obj="savedVis"
|
||||
ui-state="uiState"
|
||||
|
@ -110,7 +110,7 @@
|
|||
>
|
||||
</h1>
|
||||
<visualization-editor
|
||||
ng-if="chrome.getVisible()"
|
||||
ng-if="isVisible"
|
||||
saved-obj="savedVis"
|
||||
ui-state="uiState"
|
||||
time-range="timeRange"
|
||||
|
|
|
@ -17,27 +17,27 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import '../saved_visualizations/saved_visualizations';
|
||||
import './visualization_editor';
|
||||
import './visualization';
|
||||
|
||||
import { ensureDefaultIndexPattern } from 'ui/legacy_compat';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { migrateAppState } from './lib';
|
||||
import editorTemplate from './editor.html';
|
||||
import { DashboardConstants } from '../../dashboard/dashboard_constants';
|
||||
import { VisualizeConstants } from '../visualize_constants';
|
||||
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
|
||||
import { getEditBreadcrumbs } from '../breadcrumbs';
|
||||
|
||||
import { addHelpMenuToAppChrome } from '../help_menu/help_menu_util';
|
||||
import { FilterStateManager } from '../../../../data/public/filter/filter_manager';
|
||||
import { unhashUrl } from '../../../../../../plugins/kibana_utils/public';
|
||||
|
||||
import { initVisEditorDirective } from './visualization_editor';
|
||||
import { initVisualizationDirective } from './visualization';
|
||||
|
||||
import {
|
||||
getServices,
|
||||
angular,
|
||||
absoluteToParsedUrl,
|
||||
KibanaParsedUrl,
|
||||
migrateLegacyQuery,
|
||||
|
@ -45,108 +45,24 @@ import {
|
|||
showSaveModal,
|
||||
stateMonitorFactory,
|
||||
subscribeWithScope,
|
||||
unhashUrl
|
||||
} from '../kibana_services';
|
||||
} from '../legacy_imports';
|
||||
|
||||
const {
|
||||
core,
|
||||
capabilities,
|
||||
chrome,
|
||||
chromeLegacy,
|
||||
npData,
|
||||
docTitle,
|
||||
FilterBarQueryFilterProvider,
|
||||
getBasePath,
|
||||
toastNotifications,
|
||||
uiModules,
|
||||
uiRoutes,
|
||||
visualizations,
|
||||
share,
|
||||
} = getServices();
|
||||
import { getServices } from '../kibana_services';
|
||||
|
||||
const savedQueryService = npData.query.savedQueries;
|
||||
const { timefilter } = npData.query.timefilter;
|
||||
|
||||
uiRoutes
|
||||
.when(VisualizeConstants.CREATE_PATH, {
|
||||
template: editorTemplate,
|
||||
k7Breadcrumbs: getCreateBreadcrumbs,
|
||||
resolve: {
|
||||
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;
|
||||
const hasIndex = $route.current.params.indexPattern || $route.current.params.savedSearchId;
|
||||
if (shouldHaveIndex && !hasIndex) {
|
||||
throw new Error(
|
||||
i18n.translate('kbn.visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage', {
|
||||
defaultMessage: 'You must provide either an indexPattern or a savedSearchId',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return ensureDefaultIndexPattern(core, npData, $rootScope, kbnUrl).then(() => savedVisualizations.get($route.current.params))
|
||||
.then(savedVis => {
|
||||
if (savedVis.vis.type.setup) {
|
||||
return savedVis.vis.type.setup(savedVis)
|
||||
.catch(() => savedVis);
|
||||
}
|
||||
return savedVis;
|
||||
})
|
||||
.catch(redirectWhenMissing({
|
||||
'*': '/visualize'
|
||||
}));
|
||||
}
|
||||
}
|
||||
})
|
||||
.when(`${VisualizeConstants.EDIT_PATH}/:id`, {
|
||||
template: editorTemplate,
|
||||
k7Breadcrumbs: getEditBreadcrumbs,
|
||||
resolve: {
|
||||
savedVis: function (savedVisualizations, redirectWhenMissing, $route, $rootScope, kbnUrl) {
|
||||
return ensureDefaultIndexPattern(core, npData, $rootScope, kbnUrl)
|
||||
.then(() => savedVisualizations.get($route.current.params.id))
|
||||
.then((savedVis) => {
|
||||
chrome.recentlyAccessed.add(
|
||||
savedVis.getFullPath(),
|
||||
savedVis.title,
|
||||
savedVis.id
|
||||
);
|
||||
return savedVis;
|
||||
})
|
||||
.then(savedVis => {
|
||||
if (savedVis.vis.type.setup) {
|
||||
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,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
uiModules
|
||||
.get('app/visualize', [
|
||||
'kibana/url'
|
||||
])
|
||||
.directive('visualizeApp', function () {
|
||||
export function initEditorDirective(app, deps) {
|
||||
app.directive('visualizeApp', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
controllerAs: 'visualizeApp',
|
||||
controller: VisEditor,
|
||||
controller: VisualizeAppController,
|
||||
};
|
||||
});
|
||||
|
||||
function VisEditor(
|
||||
initVisEditorDirective(app, deps);
|
||||
initVisualizationDirective(app, deps);
|
||||
}
|
||||
|
||||
function VisualizeAppController(
|
||||
$scope,
|
||||
$element,
|
||||
$route,
|
||||
|
@ -154,19 +70,42 @@ function VisEditor(
|
|||
$window,
|
||||
$injector,
|
||||
$timeout,
|
||||
indexPatterns,
|
||||
kbnUrl,
|
||||
redirectWhenMissing,
|
||||
Private,
|
||||
Promise,
|
||||
config,
|
||||
kbnBaseUrl,
|
||||
localStorage,
|
||||
getAppState,
|
||||
globalState,
|
||||
) {
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const {
|
||||
indexPatterns,
|
||||
localStorage,
|
||||
visualizeCapabilities,
|
||||
share,
|
||||
data: {
|
||||
query: {
|
||||
filterManager,
|
||||
timefilter: { timefilter },
|
||||
},
|
||||
},
|
||||
toastNotifications,
|
||||
legacyChrome,
|
||||
chrome,
|
||||
getBasePath,
|
||||
core: { docLinks },
|
||||
savedQueryService,
|
||||
uiSettings,
|
||||
} = getServices();
|
||||
|
||||
const filterStateManager = new FilterStateManager(globalState, getAppState, filterManager);
|
||||
const queryFilter = filterManager;
|
||||
// Retrieve the resolved SavedVis instance.
|
||||
const savedVis = $route.current.locals.savedVis;
|
||||
const _applyVis = () => {
|
||||
$scope.$apply();
|
||||
};
|
||||
// This will trigger a digest cycle. This is needed when vis is updated from a global angular like in visualize_embeddable.js.
|
||||
savedVis.vis.on('apply', _applyVis);
|
||||
// vis is instance of src/legacy/ui/public/vis/vis.js.
|
||||
// SearchSource is a promise-based stream of search results that can inherit from other search sources.
|
||||
const { vis, searchSource } = savedVis;
|
||||
|
@ -177,7 +116,7 @@ function VisEditor(
|
|||
dirty: !savedVis.id
|
||||
};
|
||||
|
||||
$scope.topNavMenu = [...(capabilities.visualize.save ? [{
|
||||
$scope.topNavMenu = [...(visualizeCapabilities.save ? [{
|
||||
id: 'save',
|
||||
label: i18n.translate('kbn.topNavMenu.saveVisualizationButtonLabel', { defaultMessage: 'save' }),
|
||||
description: i18n.translate('kbn.visualize.topNavMenu.saveVisualizationButtonAriaLabel', {
|
||||
|
@ -246,7 +185,7 @@ function VisEditor(
|
|||
share.toggleShareContextMenu({
|
||||
anchorElement,
|
||||
allowEmbed: true,
|
||||
allowShortUrl: capabilities.visualize.createShortUrl,
|
||||
allowShortUrl: visualizeCapabilities.createShortUrl,
|
||||
shareableUrl: unhashUrl(window.location.href),
|
||||
objectId: savedVis.id,
|
||||
objectType: 'visualization',
|
||||
|
@ -295,7 +234,7 @@ function VisEditor(
|
|||
let stateMonitor;
|
||||
|
||||
if (savedVis.id) {
|
||||
docTitle.change(savedVis.title);
|
||||
chrome.docTitle.change(savedVis.title);
|
||||
}
|
||||
|
||||
// Extract visualization state with filtered aggs. You can see these filtered aggs in the URL.
|
||||
|
@ -306,7 +245,7 @@ function VisEditor(
|
|||
linked: !!savedVis.savedSearchId,
|
||||
query: searchSource.getOwnField('query') || {
|
||||
query: '',
|
||||
language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage')
|
||||
language: localStorage.get('kibana.userQueryLanguage') || uiSettings.get('search:queryLanguage')
|
||||
},
|
||||
filters: searchSource.getOwnField('filter') || [],
|
||||
vis: savedVisState
|
||||
|
@ -345,9 +284,9 @@ function VisEditor(
|
|||
queryFilter.setFilters(filters);
|
||||
};
|
||||
|
||||
$scope.showSaveQuery = capabilities.visualize.saveQuery;
|
||||
$scope.showSaveQuery = visualizeCapabilities.saveQuery;
|
||||
|
||||
$scope.$watch(() => capabilities.visualize.saveQuery, (newCapability) => {
|
||||
$scope.$watch(() => visualizeCapabilities.saveQuery, (newCapability) => {
|
||||
$scope.showSaveQuery = newCapability;
|
||||
});
|
||||
|
||||
|
@ -455,13 +394,15 @@ function VisEditor(
|
|||
}
|
||||
}));
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$scope.$on('$destroy', () => {
|
||||
if ($scope._handler) {
|
||||
$scope._handler.destroy();
|
||||
}
|
||||
savedVis.destroy();
|
||||
stateMonitor.destroy();
|
||||
filterStateManager.destroy();
|
||||
subscriptions.unsubscribe();
|
||||
$scope.vis.off('apply', _applyVis);
|
||||
});
|
||||
|
||||
|
||||
|
@ -503,7 +444,7 @@ function VisEditor(
|
|||
delete $state.savedQuery;
|
||||
$state.query = {
|
||||
query: '',
|
||||
language: localStorage.get('kibana.userQueryLanguage') || config.get('search:queryLanguage')
|
||||
language: localStorage.get('kibana.userQueryLanguage') || uiSettings.get('search:queryLanguage')
|
||||
};
|
||||
queryFilter.removeAll();
|
||||
$state.save();
|
||||
|
@ -589,14 +530,14 @@ 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.
|
||||
chromeLegacy.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl);
|
||||
legacyChrome.trackSubUrlForApp('kibana:visualize', savedVisualizationParsedUrl);
|
||||
|
||||
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.docTitle.change(savedVis.lastSavedTitle);
|
||||
chrome.setBreadcrumbs($injector.invoke(getEditBreadcrumbs));
|
||||
savedVis.vis.title = savedVis.title;
|
||||
savedVis.vis.description = savedVis.description;
|
||||
|
@ -661,7 +602,7 @@ function VisEditor(
|
|||
vis.type.feedbackMessage;
|
||||
};
|
||||
|
||||
addHelpMenuToAppChrome(chrome);
|
||||
addHelpMenuToAppChrome(chrome, docLinks);
|
||||
|
||||
init();
|
||||
}
|
||||
|
|
|
@ -17,13 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { getServices } from '../kibana_services';
|
||||
|
||||
const { embeddables, uiModules } = getServices();
|
||||
|
||||
uiModules
|
||||
.get('kibana/directive', ['ngSanitize'])
|
||||
.directive('visualizationEmbedded', function (Private, $timeout, getAppState) {
|
||||
export function initVisualizationDirective(app, deps) {
|
||||
app.directive('visualizationEmbedded', function ($timeout, getAppState) {
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
|
@ -37,7 +32,7 @@ uiModules
|
|||
link: function ($scope, element) {
|
||||
$scope.renderFunction = async () => {
|
||||
if (!$scope._handler) {
|
||||
$scope._handler = await embeddables.getEmbeddableFactory('visualization').createFromObject($scope.savedObj, {
|
||||
$scope._handler = await deps.embeddables.getEmbeddableFactory('visualization').createFromObject($scope.savedObj, {
|
||||
timeRange: $scope.timeRange,
|
||||
filters: $scope.filters || [],
|
||||
query: $scope.query,
|
||||
|
@ -66,3 +61,4 @@ uiModules
|
|||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,15 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { getServices, VisEditorTypesRegistryProvider } from '../kibana_services';
|
||||
|
||||
const { uiModules } = getServices();
|
||||
|
||||
uiModules
|
||||
.get('kibana/directive', ['ngSanitize'])
|
||||
.directive('visualizationEditor', function (Private, $timeout, getAppState) {
|
||||
const editorTypes = Private(VisEditorTypesRegistryProvider);
|
||||
|
||||
export function initVisEditorDirective(app, deps) {
|
||||
app.directive('visualizationEditor', function ($timeout, getAppState) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
|
@ -38,7 +31,8 @@ uiModules
|
|||
link: function ($scope, element) {
|
||||
const editorType = $scope.savedObj.vis.type.editor;
|
||||
const Editor = typeof editorType === 'function' ? editorType :
|
||||
editorTypes.find(editor => editor.key === editorType);
|
||||
deps.editorTypes.find(editor => editor.key === editorType);
|
||||
|
||||
const editor = new Editor(element[0], $scope.savedObj);
|
||||
|
||||
$scope.renderFunction = () => {
|
||||
|
@ -62,3 +56,4 @@ uiModules
|
|||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,8 +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';
|
||||
|
|
|
@ -17,11 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { getServices, getFromSavedObject, VisSavedObject } from '../kibana_services';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
|
||||
import { IIndexPattern } from '../../../../../../plugins/data/public';
|
||||
|
||||
const { savedObjectsClient, uiSettings } = getServices();
|
||||
import { VisSavedObject } from './visualize_embeddable';
|
||||
import { indexPatterns, IIndexPattern } from '../../../../../../plugins/data/public';
|
||||
|
||||
export async function getIndexPattern(
|
||||
savedVis: VisSavedObject
|
||||
|
@ -30,7 +29,8 @@ export async function getIndexPattern(
|
|||
return savedVis.vis.indexPattern;
|
||||
}
|
||||
|
||||
const defaultIndex = uiSettings.get('defaultIndex');
|
||||
const savedObjectsClient = npStart.core.savedObjects.client;
|
||||
const defaultIndex = npStart.core.uiSettings.get('defaultIndex');
|
||||
|
||||
if (savedVis.vis.params.index_pattern) {
|
||||
const indexPatternObjects = await savedObjectsClient.find({
|
||||
|
@ -39,10 +39,10 @@ export async function getIndexPattern(
|
|||
search: `"${savedVis.vis.params.index_pattern}"`,
|
||||
searchFields: ['title'],
|
||||
});
|
||||
const [indexPattern] = indexPatternObjects.savedObjects.map(getFromSavedObject);
|
||||
const [indexPattern] = indexPatternObjects.savedObjects.map(indexPatterns.getFromSavedObject);
|
||||
return indexPattern;
|
||||
}
|
||||
|
||||
const savedObject = await savedObjectsClient.get('index-pattern', defaultIndex);
|
||||
return getFromSavedObject(savedObject);
|
||||
return indexPatterns.getFromSavedObject(savedObject);
|
||||
}
|
||||
|
|
|
@ -375,6 +375,8 @@ export class VisualizeEmbeddable extends Embeddable<VisualizeInput, VisualizeOut
|
|||
if (this.handler) {
|
||||
this.handler.update(this.expression, expressionParams);
|
||||
}
|
||||
|
||||
this.vis.emit('apply');
|
||||
}
|
||||
|
||||
private handleVisUpdate = async () => {
|
||||
|
|
|
@ -17,37 +17,49 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import 'uiExports/contextMenuActions';
|
||||
import 'uiExports/devTools';
|
||||
import 'uiExports/docViews';
|
||||
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/visTypes';
|
||||
import 'uiExports/visualize';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
|
||||
import { Legacy } from 'kibana';
|
||||
|
||||
import { SavedObjectAttributes } from 'kibana/server';
|
||||
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';
|
||||
import { getIndexPattern } from './get_index_pattern';
|
||||
import { VisualizeEmbeddable, VisualizeInput, VisualizeOutput } from './visualize_embeddable';
|
||||
import {
|
||||
VisualizeEmbeddable,
|
||||
VisualizeInput,
|
||||
VisualizeOutput,
|
||||
VisSavedObject,
|
||||
} from './visualize_embeddable';
|
||||
import { VISUALIZE_EMBEDDABLE_TYPE } from './constants';
|
||||
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
|
||||
|
||||
import {
|
||||
getServices,
|
||||
Container,
|
||||
EmbeddableFactory,
|
||||
EmbeddableOutput,
|
||||
ErrorEmbeddable,
|
||||
VisSavedObject,
|
||||
} from '../kibana_services';
|
||||
|
||||
const {
|
||||
addBasePath,
|
||||
capabilities,
|
||||
embeddable,
|
||||
getInjector,
|
||||
uiSettings,
|
||||
visualizations,
|
||||
} = getServices();
|
||||
|
||||
interface VisualizationAttributes extends SavedObjectAttributes {
|
||||
visState: string;
|
||||
}
|
||||
|
@ -96,7 +108,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
|
|||
if (!visType) {
|
||||
return false;
|
||||
}
|
||||
if (uiSettings.get('visualize:enableLabs')) {
|
||||
if (npStart.core.uiSettings.get('visualize:enableLabs')) {
|
||||
return true;
|
||||
}
|
||||
return visType.stage !== 'experimental';
|
||||
|
@ -108,7 +120,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
|
|||
}
|
||||
|
||||
public isEditable() {
|
||||
return capabilities.visualize.save as boolean;
|
||||
return npStart.core.application.capabilities.visualize.save as boolean;
|
||||
}
|
||||
|
||||
public getDisplayName() {
|
||||
|
@ -122,14 +134,16 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
|
|||
input: Partial<VisualizeInput> & { id: string },
|
||||
parent?: Container
|
||||
): Promise<VisualizeEmbeddable | ErrorEmbeddable | DisabledLabEmbeddable> {
|
||||
const $injector = await getInjector();
|
||||
const $injector = await chrome.dangerouslyGetActiveInjector();
|
||||
const config = $injector.get<Legacy.KibanaConfig>('config');
|
||||
const savedVisualizations = $injector.get<SavedVisualizations>('savedVisualizations');
|
||||
|
||||
try {
|
||||
const visId = savedObject.id as string;
|
||||
|
||||
const editUrl = visId ? addBasePath(`/app/kibana${savedVisualizations.urlFor(visId)}`) : '';
|
||||
const editUrl = visId
|
||||
? npStart.core.http.basePath.prepend(`/app/kibana${savedVisualizations.urlFor(visId)}`)
|
||||
: '';
|
||||
const isLabsEnabled = config.get<boolean>('visualize:enableLabs');
|
||||
|
||||
if (!isLabsEnabled && savedObject.vis.type.stage === 'experimental') {
|
||||
|
@ -161,7 +175,7 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
|
|||
input: Partial<VisualizeInput> & { id: string },
|
||||
parent?: Container
|
||||
): Promise<VisualizeEmbeddable | ErrorEmbeddable | DisabledLabEmbeddable> {
|
||||
const $injector = await getInjector();
|
||||
const $injector = await chrome.dangerouslyGetActiveInjector();
|
||||
const savedVisualizations = $injector.get<SavedVisualizations>('savedVisualizations');
|
||||
|
||||
try {
|
||||
|
@ -179,14 +193,15 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory<
|
|||
// TODO: This is a bit of a hack to preserve the original functionality. Ideally we will clean this up
|
||||
// to allow for in place creation of visualizations without having to navigate away to a new URL.
|
||||
if (this.visTypes) {
|
||||
showNewVisModal(this.visTypes, {
|
||||
editorParams: ['addToDashboard'],
|
||||
});
|
||||
showNewVisModal(
|
||||
this.visTypes,
|
||||
{
|
||||
editorParams: ['addToDashboard'],
|
||||
},
|
||||
npStart.core.http.basePath.prepend,
|
||||
npStart.core.uiSettings
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
VisualizeEmbeddableFactory.createVisualizeEmbeddableFactory().then(embeddableFactory => {
|
||||
embeddable.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 { State } from './legacy_imports';
|
||||
import { DataPublicPluginStart as DataStart } from '../../../../../plugins/data/public';
|
||||
|
||||
/**
|
||||
* Helper function to sync the global state with the various state providers
|
||||
* when a local angular application mounts. There are three different ways
|
||||
* global state can be passed into the application:
|
||||
* * parameter in the URL hash - e.g. shared link
|
||||
* * in-memory state in the data plugin exports (timefilter and filterManager) - e.g. default values
|
||||
*
|
||||
* This function looks up the three sources (earlier in the list means it takes precedence),
|
||||
* puts it into the globalState object and syncs it with the url.
|
||||
*
|
||||
* Currently the legacy chrome takes care of restoring the global state when navigating from
|
||||
* one app to another - to migrate away from that it will become necessary to also write the current
|
||||
* state to local storage
|
||||
*/
|
||||
export function syncOnMount(
|
||||
globalState: State,
|
||||
{
|
||||
query: {
|
||||
filterManager,
|
||||
timefilter: { timefilter },
|
||||
},
|
||||
}: DataStart
|
||||
) {
|
||||
// pull in global state information from the URL
|
||||
globalState.fetch();
|
||||
// remember whether there were info in the URL
|
||||
const hasGlobalURLState = Boolean(Object.keys(globalState.toObject()).length);
|
||||
|
||||
// sync kibana platform state with the angular global state
|
||||
if (!globalState.time) {
|
||||
globalState.time = timefilter.getTime();
|
||||
}
|
||||
if (!globalState.refreshInterval) {
|
||||
globalState.refreshInterval = timefilter.getRefreshInterval();
|
||||
}
|
||||
if (!globalState.filters && filterManager.getGlobalFilters().length > 0) {
|
||||
globalState.filters = filterManager.getGlobalFilters();
|
||||
}
|
||||
// only inject cross app global state if there is none in the url itself (that takes precedence)
|
||||
if (hasGlobalURLState) {
|
||||
// set flag the global state is set from the URL
|
||||
globalState.$inheritedGlobalState = true;
|
||||
}
|
||||
globalState.save();
|
||||
}
|
|
@ -18,10 +18,8 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getServices } from '../kibana_services';
|
||||
const { docLinks } = getServices();
|
||||
|
||||
export function addHelpMenuToAppChrome(chrome) {
|
||||
export function addHelpMenuToAppChrome(chrome, docLinks) {
|
||||
chrome.setHelpExtension({
|
||||
appName: i18n.translate('kbn.visualize.helpMenu.appName', {
|
||||
defaultMessage: 'Visualize',
|
||||
|
|
|
@ -1,89 +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 { ensureDefaultIndexPattern } from 'ui/legacy_compat';
|
||||
import './editor/editor';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import './saved_visualizations/_saved_vis';
|
||||
import './saved_visualizations/saved_visualizations';
|
||||
import visualizeListingTemplate from './listing/visualize_listing.html';
|
||||
import { VisualizeListingController } from './listing/visualize_listing';
|
||||
import { VisualizeConstants } from './visualize_constants';
|
||||
import { getLandingBreadcrumbs, getWizardStep1Breadcrumbs } from './breadcrumbs';
|
||||
|
||||
import { getServices, FeatureCatalogueCategory } from './kibana_services';
|
||||
|
||||
const { FeatureCatalogueRegistryProvider, uiRoutes } = getServices();
|
||||
|
||||
uiRoutes
|
||||
.defaults(/visualize/, {
|
||||
requireUICapability: 'visualize.show',
|
||||
badge: uiCapabilities => {
|
||||
if (uiCapabilities.visualize.save) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
text: i18n.translate('kbn.visualize.badge.readOnly.text', {
|
||||
defaultMessage: 'Read only',
|
||||
}),
|
||||
tooltip: i18n.translate('kbn.visualize.badge.readOnly.tooltip', {
|
||||
defaultMessage: 'Unable to save visualizations',
|
||||
}),
|
||||
iconType: 'glasses'
|
||||
};
|
||||
}
|
||||
})
|
||||
.when(VisualizeConstants.LANDING_PAGE_PATH, {
|
||||
template: visualizeListingTemplate,
|
||||
k7Breadcrumbs: getLandingBreadcrumbs,
|
||||
controller: VisualizeListingController,
|
||||
controllerAs: 'listingController',
|
||||
resolve: {
|
||||
createNewVis: () => false,
|
||||
hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(getServices().core, getServices().npData, $rootScope, kbnUrl)
|
||||
},
|
||||
})
|
||||
.when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
|
||||
template: visualizeListingTemplate,
|
||||
k7Breadcrumbs: getWizardStep1Breadcrumbs,
|
||||
controller: VisualizeListingController,
|
||||
controllerAs: 'listingController',
|
||||
resolve: {
|
||||
createNewVis: () => true,
|
||||
hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(getServices().core, getServices().npData, $rootScope, kbnUrl)
|
||||
},
|
||||
});
|
||||
|
||||
FeatureCatalogueRegistryProvider.register(() => {
|
||||
return {
|
||||
id: 'visualize',
|
||||
title: 'Visualize',
|
||||
description: i18n.translate(
|
||||
'kbn.visualize.visualizeDescription',
|
||||
{
|
||||
defaultMessage: 'Create visualizations and aggregate data stores in your Elasticsearch indices.',
|
||||
}
|
||||
),
|
||||
icon: 'visualizeApp',
|
||||
path: `/app/kibana#${VisualizeConstants.LANDING_PAGE_PATH}`,
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.DATA
|
||||
};
|
||||
});
|
70
src/legacy/core_plugins/kibana/public/visualize/index.ts
Normal file
70
src/legacy/core_plugins/kibana/public/visualize/index.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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/collapsible_sidebar'; // used in default editor
|
||||
import 'ui/vis/editors/default/sidebar';
|
||||
|
||||
import {
|
||||
IPrivate,
|
||||
legacyChrome,
|
||||
npSetup,
|
||||
npStart,
|
||||
SavedObjectRegistryProvider,
|
||||
VisEditorTypesRegistryProvider,
|
||||
} from './legacy_imports';
|
||||
import { VisualizePlugin, LegacyAngularInjectedDependencies } from './plugin';
|
||||
import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy';
|
||||
import { start as navigation } from '../../../navigation/public/legacy';
|
||||
import { start as visualizations } from '../../../visualizations/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 getAngularDependencies(): Promise<LegacyAngularInjectedDependencies> {
|
||||
const injector = await legacyChrome.dangerouslyGetActiveInjector();
|
||||
|
||||
const Private = injector.get<IPrivate>('Private');
|
||||
|
||||
const editorTypes = Private(VisEditorTypesRegistryProvider);
|
||||
const savedObjectRegistry = Private(SavedObjectRegistryProvider);
|
||||
|
||||
return {
|
||||
legacyChrome,
|
||||
editorTypes,
|
||||
savedObjectRegistry,
|
||||
savedVisualizations: injector.get('savedVisualizations'),
|
||||
};
|
||||
}
|
||||
|
||||
(() => {
|
||||
const instance = new VisualizePlugin();
|
||||
instance.setup(npSetup.core, {
|
||||
...npSetup.plugins,
|
||||
__LEGACY: {
|
||||
getAngularDependencies,
|
||||
},
|
||||
});
|
||||
instance.start(npStart.core, {
|
||||
...npStart.plugins,
|
||||
embeddables,
|
||||
navigation,
|
||||
visualizations,
|
||||
});
|
||||
})();
|
|
@ -17,108 +17,59 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import 'angular-sanitize'; // used in visualization_editor.js and visualization.js
|
||||
import 'ui/collapsible_sidebar'; // used in default editor
|
||||
import 'ui/vis/editors/default/sidebar';
|
||||
// load directives
|
||||
import '../../../data/public';
|
||||
import {
|
||||
ChromeStart,
|
||||
LegacyCoreStart,
|
||||
SavedObjectsClientContract,
|
||||
ToastsStart,
|
||||
IUiSettingsClient,
|
||||
} from 'kibana/public';
|
||||
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import angular from 'angular'; // just used in editor.js
|
||||
import chromeLegacy from 'ui/chrome';
|
||||
import { NavigationStart } from '../../../navigation/public';
|
||||
import { Storage } from '../../../../../plugins/kibana_utils/public';
|
||||
import { IEmbeddableStart } from '../../../../../plugins/embeddable/public';
|
||||
import { SharePluginStart } from '../../../../../plugins/share/public';
|
||||
import { DataPublicPluginStart, IndexPatternsContract } from '../../../../../plugins/data/public';
|
||||
import { VisualizationsStart } from '../../../visualizations/public';
|
||||
import { SavedVisualizations } from './types';
|
||||
|
||||
import uiRoutes from 'ui/routes';
|
||||
export interface VisualizeKibanaServices {
|
||||
addBasePath: (url: string) => string;
|
||||
chrome: ChromeStart;
|
||||
core: LegacyCoreStart;
|
||||
data: DataPublicPluginStart;
|
||||
editorTypes: any;
|
||||
embeddables: IEmbeddableStart;
|
||||
getBasePath: () => string;
|
||||
indexPatterns: IndexPatternsContract;
|
||||
legacyChrome: any;
|
||||
localStorage: Storage;
|
||||
navigation: NavigationStart;
|
||||
toastNotifications: ToastsStart;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
savedObjectRegistry: any;
|
||||
savedQueryService: DataPublicPluginStart['query']['savedQueries'];
|
||||
savedVisualizations: SavedVisualizations;
|
||||
share: SharePluginStart;
|
||||
uiSettings: IUiSettingsClient;
|
||||
visualizeCapabilities: any;
|
||||
visualizations: VisualizationsStart;
|
||||
}
|
||||
|
||||
// @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';
|
||||
|
||||
// Saved objects
|
||||
import { SavedObjectsClientProvider } from 'ui/saved_objects';
|
||||
// @ts-ignore
|
||||
import { SavedObject, 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';
|
||||
import { start as embeddables } from '../../../../core_plugins/embeddable_api/public/np_ready/public/legacy';
|
||||
import { start as data } from '../../../data/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,
|
||||
getBasePath: npStart.core.http.basePath.get,
|
||||
savedObjectsClient: npStart.core.savedObjects.client,
|
||||
toastNotifications: npStart.core.notifications.toasts,
|
||||
uiSettings: npStart.core.uiSettings,
|
||||
core: npStart.core,
|
||||
|
||||
share: npStart.plugins.share,
|
||||
npData: npStart.plugins.data,
|
||||
data,
|
||||
embeddables,
|
||||
visualizations,
|
||||
|
||||
// legacy
|
||||
chromeLegacy,
|
||||
docTitle,
|
||||
FeatureCatalogueRegistryProvider,
|
||||
FilterBarQueryFilterProvider,
|
||||
getInjector: () => {
|
||||
return chromeLegacy.dangerouslyGetActiveInjector();
|
||||
},
|
||||
SavedObjectProvider,
|
||||
SavedObjectRegistryProvider,
|
||||
SavedObjectsClientProvider,
|
||||
timefilter: npStart.plugins.data.query.timefilter.timefilter,
|
||||
uiModules,
|
||||
uiRoutes,
|
||||
wrapInI18nContext,
|
||||
|
||||
createUiStatsReporter,
|
||||
};
|
||||
let services: VisualizeKibanaServices | null = null;
|
||||
export function setServices(newServices: VisualizeKibanaServices) {
|
||||
services = newServices;
|
||||
}
|
||||
|
||||
export function getServices() {
|
||||
if (!services) {
|
||||
throw new Error(
|
||||
'Kibana services not set - are you trying to import this module from outside of the visualize app?'
|
||||
);
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
// export legacy static dependencies
|
||||
export { angular };
|
||||
export { getFromSavedObject } from 'ui/index_patterns';
|
||||
export { PersistedState } from 'ui/persisted_state';
|
||||
// @ts-ignore
|
||||
export { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
|
||||
export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
|
||||
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 { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
|
||||
export { unhashUrl } from '../../../../../plugins/kibana_utils/public';
|
||||
export {
|
||||
Container,
|
||||
Embeddable,
|
||||
EmbeddableFactory,
|
||||
EmbeddableInput,
|
||||
EmbeddableOutput,
|
||||
ErrorEmbeddable,
|
||||
} from '../../../../../plugins/embeddable/public';
|
||||
|
||||
// export types
|
||||
export { METRIC_TYPE };
|
||||
export { AppState } from 'ui/state_management/app_state';
|
||||
export { VisType } from 'ui/vis';
|
||||
|
||||
// export const
|
||||
export { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
|
||||
|
||||
export { VisSavedObject } from './embeddable/visualize_embeddable';
|
||||
export function clearServices() {
|
||||
services = null;
|
||||
}
|
||||
|
|
169
src/legacy/core_plugins/kibana/public/visualize/legacy_app.js
Normal file
169
src/legacy/core_plugins/kibana/public/visualize/legacy_app.js
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* 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 { find } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import editorTemplate from './editor/editor.html';
|
||||
import visualizeListingTemplate from './listing/visualize_listing.html';
|
||||
|
||||
import { initVisualizeAppDirective } from './visualize_app';
|
||||
import { VisualizeConstants } from './visualize_constants';
|
||||
import { VisualizeListingController } from './listing/visualize_listing';
|
||||
import { ensureDefaultIndexPattern, registerTimefilterWithGlobalStateFactory } from './legacy_imports';
|
||||
import { syncOnMount } from './global_state_sync';
|
||||
|
||||
import {
|
||||
getLandingBreadcrumbs,
|
||||
getWizardStep1Breadcrumbs,
|
||||
getCreateBreadcrumbs,
|
||||
getEditBreadcrumbs
|
||||
} from './breadcrumbs';
|
||||
|
||||
export function initVisualizeApp(app, deps) {
|
||||
initVisualizeAppDirective(app, deps);
|
||||
|
||||
app.run(globalState => {
|
||||
syncOnMount(globalState, deps.data);
|
||||
});
|
||||
|
||||
app.run((globalState, $rootScope) => {
|
||||
registerTimefilterWithGlobalStateFactory(
|
||||
deps.data.query.timefilter.timefilter,
|
||||
globalState,
|
||||
$rootScope
|
||||
);
|
||||
});
|
||||
|
||||
app.config(function ($routeProvider) {
|
||||
const defaults = {
|
||||
reloadOnSearch: false,
|
||||
requireUICapability: 'visualize.show',
|
||||
badge: () => {
|
||||
if (deps.visualizeCapabilities.save) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
text: i18n.translate('kbn.visualize.badge.readOnly.text', {
|
||||
defaultMessage: 'Read only',
|
||||
}),
|
||||
tooltip: i18n.translate('kbn.visualize.badge.readOnly.tooltip', {
|
||||
defaultMessage: 'Unable to save visualizations',
|
||||
}),
|
||||
iconType: 'glasses',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
$routeProvider
|
||||
.when(VisualizeConstants.LANDING_PAGE_PATH, {
|
||||
...defaults,
|
||||
template: visualizeListingTemplate,
|
||||
k7Breadcrumbs: getLandingBreadcrumbs,
|
||||
controller: VisualizeListingController,
|
||||
controllerAs: 'listingController',
|
||||
resolve: {
|
||||
createNewVis: () => false,
|
||||
hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl),
|
||||
},
|
||||
})
|
||||
.when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
|
||||
...defaults,
|
||||
template: visualizeListingTemplate,
|
||||
k7Breadcrumbs: getWizardStep1Breadcrumbs,
|
||||
controller: VisualizeListingController,
|
||||
controllerAs: 'listingController',
|
||||
resolve: {
|
||||
createNewVis: () => true,
|
||||
hasDefaultIndex: ($rootScope, kbnUrl) => ensureDefaultIndexPattern(deps.core, deps.data, $rootScope, kbnUrl),
|
||||
},
|
||||
})
|
||||
.when(VisualizeConstants.CREATE_PATH, {
|
||||
...defaults,
|
||||
template: editorTemplate,
|
||||
k7Breadcrumbs: getCreateBreadcrumbs,
|
||||
resolve: {
|
||||
savedVis: function (redirectWhenMissing, $route, $rootScope, kbnUrl) {
|
||||
const { core, data, savedVisualizations, visualizations } = deps;
|
||||
const visTypes = visualizations.types.all();
|
||||
const visType = find(visTypes, { name: $route.current.params.type });
|
||||
const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection;
|
||||
const hasIndex = $route.current.params.indexPattern || $route.current.params.savedSearchId;
|
||||
if (shouldHaveIndex && !hasIndex) {
|
||||
throw new Error(
|
||||
i18n.translate('kbn.visualize.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage', {
|
||||
defaultMessage: 'You must provide either an indexPattern or a savedSearchId',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl).then(() => savedVisualizations.get($route.current.params))
|
||||
.then(savedVis => {
|
||||
if (savedVis.vis.type.setup) {
|
||||
return savedVis.vis.type.setup(savedVis)
|
||||
.catch(() => savedVis);
|
||||
}
|
||||
return savedVis;
|
||||
})
|
||||
.catch(redirectWhenMissing({
|
||||
'*': '/visualize'
|
||||
}));
|
||||
}
|
||||
}
|
||||
})
|
||||
.when(`${VisualizeConstants.EDIT_PATH}/:id`, {
|
||||
...defaults,
|
||||
template: editorTemplate,
|
||||
k7Breadcrumbs: getEditBreadcrumbs,
|
||||
resolve: {
|
||||
savedVis: function (redirectWhenMissing, $route, $rootScope, kbnUrl) {
|
||||
const { chrome, core, data, savedVisualizations } = deps;
|
||||
return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl)
|
||||
.then(() => savedVisualizations.get($route.current.params.id))
|
||||
.then(savedVis => {
|
||||
chrome.recentlyAccessed.add(
|
||||
savedVis.getFullPath(),
|
||||
savedVis.title,
|
||||
savedVis.id
|
||||
);
|
||||
return savedVis;
|
||||
})
|
||||
.then(savedVis => {
|
||||
if (savedVis.vis.type.setup) {
|
||||
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
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
.when(`visualize/:tail*?`, {
|
||||
redirectTo: `/${deps.core.injectedMetadata.getInjectedVar('kbnDefaultAppId')}`,
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The imports in this file are static functions and types which still live in legacy folders and are used
|
||||
* within dashboard. To consolidate them all in one place, they are re-exported from this file. Eventually
|
||||
* this list should become empty. Imports from the top level of shimmed or moved plugins can be imported
|
||||
* directly where they are needed.
|
||||
*/
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
export const legacyChrome = chrome;
|
||||
|
||||
// @ts-ignore
|
||||
export { AppState, AppStateProvider } from 'ui/state_management/app_state';
|
||||
export { State } from 'ui/state_management/state';
|
||||
// @ts-ignore
|
||||
export { GlobalStateProvider } from 'ui/state_management/global_state';
|
||||
// @ts-ignore
|
||||
export { StateManagementConfigProvider } from 'ui/state_management/config_provider';
|
||||
export { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
|
||||
export { PersistedState } from 'ui/persisted_state';
|
||||
|
||||
export { npSetup, npStart } from 'ui/new_platform';
|
||||
export { IPrivate } from 'ui/private';
|
||||
// @ts-ignore
|
||||
export { PrivateProvider } from 'ui/private/private';
|
||||
|
||||
export { SavedObjectRegistryProvider } from 'ui/saved_objects';
|
||||
export { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_save_modal';
|
||||
export { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
|
||||
export { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal';
|
||||
|
||||
export { subscribeWithScope } from 'ui/utils/subscribe_with_scope';
|
||||
export { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query';
|
||||
// @ts-ignore
|
||||
export { EventsProvider } from 'ui/events';
|
||||
// @ts-ignore
|
||||
export { createTopNavDirective, createTopNavHelper } from 'ui/kbn_top_nav/kbn_top_nav';
|
||||
// @ts-ignore
|
||||
export { PromiseServiceCreator } from 'ui/promises/promises';
|
||||
// @ts-ignore
|
||||
export { confirmModalFactory } from 'ui/modals/confirm_modal';
|
||||
export { configureAppAngularModule, ensureDefaultIndexPattern } from 'ui/legacy_compat';
|
||||
export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router';
|
||||
// @ts-ignore
|
||||
export { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
|
||||
|
||||
// @ts-ignore
|
||||
export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
|
||||
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
|
||||
export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
|
||||
|
||||
// @ts-ignore
|
||||
export { defaultEditor } from 'ui/vis/editors/default/default';
|
||||
export { VisType } from 'ui/vis';
|
||||
export { wrapInI18nContext } from 'ui/i18n';
|
||||
|
||||
export { VisSavedObject } from './embeddable/visualize_embeddable';
|
|
@ -14,6 +14,8 @@
|
|||
is-open="listingController.showNewVisModal"
|
||||
on-close="listingController.closeNewVisModal"
|
||||
vis-types-registry="listingController.visTypeRegistry"
|
||||
add-base-path="listingController.addBasePath"
|
||||
ui-settings="listingController.uiSettings"
|
||||
></new-vis-modal>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -24,36 +24,46 @@ import { VisualizeConstants } from '../visualize_constants';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { getServices } from '../kibana_services';
|
||||
import { wrapInI18nContext } from '../legacy_imports';
|
||||
|
||||
const {
|
||||
addBasePath,
|
||||
chrome,
|
||||
chromeLegacy,
|
||||
SavedObjectRegistryProvider,
|
||||
SavedObjectsClientProvider,
|
||||
timefilter,
|
||||
toastNotifications,
|
||||
uiModules,
|
||||
wrapInI18nContext,
|
||||
visualizations,
|
||||
} = getServices();
|
||||
|
||||
const app = uiModules.get('app/visualize', ['ngRoute', 'react']);
|
||||
app.directive('visualizeListingTable', reactDirective =>
|
||||
reactDirective(wrapInI18nContext(VisualizeListingTable))
|
||||
);
|
||||
app.directive('newVisModal', reactDirective => reactDirective(wrapInI18nContext(NewVisModal)));
|
||||
export function initListingDirective(app) {
|
||||
app.directive('visualizeListingTable', reactDirective => reactDirective(wrapInI18nContext(VisualizeListingTable)));
|
||||
app.directive('newVisModal', reactDirective =>
|
||||
reactDirective(wrapInI18nContext(NewVisModal), [
|
||||
['visTypesRegistry', { watchDepth: 'collection' }],
|
||||
['onClose', { watchDepth: 'reference' }],
|
||||
['addBasePath', { watchDepth: 'reference' }],
|
||||
['uiSettings', { watchDepth: 'reference' }],
|
||||
'isOpen',
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
export function VisualizeListingController($injector, createNewVis) {
|
||||
const Private = $injector.get('Private');
|
||||
const config = $injector.get('config');
|
||||
const {
|
||||
addBasePath,
|
||||
chrome,
|
||||
legacyChrome,
|
||||
savedObjectRegistry,
|
||||
savedObjectsClient,
|
||||
data: {
|
||||
query: {
|
||||
timefilter: { timefilter },
|
||||
},
|
||||
},
|
||||
toastNotifications,
|
||||
uiSettings,
|
||||
visualizations,
|
||||
core: { docLinks },
|
||||
} = getServices();
|
||||
const kbnUrl = $injector.get('kbnUrl');
|
||||
const savedObjectClient = Private(SavedObjectsClientProvider);
|
||||
|
||||
timefilter.disableAutoRefreshSelector();
|
||||
timefilter.disableTimeRangeSelector();
|
||||
|
||||
this.showNewVisModal = false;
|
||||
this.addBasePath = addBasePath;
|
||||
this.uiSettings = uiSettings;
|
||||
|
||||
this.createNewVis = () => {
|
||||
this.showNewVisModal = true;
|
||||
|
@ -82,14 +92,14 @@ export function VisualizeListingController($injector, createNewVis) {
|
|||
}
|
||||
|
||||
// TODO: Extract this into an external service.
|
||||
const services = Private(SavedObjectRegistryProvider).byLoaderPropertiesName;
|
||||
const services = savedObjectRegistry.byLoaderPropertiesName;
|
||||
const visualizationService = services.visualizations;
|
||||
this.visTypeRegistry = visualizations.types;
|
||||
|
||||
this.fetchItems = filter => {
|
||||
const isLabsEnabled = config.get('visualize:enableLabs');
|
||||
const isLabsEnabled = uiSettings.get('visualize:enableLabs');
|
||||
return visualizationService
|
||||
.findListItems(filter, config.get('savedObjects:listingLimit'))
|
||||
.findListItems(filter, uiSettings.get('savedObjects:listingLimit'))
|
||||
.then(result => {
|
||||
this.totalItems = result.total;
|
||||
|
||||
|
@ -103,11 +113,11 @@ export function VisualizeListingController($injector, createNewVis) {
|
|||
this.deleteSelectedItems = function deleteSelectedItems(selectedItems) {
|
||||
return Promise.all(
|
||||
selectedItems.map(item => {
|
||||
return savedObjectClient.delete(item.savedObjectType, item.id);
|
||||
return savedObjectsClient.delete(item.savedObjectType, item.id);
|
||||
})
|
||||
)
|
||||
.then(() => {
|
||||
chromeLegacy.untrackNavLinksForDeletedSavedObjects(selectedItems.map(item => item.id));
|
||||
legacyChrome.untrackNavLinksForDeletedSavedObjects(selectedItems.map(item => item.id));
|
||||
})
|
||||
.catch(error => {
|
||||
toastNotifications.addError(error, {
|
||||
|
@ -126,7 +136,7 @@ export function VisualizeListingController($injector, createNewVis) {
|
|||
},
|
||||
]);
|
||||
|
||||
this.listingLimit = config.get('savedObjects:listingLimit');
|
||||
this.listingLimit = uiSettings.get('savedObjects:listingLimit');
|
||||
|
||||
addHelpMenuToAppChrome(chrome);
|
||||
addHelpMenuToAppChrome(chrome, docLinks);
|
||||
}
|
||||
|
|
|
@ -27,22 +27,21 @@ import { EuiIcon, EuiBetaBadge, EuiLink, EuiButton, EuiEmptyPrompt } from '@elas
|
|||
|
||||
import { getServices } from '../kibana_services';
|
||||
|
||||
const { capabilities, toastNotifications, uiSettings } = getServices();
|
||||
|
||||
class VisualizeListingTable extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { visualizeCapabilities, uiSettings, toastNotifications } = getServices();
|
||||
return (
|
||||
<TableListView
|
||||
// we allow users to create visualizations even if they can't save them
|
||||
// for data exploration purposes
|
||||
createItem={this.props.createItem}
|
||||
findItems={this.props.findItems}
|
||||
deleteItems={capabilities.visualize.delete ? this.props.deleteItems : null}
|
||||
editItem={capabilities.visualize.save ? this.props.editItem : null}
|
||||
deleteItems={visualizeCapabilities.delete ? this.props.deleteItems : null}
|
||||
editItem={visualizeCapabilities.save ? this.props.editItem : null}
|
||||
tableColumns={this.getTableColumns()}
|
||||
listingLimit={this.props.listingLimit}
|
||||
selectable={item => item.canDelete}
|
||||
|
|
161
src/legacy/core_plugins/kibana/public/visualize/plugin.ts
Normal file
161
src/legacy/core_plugins/kibana/public/visualize/plugin.ts
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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 {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
LegacyCoreStart,
|
||||
Plugin,
|
||||
SavedObjectsClientContract,
|
||||
} from 'kibana/public';
|
||||
|
||||
import { Storage } from '../../../../../plugins/kibana_utils/public';
|
||||
import { DataPublicPluginStart } from '../../../../../plugins/data/public';
|
||||
import { IEmbeddableStart } from '../../../../../plugins/embeddable/public';
|
||||
import { NavigationStart } from '../../../navigation/public';
|
||||
import { SharePluginStart } from '../../../../../plugins/share/public';
|
||||
import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public';
|
||||
import { VisualizationsStart } from '../../../visualizations/public';
|
||||
import { VisualizeEmbeddableFactory } from './embeddable/visualize_embeddable_factory';
|
||||
import { VISUALIZE_EMBEDDABLE_TYPE } from './embeddable/constants';
|
||||
import { VisualizeConstants } from './visualize_constants';
|
||||
import { setServices, VisualizeKibanaServices } from './kibana_services';
|
||||
import {
|
||||
FeatureCatalogueCategory,
|
||||
HomePublicPluginSetup,
|
||||
} from '../../../../../plugins/home/public';
|
||||
import { defaultEditor, VisEditorTypesRegistryProvider } from './legacy_imports';
|
||||
import { SavedVisualizations } from './types';
|
||||
|
||||
export interface LegacyAngularInjectedDependencies {
|
||||
legacyChrome: any;
|
||||
editorTypes: any;
|
||||
savedObjectRegistry: any;
|
||||
savedVisualizations: SavedVisualizations;
|
||||
}
|
||||
|
||||
export interface VisualizePluginStartDependencies {
|
||||
data: DataPublicPluginStart;
|
||||
embeddables: IEmbeddableStart;
|
||||
navigation: NavigationStart;
|
||||
share: SharePluginStart;
|
||||
visualizations: VisualizationsStart;
|
||||
}
|
||||
|
||||
export interface VisualizePluginSetupDependencies {
|
||||
__LEGACY: {
|
||||
getAngularDependencies: () => Promise<LegacyAngularInjectedDependencies>;
|
||||
};
|
||||
home: HomePublicPluginSetup;
|
||||
kibana_legacy: KibanaLegacySetup;
|
||||
}
|
||||
|
||||
export class VisualizePlugin implements Plugin {
|
||||
private startDependencies: {
|
||||
data: DataPublicPluginStart;
|
||||
embeddables: IEmbeddableStart;
|
||||
navigation: NavigationStart;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
share: SharePluginStart;
|
||||
visualizations: VisualizationsStart;
|
||||
} | null = null;
|
||||
|
||||
public async setup(
|
||||
core: CoreSetup,
|
||||
{ home, kibana_legacy, __LEGACY: { getAngularDependencies } }: VisualizePluginSetupDependencies
|
||||
) {
|
||||
kibana_legacy.registerLegacyApp({
|
||||
id: 'visualize',
|
||||
title: 'Visualize',
|
||||
mount: async ({ core: contextCore }, params) => {
|
||||
if (this.startDependencies === null) {
|
||||
throw new Error('not started yet');
|
||||
}
|
||||
|
||||
const {
|
||||
savedObjectsClient,
|
||||
embeddables,
|
||||
navigation,
|
||||
visualizations,
|
||||
data,
|
||||
share,
|
||||
} = this.startDependencies;
|
||||
|
||||
const angularDependencies = await getAngularDependencies();
|
||||
const deps: VisualizeKibanaServices = {
|
||||
...angularDependencies,
|
||||
addBasePath: contextCore.http.basePath.prepend,
|
||||
core: contextCore as LegacyCoreStart,
|
||||
chrome: contextCore.chrome,
|
||||
data,
|
||||
embeddables,
|
||||
getBasePath: core.http.basePath.get,
|
||||
indexPatterns: data.indexPatterns,
|
||||
localStorage: new Storage(localStorage),
|
||||
navigation,
|
||||
savedObjectsClient,
|
||||
savedQueryService: data.query.savedQueries,
|
||||
share,
|
||||
toastNotifications: contextCore.notifications.toasts,
|
||||
uiSettings: contextCore.uiSettings,
|
||||
visualizeCapabilities: contextCore.application.capabilities.visualize,
|
||||
visualizations,
|
||||
};
|
||||
setServices(deps);
|
||||
|
||||
const { renderApp } = await import('./application');
|
||||
return renderApp(params.element, params.appBasePath, deps);
|
||||
},
|
||||
});
|
||||
|
||||
home.featureCatalogue.register({
|
||||
id: 'visualize',
|
||||
title: 'Visualize',
|
||||
description: i18n.translate('kbn.visualize.visualizeDescription', {
|
||||
defaultMessage:
|
||||
'Create visualizations and aggregate data stores in your Elasticsearch indices.',
|
||||
}),
|
||||
icon: 'visualizeApp',
|
||||
path: `/app/kibana#${VisualizeConstants.LANDING_PAGE_PATH}`,
|
||||
showOnHomePage: true,
|
||||
category: FeatureCatalogueCategory.DATA,
|
||||
});
|
||||
|
||||
VisEditorTypesRegistryProvider.register(defaultEditor);
|
||||
}
|
||||
|
||||
public start(
|
||||
{ savedObjects: { client: savedObjectsClient } }: CoreStart,
|
||||
{ embeddables, navigation, data, share, visualizations }: VisualizePluginStartDependencies
|
||||
) {
|
||||
this.startDependencies = {
|
||||
data,
|
||||
embeddables,
|
||||
navigation,
|
||||
savedObjectsClient,
|
||||
share,
|
||||
visualizations,
|
||||
};
|
||||
|
||||
const embeddableFactory = new VisualizeEmbeddableFactory(visualizations.types);
|
||||
embeddables.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory);
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { VisSavedObject } from './kibana_services';
|
||||
import { VisSavedObject } from './legacy_imports';
|
||||
|
||||
export interface SavedVisualizations {
|
||||
urlFor: (id: string) => string;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 { IModule } from 'angular';
|
||||
import { VisualizeKibanaServices } from './kibana_services';
|
||||
|
||||
// @ts-ignore
|
||||
import { initEditorDirective } from './editor/editor';
|
||||
// @ts-ignore
|
||||
import { initListingDirective } from './listing/visualize_listing';
|
||||
|
||||
export function initVisualizeAppDirective(app: IModule, deps: VisualizeKibanaServices) {
|
||||
initEditorDirective(app, deps);
|
||||
initListingDirective(app);
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
exports[`NewVisModal filter for visualization types should render as expected 1`] = `
|
||||
<NewVisModal
|
||||
addBasePath={[Function]}
|
||||
editorParams={Array []}
|
||||
intl={
|
||||
Object {
|
||||
|
@ -107,6 +108,23 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
|
|||
}
|
||||
isOpen={true}
|
||||
onClose={[Function]}
|
||||
uiSettings={
|
||||
Object {
|
||||
"get": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"visualize:enableLabs",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
visTypesRegistry={
|
||||
Object {
|
||||
"all": [Function],
|
||||
|
@ -865,6 +883,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
|
|||
className="euiModal__flex"
|
||||
>
|
||||
<TypeSelection
|
||||
addBasePath={[Function]}
|
||||
onVisTypeSelected={[Function]}
|
||||
visTypesRegistry={
|
||||
Object {
|
||||
|
@ -1235,6 +1254,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
|
|||
/>
|
||||
</EuiSpacer>
|
||||
<NewVisHelp
|
||||
addBasePath={[Function]}
|
||||
promotedTypes={Array []}
|
||||
>
|
||||
<EuiText>
|
||||
|
@ -1287,6 +1307,7 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
|
|||
|
||||
exports[`NewVisModal should render as expected 1`] = `
|
||||
<NewVisModal
|
||||
addBasePath={[Function]}
|
||||
editorParams={Array []}
|
||||
intl={
|
||||
Object {
|
||||
|
@ -1392,6 +1413,23 @@ exports[`NewVisModal should render as expected 1`] = `
|
|||
}
|
||||
isOpen={true}
|
||||
onClose={[Function]}
|
||||
uiSettings={
|
||||
Object {
|
||||
"get": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
"visualize:enableLabs",
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"type": "return",
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
visTypesRegistry={
|
||||
Object {
|
||||
"all": [Function],
|
||||
|
@ -2141,6 +2179,7 @@ exports[`NewVisModal should render as expected 1`] = `
|
|||
className="euiModal__flex"
|
||||
>
|
||||
<TypeSelection
|
||||
addBasePath={[Function]}
|
||||
onVisTypeSelected={[Function]}
|
||||
visTypesRegistry={
|
||||
Object {
|
||||
|
@ -2499,6 +2538,7 @@ exports[`NewVisModal should render as expected 1`] = `
|
|||
/>
|
||||
</EuiSpacer>
|
||||
<NewVisHelp
|
||||
addBasePath={[Function]}
|
||||
promotedTypes={Array []}
|
||||
>
|
||||
<EuiText>
|
||||
|
|
|
@ -20,33 +20,17 @@
|
|||
import React from 'react';
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
|
||||
import { NewVisModal } from './new_vis_modal';
|
||||
import { VisType } from '../kibana_services';
|
||||
import { VisType } from '../legacy_imports';
|
||||
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(),
|
||||
};
|
||||
jest.mock('../legacy_imports', () => ({
|
||||
State: () => null,
|
||||
AppState: () => null,
|
||||
}));
|
||||
|
||||
return {
|
||||
getServices: () => mock,
|
||||
VisType: {},
|
||||
METRIC_TYPE: 'metricType',
|
||||
};
|
||||
});
|
||||
|
||||
import { getServices } from '../kibana_services';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
import { NewVisModal } from './new_vis_modal';
|
||||
|
||||
describe('NewVisModal', () => {
|
||||
const settingsGet = getServices().uiSettings.get as jest.Mock;
|
||||
|
||||
const defaultVisTypeParams = {
|
||||
hidden: false,
|
||||
visualization: class Controller {
|
||||
|
@ -76,17 +60,36 @@ describe('NewVisModal', () => {
|
|||
},
|
||||
getAliases: () => [],
|
||||
};
|
||||
const addBasePath = (url: string) => `testbasepath${url}`;
|
||||
const settingsGet = jest.fn();
|
||||
const uiSettings: any = { get: settingsGet };
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should render as expected', () => {
|
||||
const wrapper = mountWithIntl(
|
||||
<NewVisModal isOpen={true} onClose={() => null} visTypesRegistry={visTypes} />
|
||||
<NewVisModal
|
||||
isOpen={true}
|
||||
onClose={() => null}
|
||||
visTypesRegistry={visTypes}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should show a button for regular visualizations', () => {
|
||||
const wrapper = mountWithIntl(
|
||||
<NewVisModal isOpen={true} onClose={() => null} visTypesRegistry={visTypes} />
|
||||
<NewVisModal
|
||||
isOpen={true}
|
||||
onClose={() => null}
|
||||
visTypesRegistry={visTypes}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="visType-vis"]').exists()).toBe(true);
|
||||
});
|
||||
|
@ -95,7 +98,13 @@ describe('NewVisModal', () => {
|
|||
it('should open the editor for visualizations without search', () => {
|
||||
window.location.assign = jest.fn();
|
||||
const wrapper = mountWithIntl(
|
||||
<NewVisModal isOpen={true} onClose={() => null} visTypesRegistry={visTypes} />
|
||||
<NewVisModal
|
||||
isOpen={true}
|
||||
onClose={() => null}
|
||||
visTypesRegistry={visTypes}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
);
|
||||
const visButton = wrapper.find('button[data-test-subj="visType-vis"]');
|
||||
visButton.simulate('click');
|
||||
|
@ -110,6 +119,8 @@ describe('NewVisModal', () => {
|
|||
onClose={() => null}
|
||||
visTypesRegistry={visTypes}
|
||||
editorParams={['foo=true', 'bar=42']}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
);
|
||||
const visButton = wrapper.find('button[data-test-subj="visType-vis"]');
|
||||
|
@ -121,7 +132,13 @@ describe('NewVisModal', () => {
|
|||
describe('filter for visualization types', () => {
|
||||
it('should render as expected', () => {
|
||||
const wrapper = mountWithIntl(
|
||||
<NewVisModal isOpen={true} onClose={() => null} visTypesRegistry={visTypes} />
|
||||
<NewVisModal
|
||||
isOpen={true}
|
||||
onClose={() => null}
|
||||
visTypesRegistry={visTypes}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
);
|
||||
const searchBox = wrapper.find('input[data-test-subj="filterVisType"]');
|
||||
searchBox.simulate('change', { target: { value: 'with' } });
|
||||
|
@ -133,7 +150,13 @@ describe('NewVisModal', () => {
|
|||
it('should not show experimental visualizations if visualize:enableLabs is false', () => {
|
||||
settingsGet.mockReturnValue(false);
|
||||
const wrapper = mountWithIntl(
|
||||
<NewVisModal isOpen={true} onClose={() => null} visTypesRegistry={visTypes} />
|
||||
<NewVisModal
|
||||
isOpen={true}
|
||||
onClose={() => null}
|
||||
visTypesRegistry={visTypes}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(false);
|
||||
});
|
||||
|
@ -141,7 +164,13 @@ describe('NewVisModal', () => {
|
|||
it('should show experimental visualizations if visualize:enableLabs is true', () => {
|
||||
settingsGet.mockReturnValue(true);
|
||||
const wrapper = mountWithIntl(
|
||||
<NewVisModal isOpen={true} onClose={() => null} visTypesRegistry={visTypes} />
|
||||
<NewVisModal
|
||||
isOpen={true}
|
||||
onClose={() => null}
|
||||
visTypesRegistry={visTypes}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="visType-visExp"]').exists()).toBe(true);
|
||||
});
|
||||
|
|
|
@ -22,20 +22,21 @@ import React from 'react';
|
|||
import { EuiModal, EuiOverlayMask } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { IUiSettingsClient } from 'kibana/public';
|
||||
import { VisType } from '../legacy_imports';
|
||||
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, METRIC_TYPE, VisType } from '../kibana_services';
|
||||
|
||||
const { addBasePath, createUiStatsReporter, uiSettings } = getServices();
|
||||
|
||||
interface TypeSelectionProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
visTypesRegistry: TypesStart;
|
||||
editorParams?: string[];
|
||||
addBasePath: (path: string) => string;
|
||||
uiSettings: IUiSettingsClient;
|
||||
}
|
||||
|
||||
interface TypeSelectionState {
|
||||
|
@ -55,7 +56,7 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
|
|||
|
||||
constructor(props: TypeSelectionProps) {
|
||||
super(props);
|
||||
this.isLabsEnabled = uiSettings.get('visualize:enableLabs');
|
||||
this.isLabsEnabled = props.uiSettings.get('visualize:enableLabs');
|
||||
|
||||
this.state = {
|
||||
showSearchVisModal: false,
|
||||
|
@ -93,6 +94,7 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
|
|||
showExperimental={this.isLabsEnabled}
|
||||
onVisTypeSelected={this.onVisTypeSelected}
|
||||
visTypesRegistry={this.props.visTypesRegistry}
|
||||
addBasePath={this.props.addBasePath}
|
||||
/>
|
||||
</EuiModal>
|
||||
);
|
||||
|
@ -124,7 +126,7 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
|
|||
this.trackUiMetric(METRIC_TYPE.CLICK, visType.name);
|
||||
|
||||
if ('aliasUrl' in visType) {
|
||||
window.location.href = addBasePath(visType.aliasUrl);
|
||||
window.location.href = this.props.addBasePath(visType.aliasUrl);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -22,9 +22,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
|
||||
import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';
|
||||
|
||||
import { VisType } from '../../kibana_services';
|
||||
import { SavedObjectFinder, VisType } from '../../legacy_imports';
|
||||
|
||||
interface SearchSelectionProps {
|
||||
onSearchSelected: (searchId: string, searchType: string) => void;
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { IUiSettingsClient } from 'kibana/public';
|
||||
import { NewVisModal } from './new_vis_modal';
|
||||
import { TypesStart } from '../../../../visualizations/public/np_ready/public/types';
|
||||
|
||||
|
@ -30,7 +31,9 @@ interface ShowNewVisModalParams {
|
|||
|
||||
export function showNewVisModal(
|
||||
visTypeRegistry: TypesStart,
|
||||
{ editorParams = [] }: ShowNewVisModalParams = {}
|
||||
{ editorParams = [] }: ShowNewVisModalParams = {},
|
||||
addBasePath: (path: string) => string,
|
||||
uiSettings: IUiSettingsClient
|
||||
) {
|
||||
const container = document.createElement('div');
|
||||
const onClose = () => {
|
||||
|
@ -40,14 +43,16 @@ export function showNewVisModal(
|
|||
|
||||
document.body.appendChild(container);
|
||||
const element = (
|
||||
<I18nContext>
|
||||
<I18nProvider>
|
||||
<NewVisModal
|
||||
isOpen={true}
|
||||
onClose={onClose}
|
||||
visTypesRegistry={visTypeRegistry}
|
||||
editorParams={editorParams}
|
||||
addBasePath={addBasePath}
|
||||
uiSettings={uiSettings}
|
||||
/>
|
||||
</I18nContext>
|
||||
</I18nProvider>
|
||||
);
|
||||
ReactDOM.render(element, container);
|
||||
}
|
||||
|
|
|
@ -21,18 +21,6 @@ import React from 'react';
|
|||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { NewVisHelp } from './new_vis_help';
|
||||
|
||||
jest.mock('../../kibana_services', () => {
|
||||
return {
|
||||
getServices: () => ({
|
||||
addBasePath: jest.fn((url: string) => `testbasepath${url}`),
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('NewVisHelp', () => {
|
||||
it('should render as expected', () => {
|
||||
expect(
|
||||
|
@ -53,6 +41,7 @@ describe('NewVisHelp', () => {
|
|||
stage: 'production',
|
||||
},
|
||||
]}
|
||||
addBasePath={(url: string) => `testbasepath${url}`}
|
||||
/>
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
|
|
|
@ -22,10 +22,9 @@ import React, { Fragment } from 'react';
|
|||
import { EuiText, EuiButton } from '@elastic/eui';
|
||||
import { VisTypeAliasListEntry } from './type_selection';
|
||||
|
||||
import { getServices } from '../../kibana_services';
|
||||
|
||||
interface Props {
|
||||
promotedTypes: VisTypeAliasListEntry[];
|
||||
addBasePath: (path: string) => string;
|
||||
}
|
||||
|
||||
export function NewVisHelp(props: Props) {
|
||||
|
@ -43,7 +42,7 @@ export function NewVisHelp(props: Props) {
|
|||
<strong>{t.promotion!.description}</strong>
|
||||
</p>
|
||||
<EuiButton
|
||||
href={getServices().addBasePath(t.aliasUrl)}
|
||||
href={props.addBasePath(t.aliasUrl)}
|
||||
fill
|
||||
size="s"
|
||||
iconType="popout"
|
||||
|
|
|
@ -34,8 +34,8 @@ import {
|
|||
EuiSpacer,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { VisType } from '../../legacy_imports';
|
||||
import { memoizeLast } from '../../../../../visualizations/public/np_ready/public/legacy/memoize';
|
||||
import { VisType } from '../../kibana_services';
|
||||
import { VisTypeAlias } from '../../../../../visualizations/public';
|
||||
import { NewVisHelp } from './new_vis_help';
|
||||
import { VisHelpText } from './vis_help_text';
|
||||
|
@ -51,6 +51,7 @@ export interface VisTypeAliasListEntry extends VisTypeAlias {
|
|||
}
|
||||
|
||||
interface TypeSelectionProps {
|
||||
addBasePath: (path: string) => string;
|
||||
onVisTypeSelected: (visType: VisType | VisTypeAlias) => void;
|
||||
visTypesRegistry: TypesStart;
|
||||
showExperimental: boolean;
|
||||
|
@ -153,6 +154,7 @@ class TypeSelection extends React.Component<TypeSelectionProps, TypeSelectionSta
|
|||
<EuiSpacer size="m" />
|
||||
<NewVisHelp
|
||||
promotedTypes={(visTypes as VisTypeAliasListEntry[]).filter(t => t.promotion)}
|
||||
addBasePath={this.props.addBasePath}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
|
|
@ -33,12 +33,11 @@ import { keyCodes } from '@elastic/eui';
|
|||
import { parentPipelineAggHelper } from 'ui/agg_types/metrics/lib/parent_pipeline_agg_helper';
|
||||
import { DefaultEditorSize } from '../../editor_size';
|
||||
|
||||
import { VisEditorTypesRegistryProvider } from '../../../registry/vis_editor_types';
|
||||
import { AggGroupNames } from './agg_groups';
|
||||
|
||||
import { start as embeddables } from '../../../../../core_plugins/embeddable_api/public/np_ready/public/legacy';
|
||||
|
||||
const defaultEditor = function ($rootScope, $compile, getAppState) {
|
||||
const defaultEditor = function ($rootScope, $compile) {
|
||||
return class DefaultEditor {
|
||||
static key = 'default';
|
||||
|
||||
|
@ -58,7 +57,7 @@ const defaultEditor = function ($rootScope, $compile, getAppState) {
|
|||
}
|
||||
}
|
||||
|
||||
render({ uiState, timeRange, filters, query }) {
|
||||
render({ uiState, timeRange, filters, query, appState }) {
|
||||
let $scope;
|
||||
|
||||
const updateScope = () => {
|
||||
|
@ -161,7 +160,7 @@ const defaultEditor = function ($rootScope, $compile, getAppState) {
|
|||
|
||||
this._handler = await embeddables.getEmbeddableFactory('visualization').createFromObject(this.savedObj, {
|
||||
uiState: uiState,
|
||||
appState: getAppState(),
|
||||
appState,
|
||||
timeRange: timeRange,
|
||||
filters: filters || [],
|
||||
query: query,
|
||||
|
@ -195,6 +194,4 @@ const defaultEditor = function ($rootScope, $compile, getAppState) {
|
|||
};
|
||||
};
|
||||
|
||||
VisEditorTypesRegistryProvider.register(defaultEditor);
|
||||
|
||||
export { defaultEditor };
|
||||
|
|
|
@ -50,12 +50,6 @@ export const UI_EXPORT_DEFAULTS = {
|
|||
fieldFormatEditors: [
|
||||
'ui/field_editor/components/field_format_editor/register'
|
||||
],
|
||||
visEditorTypes: [
|
||||
'ui/vis/editors/default/default',
|
||||
],
|
||||
embeddableFactories: [
|
||||
'plugins/kibana/visualize/embeddable/visualize_embeddable_factory',
|
||||
],
|
||||
search: [
|
||||
'ui/courier/search_strategy/default_search_strategy',
|
||||
],
|
||||
|
|
|
@ -269,7 +269,6 @@ module.exports = function (grunt) {
|
|||
'--config', 'test/plugin_functional/config.js',
|
||||
'--bail',
|
||||
'--debug',
|
||||
'--kibana-install-dir', KIBANA_INSTALL_DIR,
|
||||
],
|
||||
}),
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'ui/autoload/all';
|
|||
import 'uiExports/visTypes';
|
||||
import 'uiExports/visResponseHandlers';
|
||||
import 'uiExports/visRequestHandlers';
|
||||
import 'uiExports/visEditorTypes';
|
||||
import 'uiExports/savedObjectTypes';
|
||||
import 'uiExports/spyModes';
|
||||
import 'uiExports/embeddableFactories';
|
||||
|
|
|
@ -18,7 +18,6 @@ import 'uiExports/contextMenuActions';
|
|||
import 'uiExports/visTypes';
|
||||
import 'uiExports/visResponseHandlers';
|
||||
import 'uiExports/visRequestHandlers';
|
||||
import 'uiExports/visEditorTypes';
|
||||
import 'uiExports/inspectorViews';
|
||||
import 'uiExports/interpreter';
|
||||
import 'uiExports/savedObjectTypes';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue